aboutsummaryrefslogtreecommitdiffstats
path: root/src/crypto.rs
diff options
context:
space:
mode:
authorWill Dillon <william@housedillon.com>2025-12-04 17:07:12 +0000
committerWill Dillon <william@housedillon.com>2025-12-04 17:07:12 +0000
commitbf21ebaaae44b267cfefc87eee9608c09aab96b7 (patch)
tree67234092d3c85a9c58d1fa9ca51337ac480ebfb7 /src/crypto.rs
parentBetter than 90% everywhere. (diff)
downloadmeshcore-rs-bf21ebaaae44b267cfefc87eee9608c09aab96b7.tar.gz
meshcore-rs-bf21ebaaae44b267cfefc87eee9608c09aab96b7.zip
Getting closer to no-std being done
Diffstat (limited to 'src/crypto.rs')
-rw-r--r--src/crypto.rs117
1 files changed, 73 insertions, 44 deletions
diff --git a/src/crypto.rs b/src/crypto.rs
index b62fb5d..cd184dc 100644
--- a/src/crypto.rs
+++ b/src/crypto.rs
@@ -1,7 +1,3 @@
-use std::{fmt::{Debug, Display}, str::FromStr};
-use ed25519_dalek::{VerifyingKey, hazmat::ExpandedSecretKey};
-use bytes::{Buf, BufMut, Bytes, BytesMut};
-use hex::{decode, decode_to_slice, encode};
// This seems to be an absolute nightmare. GenericArray sucks
// but I can't seem to figure out how to pull it out of this
@@ -12,8 +8,21 @@ 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 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)>;
+}
#[derive(Debug, PartialEq)]
pub enum MeshcoreCryptoError {
@@ -23,10 +32,11 @@ pub enum MeshcoreCryptoError {
KeyCreationError,
}
-impl std::error::Error for MeshcoreCryptoError {}
-impl Display for MeshcoreCryptoError {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::error::Error for MeshcoreCryptoError {}
+
+impl core::fmt::Display for MeshcoreCryptoError {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
MeshcoreCryptoError::KeyLengthError => f.write_str("Key Length Error"),
MeshcoreCryptoError::TryFromSliceError => f.write_str("Try From Slice Error"),
@@ -39,9 +49,9 @@ impl Display for MeshcoreCryptoError {
#[derive(PartialEq)]
pub struct PrivateKey(ExpandedSecretKey);
-impl std::fmt::Debug for PrivateKey {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_tuple("PrivateKey").field(&encode(self.0.scalar.as_bytes())).finish()
+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()
}
}
@@ -74,18 +84,28 @@ impl Default for PrivateKey {
}
}
+impl PrivateKey {
+ pub fn hash_prefix(&self) -> u32 {
+ // The has prefix is the beginning of the public key of the secret
+ let public_key = PublicKey::from(self);
+ public_key.hash_prefix()
+ }
+}
+
#[derive(PartialEq, Clone)]
pub struct PublicKey(ed25519_dalek::VerifyingKey);
-impl std::fmt::Debug for PublicKey {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_tuple("PublicKey").field(&encode(self.0.as_bytes())).finish()
+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()
}
}
impl PublicKey {
- pub fn hash_prefix(&self) -> u8 {
- self.0.as_bytes()[0]
+ pub fn hash_prefix(&self) -> u32 {
+ let mut bytes = Bytes::copy_from_slice(self.0.as_bytes());
+
+ bytes.get_u32()
}
}
@@ -102,13 +122,13 @@ impl PartialEq for SharedSecret {
}
}
-impl std::fmt::Debug for SharedSecret {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_tuple("SharedSecret").field(&encode(self.0.as_bytes())).finish()
+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()
}
}
-impl FromStr for SharedSecret {
+impl core::str::FromStr for SharedSecret {
type Err = MeshcoreCryptoError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -117,7 +137,7 @@ impl FromStr for SharedSecret {
// The provided group secrets are only 16 bytes,
// but they're zero-paded to be 32. So, we're
// going to get the hex from the string and copy it in.
- if decode_to_slice(s, &mut array[0..16]).is_err() {
+ if hex::decode_to_slice(s, &mut array[0..16]).is_err() {
return Err(MeshcoreCryptoError::TryFromSliceError)
} else {
Ok(SharedSecret(MontgomeryPoint(array)))
@@ -139,6 +159,15 @@ impl TryFrom<Bytes> for SharedSecret {
}
}
+// This is kinda meaningless because a shared secret only works
+// when it's connected to a key pair, but it needs to exist for
+// Arrayvec.
+impl Default for SharedSecret {
+ fn default() -> Self {
+ Self(curve25519_dalek::MontgomeryPoint([0u8; 32]))
+ }
+}
+
impl SharedSecret {
fn get_key(&self) -> &[u8; 16] {
// Safety: The size of the slice ensures that this will never be wrong.
@@ -289,11 +318,11 @@ impl TryFrom<Bytes> for PublicKey {
}
-impl FromStr for PublicKey {
+impl core::str::FromStr for PublicKey {
type Err = MeshcoreCryptoError;
fn from_str(hex_str: &str) -> Result<Self, Self::Err> {
- if let Ok(hex) = decode(hex_str) {
+ if let Ok(hex) = hex::decode(hex_str) {
if let Ok(slice) = TryInto::<[u8; 32]>::try_into(hex) {
if let Ok(key) = VerifyingKey::from_bytes(&slice) {
Ok(PublicKey(key))
@@ -309,11 +338,11 @@ impl FromStr for PublicKey {
}
}
-impl FromStr for PrivateKey {
+impl core::str::FromStr for PrivateKey {
type Err = MeshcoreCryptoError;
fn from_str(hex_str: &str) -> Result<Self, Self::Err> {
- if let Ok(hex) = decode(hex_str) {
+ if let Ok(hex) = hex::decode(hex_str) {
if let Ok(bytes) = TryInto::<[u8; 64]>::try_into(hex) {
Ok(PrivateKey(ExpandedSecretKey::from_bytes(&bytes)))
} else {
@@ -355,9 +384,11 @@ impl SharedSecret {
}
}
+// Tests for std operations
#[cfg(test)]
mod tests {
- use hex::{decode_to_slice, encode};
+ use core::str::FromStr;
+ use hex::{decode_to_slice, encode, decode};
use super::*;
#[test]
@@ -365,7 +396,7 @@ mod tests {
let mut slice = [0_u8; 32];
decode_to_slice("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec", &mut slice).unwrap();
let public_key = PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec");
- assert!(Ok(PublicKey(VerifyingKey::from_bytes(&slice).unwrap())) == public_key);
+ assert_eq!(Ok(PublicKey(VerifyingKey::from_bytes(&slice).unwrap())), public_key);
}
#[test]
@@ -373,7 +404,7 @@ mod tests {
let private_key = PrivateKey::from_str("38DAA98490B7284697C7ADA6175FD1F8DAD12032AD7ABAE625B7EAD8FEC6444CA281C3370B97155D9C8CECD89A929FDDE0FBF3A9D5C92A1B3C24D711934CD69D").unwrap();
let public_key = PublicKey::from(&private_key);
println!("Public key: {:#?}", public_key);
- assert!(PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec").unwrap() == public_key);
+ assert_eq!(PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec").unwrap(), public_key);
}
#[test]
@@ -385,8 +416,8 @@ mod tests {
let alice_public = PublicKey::from(&alice_private);
let bob_public = PublicKey::from(&bob_private);
- assert!(alice_public.0.as_bytes().to_vec() == decode("34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f").unwrap());
- assert!( 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()));
@@ -394,12 +425,12 @@ mod tests {
let left_secret = alice_private.create_secret(&bob_public);
let right_secret = bob_private.create_secret(&alice_public);
- assert!(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()));
- assert!(left_secret == right_secret);
+ assert_eq!(left_secret, right_secret);
}
#[test]
@@ -407,12 +438,12 @@ mod tests {
// 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();
- assert!(group_secret == test_group_secret);
+ 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 mac = group_secret.get_hmac(&sample_data);
- assert!(0xC3C1 == mac);
+ assert_eq!(0xC3C1, mac);
}
#[test]
@@ -430,7 +461,7 @@ mod tests {
let cleartext = secret.decrypt(&ciphertext);
let vec = cleartext.to_vec();
let string = String::from_utf8_lossy(&vec);
- assert!("Hello my world!!" == string);
+ assert_eq!("Hello my world!!", string);
}
#[test]
@@ -438,7 +469,7 @@ mod tests {
let plaintext = Bytes::copy_from_slice("Meshcore!".as_bytes());
let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("44A6F78DAD2E54D73A32CDE3ECAA9E75").unwrap()));
let ciphertext = secret.encrypt(plaintext);
- assert!(ciphertext == decode("62374852B6A11405A081F87356C88861").unwrap());
+ assert_eq!(ciphertext, decode("62374852B6A11405A081F87356C88861").unwrap());
}
#[test]
@@ -468,7 +499,7 @@ mod tests {
println!("Result: {:#?}", encode(&text));
- assert!(text == decode("102030405060708090A0B0C0D0E0F0").unwrap());
+ assert_eq!(text, decode("102030405060708090A0B0C0D0E0F0").unwrap());
}
@@ -525,15 +556,15 @@ mod tests {
let mac = 0xC3C1;
let cleartext = group_secret.mac_then_decrypt(mac, &sample_data).unwrap();
- assert!(cleartext == decode("3757d06800f09f8cb220547265653a20e29881efb88f00000000000000000000").unwrap());
+ assert_eq!(cleartext, decode("3757d06800f09f8cb220547265653a20e29881efb88f00000000000000000000").unwrap());
}
#[test]
fn test_error_display() {
- assert!(format!("{}", MeshcoreCryptoError::KeyLengthError) == "Key Length Error");
- assert!(format!("{}", MeshcoreCryptoError::TryFromSliceError) == "Try From Slice Error");
- assert!(format!("{}", MeshcoreCryptoError::HexDecodeError) == "Hex Decode Error");
- assert!(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]
@@ -565,9 +596,7 @@ mod tests {
.first()
.unwrap();
- assert!(lhs_string == cleartext, "{}",
- format!("\"{}\" != \"{}\"", lhs_string, cleartext)
- );
+ assert_eq!(lhs_string, cleartext);
} else {
assert!(false, "Unable to decrypt");
}