aboutsummaryrefslogtreecommitdiffstats
path: root/src/std_identity.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/std_identity.rs')
-rw-r--r--src/std_identity.rs260
1 files changed, 170 insertions, 90 deletions
diff --git a/src/std_identity.rs b/src/std_identity.rs
index fdc8dff..80c1651 100644
--- a/src/std_identity.rs
+++ b/src/std_identity.rs
@@ -1,14 +1,18 @@
-use std::{collections::{HashMap, HashSet}, rc::Rc, str::FromStr};
+use crate::crypto::{PrivateKey, PublicKey, SharedSecret};
use bytes::Bytes;
use log::warn;
-use crate::{crypto::{PrivateKey, PublicKey, SharedSecret}};
+use std::{
+ collections::{HashMap, HashSet},
+ rc::Rc,
+ str::FromStr,
+};
use serde::{Deserialize, de};
#[derive(PartialEq, Clone, Deserialize, Debug)]
/// The Identity structure contains the information to decrypt
/// incoming messages and sign and encrypt outgoing messages.
-///
+///
/// It has the necessary cryptographic material needed to appear
/// as this identity when creating messages.
pub struct Identity {
@@ -34,14 +38,14 @@ pub struct Identity {
/// used because there are many many hash collisions
/// when using just the 1-byte hash prefix.
#[serde(skip)]
- pub secrets: HashSet<(Rc<String>, SharedSecret)>
+ pub secrets: HashSet<(Rc<String>, SharedSecret)>,
}
#[derive(PartialEq, Clone, Deserialize, Debug)]
/// The Contact structure contains the information needed
/// to decrypt messages from a remote user intended for
/// either an identity or a channel.
-///
+///
/// It's cryptographic material is also needed to uniquely
/// identify the origin of a message. Most source values
/// are only one byte, so that information just limits the
@@ -53,7 +57,7 @@ pub struct Contact {
/// The provided public key of the remote contact
#[serde(deserialize_with = "deserialize_public_key")]
- pub public_key: PublicKey
+ pub public_key: PublicKey,
}
#[derive(PartialEq, Clone, Deserialize, Debug)]
@@ -68,7 +72,7 @@ pub struct Group {
/// The group's shared secret
#[serde(deserialize_with = "deserialize_secret")]
- pub secret: SharedSecret
+ pub secret: SharedSecret,
}
#[derive(PartialEq, Clone, Deserialize, Debug)]
@@ -87,7 +91,13 @@ impl Keystore {
}
}
- pub fn decrypt_and_id_p2p(&self, _source: u8, _dest: u8, mac: u16, data: &Bytes) -> Option<(Bytes, Rc<String>, Rc<String>)> {
+ pub fn decrypt_and_id_p2p(
+ &self,
+ _source: u8,
+ _dest: u8,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, Rc<String>, Rc<String>)> {
// Just brute-force all the secrets until one matches...
for identity in self.identities.iter() {
for secret in identity.1.secrets.iter() {
@@ -100,7 +110,12 @@ impl Keystore {
None
}
- pub fn decrypt_and_id_group(&self, _group_hash_prefix: u8, mac: u16, data: &Bytes) -> Option<(Bytes, u32)> {
+ pub fn decrypt_and_id_group(
+ &self,
+ _group_hash_prefix: u8,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, u32)> {
for group in self.groups.iter() {
let result = group.1.secret.mac_then_decrypt(mac, data);
if let Some(result) = result {
@@ -111,7 +126,13 @@ impl Keystore {
None
}
- pub fn decrypt_anon(&self, _dest: u8, pub_key: &PublicKey, mac: u16, data: &Bytes) -> Option<(Bytes, Rc<String>)> {
+ pub fn decrypt_anon(
+ &self,
+ _dest: u8,
+ pub_key: &PublicKey,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, Rc<String>)> {
// For each identity, create a shared secret against the provided public key and check it.
for identity in self.identities.iter() {
let secret = identity.1.private_key.create_secret(pub_key);
@@ -136,7 +157,7 @@ impl KeystoreInput {
let mut retval = Keystore {
identities: HashMap::new(),
contacts: HashMap::new(),
- groups: HashMap::new()
+ groups: HashMap::new(),
};
// Iterate through the input keystore file
@@ -152,15 +173,18 @@ impl KeystoreInput {
for name in contact_names {
if let Some(key_string) = self.contacts.get(name) {
match PublicKey::from_str(&key_string) {
- Ok(pub_key) => {
- contacts.push(Contact {
- name: Rc::new(name.to_string()),
- public_key: pub_key
- });
- },
- Err(e) => {
- warn!("Unable to add contact named \"{}\" because there was a problem with the public key: {}", name, e);
- }
+ Ok(pub_key) => {
+ contacts.push(Contact {
+ name: Rc::new(name.to_string()),
+ public_key: pub_key,
+ });
+ }
+ Err(e) => {
+ warn!(
+ "Unable to add contact named \"{}\" because there was a problem with the public key: {}",
+ name, e
+ );
+ }
}
}
}
@@ -177,18 +201,21 @@ impl KeystoreInput {
name: Rc::new(name.to_string()),
private_key,
public_key,
- secrets: HashSet::new()
+ secrets: HashSet::new(),
};
- i.secrets = contacts.iter().map(|c| {
- (c.name.clone(), i.private_key.create_secret(&c.public_key))
- }).collect();
-
+ i.secrets = contacts
+ .iter()
+ .map(|c| (c.name.clone(), i.private_key.create_secret(&c.public_key)))
+ .collect();
identities.push((i.name.clone(), i));
- },
+ }
Err(e) => {
- warn!("Unable to add identity named \"{}\" because there was a problem with the private key: {}", name, e);
+ warn!(
+ "Unable to add identity named \"{}\" because there was a problem with the private key: {}",
+ name, e
+ );
}
}
}
@@ -197,9 +224,7 @@ impl KeystoreInput {
retval.identities = HashMap::from_iter(identities);
// Create a hash of contacts
- let contacts = contacts.into_iter().map(|c| {
- (c.name.clone(), c)
- });
+ let contacts = contacts.into_iter().map(|c| (c.name.clone(), c));
retval.contacts = HashMap::from_iter(contacts);
@@ -218,136 +243,179 @@ impl KeystoreInput {
});
retval.groups = HashMap::from_iter(groups);
-
+
retval
}
}
fn deserialize_private_key<'de, D>(deserializer: D) -> Result<PrivateKey, D::Error>
- where D: de::Deserializer<'de> {
-
+where
+ D: de::Deserializer<'de>,
+{
+ use crate::crypto::PrivateKey;
use std::str::FromStr;
- use crate::crypto::{PrivateKey};
let s: String = de::Deserialize::deserialize(deserializer)?;
match PrivateKey::from_str(&s) {
Ok(key) => Ok(key),
- Err(e) => {
- Err(de::Error::custom(format!("{}", e)))
- }
+ Err(e) => Err(de::Error::custom(format!("{}", e))),
}
}
fn deserialize_public_key<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
- where D: de::Deserializer<'de> {
-
- use hex::decode;
+where
+ D: de::Deserializer<'de>,
+{
use crate::crypto::{MeshcoreCryptoError, PublicKey};
+ use hex::decode;
let s: String = de::Deserialize::deserialize(deserializer)?;
match decode(s) {
Err(hex::FromHexError::InvalidHexCharacter { c, index }) => {
- Err(de::Error::custom(format!("Invalid hex character {} at {} when decoding Public Key.", c, index)))
- },
- Err(hex::FromHexError::OddLength) => {
- Err(de::Error::custom(format!("Odd number of characters when decoding Public Key.")))
- },
- Err(hex::FromHexError::InvalidStringLength) => {
- Err(de::Error::custom(format!("Invalid hex string length when decoding Public Key.")))
+ Err(de::Error::custom(format!(
+ "Invalid hex character {} at {} when decoding Public Key.",
+ c, index
+ )))
}
+ Err(hex::FromHexError::OddLength) => Err(de::Error::custom(format!(
+ "Odd number of characters when decoding Public Key."
+ ))),
+ Err(hex::FromHexError::InvalidStringLength) => Err(de::Error::custom(format!(
+ "Invalid hex string length when decoding Public Key."
+ ))),
Ok(hex) => {
let key = PublicKey::try_from(hex.as_slice());
match key {
Ok(key) => Ok(key),
- Err(MeshcoreCryptoError::KeyCreationError) => {
- Err(de::Error::custom(format!("Unable to decompress public key points")))
- }
- Err(_) => {
- Err(de::Error::custom(format!("Invalid hex string length when decoding Public Key.")))
- }
+ Err(MeshcoreCryptoError::KeyCreationError) => Err(de::Error::custom(format!(
+ "Unable to decompress public key points"
+ ))),
+ Err(_) => Err(de::Error::custom(format!(
+ "Invalid hex string length when decoding Public Key."
+ ))),
}
}
}
}
fn deserialize_secret<'de, D>(deserializer: D) -> Result<SharedSecret, D::Error>
- where D: de::Deserializer<'de> {
-
- use std::str::FromStr;
+where
+ D: de::Deserializer<'de>,
+{
use crate::crypto::SharedSecret;
+ use std::str::FromStr;
let s: String = de::Deserialize::deserialize(deserializer)?;
match SharedSecret::from_str(&s) {
Ok(secret) => Ok(secret),
- Err(e) => {
- Err(de::Error::custom(format!("{}", e)))
- }
+ Err(e) => Err(de::Error::custom(format!("{}", e))),
}
}
// Tests for std operations
#[cfg(test)]
mod tests {
+ use hex::decode;
+ use log::LevelFilter;
+ use serde::de::IntoDeserializer;
+ use serde::de::value::{Error as ValueError, StrDeserializer};
use std::io;
use std::str::FromStr;
use std::sync::mpsc::{Sender, channel};
use std::vec;
- use hex::decode;
- use log::{LevelFilter};
- use serde::de::IntoDeserializer;
- use serde::de::value::{StrDeserializer, Error as ValueError};
- use crate::std_identity::KeystoreInput;
- use crate::crypto::*;
use super::*;
+ use crate::crypto::*;
+ use crate::std_identity::KeystoreInput;
#[test]
fn secret_deserializer() {
- let deserializer: StrDeserializer<ValueError> = "eb50a1bcb3e4e5d7bf69a57c9dada211".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "eb50a1bcb3e4e5d7bf69a57c9dada211".into_deserializer();
let result = deserialize_secret(deserializer);
match result {
- Ok(result) => assert_eq!(result, SharedSecret::from_str("eb50a1bcb3e4e5d7bf69a57c9dada211").unwrap()),
+ Ok(result) => assert_eq!(
+ result,
+ SharedSecret::from_str("eb50a1bcb3e4e5d7bf69a57c9dada211").unwrap()
+ ),
Err(err) => assert!(false, "Shouldn't have had an error, but got one: {}", err),
}
// Test failure conditions
- let deserializer: StrDeserializer<ValueError> = "eb50a1bcb3e4e5d7bf69a57c9dada21".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "eb50a1bcb3e4e5d7bf69a57c9dada21".into_deserializer();
let result = deserialize_secret(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Try From Slice Error", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Try From Slice Error",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
}
#[test]
fn public_key_deserializer() {
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f".into_deserializer();
let result = deserialize_public_key(deserializer);
match result {
- Ok(result) => assert_eq!(result, PublicKey::from_str("34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f").unwrap()),
+ Ok(result) => assert_eq!(
+ result,
+ PublicKey::from_str(
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f"
+ )
+ .unwrap()
+ ),
Err(err) => assert!(false, "Shouldn't have had an error, but got one: {}", err),
}
// Test failure conditions
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219".into_deserializer();
let result = deserialize_public_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Odd number of characters when decoding Public Key.", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Odd number of characters when decoding Public Key.",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec21".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec21".into_deserializer();
let result = deserialize_public_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Invalid hex string length when decoding Public Key.", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Invalid hex string length when decoding Public Key.",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8025eccb9ddb0499cddad4b164f4c219a8b8f".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4b164f4c219a8b8f".into_deserializer();
let result = deserialize_public_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Unable to decompress public key points", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Unable to decompress public key points",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8z25eccb9ddb0499cddad4b164f4c219a8b8f".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8z25eccb9ddb0499cddad4b164f4c219a8b8f".into_deserializer();
let result = deserialize_public_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Invalid hex character z at 28 when decoding Public Key.", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Invalid hex character z at 28 when decoding Public Key.",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
}
#[test]
@@ -363,12 +431,22 @@ mod tests {
let deserializer: StrDeserializer<ValueError> = "4885CF25975EA09742EF76DA587D0957E74EE02AAA34A001458E207E63CF7E6C4940C8C42C335862C71CC2F139633057D1FEE5687B172B27E1E0302A1D480E0".into_deserializer();
let result = deserialize_private_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Hex Decode Error", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Hex Decode Error",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
let deserializer: StrDeserializer<ValueError> = "4885CF25975EA09742EF76DA587D0957E74EE02AAA34A001458E207E63CF7E6C4940C8C42C335862C71CC2F139633057D1FEE5687B172B27E1E0302A1D480E".into_deserializer();
let result = deserialize_private_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Try From Slice Error", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Try From Slice Error",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
}
#[test]
@@ -394,7 +472,6 @@ mod tests {
])
};
assert_eq!(lhs, rhs);
-
}
// This struct is used as an adaptor, it implements io::Write and forwards the buffer to a mpsc::Sender
@@ -432,7 +509,9 @@ mod tests {
let _ = pretty_env_logger::env_logger::builder()
.is_test(true)
.filter_level(LevelFilter::max())
- .target(pretty_env_logger::env_logger::Target::Pipe(Box::new(WriteAdapter { sender: rx })))
+ .target(pretty_env_logger::env_logger::Target::Pipe(Box::new(
+ WriteAdapter { sender: rx },
+ )))
.try_init();
// Test failure conditions
@@ -459,11 +538,12 @@ mod tests {
.zip(expect.into_iter())
.for_each(|(got, expect)| {
println!("{}", &got);
- assert!(got.contains(expect), "Got log line: \"{}\" and didn't find \"{}\" within it as expected.", got, expect);
- }
- );
-
+ assert!(
+ got.contains(expect),
+ "Got log line: \"{}\" and didn't find \"{}\" within it as expected.",
+ got,
+ expect
+ );
+ });
}
-
-
-} \ No newline at end of file
+}