diff --git a/ethcore/src/secret_store.rs b/ethcore/src/secret_store.rs index e610fa65b..a7289f4e4 100644 --- a/ethcore/src/secret_store.rs +++ b/ethcore/src/secret_store.rs @@ -24,18 +24,8 @@ enum CryptoCipherType { Aes128Ctr(U128) } -enum KeyFileKdf { - Pbkdf2(KdfPbkdf2Params), - Scrypt(KdfScryptParams) -} - -struct KeyFileCrypto { - cipher: CryptoCipherType, - Kdf: KeyFileKdf, -} - enum KeyFileVersion { - V1, V2, V3 + V3(u64) } enum Pbkdf2CryptoFunction { @@ -56,6 +46,22 @@ struct KdfPbkdf2Params { prf: Pbkdf2CryptoFunction } +#[derive(Debug)] +enum KdfPbkdf2ParseError { + InvalidParameter(String) +} + +impl KdfPbkdf2Params { + fn new(_json: &Json) -> Result { + KdfPbkdf2Params{ + dkLen: 0, + salt: H256::zero(), + c: 0, + prf: Pbkdf2CryptoFunction::HMacSha256 + } + } +} + #[allow(non_snake_case)] // Kdf of type `Scrypt` // https://en.wikipedia.org/wiki/Scrypt @@ -70,15 +76,157 @@ struct KdfScryptParams { r: u32, } -type Uuid = String; +#[derive(Debug)] +enum ScryptParseError { + InvalidParameter(String) +} + +impl KdfScryptParams { + fn new(_json: &Json) -> Result { + Ok(KdfScryptParams{ + dkLen: 0, + p: 0, + n: 0, + r: 0 + }) + } +} enum Kdf { Pbkdf2(KdfPbkdf2Params), Scrypt(KdfScryptParams) } +enum KeyFileKdf { + Pbkdf2(KdfPbkdf2Params), + Scrypt(KdfScryptParams) +} + +struct KeyFileCrypto { + cipher_type: CryptoCipherType, + cipher_text: Bytes, + kdf: KeyFileKdf, +} + +impl KeyFileCrypto { + fn new(json: &Json) -> Result { + let as_object = match json.as_object() { + None => { return Err(CryptoParseError::InvalidJsonFormat); } + Some(obj) => obj + }; + + let cipher_type = match as_object["cipher"].as_string() { + None => { return Err(CryptoParseError::NoCipherType); } + Some("aes-128-ctr") => CryptoCipherType::Aes128Ctr( + match as_object["cipherparams"].as_string() { + None => { return Err(CryptoParseError::NoCipherParameters); }, + Some(cipher_param) => H128::from(cipher_param) + } + ), + Some(oter_cipher_type) => { + return Err(CryptoParseError::InvalidCipherType( + Mismatch { expected: "aes-128-ctr".to_owned(), found: other_cipher_type.to_owned() })); + } + }; + + let kdf = match (as_object["kdf"].as_string(), as_object["kdfparams"]) { + (None, _) => { return Err(CryptoParseError::NoKdfType); }, + (_, None) => { return Err(CryptoParseError::NoKdfParams); }, + (Some("scrypt"), Some(kdf_params)) => + match KdfScryptParams::new(kdf_params) { + Err(scrypt_params_error) => return Err(CryptoParseError::Scrypt(scrypt_params_error)), + Ok(scrypt_params) => scrypt_params + }, + (Some("pbkdf2"), Some(kdf_params)) => + match KdfPbkdf2Params::new(kdf_params) { + Err(kdfPbkdf2_params_error) => return Err(CryptoParseError::Scrypt(scrypt_params_error)), + Ok(kdfPbkdf2_params) => kdfPbkdf2_params + }, + (Some(other_kdf), _) => { + return Err(CryptoParseError::InvalidKdfType( + Mismatch { expected: "pbkdf2/scrypt".to_owned(), found: other_kdf.to_ownded()})); + } + }; + + let cipher_text = match as_object["ciphertext"].as_string() { + None => { return Err(CryptoParseError::NoCipherText); } + Some(text) => text + }; + + Ok(KeyFileCrypto { + cipher_text: Bytes::from(cipher_text), + cipher_type: cipher_type, + kdf: kdf, + }) + } +} + +type Uuid = String; + struct KeyFileContent { version: KeyFileVersion, crypto: KeyFileCrypto, id: Uuid } + +#[derive(Debug)] +enum CryptoParseError { + InvalidJsonFormat, + InvalidCryptoVersion, + NoCryptoVersion, + InvalidKdfType(Mismatch), + InvalidCipherType(Mismatch), + NoCipherText, + NoKdfType, + NoKdfParams, + Scrypt(ScryptParseError), + KdfPbkdf2(KdfPbkdf2ParseError) +} + +#[derive(Debug)] +enum KeyFileParseError { + InvalidVersion, + UnsupportedVersion(OutOfBounds), + InvalidJsonFormat, + NoIdentifier, + NoCryptoSection, + Crypto(CryptoParseError), +} + +impl KeyFileContent { + fn new(json: &Json) -> Result { + let as_object = match json.as_object() { + None => { return Err(KeyFileParseError::InvalidJsonFormat); }, + Some(obj) => obj + }; + + let version = match as_object["version"].as_u64() { + None => { return Err(KeyFileParseError::InvalidVersion); }, + Some(json_version) => { + if json_version <= 2 { + return Err(KeyFileParseError::UnsupportedVersion(OutOfBounds { min: Some(3), max: None, found: json_version })) + }; + KeyFileVersion::V3(json_version) + } + }; + + let id = match as_object["id"].as_string() { + None => { return Err(KeyFileParseError::NoIdentifier); }, + Some(id) => id + }; + + let crypto = match as_object.get("crypto") { + None => { return Err(KeyFileParseError::NoCryptoSection); } + Some(crypto_json) => match KeyFileCrypto::new(crypto_json) { + Ok(crypto) => crypto, + Err(crypto_error) => { return Err(KeyFileParseError::Crypto(crypto_error)); } + } + }; + + Ok(KeyFileContent { + version: version, + id: id.to_owned(), + crypto: crypto + }) + } +}