~yujiri/libsufec

b228c61e1983c603fea5e657f729d2a396d7470b — Yujiri 2 years ago e54055d
protocol update

* address wire format changed
* server-side timestamps removed
* when sending multiple copies, length is only prepended once
4 files changed, 75 insertions(+), 50 deletions(-)

M src/addr.rs
M src/crypto.rs
M src/message.rs
M src/server.rs
M src/addr.rs => src/addr.rs +26 -9
@@ 1,22 1,19 @@
use crate::prelude::*;
use serde::{ser::Serializer, de::{self, Deserializer}};

#[derive(PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
#[derive(PartialEq, Eq, Clone, Hash)]
pub struct SufecAddr {
	pub id: PublicKey,
	pub at: String,
}
impl SufecAddr {
	pub fn to_bytes(&self) -> Vec<u8> {
		let at = self.at.as_bytes();
		[self.id.0.as_ref(), &[at.len() as u8], at].concat()
		[self.id.0.as_ref(), self.at.as_bytes()].concat()
	}
	// The `usize` returned is how many bytes were consumed.
	pub fn from_bytes(bytes: &[u8]) -> Option<(Self, usize)> {
	pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
		let id = PublicKey::from_slice(bytes.get(0..PUBLICKEYBYTES)?)?;
		let at_len = *bytes.get(PUBLICKEYBYTES)? as usize;
		let at_bytes = bytes.get(PUBLICKEYBYTES+1..PUBLICKEYBYTES+1+at_len)?;
		let at = String::from_utf8(at_bytes.to_vec()).ok()?;
		Some((Self{id, at}, PUBLICKEYBYTES + 1 + at_len))
		let at = String::from_utf8(bytes[PUBLICKEYBYTES..].to_vec()).ok()?;
		Some(Self{id, at})
	}
}
impl From<SufecAddr> for String {


@@ 48,3 45,23 @@ impl Debug for SufecAddr {
		<Self as fmt::Display>::fmt(self, f)
	}
}
impl Serialize for SufecAddr {
	fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
		s.serialize_str(&self.to_string())
	}
}
impl<'de> Deserialize<'de> for SufecAddr {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<SufecAddr, D::Error> {
        deserializer.deserialize_str(AddrVisitor)
    }
}
struct AddrVisitor;
impl<'de> de::Visitor<'de> for AddrVisitor {
	type Value = SufecAddr;
	fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		formatter.write_str("a string")
	}
	fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
		Self::Value::try_from(value).map_err(|_| E::custom("not a valid sufec address"))
	}
}

M src/crypto.rs => src/crypto.rs +13 -24
@@ 2,7 2,6 @@ use crate::prelude::*;
use crate::addr::*;
use crate::account::*;
use crate::message::*;
use crate::error::*;

pub fn encrypt_message(
	account: &Account,


@@ 14,7 13,14 @@ pub fn encrypt_message(
	let shared_key = tripledh(&account.seckey, &eph_sec, recipient_id, recipient_eph);
	let nonce = gen_nonce();
	let ciphertext = seal_precomputed(&message.to_bytes(), &nonce, &shared_key);
	let concat = [&account.addr.to_bytes(), eph_pub.0.as_ref(), &nonce.0, &ciphertext].concat();
	let addr_bytes = account.addr.to_bytes();
	let concat = [
		(addr_bytes.len() as u32).to_be_bytes().as_ref(),
		&addr_bytes,
		eph_pub.0.as_ref(),
		&nonce.0,
		&ciphertext,
	].concat();
	sealedbox::seal(&concat, recipient_id)
}



@@ 25,7 31,11 @@ pub fn decrypt_message(
	old_eph: &SecretKey,
) -> Option<(SufecAddr, Message)> {
	let inner = sealedbox::open(outer, &account.addr.id, &account.seckey).ok()?;
	let (their_addr, mut offset) = SufecAddr::from_bytes(&inner)?;
	let mut offset = 0;
	let addr_len = u32::from_be_bytes(inner.get(..4)?.try_into().unwrap()) as usize;
	offset += 4;
	let their_addr = SufecAddr::from_bytes(inner.get(offset..offset+addr_len)?)?;
	offset += addr_len;
	let their_eph = inner.get(offset..offset+PUBLICKEYBYTES)?;
	let their_eph = PublicKey::from_slice(their_eph).unwrap();
	offset += PUBLICKEYBYTES;


@@ 62,24 72,3 @@ fn tripledh(
	}
	shared_key
}

pub struct EncryptedStream {
	pub stream: TcpStream,
	pub key: PrecomputedKey,
	pub nonce: Nonce,
}
impl EncryptedStream {
	pub fn send<T: AsRef<[u8]>>(&mut self, data: T) -> io::Result<()> {
		let encrypted = seal_precomputed(data.as_ref(), &self.nonce, &self.key);
		self.nonce.increment_le_inplace();
		self.stream.write_all(&encrypted)
	}
	pub fn receive(&mut self, len: usize) -> Result<Vec<u8>, ServerError> {
		let mut ciphertext_buf = vec![0; len + MACBYTES];
		self.stream.read_exact(&mut ciphertext_buf)?;
		let decrypted = open_precomputed(&ciphertext_buf, &self.nonce, &self.key)
			.map_err(|_| ServerError::DecryptionFailed)?;
		self.nonce.increment_le_inplace();
		Ok(decrypted)
	}
}

M src/message.rs => src/message.rs +7 -5
@@ 9,7 9,7 @@ pub struct Message {
	pub content: MessageContent,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Debug, Clone)]
pub enum MessageContent {
	Text(String),
}


@@ 50,17 50,19 @@ impl Message {
		bytes = &bytes[1..];
		let mut other_recipients = Vec::new();
		for _ in 0..num_other_recipients {
			let (recipient, len) = SufecAddr::from_bytes(bytes)?;
			let len = u32::from_be_bytes(bytes.get(..4)?.try_into().unwrap()) as usize;
			bytes = &bytes[4..];
			let addr = SufecAddr::from_bytes(&bytes[..len])?;
			bytes = &bytes[len..];
			other_recipients.push(recipient);
			other_recipients.push(addr);
		}
		let timestamp = u64::from_be_bytes(bytes[..8].try_into().unwrap());
		let timestamp = u64::from_be_bytes(bytes.get(..8)?.try_into().unwrap());
		bytes = &bytes[8..];
		let mut hashes = vec![];
		let num_hashes = *bytes.first()?;
		bytes = &bytes[1..];
		for _ in 0..num_hashes {
			let timestamp = u64::from_be_bytes(bytes[..8].try_into().unwrap());
			let timestamp = u64::from_be_bytes(bytes.get(..8)?.try_into().unwrap());
			bytes = &bytes[8..];
			let hash = bytes[..DIGESTBYTES].try_into().unwrap();
			hashes.push((timestamp, Digest(hash)));

M src/server.rs => src/server.rs +29 -12
@@ 46,9 46,12 @@ pub fn send(
		return Err(ServerError::BadServer("invalid recipient keys"));
	}
	let keys_buf = stream.receive(keys_length)?;
	for key in keys_buf.chunks(PUBLICKEYBYTES).map(|k| PublicKey::from_slice(k).unwrap()) {
	let keys = keys_buf.chunks(PUBLICKEYBYTES).map(|k| PublicKey::from_slice(k).unwrap());
	for (i, key) in keys.enumerate() {
		let copy = encrypt_message(account, &recipient, &key, &message);
		stream.send(&(copy.len() as u32).to_be_bytes())?;
		if i == 0 {
			stream.send(&(copy.len() as u32).to_be_bytes())?;
		}
		stream.send(&copy)?;
	}
	_ = stream.receive(1)?;


@@ 86,20 89,34 @@ pub struct ListeningConn {
	stream: EncryptedStream,
}
impl ListeningConn {
	/// The 3 values returned are the timestamp the server received the message,
	/// the sender's address and the message.
	/// Returns the sender's address and the message.
	/// `Ok(None)` means you were sent an invalid message by a misbehaving client.
	pub fn receive(&mut self) -> Result<Option<(u64, SufecAddr, Message)>, ServerError> {
	pub fn receive(&mut self) -> Result<Option<(SufecAddr, Message)>, ServerError> {
		let length_buf = self.stream.receive(4)?.try_into().unwrap();
		let length = u32::from_be_bytes(length_buf) as usize;
		let msg_buf = self.stream.receive(length)?;
		// Avoid panicking on reading the timestamp.
		if msg_buf.len() < 8 {
			return Err(ServerError::BadServer("transmission has invalid length"));
		}
		let timestamp = u64::from_be_bytes(msg_buf[..8].try_into().unwrap());
		self.stream.send(&[0])?;
		Ok(decrypt_message(&self.account, &msg_buf[8..], &self.new_eph_sec, &self.old_eph_sec)
			.map(|(from, msg)| (timestamp, from, msg)))
		Ok(decrypt_message(&self.account, &msg_buf, &self.new_eph_sec, &self.old_eph_sec))
	}
}

pub struct EncryptedStream {
	pub stream: TcpStream,
	pub key: PrecomputedKey,
	pub nonce: Nonce,
}
impl EncryptedStream {
	pub fn send<T: AsRef<[u8]>>(&mut self, data: T) -> io::Result<()> {
		let encrypted = seal_precomputed(data.as_ref(), &self.nonce, &self.key);
		self.nonce.increment_le_inplace();
		self.stream.write_all(&encrypted)
	}
	pub fn receive(&mut self, len: usize) -> Result<Vec<u8>, ServerError> {
		let mut ciphertext_buf = vec![0; len + MACBYTES];
		self.stream.read_exact(&mut ciphertext_buf)?;
		let decrypted = open_precomputed(&ciphertext_buf, &self.nonce, &self.key)
			.map_err(|_| ServerError::DecryptionFailed)?;
		self.nonce.increment_le_inplace();
		Ok(decrypted)
	}
}