From c2ffa904789f27d1a4982494489c481c87b3e829 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 21 Jun 2016 13:09:27 +0200 Subject: [PATCH 1/6] importing presale wallet in progress --- ethstore/src/crypto.rs | 11 ++++++-- ethstore/src/ethkey.rs | 8 ++++++ ethstore/src/json/hash.rs | 27 +++++++++++++++++- ethstore/src/json/mod.rs.in | 4 ++- ethstore/src/json/presale.rs | 42 ++++++++++++++++++++++++++++ ethstore/src/lib.rs | 1 + ethstore/src/presale.rs | 53 ++++++++++++++++++++++++++++++++++++ 7 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 ethstore/src/json/presale.rs create mode 100644 ethstore/src/presale.rs diff --git a/ethstore/src/crypto.rs b/ethstore/src/crypto.rs index 2858808d703..2733fa7202c 100644 --- a/ethstore/src/crypto.rs +++ b/ethstore/src/crypto.rs @@ -65,8 +65,8 @@ impl Keccak256<[u8; 32]> for [u8] { /// AES encryption pub mod aes { - use rcrypto::blockmodes::CtrMode; - use rcrypto::aessafe::AesSafe128Encryptor; + use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding}; + use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor}; use rcrypto::symmetriccipher::{Encryptor, Decryptor}; use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer}; @@ -81,5 +81,12 @@ pub mod aes { let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec()); encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding"); } + + /// Decrypt a message using cbc mode + pub fn decrypt_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) { + let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec()); + encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding"); + } + } diff --git a/ethstore/src/ethkey.rs b/ethstore/src/ethkey.rs index eba8773976d..9d8858b79c8 100644 --- a/ethstore/src/ethkey.rs +++ b/ethstore/src/ethkey.rs @@ -31,3 +31,11 @@ impl From for Address { From::from(a) } } + +impl<'a> From<&'a json::H160> for Address { + fn from(json: &'a json::H160) -> Self { + let mut a = [0u8; 20]; + a.copy_from_slice(json); + From::from(a) + } +} diff --git a/ethstore/src/json/hash.rs b/ethstore/src/json/hash.rs index f0fb91e7a08..2edc7b80b3b 100644 --- a/ethstore/src/json/hash.rs +++ b/ethstore/src/json/hash.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::fmt; +use std::ops; use std::str::FromStr; use rustc_serialize::hex::{FromHex, ToHex}; use serde::{Serialize, Serializer, Deserialize, Deserializer, Error as SerdeError}; @@ -22,9 +24,31 @@ use super::Error; macro_rules! impl_hash { ($name: ident, $size: expr) => { - #[derive(Debug, PartialEq)] pub struct $name([u8; $size]); + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let self_ref: &[u8] = &self.0; + write!(f, "{:?}", self_ref) + } + } + + impl PartialEq for $name { + fn eq(&self, other: &Self) -> bool { + let self_ref: &[u8] = &self.0; + let other_ref: &[u8] = &other.0; + self_ref == other_ref + } + } + + impl ops::Deref for $name { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl Serialize for $name { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { @@ -85,3 +109,4 @@ macro_rules! impl_hash { impl_hash!(H128, 16); impl_hash!(H160, 20); impl_hash!(H256, 32); +impl_hash!(H768, 96); diff --git a/ethstore/src/json/mod.rs.in b/ethstore/src/json/mod.rs.in index c4a67a28775..7272d7e2e8d 100644 --- a/ethstore/src/json/mod.rs.in +++ b/ethstore/src/json/mod.rs.in @@ -5,14 +5,16 @@ mod hash; mod id; mod kdf; mod key_file; +mod presale; mod version; pub use self::cipher::{Cipher, CipherSer, CipherSerParams, Aes128Ctr}; pub use self::crypto::Crypto; pub use self::error::Error; -pub use self::hash::{H128, H160, H256}; +pub use self::hash::{H128, H160, H256, H768}; pub use self::id::UUID; pub use self::kdf::{Kdf, KdfSer, Prf, Pbkdf2, Scrypt, KdfSerParams}; pub use self::key_file::KeyFile; +pub use self::presale::PresaleWallet; pub use self::version::Version; diff --git a/ethstore/src/json/presale.rs b/ethstore/src/json/presale.rs new file mode 100644 index 00000000000..cba50695fbc --- /dev/null +++ b/ethstore/src/json/presale.rs @@ -0,0 +1,42 @@ +use std::io::Read; +use serde_json; +use super::{H160, H768}; + +#[derive(Debug, PartialEq, Deserialize)] +pub struct PresaleWallet { + pub encseed: H768, + #[serde(rename = "ethaddr")] + pub address: H160, +} + +impl PresaleWallet { + pub fn load(reader: R) -> Result where R: Read { + serde_json::from_reader(reader) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use serde_json; + use json::{PresaleWallet, H160, H768}; + + #[test] + fn presale_wallet() { + let json = r#" + { + "encseed": "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066", + "ethaddr": "ede84640d1a1d3e06902048e67aa7db8d52c2ce1", + "email": "123@gmail.com", + "btcaddr": "1JvqEc6WLhg6GnyrLBe2ztPAU28KRfuseH" + } "#; + + let expected = PresaleWallet { + encseed: H768::from_str("137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066").unwrap(), + address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(), + }; + + let wallet: PresaleWallet = serde_json::from_str(json).unwrap(); + assert_eq!(expected, wallet); + } +} diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs index 19f1c480605..90bb367fa9d 100644 --- a/ethstore/src/lib.rs +++ b/ethstore/src/lib.rs @@ -37,6 +37,7 @@ mod crypto; mod error; mod ethstore; mod import; +mod presale; mod random; mod secret_store; diff --git a/ethstore/src/presale.rs b/ethstore/src/presale.rs new file mode 100644 index 00000000000..aad19b15c37 --- /dev/null +++ b/ethstore/src/presale.rs @@ -0,0 +1,53 @@ +use rcrypto::pbkdf2::pbkdf2; +use rcrypto::sha2::Sha256; +use rcrypto::hmac::Hmac; +use json::PresaleWallet; +use ethkey::{Address, Secret, KeyPair}; +use crypto::Keccak256; +use {crypto, Error}; + +fn decrypt_presale_wallet(wallet: &PresaleWallet, password: &str) -> Result { + let mut iv = [0u8; 16]; + iv.copy_from_slice(&wallet.encseed[..16]); + + let mut ciphertext = [0u8; 80]; + ciphertext.copy_from_slice(&wallet.encseed[16..]); + + let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes()); + let mut derived_key = vec![0u8; 16]; + pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key); + + let mut key = [0u8; 64]; + crypto::aes::decrypt_cbc(&derived_key, &iv, &ciphertext, &mut key); + + let secret = Secret::from(key.keccak256()); + if let Ok(kp) = KeyPair::from_secret(secret) { + if kp.address() == Address::from(&wallet.address) { + return Ok(kp) + } + } + + Err(Error::InvalidPassword) +} + +#[cfg(test)] +mod tests { + use ethkey::{KeyPair, Address}; + use super::decrypt_presale_wallet; + use json::PresaleWallet; + + #[test] + fn test() { + let json = r#" + { + "encseed": "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066", + "ethaddr": "ede84640d1a1d3e06902048e67aa7db8d52c2ce1", + "email": "123@gmail.com", + "btcaddr": "1JvqEc6WLhg6GnyrLBe2ztPAU28KRfuseH" + } "#; + + let wallet = PresaleWallet::load(json.as_bytes()).unwrap(); + let kp = decrypt_presale_wallet(&wallet, "123").unwrap(); + assert_eq!(kp.address(), Address::from(wallet.address)); + } +} From a8a731ba11fee703516bc3aaaac1cfa9776873f5 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 21 Jun 2016 13:30:32 +0200 Subject: [PATCH 2/6] PresaleWallet data structure --- ethstore/src/lib.rs | 1 + ethstore/src/presale.rs | 71 ++++++++++++++++++++++++++++------------- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs index 90bb367fa9d..96d860db467 100644 --- a/ethstore/src/lib.rs +++ b/ethstore/src/lib.rs @@ -45,5 +45,6 @@ pub use self::account::SafeAccount; pub use self::error::Error; pub use self::ethstore::EthStore; pub use self::import::import_accounts; +pub use self::presale::PresaleWallet; pub use self::secret_store::SecretStore; diff --git a/ethstore/src/presale.rs b/ethstore/src/presale.rs index aad19b15c37..5ba57b8d4e1 100644 --- a/ethstore/src/presale.rs +++ b/ethstore/src/presale.rs @@ -1,40 +1,66 @@ +use std::fs; +use std::path::Path; use rcrypto::pbkdf2::pbkdf2; use rcrypto::sha2::Sha256; use rcrypto::hmac::Hmac; -use json::PresaleWallet; +use json; use ethkey::{Address, Secret, KeyPair}; use crypto::Keccak256; use {crypto, Error}; -fn decrypt_presale_wallet(wallet: &PresaleWallet, password: &str) -> Result { - let mut iv = [0u8; 16]; - iv.copy_from_slice(&wallet.encseed[..16]); - - let mut ciphertext = [0u8; 80]; - ciphertext.copy_from_slice(&wallet.encseed[16..]); +pub struct PresaleWallet { + iv: [u8; 16], + ciphertext: [u8; 80], + address: Address, +} - let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes()); - let mut derived_key = vec![0u8; 16]; - pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key); +impl From for PresaleWallet { + fn from(wallet: json::PresaleWallet) -> Self { + let mut iv = [0u8; 16]; + iv.copy_from_slice(&wallet.encseed[..16]); - let mut key = [0u8; 64]; - crypto::aes::decrypt_cbc(&derived_key, &iv, &ciphertext, &mut key); + let mut ciphertext = [0u8; 80]; + ciphertext.copy_from_slice(&wallet.encseed[16..]); - let secret = Secret::from(key.keccak256()); - if let Ok(kp) = KeyPair::from_secret(secret) { - if kp.address() == Address::from(&wallet.address) { - return Ok(kp) + PresaleWallet { + iv: iv, + ciphertext: ciphertext, + address: Address::from(wallet.address), } } +} + +impl PresaleWallet { + pub fn open

(path: P) -> Result where P: AsRef { + let file = try!(fs::File::open(path)); + let presale = json::PresaleWallet::load(file).unwrap(); + Ok(PresaleWallet::from(presale)) + } - Err(Error::InvalidPassword) + pub fn decrypt(&self, password: &str) -> Result { + let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes()); + let mut derived_key = vec![0u8; 16]; + pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key); + + let mut key = [0u8; 64]; + crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key); + + let secret = Secret::from(key.keccak256()); + if let Ok(kp) = KeyPair::from_secret(secret) { + if kp.address() == self.address { + return Ok(kp) + } + } + + Err(Error::InvalidPassword) + } } #[cfg(test)] mod tests { - use ethkey::{KeyPair, Address}; - use super::decrypt_presale_wallet; - use json::PresaleWallet; + use ethkey::Address; + use super::PresaleWallet; + use json; #[test] fn test() { @@ -46,8 +72,9 @@ mod tests { "btcaddr": "1JvqEc6WLhg6GnyrLBe2ztPAU28KRfuseH" } "#; - let wallet = PresaleWallet::load(json.as_bytes()).unwrap(); - let kp = decrypt_presale_wallet(&wallet, "123").unwrap(); + let wallet = json::PresaleWallet::load(json.as_bytes()).unwrap(); + let wallet = PresaleWallet::from(wallet); + let kp = wallet.decrypt("123").unwrap(); assert_eq!(kp.address(), Address::from(wallet.address)); } } From be03a6acbdaa58d884c6fb454e38178af68a8ed8 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 21 Jun 2016 15:04:36 +0200 Subject: [PATCH 3/6] import-wallet option for ethstore executable --- ethstore/README.md | 15 +++++++++++++++ ethstore/src/bin/ethstore.rs | 11 ++++++++++- ethstore/src/crypto.rs | 7 ++++--- ethstore/src/ethkey.rs | 8 -------- ethstore/src/presale.rs | 2 +- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/ethstore/README.md b/ethstore/README.md index aba4911bf7d..0cf50f4544d 100644 --- a/ethstore/README.md +++ b/ethstore/README.md @@ -20,6 +20,7 @@ Usage: ethstore change-pwd

[--dir DIR] ethstore list [--dir DIR] ethstore import [--src DIR] [--dir DIR] + ethstore import-wallet [--dir DIR] ethstore remove
[--dir DIR] ethstore sign
[--dir DIR] ethstore [-h | --help] @@ -38,6 +39,7 @@ Commands: change-pwd Change account password. list List accounts. import Import accounts from src. + import-wallet Import presale wallet. remove Remove account. sign Sign message. ``` @@ -119,6 +121,19 @@ ethstore list -- +#### `import-wallet [--dir DIR]` +*Import account from presale wallet.* + +- `` - presale wallet path +- `` - account password, any string +- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity + +``` +e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb +``` + +-- + #### `remove
[--dir DIR]` *Remove account from secret store.* diff --git a/ethstore/src/bin/ethstore.rs b/ethstore/src/bin/ethstore.rs index 6020679d4e4..948d7a76e5e 100644 --- a/ethstore/src/bin/ethstore.rs +++ b/ethstore/src/bin/ethstore.rs @@ -24,7 +24,7 @@ use std::str::FromStr; use docopt::Docopt; use ethstore::ethkey::{Secret, Address, Message}; use ethstore::dir::{KeyDirectory, ParityDirectory, DiskDirectory, GethDirectory, DirectoryType}; -use ethstore::{EthStore, SecretStore, import_accounts, Error}; +use ethstore::{EthStore, SecretStore, import_accounts, Error, PresaleWallet}; pub const USAGE: &'static str = r#" Ethereum key management. @@ -35,6 +35,7 @@ Usage: ethstore change-pwd
[--dir DIR] ethstore list [--dir DIR] ethstore import [--src DIR] [--dir DIR] + ethstore import-wallet [--dir DIR] ethstore remove
[--dir DIR] ethstore sign
[--dir DIR] ethstore [-h | --help] @@ -53,6 +54,7 @@ Commands: change-pwd Change password. list List accounts. import Import accounts from src. + import-wallet Import presale wallet. remove Remove account. sign Sign message. "#; @@ -63,6 +65,7 @@ struct Args { cmd_change_pwd: bool, cmd_list: bool, cmd_import: bool, + cmd_import_wallet: bool, cmd_remove: bool, cmd_sign: bool, arg_secret: String, @@ -71,6 +74,7 @@ struct Args { arg_new_pwd: String, arg_address: String, arg_message: String, + arg_path: String, flag_src: String, flag_dir: String, } @@ -128,6 +132,11 @@ fn execute(command: I) -> Result where I: IntoIterator for [u8] { pub mod aes { use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding}; use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor}; - use rcrypto::symmetriccipher::{Encryptor, Decryptor}; + use rcrypto::symmetriccipher::{Encryptor, Decryptor, SymmetricCipherError}; use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer}; /// Encrypt a message @@ -83,9 +83,10 @@ pub mod aes { } /// Decrypt a message using cbc mode - pub fn decrypt_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) { + pub fn decrypt_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmetricCipherError> { let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec()); - encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding"); + try!(encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true)); + Ok(()) } } diff --git a/ethstore/src/ethkey.rs b/ethstore/src/ethkey.rs index 9d8858b79c8..eba8773976d 100644 --- a/ethstore/src/ethkey.rs +++ b/ethstore/src/ethkey.rs @@ -31,11 +31,3 @@ impl From for Address { From::from(a) } } - -impl<'a> From<&'a json::H160> for Address { - fn from(json: &'a json::H160) -> Self { - let mut a = [0u8; 20]; - a.copy_from_slice(json); - From::from(a) - } -} diff --git a/ethstore/src/presale.rs b/ethstore/src/presale.rs index 5ba57b8d4e1..8c817247323 100644 --- a/ethstore/src/presale.rs +++ b/ethstore/src/presale.rs @@ -43,7 +43,7 @@ impl PresaleWallet { pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key); let mut key = [0u8; 64]; - crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key); + try!(crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key).map_err(|_| Error::InvalidPassword)); let secret = Secret::from(key.keccak256()); if let Ok(kp) = KeyPair::from_secret(secret) { From 7136cd7057b2ea42910fd24fc718c1e2c91073f4 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 21 Jun 2016 15:07:15 +0200 Subject: [PATCH 4/6] improved import wallet test --- ethstore/src/presale.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ethstore/src/presale.rs b/ethstore/src/presale.rs index 8c817247323..09c86abeae7 100644 --- a/ethstore/src/presale.rs +++ b/ethstore/src/presale.rs @@ -58,7 +58,6 @@ impl PresaleWallet { #[cfg(test)] mod tests { - use ethkey::Address; use super::PresaleWallet; use json; @@ -74,7 +73,7 @@ mod tests { let wallet = json::PresaleWallet::load(json.as_bytes()).unwrap(); let wallet = PresaleWallet::from(wallet); - let kp = wallet.decrypt("123").unwrap(); - assert_eq!(kp.address(), Address::from(wallet.address)); + assert!(wallet.decrypt("123").is_ok()); + assert!(wallet.decrypt("124").is_err()); } } From bbe5cd001a1663e544237b83c7528eb7be5e9b3b Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 21 Jun 2016 17:50:22 +0200 Subject: [PATCH 5/6] presale wallet cli for parity --- parity/cli.rs | 2 ++ parity/main.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/parity/cli.rs b/parity/cli.rs index 507137f8b5d..d8effec884e 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -25,6 +25,7 @@ Usage: parity daemon [options] parity account (new | list ) [options] parity account import ... [options] + parity wallet import --password FILE [options] parity import [ ] [options] parity export [ ] [options] parity signer new-token [options] @@ -215,6 +216,7 @@ Miscellaneous Options: pub struct Args { pub cmd_daemon: bool, pub cmd_account: bool, + pub cmd_wallet: bool, pub cmd_new: bool, pub cmd_list: bool, pub cmd_export: bool, diff --git a/parity/main.rs b/parity/main.rs index a44cdf6d30d..b610e3025c5 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -129,6 +129,11 @@ fn execute(conf: Configuration) { return; } + if conf.args.cmd_wallet { + execute_wallet_cli(conf); + return; + } + if conf.args.cmd_export { execute_export(conf); return; @@ -534,6 +539,30 @@ fn execute_account_cli(conf: Configuration) { } } +fn execute_wallet_cli(conf: Configuration) { + use ethcore::ethstore::{PresaleWallet, SecretStore, EthStore}; + use ethcore::ethstore::dir::DiskDirectory; + use ethcore::account_provider::AccountProvider; + + let wallet_path = conf.args.arg_path.first().unwrap(); + let filename = conf.args.flag_password.first().unwrap(); + let mut file = File::open(filename).unwrap_or_else(|_| die!("{} Unable to read password file.", filename)); + let mut file_content = String::new(); + file.read_to_string(&mut file_content).unwrap_or_else(|_| die!("{} Unable to read password file.", filename)); + + let dir = Box::new(DiskDirectory::create(conf.keys_path()).unwrap()); + let iterations = conf.keys_iterations(); + let store = AccountProvider::new(Box::new(EthStore::open_with_iterations(dir, iterations).unwrap())); + + // remove eof + let pass = &file_content[..file_content.len() - 1]; + let wallet = PresaleWallet::open(wallet_path).unwrap_or_else(|_| die!("Unable to open presale wallet.")); + let kp = wallet.decrypt(pass).unwrap_or_else(|_| die!("Invalid password")); + let address = store.insert_account(kp.secret().clone(), pass).unwrap(); + + println!("Imported account: {}", address); +} + fn wait_for_exit( panic_handler: Arc, _rpc_server: Option, From 9547324b464e5680afa7e88c4fc488bea2fa5fef Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 22 Jun 2016 17:02:40 +0200 Subject: [PATCH 6/6] ethstore cli loads passwords from files --- ethstore/README.md | 28 ++++++++++++++++++---------- ethstore/src/bin/ethstore.rs | 30 +++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/ethstore/README.md b/ethstore/README.md index 0cf50f4544d..0b85d99b431 100644 --- a/ethstore/README.md +++ b/ethstore/README.md @@ -50,11 +50,11 @@ Commands: *Encrypt secret with a password and save it in secret store.* - `` - ethereum secret, 32 bytes long -- `` - account password, any string +- `` - account password, file path - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity ``` -ethstore insert 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 "this is sparta" +ethstore insert 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 password.txt ``` ``` @@ -77,12 +77,12 @@ ethstore insert `ethkey generate random -s` "this is sparta" *Change account password.* - `
` - ethereum address, 20 bytes long -- `` - old account password, any string -- `` - new account password, any string +- `` - old account password, file path +- `` - new account password, file path - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity ``` -ethstore change-pwd a8fa5dd30a87bb9e3288d604eb74949c515ab66e "this is sparta" "hello world" +ethstore change-pwd a8fa5dd30a87bb9e3288d604eb74949c515ab66e old_pwd.txt new_pwd.txt ``` ``` @@ -114,6 +114,10 @@ ethstore list - `[--src DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: geth - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity +``` +ethstore import +``` + ``` 0: e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb 1: 6edddfc6349aff20bc6467ccf276c5b52487f7a8 @@ -125,9 +129,13 @@ ethstore list *Import account from presale wallet.* - `` - presale wallet path -- `` - account password, any string +- `` - account password, file path - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity +``` +ethstore import-wallet ethwallet.json password.txt +``` + ``` e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb ``` @@ -138,11 +146,11 @@ e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb *Remove account from secret store.* - `
` - ethereum address, 20 bytes long -- `` - account password, any string +- `` - account password, file path - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity ``` -ethstore remove a8fa5dd30a87bb9e3288d604eb74949c515ab66e "hello world" +ethstore remove a8fa5dd30a87bb9e3288d604eb74949c515ab66e password.txt ``` ``` @@ -155,12 +163,12 @@ true *Sign message with account's secret.* - `
` - ethereum address, 20 bytes long -- `` - account password, any string +- `` - account password, file path - `` - message to sign, 32 bytes long - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity ``` -ethstore sign 24edfff680d536a5f6fe862d36df6f8f6f40f115 "this is sparta" 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 +ethstore sign 24edfff680d536a5f6fe862d36df6f8f6f40f115 password.txt 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 ``` ``` diff --git a/ethstore/src/bin/ethstore.rs b/ethstore/src/bin/ethstore.rs index 948d7a76e5e..5683a8116b3 100644 --- a/ethstore/src/bin/ethstore.rs +++ b/ethstore/src/bin/ethstore.rs @@ -18,7 +18,8 @@ extern crate rustc_serialize; extern crate docopt; extern crate ethstore; -use std::{env, process}; +use std::{env, process, fs}; +use std::io::Read; use std::ops::Deref; use std::str::FromStr; use docopt::Docopt; @@ -109,6 +110,15 @@ fn format_accounts(accounts: &[Address]) -> String { .join("\n") } +fn load_password(path: &str) -> Result { + let mut file = try!(fs::File::open(path)); + let mut password = String::new(); + try!(file.read_to_string(&mut password)); + // drop EOF + let _ = password.pop(); + Ok(password) +} + fn execute(command: I) -> Result where I: IntoIterator, S: AsRef { let args: Args = Docopt::new(USAGE) .and_then(|d| d.argv(command).decode()) @@ -118,11 +128,14 @@ fn execute(command: I) -> Result where I: IntoIterator(command: I) -> Result where I: IntoIterator