first vector up
This commit is contained in:
parent
ac0ca94230
commit
a649d6f131
@ -168,6 +168,8 @@ pub struct KeyFileCrypto {
|
||||
pub cipher_text: Bytes,
|
||||
/// Password derived key generator function settings.
|
||||
pub kdf: KeyFileKdf,
|
||||
/// Mac
|
||||
pub mac: H256
|
||||
}
|
||||
|
||||
impl KeyFileCrypto {
|
||||
@ -216,15 +218,24 @@ impl KeyFileCrypto {
|
||||
}
|
||||
};
|
||||
|
||||
let cipher_text = match as_object["ciphertext"].as_string() {
|
||||
None => { return Err(CryptoParseError::NoCipherText); }
|
||||
let cipher_text = match try!(as_object.get("ciphertext").ok_or(CryptoParseError::NoCipherText)).as_string() {
|
||||
None => { return Err(CryptoParseError::InvalidCipherText); }
|
||||
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 {
|
||||
cipher_text: Bytes::from(cipher_text),
|
||||
cipher_type: cipher_type,
|
||||
kdf: kdf,
|
||||
mac: mac,
|
||||
})
|
||||
}
|
||||
|
||||
@ -251,6 +262,8 @@ impl KeyFileCrypto {
|
||||
KeyFileKdf::Scrypt(ref scrypt_params) => scrypt_params.to_json()
|
||||
});
|
||||
|
||||
map.insert("mac".to_owned(), Json::String(format!("{:?}", self.mac)));
|
||||
|
||||
Json::Object(map)
|
||||
}
|
||||
|
||||
@ -270,6 +283,7 @@ impl KeyFileCrypto {
|
||||
c: c,
|
||||
prf: Pbkdf2CryptoFunction::HMacSha256
|
||||
}),
|
||||
mac: H256::random(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -324,7 +338,10 @@ pub struct KeyFileContent {
|
||||
|
||||
#[derive(Debug)]
|
||||
enum CryptoParseError {
|
||||
InvalidMacFormat(Option<UtilError>),
|
||||
NoMac,
|
||||
NoCipherText,
|
||||
InvalidCipherText,
|
||||
NoCipherType,
|
||||
InvalidJsonFormat,
|
||||
InvalidKdfType(Mismatch<String>),
|
||||
|
@ -18,4 +18,4 @@
|
||||
|
||||
pub mod directory;
|
||||
|
||||
mod encryptor;
|
||||
mod store;
|
||||
|
@ -27,6 +27,9 @@ const KEY_LENGTH: u32 = 32;
|
||||
const KEY_ITERATIONS: u32 = 4096;
|
||||
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> {
|
||||
// Returns existing value for the key, if any
|
||||
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 {
|
||||
fn get<Value: Populatable + Default + BytesConvertable>(&self, key: &H128, password: &str) -> Option<Value> {
|
||||
match self.directory.get(key) {
|
||||
@ -81,14 +104,13 @@ impl EncryptedHashMap<H128> for SecretStore {
|
||||
let iv = H128::random();
|
||||
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 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 (derived_left_bits, derived_right_bits) = derive_key(password, &salt);
|
||||
|
||||
let mut cipher_text = vec![0u8; value.as_slice().len()];
|
||||
crypto::aes::encrypt(&key, &iv.as_slice(), &value.as_slice(), &mut cipher_text);
|
||||
key_file.crypto.cipher_text = cipher_text;
|
||||
crypto::aes::encrypt(&derived_left_bits, &iv.as_slice(), &value.as_slice(), &mut cipher_text);
|
||||
key_file.crypto.cipher_text = cipher_text.clone();
|
||||
|
||||
key_file.crypto.mac = derive_mac(&derived_right_bits, &cipher_text).sha3();
|
||||
|
||||
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)]
|
||||
mod tests {
|
||||
@ -118,4 +165,6 @@ mod tests {
|
||||
sstore.insert(H128::random(), "Cat".to_owned(), "pass");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user