diff --git a/src/crypto.rs b/src/crypto.rs index ad164ed..05e7bd0 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -27,7 +27,17 @@ impl PublicKey { } pub fn to_vec(&self) -> serde_cbor::Result> { - serde_cbor::to_vec(&self) + serde_cbor::to_vec(&self.key) + } + + pub fn from_vec(data: Vec) -> serde_cbor::Result { + serde_cbor::from_slice(data.as_slice()) + } +} + +impl PublicKey { + fn hash(&self) -> Vec { + self.to_vec().unwrap() } } @@ -103,3 +113,8 @@ fn test_invalid_signing() { let keys_2 = Keys::generate(); assert!(!keys_2.get_public().verify_sign(&data, &keys_1.sign(&data).unwrap())); } + +#[test] +fn test_pkey_caching() { + assert_ne!(Keys::generate().get_public().hash(), Keys::generate().get_public().hash()) +} diff --git a/src/message.rs b/src/message.rs index c29c003..77b7619 100644 --- a/src/message.rs +++ b/src/message.rs @@ -4,6 +4,7 @@ use crate::crypto::{Keys, PublicKey}; use crate::res::IFResult; use crate::tunnel::TunnelPublic; use serde::{Serialize, Deserialize}; +use sha2::Digest; /// A serialized message @@ -28,7 +29,7 @@ pub enum Signature { /// Network name and version #[derive(Serialize, Deserialize, Clone)] -struct NetworkInfo { +pub struct NetworkInfo { network_name: String, version: String, } @@ -46,6 +47,16 @@ pub enum MessageType { Service(ServiceMessageType), } +impl MessageType { + fn hash(&self) -> Vec { + match self { + MessageType::SingleCast => Vec::from([0]), + MessageType::Broadcast => Vec::from([1]), + MessageType::Service(ServiceMessageType::TunnelBuilding(tunnel)) => [2, 0].iter().chain(tunnel.hash().iter()).copied().collect() + } + } +} + #[derive(Serialize, Deserialize, Clone)] pub enum ServiceMessageType { TunnelBuilding(TunnelPublic) @@ -61,6 +72,22 @@ pub enum MessageContent { None, } +impl MessageContent { + pub fn hash(&self) -> Vec { + match self { + MessageContent::Plain(v) => sha2::Sha512::new() + .chain(&[0u8; 1]) + .chain(v.as_slice()) + .result().to_vec(), + MessageContent::Encrypted(v) => sha2::Sha512::new() + .chain(&[1; 1]) + .chain(v.as_slice()) + .result().to_vec(), + MessageContent::None => Vec::new() + } + } +} + /// The struct for messages that are sent in the network #[derive(Serialize, Deserialize, Clone)] pub struct Message { @@ -100,8 +127,14 @@ impl Message { todo!() } - pub fn calculate_hash(_content: &MessageContent, _message_type: MessageType, _sender_or_encrypted_sender: Option>) -> Vec { - todo!() + pub fn calculate_hash(content: &MessageContent, message_type: MessageType, sender_or_encrypted_sender: Option>, network_info: &NetworkInfo) -> Vec { + sha2::Sha512::new() + .chain(content.hash().as_slice()) + .chain(message_type.hash().as_slice()) + .chain(sender_or_encrypted_sender.unwrap_or_default().as_slice()) + .chain(network_info.network_name.as_bytes()) + .chain(network_info.version.as_bytes()) + .result().to_vec() } /// Encrypt hash of the message for the recipient @@ -171,6 +204,7 @@ impl MessageBuilder { let sender_encrypted = if let (Some(sender_keys), Some(recipient)) = (self.sender.as_ref(), self.recipient.as_ref()) { Some(recipient.encrypt_data(&sender_keys.get_public().to_vec()?)?) } else { None }; + let network_info = NetworkInfo::default(); let hash = Message::calculate_hash( &self.content, self.message_type.clone().unwrap(), @@ -179,6 +213,7 @@ impl MessageBuilder { || self.sender.as_ref() .map(|sender_keys| sender_keys.get_public().to_vec().unwrap()) ), + &network_info ); let recipient_verification = self.recipient.as_ref().map(|rec| rec.encrypt_data(&hash).unwrap()); let signature = match (self.sender, self.recipient) { @@ -197,7 +232,31 @@ impl MessageBuilder { hash, recipient_verification, tunnel_id: self.tunnel_id, - network_info: Default::default(), + network_info, }) } } + +#[cfg(test)] +use alloc::vec; + +#[test] +fn test_hashing_message_type() { + let msg_type_1 = MessageType::Broadcast; + let msg_type_2 = MessageType::Service(ServiceMessageType::TunnelBuilding(TunnelPublic::new_for_test())); + assert_eq!(msg_type_1.hash(), msg_type_1.hash()); + assert_eq!(msg_type_2.hash(), msg_type_2.hash()); + assert_ne!(msg_type_1.hash(), msg_type_2.hash()) +} + +#[test] +fn test_hash_message_content() { + let content_1 = MessageContent::Plain(vec![1, 2, 4, 5]); + let content_2 = MessageContent::Encrypted(vec![1, 2, 4, 5]); + let content_3 = MessageContent::Plain(vec![1, 3, 4, 5]); + assert_eq!(content_1.hash(), content_1.hash()); + assert_ne!(content_1.hash(), MessageContent::None.hash()); + assert_ne!(content_1.hash(), content_2.hash()); + assert_ne!(content_1.hash(), content_3.hash()); + assert_ne!(content_3.hash(), content_2.hash()); +} diff --git a/src/tunnel.rs b/src/tunnel.rs index db5be37..ed179b8 100644 --- a/src/tunnel.rs +++ b/src/tunnel.rs @@ -1,6 +1,7 @@ use alloc::vec::Vec; use crate::crypto::PublicKey; use serde::{Serialize, Deserialize}; +use sha2::Digest; /// A tunnel that is used for communication #[derive(Serialize, Clone, Deserialize)] @@ -34,3 +35,36 @@ pub struct TunnelPublic { /// Public keys of nodes in the tunnel nodes_in_tunnel: Option>, } + +impl TunnelPublic { + pub fn hash(&self) -> Vec { + sha2::Sha224::new() + .chain(serde_cbor::to_vec(self).unwrap().as_slice()) + .result().to_vec() + } + + #[cfg(test)] + pub fn new_for_test() -> Self { + TunnelPublic { + id: Some(56), + local_ids: vec![5, 500, 120], + ttd: 56, + nodes_in_tunnel: Some(vec![crate::crypto::Keys::generate().get_public()]) + } + } +} + +#[cfg(test)] +use alloc::vec; + +#[test] +fn test_tunnel_hashing() { + let tun = TunnelPublic::new_for_test(); + assert_eq!(tun.hash(), tun.hash()); + assert_ne!(tun.hash(), TunnelPublic { + id: Some(56), + local_ids: vec![5, 500, 120], + ttd: 56, + nodes_in_tunnel: Some(vec![crate::crypto::Keys::generate().get_public()]) + }.hash()); +}