diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 0006827e8..a26804c5b 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -256,6 +256,49 @@ impl Populatable for [T] where T: Sized { } } +#[derive(Debug)] +/// Bytes array deserialization error +pub enum FromBytesError { + /// Not enough bytes for the requested type + NotLongEnough, + /// Too many bytes for the requested type + TooLong, +} + +/// Value that can be serialized from bytes array +pub trait FromRawBytes : Sized { + /// function that will instantiate and initialize object from slice + fn from_bytes(d: &[u8]) -> Result; +} + +impl FromRawBytes for T where T: Sized + FixedHash { + fn from_bytes(bytes: &[u8]) -> Result { + use std::mem; + use std::cmp::Ordering; + match bytes.len().cmp(&mem::size_of::()) { + Ordering::Less => return Err(FromBytesError::NotLongEnough), + Ordering::Greater => return Err(FromBytesError::TooLong), + Ordering::Equal => () + }; + + let mut res: Self = unsafe { mem::uninitialized() }; + res.copy_raw(bytes); + Ok(res) + } +} + +impl FromRawBytes for String { + fn from_bytes(bytes: &[u8]) -> Result { + Ok(::std::str::from_utf8(bytes).unwrap().to_owned()) + } +} + +impl FromRawBytes for Vec { + fn from_bytes(bytes: &[u8]) -> Result, FromBytesError> { + Ok(bytes.clone().to_vec()) + } +} + #[test] fn fax_raw() { let mut x = [255u8; 4]; diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index 7656a938f..73f2542f4 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -232,7 +232,7 @@ impl KeyFileCrypto { }; Ok(KeyFileCrypto { - cipher_text: Bytes::from(cipher_text), + cipher_text: match FromHex::from_hex(cipher_text) { Ok(bytes) => bytes, Err(_) => { return Err(CryptoParseError::InvalidCipherText); } }, cipher_type: cipher_type, kdf: kdf, mac: mac, diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index f473d0ea2..c72a0a7f3 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -32,14 +32,14 @@ const KEY_LENGTH_AES_USIZE: usize = KEY_LENGTH_AES as usize; /// Encrypted hash-map, each request should contain password pub trait EncryptedHashMap { /// Returns existing value for the key, if any - fn get(&self, key: &Key, password: &str) -> Result; + fn get(&self, key: &Key, password: &str) -> Result; /// Insert new encrypted key-value and returns previous if there was any - fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; + fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; /// Removes key-value by key and returns the removed one, if any exists and password was provided - fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; + fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; /// Deletes key-value by key and returns if the key-value existed fn delete(&mut self, key: &Key) -> bool { - self.remove::<&[u8]>(key, None).is_some() + self.remove::(key, None).is_some() } } @@ -49,7 +49,9 @@ pub enum EncryptedHashMapError { /// Encryption failed InvalidPassword, /// No key in the hashmap - UnknownIdentifier + UnknownIdentifier, + /// Stored value is not well formed for the requested type + InvalidValueFormat(FromBytesError), } /// Represent service for storing encrypted arbitrary data @@ -96,14 +98,16 @@ fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Bytes { } impl EncryptedHashMap for SecretStore { - fn get(&self, key: &H128, password: &str) -> Result { + fn get(&self, key: &H128, password: &str) -> Result { match self.directory.get(key) { Some(key_file) => { let decrypted_bytes = match key_file.crypto.kdf { KeyFileKdf::Pbkdf2(ref params) => { - let (derived_left_bits, derived_right_bits) = derive_key(password, ¶ms.salt); - let expected_mac = derive_mac(&derived_right_bits, &key_file.crypto.cipher_text).sha3(); - if expected_mac != key_file.crypto.mac { return Err(EncryptedHashMapError::InvalidPassword); } + let (derived_left_bits, derived_right_bits) = derive_key_iterations(password, ¶ms.salt, params.c); + //assert_eq!(derive_mac(&derived_right_bits, &key_file.crypto.cipher_text).to_hex(), ""); + assert_eq!(&key_file.crypto.cipher_text.to_hex(), "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46"); + if derive_mac(&derived_right_bits, &key_file.crypto.cipher_text) + .sha3() != key_file.crypto.mac { return Err(EncryptedHashMapError::InvalidPassword); } let mut val = vec![0u8; key_file.crypto.cipher_text.len()]; match key_file.crypto.cipher_type { @@ -116,15 +120,16 @@ impl EncryptedHashMap for SecretStore { _ => { unimplemented!(); } }; - let mut instance = Value::default(); - instance.populate_raw(&decrypted_bytes); - Ok(instance) + match Value::from_bytes(&decrypted_bytes) { + Ok(value) => Ok(value), + Err(bytes_error) => Err(EncryptedHashMapError::InvalidValueFormat(bytes_error)) + } }, None => Err(EncryptedHashMapError::UnknownIdentifier) } } - fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { + fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { let previous = if let Ok(previous_value) = self.get(&key, password) { Some(previous_value) } else { None }; // crypto random initiators @@ -156,7 +161,7 @@ impl EncryptedHashMap for SecretStore { previous } - fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { + fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { let previous = if let Some(pass) = password { if let Ok(previous_value) = self.get(&key, pass) { Some(previous_value) } else { None } } @@ -229,7 +234,7 @@ mod tests { } let sstore = SecretStore::new_test(&temp); if let Ok(_) = sstore.get::(&H128::from_str("3198bc9c66725ab3d9954942343ae5b6").unwrap(), "testpassword") { - panic!("shoud be error loading key, we requested the wrong key"); + panic!("should be error loading key, we requested the wrong key"); } }