first vector up

This commit is contained in:
Nikolay Volf 2016-02-16 19:19:32 +03:00
parent ac0ca94230
commit a649d6f131
3 changed files with 75 additions and 9 deletions

View File

@ -168,6 +168,8 @@ pub struct KeyFileCrypto {
pub cipher_text: Bytes, pub cipher_text: Bytes,
/// Password derived key generator function settings. /// Password derived key generator function settings.
pub kdf: KeyFileKdf, pub kdf: KeyFileKdf,
/// Mac
pub mac: H256
} }
impl KeyFileCrypto { impl KeyFileCrypto {
@ -216,15 +218,24 @@ impl KeyFileCrypto {
} }
}; };
let cipher_text = match as_object["ciphertext"].as_string() { let cipher_text = match try!(as_object.get("ciphertext").ok_or(CryptoParseError::NoCipherText)).as_string() {
None => { return Err(CryptoParseError::NoCipherText); } None => { return Err(CryptoParseError::InvalidCipherText); }
Some(text) => text Some(text) => text
}; };
let mac: H256 = match try!(as_object.get("mac").ok_or(CryptoParseError::NoMac)).as_string() {
None => { return Err(CryptoParseError::InvalidMacFormat(None)) },
Some(salt_value) => match H256::from_str(salt_value) {
Ok(salt_hex_value) => salt_hex_value,
Err(from_hex_error) => { return Err(CryptoParseError::InvalidMacFormat(Some(from_hex_error))); },
}
};
Ok(KeyFileCrypto { Ok(KeyFileCrypto {
cipher_text: Bytes::from(cipher_text), cipher_text: Bytes::from(cipher_text),
cipher_type: cipher_type, cipher_type: cipher_type,
kdf: kdf, kdf: kdf,
mac: mac,
}) })
} }
@ -251,6 +262,8 @@ impl KeyFileCrypto {
KeyFileKdf::Scrypt(ref scrypt_params) => scrypt_params.to_json() KeyFileKdf::Scrypt(ref scrypt_params) => scrypt_params.to_json()
}); });
map.insert("mac".to_owned(), Json::String(format!("{:?}", self.mac)));
Json::Object(map) Json::Object(map)
} }
@ -270,6 +283,7 @@ impl KeyFileCrypto {
c: c, c: c,
prf: Pbkdf2CryptoFunction::HMacSha256 prf: Pbkdf2CryptoFunction::HMacSha256
}), }),
mac: H256::random(),
} }
} }
} }
@ -324,7 +338,10 @@ pub struct KeyFileContent {
#[derive(Debug)] #[derive(Debug)]
enum CryptoParseError { enum CryptoParseError {
InvalidMacFormat(Option<UtilError>),
NoMac,
NoCipherText, NoCipherText,
InvalidCipherText,
NoCipherType, NoCipherType,
InvalidJsonFormat, InvalidJsonFormat,
InvalidKdfType(Mismatch<String>), InvalidKdfType(Mismatch<String>),

View File

@ -18,4 +18,4 @@
pub mod directory; pub mod directory;
mod encryptor; mod store;

View File

@ -27,6 +27,9 @@ const KEY_LENGTH: u32 = 32;
const KEY_ITERATIONS: u32 = 4096; const KEY_ITERATIONS: u32 = 4096;
const KEY_LENGTH_AES: u32 = KEY_LENGTH/2; const KEY_LENGTH_AES: u32 = KEY_LENGTH/2;
const KEY_LENGTH_USIZE: usize = KEY_LENGTH as usize;
const KEY_LENGTH_AES_USIZE: usize = KEY_LENGTH_AES as usize;
pub trait EncryptedHashMap<Key: Hash + Eq> { pub trait EncryptedHashMap<Key: Hash + Eq> {
// Returns existing value for the key, if any // Returns existing value for the key, if any
fn get<Value: Populatable + Default + BytesConvertable>(&self, key: &Key, password: &str) -> Option<Value>; fn get<Value: Populatable + Default + BytesConvertable>(&self, key: &Key, password: &str) -> Option<Value>;
@ -61,6 +64,26 @@ impl SecretStore {
} }
} }
fn derive_key_iterations(password: &str, salt: &H256, c: u32) -> (Bytes, Bytes) {
let mut h_mac = Hmac::new(::rcrypto::sha2::Sha256::new(), password.as_bytes());
let mut derived_key = vec![0u8; KEY_LENGTH_USIZE];
pbkdf2(&mut h_mac, &salt.as_slice(), c, &mut derived_key);
let derived_right_bits = &derived_key[0..KEY_LENGTH_AES_USIZE];
let derived_left_bits = &derived_key[KEY_LENGTH_AES_USIZE..KEY_LENGTH_USIZE];
(derived_right_bits.to_vec(), derived_left_bits.to_vec())
}
fn derive_key(password: &str, salt: &H256) -> (Bytes, Bytes) {
derive_key_iterations(password, salt, KEY_ITERATIONS)
}
fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Bytes {
let mut mac = vec![0u8; KEY_LENGTH_AES_USIZE + cipher_text.len()];
mac[0..KEY_LENGTH_AES_USIZE].clone_from_slice(derived_left_bits);
mac[KEY_LENGTH_AES_USIZE..cipher_text.len()+KEY_LENGTH_AES_USIZE].clone_from_slice(cipher_text);
mac
}
impl EncryptedHashMap<H128> for SecretStore { impl EncryptedHashMap<H128> for SecretStore {
fn get<Value: Populatable + Default + BytesConvertable>(&self, key: &H128, password: &str) -> Option<Value> { fn get<Value: Populatable + Default + BytesConvertable>(&self, key: &H128, password: &str) -> Option<Value> {
match self.directory.get(key) { match self.directory.get(key) {
@ -81,14 +104,13 @@ impl EncryptedHashMap<H128> for SecretStore {
let iv = H128::random(); let iv = H128::random();
let mut key_file = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(vec![], iv.clone(), salt.clone(), KEY_ITERATIONS, KEY_LENGTH)); let mut key_file = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(vec![], iv.clone(), salt.clone(), KEY_ITERATIONS, KEY_LENGTH));
let mut mac = Hmac::new(::rcrypto::sha2::Sha256::new(), password.as_bytes()); let (derived_left_bits, derived_right_bits) = derive_key(password, &salt);
let mut derived_key = vec![0u8; KEY_LENGTH as usize];
pbkdf2(&mut mac, &salt.as_slice(), KEY_ITERATIONS, &mut derived_key);
let key = &derived_key[KEY_LENGTH_AES as usize..KEY_LENGTH as usize];
let mut cipher_text = vec![0u8; value.as_slice().len()]; let mut cipher_text = vec![0u8; value.as_slice().len()];
crypto::aes::encrypt(&key, &iv.as_slice(), &value.as_slice(), &mut cipher_text); crypto::aes::encrypt(&derived_left_bits, &iv.as_slice(), &value.as_slice(), &mut cipher_text);
key_file.crypto.cipher_text = cipher_text; key_file.crypto.cipher_text = cipher_text.clone();
key_file.crypto.mac = derive_mac(&derived_right_bits, &cipher_text).sha3();
previous previous
} }
@ -103,6 +125,31 @@ impl EncryptedHashMap<H128> for SecretStore {
} }
#[cfg(test)]
mod vector_tests {
use super::{derive_key,derive_mac,derive_key_iterations};
use common::*;
#[test]
fn mac_vector() {
let password = "testpassword";
let salt = H256::from_str("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd").unwrap();
let cipher_text = FromHex::from_hex("5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46").unwrap();
let iterations = 262144u32;
let (derived_left_bits, derived_right_bits) = derive_key_iterations(password, &salt, iterations);
assert_eq!("f06d69cdc7da0faffb1008270bca38f5", derived_left_bits.to_hex());
assert_eq!("e31891a3a773950e6d0fea48a7188551", derived_right_bits.to_hex());
let mut mac_body = derive_mac(&derived_right_bits, &cipher_text);
assert_eq!("e31891a3a773950e6d0fea48a71885515318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46", mac_body.to_hex());
let mac = mac_body.sha3();
assert_eq!("517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2", format!("{:?}", mac));
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -118,4 +165,6 @@ mod tests {
sstore.insert(H128::random(), "Cat".to_owned(), "pass"); sstore.insert(H128::random(), "Cat".to_owned(), "pass");
} }
} }