* 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:
parent
15a14a5f49
commit
c0e72209e8
@ -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, ¶ms.salt, params.c),
|
Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, ¶ms.salt, params.c),
|
||||||
Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, ¶ms.salt, params.n, params.p, params.r),
|
Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, ¶ms.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, ¶ms.iv, &self.ciphertext, &mut *secret)
|
let from = 32 - self.ciphertext.len();
|
||||||
|
crypto::aes::decrypt(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut (&mut *secret)[from..])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
ethstore/src/json/bytes.rs
Normal file
58
ethstore/src/json/bytes.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
21
ethstore/tests/res/ciphertext/30.json
Normal file
21
ethstore/tests/res/ciphertext/30.json
Normal 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
|
||||||
|
}
|
21
ethstore/tests/res/ciphertext/31.json
Normal file
21
ethstore/tests/res/ciphertext/31.json
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user