aboutsummaryrefslogtreecommitdiffstats
path: root/src/crypto.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto.rs')
-rw-r--r--src/crypto.rs236
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
+}