fixed #2263, geth keys with ciphertext shorter than 32 bytes (#2318)

* fixed #2263, geth keys with ciphertext shorter than 32 bytes

* replace unwrap with more helpful expect

* tests for decrypting short secrets
This commit is contained in:
Marek Kotewicz 2016-09-28 15:47:52 +02:00 committed by Gav Wood
parent 15a14a5f49
commit c0e72209e8
11 changed files with 194 additions and 73 deletions

View File

@ -16,14 +16,14 @@
use ethkey::{KeyPair, sign, Address, Secret, Signature, Message}; use ethkey::{KeyPair, sign, Address, Secret, Signature, Message};
use {json, Error, crypto}; use {json, Error, crypto};
use crypto::{Keccak256}; use crypto::Keccak256;
use random::Random; use random::Random;
use account::{Version, Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf}; use account::{Version, Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Crypto { pub struct Crypto {
pub cipher: Cipher, pub cipher: Cipher,
pub ciphertext: [u8; 32], pub ciphertext: Vec<u8>,
pub kdf: Kdf, pub kdf: Kdf,
pub mac: [u8; 32], pub mac: [u8; 32],
} }
@ -95,7 +95,7 @@ impl Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr { cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: iv, iv: iv,
}), }),
ciphertext: ciphertext, ciphertext: ciphertext.to_vec(),
kdf: Kdf::Pbkdf2(Pbkdf2 { kdf: Kdf::Pbkdf2(Pbkdf2 {
dklen: crypto::KEY_LENGTH as u32, dklen: crypto::KEY_LENGTH as u32,
salt: salt, salt: salt,
@ -107,6 +107,10 @@ impl Crypto {
} }
pub fn secret(&self, password: &str) -> Result<Secret, Error> { pub fn secret(&self, password: &str) -> Result<Secret, Error> {
if self.ciphertext.len() > 32 {
return Err(Error::InvalidSecret);
}
let (derived_left_bits, derived_right_bits) = match self.kdf { let (derived_left_bits, derived_right_bits) = match self.kdf {
Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, &params.salt, params.c), Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, &params.salt, params.c),
Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, &params.salt, params.n, params.p, params.r), Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, &params.salt, params.n, params.p, params.r),
@ -122,7 +126,8 @@ impl Crypto {
match self.cipher { match self.cipher {
Cipher::Aes128Ctr(ref params) => { Cipher::Aes128Ctr(ref params) => {
crypto::aes::decrypt(&derived_left_bits, &params.iv, &self.ciphertext, &mut *secret) let from = 32 - self.ciphertext.len();
crypto::aes::decrypt(&derived_left_bits, &params.iv, &self.ciphertext, &mut (&mut *secret)[from..])
}, },
} }

View File

@ -0,0 +1,58 @@
use std::{ops, str};
use serde::{Deserialize, Deserializer, Error, Serialize, Serializer};
use rustc_serialize::hex::{ToHex, FromHex, FromHexError};
#[derive(Debug, PartialEq)]
pub struct Bytes(Vec<u8>);
impl ops::Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Deserialize for Bytes {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer
{
let s = try!(String::deserialize(deserializer));
let data = try!(s.from_hex().map_err(|e| Error::custom(format!("Invalid hex value {}", e))));
Ok(Bytes(data))
}
}
impl Serialize for Bytes {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
serializer.serialize_str(&self.0.to_hex())
}
}
impl str::FromStr for Bytes {
type Err = FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.from_hex().map(Bytes)
}
}
impl From<&'static str> for Bytes {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s))
}
}
impl From<Vec<u8>> for Bytes {
fn from(v: Vec<u8>) -> Self {
Bytes(v)
}
}
impl From<Bytes> for Vec<u8> {
fn from(b: Bytes) -> Self {
b.0
}
}

View File

@ -16,12 +16,14 @@
use serde::{Deserialize, Deserializer, Serialize, Serializer, Error}; use serde::{Deserialize, Deserializer, Serialize, Serializer, Error};
use serde::de::{Visitor, MapVisitor}; use serde::de::{Visitor, MapVisitor};
use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256}; use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256, Bytes};
pub type CipherText = Bytes;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Crypto { pub struct Crypto {
pub cipher: Cipher, pub cipher: Cipher,
pub ciphertext: H256, pub ciphertext: CipherText,
pub kdf: Kdf, pub kdf: Kdf,
pub mac: H256, pub mac: H256,
} }

View File

@ -14,9 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::fmt; use std::{ops, fmt, str};
use std::ops;
use std::str::FromStr;
use rustc_serialize::hex::{FromHex, ToHex}; use rustc_serialize::hex::{FromHex, ToHex};
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error as SerdeError}; use serde::{Serialize, Serializer, Deserialize, Deserializer, Error as SerdeError};
use serde::de::Visitor; use serde::de::Visitor;
@ -65,7 +63,7 @@ macro_rules! impl_hash {
type Value = $name; type Value = $name;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError { fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
FromStr::from_str(value).map_err(SerdeError::custom) value.parse().map_err(SerdeError::custom)
} }
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError { fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError {
@ -77,7 +75,7 @@ macro_rules! impl_hash {
} }
} }
impl FromStr for $name { impl str::FromStr for $name {
type Err = Error; type Err = Error;
fn from_str(value: &str) -> Result<Self, Self::Err> { fn from_str(value: &str) -> Result<Self, Self::Err> {
@ -92,6 +90,12 @@ macro_rules! impl_hash {
} }
} }
impl From<&'static str> for $name {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s))
}
}
impl From<[u8; $size]> for $name { impl From<[u8; $size]> for $name {
fn from(bytes: [u8; $size]) -> Self { fn from(bytes: [u8; $size]) -> Self {
$name(bytes) $name(bytes)

View File

@ -15,8 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Universaly unique identifier. //! Universaly unique identifier.
use std::str::FromStr; use std::{fmt, str};
use std::fmt;
use rustc_serialize::hex::{ToHex, FromHex}; use rustc_serialize::hex::{ToHex, FromHex};
use serde::{Deserialize, Serialize, Deserializer, Serializer, Error as SerdeError}; use serde::{Deserialize, Serialize, Deserializer, Serializer, Error as SerdeError};
use serde::de::Visitor; use serde::de::Visitor;
@ -73,7 +72,7 @@ fn copy_into(from: &str, into: &mut [u8]) -> Result<(), Error> {
Ok(()) Ok(())
} }
impl FromStr for UUID { impl str::FromStr for UUID {
type Err = Error; type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
@ -95,6 +94,12 @@ impl FromStr for UUID {
} }
} }
impl From<&'static str> for UUID {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s))
}
}
impl Serialize for UUID { impl Serialize for UUID {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer { where S: Serializer {
@ -116,7 +121,7 @@ impl Visitor for UUIDVisitor {
type Value = UUID; type Value = UUID;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError { fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
UUID::from_str(value).map_err(SerdeError::custom) value.parse().map_err(SerdeError::custom)
} }
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError { fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError {
@ -126,19 +131,18 @@ impl Visitor for UUIDVisitor {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::str::FromStr;
use super::UUID; use super::UUID;
#[test] #[test]
fn uuid_from_str() { fn uuid_from_str() {
let uuid = UUID::from_str("3198bc9c-6672-5ab3-d995-4942343ae5b6").unwrap(); let uuid: UUID = "3198bc9c-6672-5ab3-d995-4942343ae5b6".into();
assert_eq!(uuid, UUID::from([0x31, 0x98, 0xbc, 0x9c, 0x66, 0x72, 0x5a, 0xb3, 0xd9, 0x95, 0x49, 0x42, 0x34, 0x3a, 0xe5, 0xb6])); assert_eq!(uuid, UUID::from([0x31, 0x98, 0xbc, 0x9c, 0x66, 0x72, 0x5a, 0xb3, 0xd9, 0x95, 0x49, 0x42, 0x34, 0x3a, 0xe5, 0xb6]));
} }
#[test] #[test]
fn uuid_from_and_to_str() { fn uuid_from_and_to_str() {
let from = "3198bc9c-6672-5ab3-d995-4942343ae5b6"; let from = "3198bc9c-6672-5ab3-d995-4942343ae5b6";
let uuid = UUID::from_str(from).unwrap(); let uuid: UUID = from.into();
let to: String = uuid.into(); let to: String = uuid.into();
assert_eq!(from, &to); assert_eq!(from, &to);
} }

View File

@ -98,7 +98,7 @@ impl Visitor for KeyFileVisitor {
Some(KeyFileField::Version) => { version = Some(try!(visitor.visit_value())); } Some(KeyFileField::Version) => { version = Some(try!(visitor.visit_value())); }
Some(KeyFileField::Crypto) => { crypto = Some(try!(visitor.visit_value())); } Some(KeyFileField::Crypto) => { crypto = Some(try!(visitor.visit_value())); }
Some(KeyFileField::Address) => { address = Some(try!(visitor.visit_value())); } Some(KeyFileField::Address) => { address = Some(try!(visitor.visit_value())); }
Some(KeyFileField::Name) => { name = visitor.visit_value().ok(); } // ignore anyhing that is not a string to be permissive. Some(KeyFileField::Name) => { name = visitor.visit_value().ok(); } // ignore anyhing that is not a string to be permissive.
Some(KeyFileField::Meta) => { meta = visitor.visit_value().ok(); } // ignore anyhing that is not a string to be permissive. Some(KeyFileField::Meta) => { meta = visitor.visit_value().ok(); } // ignore anyhing that is not a string to be permissive.
None => { break; } None => { break; }
} }
@ -153,7 +153,7 @@ impl KeyFile {
mod tests { mod tests {
use std::str::FromStr; use std::str::FromStr;
use serde_json; use serde_json;
use json::{KeyFile, UUID, Version, Crypto, Cipher, Aes128Ctr, Kdf, Scrypt, H128, H160, H256}; use json::{KeyFile, UUID, Version, Crypto, Cipher, Aes128Ctr, Kdf, Scrypt};
#[test] #[test]
fn basic_keyfile() { fn basic_keyfile() {
@ -185,20 +185,20 @@ mod tests {
let expected = KeyFile { let expected = KeyFile {
id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(), id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
version: Version::V3, version: Version::V3,
address: H160::from_str("6edddfc6349aff20bc6467ccf276c5b52487f7a8").unwrap(), address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
crypto: Crypto { crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr { cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: H128::from_str("b5a7ec855ec9e2c405371356855fec83").unwrap(), iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}), }),
ciphertext: H256::from_str("7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc").unwrap(), ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc".into(),
kdf: Kdf::Scrypt(Scrypt { kdf: Kdf::Scrypt(Scrypt {
n: 262144, n: 262144,
dklen: 32, dklen: 32,
p: 1, p: 1,
r: 8, r: 8,
salt: H256::from_str("1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209").unwrap(), salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}), }),
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(), mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
}, },
name: Some("Test".to_owned()), name: Some("Test".to_owned()),
meta: Some("{}".to_owned()), meta: Some("{}".to_owned()),
@ -234,22 +234,22 @@ mod tests {
}"#; }"#;
let expected = KeyFile { let expected = KeyFile {
id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(), id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
version: Version::V3, version: Version::V3,
address: H160::from_str("6edddfc6349aff20bc6467ccf276c5b52487f7a8").unwrap(), address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
crypto: Crypto { crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr { cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: H128::from_str("b5a7ec855ec9e2c405371356855fec83").unwrap(), iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}), }),
ciphertext: H256::from_str("7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc").unwrap(), ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc".into(),
kdf: Kdf::Scrypt(Scrypt { kdf: Kdf::Scrypt(Scrypt {
n: 262144, n: 262144,
dklen: 32, dklen: 32,
p: 1, p: 1,
r: 8, r: 8,
salt: H256::from_str("1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209").unwrap(), salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}), }),
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(), mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
}, },
name: None, name: None,
meta: None, meta: None,
@ -262,22 +262,22 @@ mod tests {
#[test] #[test]
fn to_and_from_json() { fn to_and_from_json() {
let file = KeyFile { let file = KeyFile {
id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(), id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
version: Version::V3, version: Version::V3,
address: H160::from_str("6edddfc6349aff20bc6467ccf276c5b52487f7a8").unwrap(), address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
crypto: Crypto { crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr { cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: H128::from_str("b5a7ec855ec9e2c405371356855fec83").unwrap(), iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}), }),
ciphertext: H256::from_str("7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc").unwrap(), ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc".into(),
kdf: Kdf::Scrypt(Scrypt { kdf: Kdf::Scrypt(Scrypt {
n: 262144, n: 262144,
dklen: 32, dklen: 32,
p: 1, p: 1,
r: 8, r: 8,
salt: H256::from_str("1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209").unwrap(), salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}), }),
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(), mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
}, },
name: Some("Test".to_owned()), name: Some("Test".to_owned()),
meta: None, meta: None,

View File

@ -1,3 +1,4 @@
mod bytes;
mod cipher; mod cipher;
mod crypto; mod crypto;
mod error; mod error;
@ -8,8 +9,9 @@ mod key_file;
mod presale; mod presale;
mod version; mod version;
pub use self::bytes::Bytes;
pub use self::cipher::{Cipher, CipherSer, CipherSerParams, Aes128Ctr}; pub use self::cipher::{Cipher, CipherSer, CipherSerParams, Aes128Ctr};
pub use self::crypto::Crypto; pub use self::crypto::{Crypto, CipherText};
pub use self::error::Error; pub use self::error::Error;
pub use self::hash::{H128, H160, H256}; pub use self::hash::{H128, H160, H256};
pub use self::id::UUID; pub use self::id::UUID;

View File

@ -1,30 +1,8 @@
use std::io::Read; use std::io::Read;
use std::ops::Deref;
use serde_json; use serde_json;
use serde::{Deserialize, Deserializer, Error}; use super::{H160, Bytes};
use rustc_serialize::hex::FromHex;
use super::{H160};
#[derive(Debug, PartialEq)] pub type Encseed = Bytes;
pub struct Encseed(Vec<u8>);
impl Deref for Encseed {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Deserialize for Encseed {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer
{
let s = try!(String::deserialize(deserializer));
let data = try!(s.from_hex().map_err(|e| Error::custom(format!("Invalid hex value {}", e))));
Ok(Encseed(data))
}
}
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
pub struct PresaleWallet { pub struct PresaleWallet {
@ -43,8 +21,7 @@ impl PresaleWallet {
mod tests { mod tests {
use std::str::FromStr; use std::str::FromStr;
use serde_json; use serde_json;
use rustc_serialize::hex::FromHex; use json::{PresaleWallet, H160};
use json::{PresaleWallet, H160, Encseed};
#[test] #[test]
fn presale_wallet() { fn presale_wallet() {
@ -57,7 +34,7 @@ mod tests {
} "#; } "#;
let expected = PresaleWallet { let expected = PresaleWallet {
encseed: Encseed("137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066".from_hex().unwrap()), encseed: "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066".into(),
address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(), address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(),
}; };
@ -77,7 +54,7 @@ mod tests {
} "#; } "#;
let expected = PresaleWallet { let expected = PresaleWallet {
encseed: Encseed("137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0d".from_hex().unwrap()), encseed: "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0d".into(),
address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(), address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(),
}; };

View File

@ -19,9 +19,8 @@ extern crate ethstore;
mod util; mod util;
use std::str::FromStr;
use ethstore::{SecretStore, EthStore}; use ethstore::{SecretStore, EthStore};
use ethstore::ethkey::{Random, Generator, Secret, Address}; use ethstore::ethkey::{Random, Generator, Secret, KeyPair, verify_address};
use ethstore::dir::DiskDirectory; use ethstore::dir::DiskDirectory;
use util::TransientDir; use util::TransientDir;
@ -103,14 +102,21 @@ fn pat_path() -> &'static str {
} }
} }
fn ciphertext_path() -> &'static str {
match ::std::fs::metadata("ethstore") {
Ok(_) => "ethstore/tests/res/ciphertext",
Err(_) => "tests/res/ciphertext",
}
}
#[test] #[test]
fn secret_store_laod_geth_files() { fn secret_store_laod_geth_files() {
let dir = DiskDirectory::at(test_path()); let dir = DiskDirectory::at(test_path());
let store = EthStore::open(Box::new(dir)).unwrap(); let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts().unwrap(), vec![ assert_eq!(store.accounts().unwrap(), vec![
Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap(), "3f49624084b67849c7b4e805c5988c21a430f9d9".into(),
Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap(), "5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into(),
Address::from_str("63121b431a52f8043c16fcf0d1df9cb7b5f66649").unwrap(), "63121b431a52f8043c16fcf0d1df9cb7b5f66649".into(),
]); ]);
} }
@ -119,9 +125,30 @@ fn secret_store_load_pat_files() {
let dir = DiskDirectory::at(pat_path()); let dir = DiskDirectory::at(pat_path());
let store = EthStore::open(Box::new(dir)).unwrap(); let store = EthStore::open(Box::new(dir)).unwrap();
assert_eq!(store.accounts().unwrap(), vec![ assert_eq!(store.accounts().unwrap(), vec![
Address::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap(), "3f49624084b67849c7b4e805c5988c21a430f9d9".into(),
Address::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap(), "5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into(),
]); ]);
} }
#[test]
fn test_decrypting_files_with_short_ciphertext() {
// 31e9d1e6d844bd3a536800ef8d8be6a9975db509, 30
let kp1 = KeyPair::from_secret("000081c29e8142bb6a81bef5a92bda7a8328a5c85bb2f9542e76f9b0f94fc018".into()).unwrap();
// d1e64e5480bfaf733ba7d48712decb8227797a4e , 31
let kp2 = KeyPair::from_secret("00fa7b3db73dc7dfdf8c5fbdb796d741e4488628c41fc4febd9160a866ba0f35".into()).unwrap();
let dir = DiskDirectory::at(ciphertext_path());
let store = EthStore::open(Box::new(dir)).unwrap();
let accounts = store.accounts().unwrap();
assert_eq!(accounts, vec![
"31e9d1e6d844bd3a536800ef8d8be6a9975db509".into(),
"d1e64e5480bfaf733ba7d48712decb8227797a4e".into(),
]);
let message = Default::default();
let s1 = store.sign(&accounts[0], "foo", &message).unwrap();
let s2 = store.sign(&accounts[1], "foo", &message).unwrap();
assert!(verify_address(&accounts[0], &s1, &message).unwrap());
assert!(verify_address(&kp1.address(), &s1, &message).unwrap());
assert!(verify_address(&kp2.address(), &s2, &message).unwrap());
}

View File

@ -0,0 +1,21 @@
{
"address" : "31e9d1e6d844bd3a536800ef8d8be6a9975db509",
"crypto" : {
"cipher" : "aes-128-ctr",
"cipherparams" : {
"iv" : "3ca92af36ad7c2cd92454c59cea5ef00"
},
"ciphertext" : "108b7d34f3442fc26ab1ab90ca91476ba6bfa8c00975a49ef9051dc675aa",
"kdf" : "scrypt",
"kdfparams" : {
"dklen" : 32,
"n" : 2,
"r" : 8,
"p" : 1,
"salt" : "d0769e608fb86cda848065642a9c6fa046845c928175662b8e356c77f914cd3b"
},
"mac" : "75d0e6759f7b3cefa319c3be41680ab6beea7d8328653474bd06706d4cc67420"
},
"id" : "a37e1559-5955-450d-8075-7b8931b392b2",
"version" : 3
}

View File

@ -0,0 +1,21 @@
{
"address" : "d1e64e5480bfaf733ba7d48712decb8227797a4e",
"crypto" : {
"cipher" : "aes-128-ctr",
"cipherparams" : {
"iv" : "e0c41130a323adc1446fc82f724bca2f"
},
"ciphertext" : "9517cd5bdbe69076f9bf5057248c6c050141e970efa36ce53692d5d59a3984",
"kdf" : "scrypt",
"kdfparams" : {
"dklen" : 32,
"n" : 2,
"r" : 8,
"p" : 1,
"salt" : "711f816911c92d649fb4c84b047915679933555030b3552c1212609b38208c63"
},
"mac" : "d5e116151c6aa71470e67a7d42c9620c75c4d23229847dcc127794f0732b0db5"
},
"id" : "fecfc4ce-e956-48fd-953b-30f8b52ed66c",
"version" : 3
}