diff options
Diffstat (limited to 'src/crypto.rs')
| -rw-r--r-- | src/crypto.rs | 236 |
1 files changed, 166 insertions, 70 deletions
diff --git a/src/crypto.rs b/src/crypto.rs index cd184dc..acbb464 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -1,27 +1,42 @@ - // This seems to be an absolute nightmare. GenericArray sucks // but I can't seem to figure out how to pull it out of this // stack of software +use aes::Aes128; #[allow(deprecated)] -use aes::cipher::{BlockEncrypt, BlockDecrypt, generic_array::GenericArray}; +use aes::cipher::{BlockDecrypt, BlockEncrypt, generic_array::GenericArray}; +use bytes::{Buf, BufMut, Bytes, BytesMut}; use curve25519_dalek::MontgomeryPoint; -use aes::Aes128; -use sha2::{Sha256}; -use hmac::{Hmac, Mac}; use ed25519_dalek::{VerifyingKey, hazmat::ExpandedSecretKey}; -use bytes::{Buf, BufMut, Bytes, BytesMut}; +use hmac::{Hmac, Mac}; +use sha2::Sha256; use crate::string_helper::NameString; - type HmacSha256 = Hmac<Sha256>; pub trait Keystore { - fn decrypt_and_id_p2p(&self, source: u8, _dest: u8, mac: u16, data: &Bytes) -> Option<(Bytes, u32, u32)>; - - fn decrypt_and_id_group(&self, group_hash_prefix: u8, mac: u16, data: &Bytes) -> Option<(Bytes, Option<NameString>)>; - - fn decrypt_anon(&self, dest: u8, pub_key: &PublicKey, mac: u16, data: &Bytes) -> Option<(Bytes, u32)>; + fn decrypt_and_id_p2p( + &self, + source: u8, + _dest: u8, + mac: u16, + data: &Bytes, + ) -> Option<(Bytes, u32, u32)>; + + fn decrypt_and_id_group( + &self, + group_hash_prefix: u8, + mac: u16, + data: &Bytes, + ) -> Option<(Bytes, Option<NameString>)>; + + fn decrypt_anon( + &self, + dest: u8, + pub_key: &PublicKey, + mac: u16, + data: &Bytes, + ) -> Option<(Bytes, u32)>; } #[derive(Debug, PartialEq)] @@ -32,7 +47,6 @@ pub enum MeshcoreCryptoError { KeyCreationError, } - impl core::error::Error for MeshcoreCryptoError {} impl core::fmt::Display for MeshcoreCryptoError { @@ -51,7 +65,9 @@ pub struct PrivateKey(ExpandedSecretKey); impl core::fmt::Debug for PrivateKey { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("PrivateKey").field(&hex::encode(self.0.scalar.as_bytes())).finish() + f.debug_tuple("PrivateKey") + .field(&hex::encode(self.0.scalar.as_bytes())) + .finish() } } @@ -59,7 +75,7 @@ impl Clone for PrivateKey { fn clone(&self) -> Self { Self(ExpandedSecretKey { scalar: self.0.scalar, - hash_prefix: self.0.hash_prefix + hash_prefix: self.0.hash_prefix, }) } } @@ -68,8 +84,8 @@ impl Default for PrivateKey { fn default() -> Self { // To make a key whole-cloth, we need to start with a SigningKey made // using a good RNG. Then we can use that to make an ExpandedSecretKey. - use rand::rngs::OsRng; use ed25519_dalek::SigningKey; + use rand::rngs::OsRng; // This seems like the same sequence of steps that's used with ed25519 itself. // I have to copy-pasta it because I don't see a way to do it directly with @@ -97,7 +113,9 @@ pub struct PublicKey(ed25519_dalek::VerifyingKey); impl core::fmt::Debug for PublicKey { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("PublicKey").field(&hex::encode(self.0.as_bytes())).finish() + f.debug_tuple("PublicKey") + .field(&hex::encode(self.0.as_bytes())) + .finish() } } @@ -116,7 +134,7 @@ impl PartialEq for SharedSecret { fn eq(&self, other: &Self) -> bool { self.0.as_bytes() == other.0.as_bytes() } - + fn ne(&self, other: &Self) -> bool { !self.eq(other) } @@ -124,7 +142,9 @@ impl PartialEq for SharedSecret { impl core::fmt::Debug for SharedSecret { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("SharedSecret").field(&hex::encode(self.0.as_bytes())).finish() + f.debug_tuple("SharedSecret") + .field(&hex::encode(self.0.as_bytes())) + .finish() } } @@ -138,7 +158,7 @@ impl core::str::FromStr for SharedSecret { // but they're zero-paded to be 32. So, we're // going to get the hex from the string and copy it in. if hex::decode_to_slice(s, &mut array[0..16]).is_err() { - return Err(MeshcoreCryptoError::TryFromSliceError) + return Err(MeshcoreCryptoError::TryFromSliceError); } else { Ok(SharedSecret(MontgomeryPoint(array))) } @@ -149,8 +169,9 @@ impl TryFrom<Bytes> for SharedSecret { type Error = MeshcoreCryptoError; fn try_from(value: Bytes) -> Result<Self, Self::Error> { - if value.len() != 32 { Err(MeshcoreCryptoError::KeyLengthError) } - else { + if value.len() != 32 { + Err(MeshcoreCryptoError::KeyLengthError) + } else { let mut value = value; let mut retval = Self(MontgomeryPoint([0_u8; 32])); value.copy_to_slice(&mut retval.0.0); @@ -190,8 +211,8 @@ impl SharedSecret { // At this point, we're sure that the key is an appropriate size for // the Hmac. So, I don't think we should complicate the API with making // this failable. - let mut mac = HmacSha256::new_from_slice(self.0.as_bytes()) - .expect("Programming error in hmac"); + let mut mac = + HmacSha256::new_from_slice(self.0.as_bytes()).expect("Programming error in hmac"); mac.update(&ciphertext); let result = mac.finalize(); let mut bytes = Bytes::copy_from_slice(&result.into_bytes()); @@ -219,7 +240,7 @@ impl SharedSecret { text.reserve(padding); text.put_bytes(0, padding); } - + let chunks = text.chunks_exact_mut(chunk_size); for chunk in chunks { #[allow(deprecated)] @@ -262,7 +283,7 @@ impl SharedSecret { text.reserve(padding); text.put_bytes(0, padding); } - + let chunks = text.chunks_exact_mut(chunk_size); for chunk in chunks { #[allow(deprecated)] @@ -300,13 +321,13 @@ impl TryFrom<Bytes> for PublicKey { fn try_from(mut value: Bytes) -> Result<Self, Self::Error> { if value.len() < 32 { - return Err(MeshcoreCryptoError::KeyLengthError) + return Err(MeshcoreCryptoError::KeyLengthError); } let mut slice = [0_u8; 32]; if value.try_copy_to_slice(&mut slice).is_err() { - return Err(MeshcoreCryptoError::KeyLengthError) + return Err(MeshcoreCryptoError::KeyLengthError); } if let Ok(key) = VerifyingKey::from_bytes(&slice) { @@ -315,7 +336,6 @@ impl TryFrom<Bytes> for PublicKey { Err(MeshcoreCryptoError::KeyCreationError) } } - } impl core::str::FromStr for PublicKey { @@ -371,7 +391,9 @@ impl SharedSecret { pub fn mac_then_decrypt(&self, mac: u16, data: &Bytes) -> Option<Bytes> { // Get the MAC of the message and key to check vailidity let our_mac = self.get_hmac(&data); - if our_mac != mac { return None } + if our_mac != mac { + return None; + } // Attempt to decrypt the packet itself Some(self.decrypt(&data)) @@ -387,16 +409,24 @@ impl SharedSecret { // Tests for std operations #[cfg(test)] mod tests { - use core::str::FromStr; - use hex::{decode_to_slice, encode, decode}; use super::*; + use core::str::FromStr; + use hex::{decode, decode_to_slice, encode}; #[test] fn public_key() { let mut slice = [0_u8; 32]; - decode_to_slice("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec", &mut slice).unwrap(); - let public_key = PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec"); - assert_eq!(Ok(PublicKey(VerifyingKey::from_bytes(&slice).unwrap())), public_key); + decode_to_slice( + "12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec", + &mut slice, + ) + .unwrap(); + let public_key = + PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec"); + assert_eq!( + Ok(PublicKey(VerifyingKey::from_bytes(&slice).unwrap())), + public_key + ); } #[test] @@ -404,7 +434,11 @@ mod tests { let private_key = PrivateKey::from_str("38DAA98490B7284697C7ADA6175FD1F8DAD12032AD7ABAE625B7EAD8FEC6444CA281C3370B97155D9C8CECD89A929FDDE0FBF3A9D5C92A1B3C24D711934CD69D").unwrap(); let public_key = PublicKey::from(&private_key); println!("Public key: {:#?}", public_key); - assert_eq!(PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec").unwrap(), public_key); + assert_eq!( + PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec") + .unwrap(), + public_key + ); } #[test] @@ -416,19 +450,31 @@ mod tests { let alice_public = PublicKey::from(&alice_private); let bob_public = PublicKey::from(&bob_private); - assert_eq!(alice_public.0.as_bytes().to_vec(), decode("34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f").unwrap()); - assert_eq!( bob_public.0.as_bytes().to_vec(), decode("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec").unwrap()); + assert_eq!( + alice_public.0.as_bytes().to_vec(), + decode("34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f").unwrap() + ); + assert_eq!( + bob_public.0.as_bytes().to_vec(), + decode("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec").unwrap() + ); println!("Alice's public key: {}", encode(&alice_public.0.to_bytes())); println!("Bob's public key: {}", encode(&bob_public.0.to_bytes())); - let left_secret = alice_private.create_secret(&bob_public); + let left_secret = alice_private.create_secret(&bob_public); let right_secret = bob_private.create_secret(&alice_public); - assert_eq!(left_secret.0.as_bytes().to_vec(), decode("eb7a365363bd8548ee2b54b9234247be5e42e96be9625adcdf3a55b6c1d04850").unwrap()); + assert_eq!( + left_secret.0.as_bytes().to_vec(), + decode("eb7a365363bd8548ee2b54b9234247be5e42e96be9625adcdf3a55b6c1d04850").unwrap() + ); println!("Left shared secret: {}", encode(&left_secret.0.as_bytes())); - println!("Right shared secret: {}", encode(&right_secret.0.as_bytes())); + println!( + "Right shared secret: {}", + encode(&right_secret.0.as_bytes()) + ); assert_eq!(left_secret, right_secret); } @@ -436,28 +482,39 @@ mod tests { #[test] fn hmac() { // Test using a group secret - let group_secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap())); - let test_group_secret =SharedSecret::from_str("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap(); + let group_secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice( + &decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap(), + )); + let test_group_secret = SharedSecret::from_str("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap(); assert_eq!(group_secret, test_group_secret); // Test using the secret and ciphertext to make a MAC and ensure it matches an example for a group secret - let sample_data = Bytes::copy_from_slice(&decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap()); + let sample_data = Bytes::copy_from_slice( + &decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap(), + ); let mac = group_secret.get_hmac(&sample_data); assert_eq!(0xC3C1, mac); } #[test] fn decrypt() { - let ciphertext = Bytes::copy_from_slice(&decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap()); - let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap())); + let ciphertext = Bytes::copy_from_slice( + &decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap(), + ); + let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice( + &decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap(), + )); let cleartext = secret.decrypt(&ciphertext); println!("Cleartext: {}", encode(&cleartext)); } #[test] fn decrypt_online_example() { - let ciphertext = Bytes::copy_from_slice(&decode("9A1FD57EDFE7E4369F9FD9420C48FFAD").unwrap()); - let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("949E911CA6A6196275FF319B28C3A143").unwrap())); + let ciphertext = + Bytes::copy_from_slice(&decode("9A1FD57EDFE7E4369F9FD9420C48FFAD").unwrap()); + let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice( + &decode("949E911CA6A6196275FF319B28C3A143").unwrap(), + )); let cleartext = secret.decrypt(&ciphertext); let vec = cleartext.to_vec(); let string = String::from_utf8_lossy(&vec); @@ -467,9 +524,14 @@ mod tests { #[test] fn encrypt_online_example() { let plaintext = Bytes::copy_from_slice("Meshcore!".as_bytes()); - let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("44A6F78DAD2E54D73A32CDE3ECAA9E75").unwrap())); + let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice( + &decode("44A6F78DAD2E54D73A32CDE3ECAA9E75").unwrap(), + )); let ciphertext = secret.encrypt(plaintext); - assert_eq!(ciphertext, decode("62374852B6A11405A081F87356C88861").unwrap()); + assert_eq!( + ciphertext, + decode("62374852B6A11405A081F87356C88861").unwrap() + ); } #[test] @@ -486,11 +548,13 @@ mod tests { let padding = chunk_size - (length % chunk_size); text.reserve(padding); text.put_bytes(0, padding); - + let chunks = text.chunks_exact_mut(4); { for chunk in chunks { - for item in chunk { *item = *item << 4; } + for item in chunk { + *item = *item << 4; + } } } @@ -500,7 +564,6 @@ mod tests { println!("Result: {:#?}", encode(&text)); assert_eq!(text, decode("102030405060708090A0B0C0D0E0F0").unwrap()); - } // Example from the crate we're using @@ -508,13 +571,19 @@ mod tests { fn aes_test() { use aes::Aes128; #[allow(deprecated)] - use aes::cipher::{BlockEncrypt, BlockDecrypt, KeyInit}; + use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit}; // Initialize cipher - let key: [u8; 16] = decode("0A1BB8C05063D9941F0F1019D001B743").unwrap().try_into().unwrap(); + let key: [u8; 16] = decode("0A1BB8C05063D9941F0F1019D001B743") + .unwrap() + .try_into() + .unwrap(); let cipher = Aes128::new(&key.into()); - let message: [u8; 16] = decode("7D69AB072E09AF74EBA47EB95BF00AE3").unwrap().try_into().unwrap(); + let message: [u8; 16] = decode("7D69AB072E09AF74EBA47EB95BF00AE3") + .unwrap() + .try_into() + .unwrap(); let message_copy = message.clone(); // Encrypt block in-place @@ -533,10 +602,18 @@ mod tests { #[test] fn shared_secrets_example() { - use x25519_dalek::{StaticSecret, PublicKey}; + use x25519_dalek::{PublicKey, StaticSecret}; - let a_s: [u8; 32] = decode("58f5052c13275c8a3f4863a082555fed7ea08b9dec2eb00dd86f6b5412174458").unwrap().try_into().unwrap(); - let b_s: [u8; 32] = decode("586c4cc29635af5865abe4f231bafbd373969725493c07271e02c7fec8ff3b5f").unwrap().try_into().unwrap(); + let a_s: [u8; 32] = + decode("58f5052c13275c8a3f4863a082555fed7ea08b9dec2eb00dd86f6b5412174458") + .unwrap() + .try_into() + .unwrap(); + let b_s: [u8; 32] = + decode("586c4cc29635af5865abe4f231bafbd373969725493c07271e02c7fec8ff3b5f") + .unwrap() + .try_into() + .unwrap(); let alice_secret = StaticSecret::from(a_s); let alice_public = PublicKey::from(&alice_secret); @@ -545,26 +622,45 @@ mod tests { let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); - + assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); } #[test] fn mac_then_decrypt() { - let group_secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap())); - let sample_data = Bytes::copy_from_slice(&decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap()); + let group_secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice( + &decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap(), + )); + let sample_data = Bytes::copy_from_slice( + &decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap(), + ); let mac = 0xC3C1; let cleartext = group_secret.mac_then_decrypt(mac, &sample_data).unwrap(); - assert_eq!(cleartext, decode("3757d06800f09f8cb220547265653a20e29881efb88f00000000000000000000").unwrap()); + assert_eq!( + cleartext, + decode("3757d06800f09f8cb220547265653a20e29881efb88f00000000000000000000").unwrap() + ); } #[test] fn test_error_display() { - assert_eq!(format!("{}", MeshcoreCryptoError::KeyLengthError), "Key Length Error"); - assert_eq!(format!("{}", MeshcoreCryptoError::TryFromSliceError), "Try From Slice Error"); - assert_eq!(format!("{}", MeshcoreCryptoError::HexDecodeError), "Hex Decode Error"); - assert_eq!(format!("{}", MeshcoreCryptoError::KeyCreationError), "Key Creation Error"); + assert_eq!( + format!("{}", MeshcoreCryptoError::KeyLengthError), + "Key Length Error" + ); + assert_eq!( + format!("{}", MeshcoreCryptoError::TryFromSliceError), + "Try From Slice Error" + ); + assert_eq!( + format!("{}", MeshcoreCryptoError::HexDecodeError), + "Hex Decode Error" + ); + assert_eq!( + format!("{}", MeshcoreCryptoError::KeyCreationError), + "Key Creation Error" + ); } #[test] @@ -578,7 +674,8 @@ mod tests { let cleartext = "Hi Bob. This is alice. How are you?"; let alice_secret = alice_private.create_secret(&bob_public); - let (mac, ciphertext) = alice_secret.encrypt_then_mac(Bytes::copy_from_slice(cleartext.as_bytes())); + let (mac, ciphertext) = + alice_secret.encrypt_then_mac(Bytes::copy_from_slice(cleartext.as_bytes())); let bob_secret = bob_private.create_secret(&alice_public); let decrypted_data = bob_secret.mac_then_decrypt(mac, &ciphertext); @@ -600,6 +697,5 @@ mod tests { } else { assert!(false, "Unable to decrypt"); } - } -}
\ No newline at end of file +} |
