easy to use conversion from and to string for ethstore::Crypto (#5437)

* easy to use conversion from and to string for ethstore::Crypto

* ethstore uses tempdir instead of devtools

* ethstore does not depend on ethcore-util
This commit is contained in:
Marek Kotewicz 2017-04-11 16:24:56 +08:00 committed by Gav Wood
parent d3b2bcdd79
commit 4f8e61dce9
10 changed files with 82 additions and 47 deletions

4
Cargo.lock generated
View File

@ -784,8 +784,7 @@ name = "ethstore"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.7.0", "ethcore-bigint 0.1.2",
"ethcore-util 1.7.0",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethkey 0.2.0", "ethkey 0.2.0",
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -800,6 +799,7 @@ dependencies = [
"serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -94,11 +94,11 @@ pub trait Keccak256<T> {
fn keccak256(&self) -> T where T: Sized; fn keccak256(&self) -> T where T: Sized;
} }
impl Keccak256<[u8; 32]> for [u8] { impl<T> Keccak256<[u8; 32]> for T where T: AsRef<[u8]> {
fn keccak256(&self) -> [u8; 32] { fn keccak256(&self) -> [u8; 32] {
let mut keccak = Keccak::new_keccak256(); let mut keccak = Keccak::new_keccak256();
let mut result = [0u8; 32]; let mut result = [0u8; 32];
keccak.update(self); keccak.update(self.as_ref());
keccak.finalize(&mut result); keccak.finalize(&mut result);
result result
} }

View File

@ -19,10 +19,10 @@ time = "0.1.34"
itertools = "0.5" itertools = "0.5"
parking_lot = "0.4" parking_lot = "0.4"
ethcrypto = { path = "../ethcrypto" } ethcrypto = { path = "../ethcrypto" }
ethcore-util = { path = "../util" } ethcore-bigint = { path = "../util/bigint" }
smallvec = "0.3.1" smallvec = "0.3.1"
ethcore-devtools = { path = "../devtools" }
parity-wordlist = "1.0" parity-wordlist = "1.0"
tempdir = "0.3"
[features] [features]
cli = ["docopt"] cli = ["docopt"]

View File

@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::iter::repeat; use std::iter::repeat;
use std::str;
use ethkey::Secret; use ethkey::Secret;
use {json, Error, crypto}; use {json, Error, crypto};
use crypto::Keccak256; use crypto::Keccak256;
@ -46,17 +47,31 @@ impl From<json::Crypto> for Crypto {
} }
} }
impl Into<json::Crypto> for Crypto { impl From<Crypto> for json::Crypto {
fn into(self) -> json::Crypto { fn from(c: Crypto) -> Self {
json::Crypto { json::Crypto {
cipher: self.cipher.into(), cipher: c.cipher.into(),
ciphertext: self.ciphertext.into(), ciphertext: c.ciphertext.into(),
kdf: self.kdf.into(), kdf: c.kdf.into(),
mac: self.mac.into(), mac: c.mac.into(),
} }
} }
} }
impl str::FromStr for Crypto {
type Err = <json::Crypto as str::FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse::<json::Crypto>().map(Into::into)
}
}
impl From<Crypto> for String {
fn from(c: Crypto) -> Self {
json::Crypto::from(c).into()
}
}
impl Crypto { impl Crypto {
pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Self { pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Self {
Crypto::with_plain(&*secret, password, iterations) Crypto::with_plain(&*secret, password, iterations)

View File

@ -225,8 +225,8 @@ impl<T> KeyDirectory for DiskDirectory<T> where T: KeyFileManager {
Some(self) Some(self)
} }
fn unique_repr(&self) -> Result<u64, Error> { fn unique_repr(&self) -> Result<u64, Error> {
self.files_hash() self.files_hash()
} }
} }
@ -280,12 +280,14 @@ impl KeyFileManager for DiskKeyFileManager {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
extern crate tempdir;
use std::{env, fs}; use std::{env, fs};
use super::RootDiskDirectory; use super::RootDiskDirectory;
use dir::{KeyDirectory, VaultKey}; use dir::{KeyDirectory, VaultKey};
use account::SafeAccount; use account::SafeAccount;
use ethkey::{Random, Generator}; use ethkey::{Random, Generator};
use devtools::RandomTempPath; use self::tempdir::TempDir;
#[test] #[test]
fn should_create_new_account() { fn should_create_new_account() {
@ -344,7 +346,7 @@ mod test {
#[test] #[test]
fn should_list_vaults() { fn should_list_vaults() {
// given // given
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let directory = RootDiskDirectory::create(&temp_path).unwrap(); let directory = RootDiskDirectory::create(&temp_path).unwrap();
let vault_provider = directory.as_vault_provider().unwrap(); let vault_provider = directory.as_vault_provider().unwrap();
vault_provider.create("vault1", VaultKey::new("password1", 1)).unwrap(); vault_provider.create("vault1", VaultKey::new("password1", 1)).unwrap();
@ -359,11 +361,11 @@ mod test {
#[test] #[test]
fn hash_of_files() { fn hash_of_files() {
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let directory = RootDiskDirectory::create(&temp_path).unwrap(); let directory = RootDiskDirectory::create(&temp_path).unwrap();
let hash = directory.files_hash().expect("Files hash should be calculated ok"); let hash = directory.files_hash().expect("Files hash should be calculated ok");
assert_eq!( assert_eq!(
hash, hash,
15130871412783076140 15130871412783076140
); );
@ -373,7 +375,7 @@ mod test {
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()); let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
directory.insert(account).expect("Account should be inserted ok"); directory.insert(account).expect("Account should be inserted ok");
let new_hash = directory.files_hash().expect("New files hash should be calculated ok"); let new_hash = directory.files_hash().expect("New files hash should be calculated ok");
assert!(new_hash != hash, "hash of the file list should change once directory content changed"); assert!(new_hash != hash, "hash of the file list should change once directory content changed");
} }

View File

@ -18,7 +18,7 @@ use std::{fs, io};
use std::path::{PathBuf, Path}; use std::path::{PathBuf, Path};
use parking_lot::Mutex; use parking_lot::Mutex;
use {json, SafeAccount, Error}; use {json, SafeAccount, Error};
use util::sha3::Hashable; use crypto::Keccak256;
use super::super::account::Crypto; use super::super::account::Crypto;
use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError}; use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
use super::disk::{DiskDirectory, KeyFileManager}; use super::disk::{DiskDirectory, KeyFileManager};
@ -234,7 +234,7 @@ fn check_vault_name(name: &str) -> bool {
/// Vault can be empty, but still must be pluggable => we store vault password in separate file /// Vault can be empty, but still must be pluggable => we store vault password in separate file
fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef<Path> { fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef<Path> {
let password_hash = key.password.sha3(); let password_hash = key.password.keccak256();
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations); let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations);
let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into(); let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into();
@ -268,8 +268,8 @@ fn read_vault_file<P>(vault_dir_path: P, key: Option<&VaultKey>) -> Result<Strin
if let Some(key) = key { if let Some(key) = key {
let password_bytes = vault_file_crypto.decrypt(&key.password)?; let password_bytes = vault_file_crypto.decrypt(&key.password)?;
let password_hash = key.password.sha3(); let password_hash = key.password.keccak256();
if &*password_hash != password_bytes.as_slice() { if password_hash != password_bytes.as_slice() {
return Err(Error::InvalidPassword); return Err(Error::InvalidPassword);
} }
} }
@ -279,12 +279,14 @@ fn read_vault_file<P>(vault_dir_path: P, key: Option<&VaultKey>) -> Result<Strin
#[cfg(test)] #[cfg(test)]
mod test { mod test {
extern crate tempdir;
use std::fs; use std::fs;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use dir::VaultKey; use dir::VaultKey;
use super::{VAULT_FILE_NAME, check_vault_name, make_vault_dir_path, create_vault_file, read_vault_file, VaultDiskDirectory}; use super::{VAULT_FILE_NAME, check_vault_name, make_vault_dir_path, create_vault_file, read_vault_file, VaultDiskDirectory};
use devtools::RandomTempPath; use self::tempdir::TempDir;
#[test] #[test]
fn check_vault_name_succeeds() { fn check_vault_name_succeeds() {
@ -320,9 +322,9 @@ mod test {
#[test] #[test]
fn create_vault_file_succeeds() { fn create_vault_file_succeeds() {
// given // given
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let mut vault_dir: PathBuf = temp_path.as_path().into(); let mut vault_dir: PathBuf = temp_path.path().into();
vault_dir.push("vault"); vault_dir.push("vault");
fs::create_dir_all(&vault_dir).unwrap(); fs::create_dir_all(&vault_dir).unwrap();
@ -339,10 +341,10 @@ mod test {
#[test] #[test]
fn read_vault_file_succeeds() { fn read_vault_file_succeeds() {
// given // given
let temp_path = RandomTempPath::create_dir(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let vault_file_contents = r#"{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"758696c8dc6378ab9b25bb42790da2f5"},"ciphertext":"54eb50683717d41caaeb12ea969f2c159daada5907383f26f327606a37dc7168","kdf":"pbkdf2","kdfparams":{"c":1024,"dklen":32,"prf":"hmac-sha256","salt":"3c320fa566a1a7963ac8df68a19548d27c8f40bf92ef87c84594dcd5bbc402b6"},"mac":"9e5c2314c2a0781962db85611417c614bd6756666b6b1e93840f5b6ed895f003"}}"#; let vault_file_contents = r#"{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"758696c8dc6378ab9b25bb42790da2f5"},"ciphertext":"54eb50683717d41caaeb12ea969f2c159daada5907383f26f327606a37dc7168","kdf":"pbkdf2","kdfparams":{"c":1024,"dklen":32,"prf":"hmac-sha256","salt":"3c320fa566a1a7963ac8df68a19548d27c8f40bf92ef87c84594dcd5bbc402b6"},"mac":"9e5c2314c2a0781962db85611417c614bd6756666b6b1e93840f5b6ed895f003"}}"#;
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
let mut vault_file_path: PathBuf = dir.clone(); let mut vault_file_path: PathBuf = dir.clone();
vault_file_path.push(VAULT_FILE_NAME); vault_file_path.push(VAULT_FILE_NAME);
{ {
@ -360,9 +362,9 @@ mod test {
#[test] #[test]
fn read_vault_file_fails() { fn read_vault_file_fails() {
// given // given
let temp_path = RandomTempPath::create_dir(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password1", 1024); let key = VaultKey::new("password1", 1024);
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
let mut vault_file_path: PathBuf = dir.clone(); let mut vault_file_path: PathBuf = dir.clone();
vault_file_path.push(VAULT_FILE_NAME); vault_file_path.push(VAULT_FILE_NAME);
@ -389,9 +391,9 @@ mod test {
#[test] #[test]
fn vault_directory_can_be_created() { fn vault_directory_can_be_created() {
// given // given
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
// when // when
let vault = VaultDiskDirectory::create(&dir, "vault", key.clone()); let vault = VaultDiskDirectory::create(&dir, "vault", key.clone());
@ -409,9 +411,9 @@ mod test {
#[test] #[test]
fn vault_directory_cannot_be_created_if_already_exists() { fn vault_directory_cannot_be_created_if_already_exists() {
// given // given
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
let mut vault_dir = dir.clone(); let mut vault_dir = dir.clone();
vault_dir.push("vault"); vault_dir.push("vault");
fs::create_dir_all(&vault_dir).unwrap(); fs::create_dir_all(&vault_dir).unwrap();
@ -426,9 +428,9 @@ mod test {
#[test] #[test]
fn vault_directory_cannot_be_opened_if_not_exists() { fn vault_directory_cannot_be_opened_if_not_exists() {
// given // given
let temp_path = RandomTempPath::create_dir(); let temp_path = TempDir::new("").unwrap();
let key = VaultKey::new("password", 1024); let key = VaultKey::new("password", 1024);
let dir: PathBuf = temp_path.as_path().into(); let dir: PathBuf = temp_path.path().into();
// when // when
let vault = VaultDiskDirectory::at(&dir, "vault", key); let vault = VaultDiskDirectory::at(&dir, "vault", key);

View File

@ -620,13 +620,14 @@ impl SimpleSecretStore for EthMultiStore {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
extern crate tempdir;
use dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory}; use dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory};
use ethkey::{Random, Generator, KeyPair}; use ethkey::{Random, Generator, KeyPair};
use secret_store::{SimpleSecretStore, SecretStore, SecretVaultRef, StoreAccountRef, Derivation}; use secret_store::{SimpleSecretStore, SecretStore, SecretVaultRef, StoreAccountRef, Derivation};
use super::{EthStore, EthMultiStore}; use super::{EthStore, EthMultiStore};
use devtools::RandomTempPath; use self::tempdir::TempDir;
use util::H256; use bigint::hash::H256;
fn keypair() -> KeyPair { fn keypair() -> KeyPair {
Random.generate().unwrap() Random.generate().unwrap()
@ -642,13 +643,13 @@ mod tests {
struct RootDiskDirectoryGuard { struct RootDiskDirectoryGuard {
pub key_dir: Option<Box<KeyDirectory>>, pub key_dir: Option<Box<KeyDirectory>>,
_path: RandomTempPath, _path: TempDir,
} }
impl RootDiskDirectoryGuard { impl RootDiskDirectoryGuard {
pub fn new() -> Self { pub fn new() -> Self {
let temp_path = RandomTempPath::new(); let temp_path = TempDir::new("").unwrap();
let disk_dir = Box::new(RootDiskDirectory::create(temp_path.as_path()).unwrap()); let disk_dir = Box::new(RootDiskDirectory::create(temp_path.path()).unwrap());
RootDiskDirectoryGuard { RootDiskDirectoryGuard {
key_dir: Some(disk_dir), key_dir: Some(disk_dir),

View File

@ -14,10 +14,11 @@
// 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::{fmt, str};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::ser::SerializeStruct; use serde::ser::SerializeStruct;
use serde::de::{Visitor, MapVisitor, Error}; use serde::de::{Visitor, MapVisitor, Error};
use serde_json;
use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256, Bytes}; use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256, Bytes};
pub type CipherText = Bytes; pub type CipherText = Bytes;
@ -30,6 +31,20 @@ pub struct Crypto {
pub mac: H256, pub mac: H256,
} }
impl str::FromStr for Crypto {
type Err = serde_json::error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
serde_json::from_str(s)
}
}
impl From<Crypto> for String {
fn from(c: Crypto) -> Self {
serde_json::to_string(&c).expect("serialization cannot fail, cause all crypto keys are strings")
}
}
enum CryptoField { enum CryptoField {
Cipher, Cipher,
CipherParams, CipherParams,

View File

@ -29,9 +29,9 @@ extern crate serde_json;
extern crate smallvec; extern crate smallvec;
extern crate time; extern crate time;
extern crate tiny_keccak; extern crate tiny_keccak;
extern crate tempdir;
extern crate ethcore_devtools as devtools; extern crate ethcore_bigint as bigint;
extern crate ethcore_util as util;
extern crate ethcrypto as crypto; extern crate ethcrypto as crypto;
extern crate ethkey as _ethkey; extern crate ethkey as _ethkey;
extern crate parity_wordlist; extern crate parity_wordlist;
@ -54,7 +54,7 @@ mod presale;
mod random; mod random;
mod secret_store; mod secret_store;
pub use self::account::SafeAccount; pub use self::account::{SafeAccount, Crypto};
pub use self::error::Error; pub use self::error::Error;
pub use self::ethstore::{EthStore, EthMultiStore}; pub use self::ethstore::{EthStore, EthMultiStore};
pub use self::import::{import_accounts, read_geth_accounts}; pub use self::import::{import_accounts, read_geth_accounts};

View File

@ -19,7 +19,7 @@ use std::path::PathBuf;
use ethkey::{Address, Message, Signature, Secret, Public}; use ethkey::{Address, Message, Signature, Secret, Public};
use Error; use Error;
use json::{Uuid, OpaqueKeyFile}; use json::{Uuid, OpaqueKeyFile};
use util::H256; use bigint::hash::H256;
/// Key directory reference /// Key directory reference
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]