tests and serialization fixes

This commit is contained in:
Nikolay Volf 2016-02-12 20:09:24 +03:00
parent f198e53891
commit 89c5d9f6f6

View File

@ -161,8 +161,11 @@ pub enum KeyFileKdf {
/// Encrypted password or other arbitrary message /// Encrypted password or other arbitrary message
/// with settings for password derived key generator for decrypting content /// with settings for password derived key generator for decrypting content
pub struct KeyFileCrypto { pub struct KeyFileCrypto {
/// Cipher type
pub cipher_type: CryptoCipherType, pub cipher_type: CryptoCipherType,
/// Cipher text (encrypted message)
pub cipher_text: Bytes, pub cipher_text: Bytes,
/// password derived key geberator function settings
pub kdf: KeyFileKdf, pub kdf: KeyFileKdf,
} }
@ -173,10 +176,10 @@ impl KeyFileCrypto {
Some(obj) => obj Some(obj) => obj
}; };
let cipher_type = match as_object["cipher"].as_string() { let cipher_type = match try!(as_object.get("cipher").ok_or(CryptoParseError::NoCipherType)).as_string() {
None => { return Err(CryptoParseError::NoCipherType); } None => { return Err(CryptoParseError::InvalidCipherType(Mismatch { expected: "aes-128-ctr".to_owned(), found: "not a json string".to_owned() })); }
Some("aes-128-ctr") => CryptoCipherType::Aes128Ctr( Some("aes-128-ctr") => CryptoCipherType::Aes128Ctr(
match as_object["cipherparams"].as_object() { match try!(as_object.get("cipherparams").ok_or(CryptoParseError::NoCipherParameters)).as_object() {
None => { return Err(CryptoParseError::NoCipherParameters); }, None => { return Err(CryptoParseError::NoCipherParameters); },
Some(cipher_param) => match U128::from_str(match cipher_param["iv"].as_string() { Some(cipher_param) => match U128::from_str(match cipher_param["iv"].as_string() {
None => { return Err(CryptoParseError::NoInitialVector); }, None => { return Err(CryptoParseError::NoInitialVector); },
@ -194,7 +197,7 @@ impl KeyFileCrypto {
} }
}; };
let kdf = match (as_object["kdf"].as_string(), as_object["kdfparams"].as_object()) { let kdf = match (try!(as_object.get("kdf").ok_or(CryptoParseError::NoKdf)).as_string(), try!(as_object.get("kdfparams").ok_or(CryptoParseError::NoKdfType)).as_object()) {
(None, _) => { return Err(CryptoParseError::NoKdfType); }, (None, _) => { return Err(CryptoParseError::NoKdfType); },
(Some("scrypt"), Some(kdf_params)) => (Some("scrypt"), Some(kdf_params)) =>
match KdfScryptParams::from_json(kdf_params) { match KdfScryptParams::from_json(kdf_params) {
@ -226,10 +229,23 @@ impl KeyFileCrypto {
fn to_json(&self) -> Json { fn to_json(&self) -> Json {
let mut map = BTreeMap::new(); let mut map = BTreeMap::new();
map.insert("cipher_type".to_owned(), Json::String("aes-128-ctr".to_owned())); match self.cipher_type {
map.insert("cipher_text".to_owned(), Json::String( CryptoCipherType::Aes128Ctr(iv) => {
map.insert("cipher".to_owned(), Json::String("aes-128-ctr".to_owned()));
let mut cipher_params = BTreeMap::new();
cipher_params.insert("iv".to_owned(), Json::String(format!("{:?}", iv)));
map.insert("cipherparams".to_owned(), Json::Object(cipher_params));
}
}
map.insert("ciphertext".to_owned(), Json::String(
self.cipher_text.iter().map(|b| format!("{:02x}", b)).collect::<Vec<String>>().join(""))); self.cipher_text.iter().map(|b| format!("{:02x}", b)).collect::<Vec<String>>().join("")));
map.insert("kdf".to_owned(), match self.kdf {
map.insert("kdf".to_owned(), Json::String(match self.kdf {
KeyFileKdf::Pbkdf2(_) => "pbkdf2".to_owned(),
KeyFileKdf::Scrypt(_) => "scrypt".to_owned()
}));
map.insert("kdfparams".to_owned(), match self.kdf {
KeyFileKdf::Pbkdf2(ref pbkdf2_params) => pbkdf2_params.to_json(), KeyFileKdf::Pbkdf2(ref pbkdf2_params) => pbkdf2_params.to_json(),
KeyFileKdf::Scrypt(ref scrypt_params) => scrypt_params.to_json() KeyFileKdf::Scrypt(ref scrypt_params) => scrypt_params.to_json()
}); });
@ -313,6 +329,7 @@ enum CryptoParseError {
NoInitialVector, NoInitialVector,
NoCipherParameters, NoCipherParameters,
InvalidInitialVector(FromHexError), InvalidInitialVector(FromHexError),
NoKdf,
NoKdfType, NoKdfType,
Scrypt(ScryptParseError), Scrypt(ScryptParseError),
KdfPbkdf2(Pbkdf2ParseError) KdfPbkdf2(Pbkdf2ParseError)
@ -340,6 +357,13 @@ impl KeyFileContent {
} }
} }
/// returns key file version if it is known
pub fn version(&self) -> Option<u64> {
match self.version {
KeyFileVersion::V3(declared) => Some(declared)
}
}
fn from_json(json: &Json) -> Result<KeyFileContent, KeyFileParseError> { fn from_json(json: &Json) -> Result<KeyFileContent, KeyFileParseError> {
let as_object = match json.as_object() { let as_object = match json.as_object() {
None => { return Err(KeyFileParseError::InvalidJsonFormat); }, None => { return Err(KeyFileParseError::InvalidJsonFormat); },
@ -414,7 +438,7 @@ impl KeyDirectory {
} }
/// saves (inserts or updates) given key /// saves (inserts or updates) given key
pub fn save(&mut self, key_file: KeyFileContent) -> Result<(), ::std::io::Error> { pub fn save(&mut self, key_file: KeyFileContent) -> Result<(Uuid), ::std::io::Error> {
{ {
let mut file = try!(fs::File::create(self.key_path(&key_file.id))); let mut file = try!(fs::File::create(self.key_path(&key_file.id)));
let json = key_file.to_json(); let json = key_file.to_json();
@ -422,8 +446,9 @@ impl KeyDirectory {
let json_bytes = json_text.into_bytes(); let json_bytes = json_text.into_bytes();
try!(file.write(&json_bytes)); try!(file.write(&json_bytes));
} }
self.cache.insert(key_file.id.clone(), key_file); let id = key_file.id.clone();
Ok(()) self.cache.insert(id.clone(), key_file);
Ok(id.clone())
} }
/// returns key given by id if corresponding file exists and no load error occured /// returns key given by id if corresponding file exists and no load error occured
@ -491,7 +516,7 @@ impl KeyDirectory {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{KeyFileContent, KeyFileVersion, KeyFileKdf, KeyFileParseError, CryptoParseError, uuid_from_string, uuid_to_string}; use super::{KeyFileContent, KeyFileVersion, KeyFileKdf, KeyFileParseError, CryptoParseError, uuid_from_string, uuid_to_string, KeyFileCrypto};
use common::*; use common::*;
#[test] #[test]
@ -699,6 +724,24 @@ mod tests {
Err(other_error) => { panic!("should be error of invalid initial vector, got {:?}", other_error); } Err(other_error) => { panic!("should be error of invalid initial vector, got {:?}", other_error); }
} }
} }
#[test]
fn can_create_key_with_new_id() {
let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap();
let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32));
assert!(!uuid_to_string(&key.id).is_empty());
}
#[test]
fn can_load_json_from_itself() {
let cipher_text: Bytes = FromHex::from_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaa22222222222222222222222").unwrap();
let key = KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32));
let json = key.to_json();
let loaded_key = KeyFileContent::from_json(&json).unwrap();
assert_eq!(loaded_key.id, key.id);
}
} }
#[cfg(test)] #[cfg(test)]
@ -710,9 +753,18 @@ mod specs {
#[test] #[test]
fn can_initiate_key_directory() { fn can_initiate_key_directory() {
let temp_path = RandomTempPath::create_dir(); let temp_path = RandomTempPath::create_dir();
let directory = KeyDirectory::new(&temp_path.as_path()); let directory = KeyDirectory::new(&temp_path.as_path());
assert!(directory.path().len() > 0); assert!(directory.path().len() > 0);
} }
#[test]
fn can_save_key() {
let cipher_text: Bytes = FromHex::from_hex("a0f05555").unwrap();
let temp_path = RandomTempPath::create_dir();
let mut directory = KeyDirectory::new(&temp_path.as_path());
let uuid = directory.save(KeyFileContent::new(KeyFileCrypto::new_pbkdf2(cipher_text, U128::zero(), H256::random(), 32, 32)));
assert!(uuid.is_ok());
}
} }