Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Presale wallet #1376

Merged
merged 8 commits into from
Jun 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions ethstore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Usage:
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR]
ethstore list [--dir DIR]
ethstore import [--src DIR] [--dir DIR]
ethstore import-wallet <path> <password> [--dir DIR]
Copy link
Contributor

@gavofyork gavofyork Jun 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<password> is a file containing the password, right?

ethstore remove <address> <password> [--dir DIR]
ethstore sign <address> <password> <message> [--dir DIR]
ethstore [-h | --help]
Expand All @@ -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.
```
Expand All @@ -48,11 +50,11 @@ Commands:
*Encrypt secret with a password and save it in secret store.*

- `<secret>` - ethereum secret, 32 bytes long
- `<password>` - account password, any string
- `<password>` - 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
```

```
Expand All @@ -75,12 +77,12 @@ ethstore insert `ethkey generate random -s` "this is sparta"
*Change account password.*

- `<address>` - ethereum address, 20 bytes long
- `<old-pwd>` - old account password, any string
- `<new-pwd>` - new account password, any string
- `<old-pwd>` - old account password, file path
- `<new-pwd>` - 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
```

```
Expand Down Expand Up @@ -112,22 +114,43 @@ 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
```

--

#### `import-wallet <path> <password> [--dir DIR]`
*Import account from presale wallet.*

- `<path>` - presale wallet path
- `<password>` - 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
```

--

#### `remove <address> <password> [--dir DIR]`
*Remove account from secret store.*

- `<address>` - ethereum address, 20 bytes long
- `<password>` - account password, any string
- `<password>` - 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
```

```
Expand All @@ -140,12 +163,12 @@ true
*Sign message with account's secret.*

- `<address>` - ethereum address, 20 bytes long
- `<password>` - account password, any string
- `<password>` - account password, file path
- `<message>` - 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
```

```
Expand Down
37 changes: 31 additions & 6 deletions ethstore/src/bin/ethstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ 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;
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.
Expand All @@ -35,6 +36,7 @@ Usage:
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR]
ethstore list [--dir DIR]
ethstore import [--src DIR] [--dir DIR]
ethstore import-wallet <path> <password> [--dir DIR]
ethstore remove <address> <password> [--dir DIR]
ethstore sign <address> <password> <message> [--dir DIR]
ethstore [-h | --help]
Expand All @@ -53,6 +55,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.
"#;
Expand All @@ -63,6 +66,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,
Expand All @@ -71,6 +75,7 @@ struct Args {
arg_new_pwd: String,
arg_address: String,
arg_message: String,
arg_path: String,
flag_src: String,
flag_dir: String,
}
Expand Down Expand Up @@ -105,6 +110,15 @@ fn format_accounts(accounts: &[Address]) -> String {
.join("\n")
}

fn load_password(path: &str) -> Result<String, Error> {
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<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item=S>, S: AsRef<str> {
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.argv(command).decode())
Expand All @@ -114,11 +128,14 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item

return if args.cmd_insert {
let secret = try!(Secret::from_str(&args.arg_secret));
let address = try!(store.insert_account(secret, &args.arg_password));
let password = try!(load_password(&args.arg_password));
let address = try!(store.insert_account(secret, &password));
Ok(format!("{}", address))
} else if args.cmd_change_pwd {
let address = try!(Address::from_str(&args.arg_address));
let ok = store.change_password(&address, &args.arg_old_pwd, &args.arg_new_pwd).is_ok();
let old_pwd = try!(load_password(&args.arg_old_pwd));
let new_pwd = try!(load_password(&args.arg_new_pwd));
let ok = store.change_password(&address, &old_pwd, &new_pwd).is_ok();
Ok(format!("{}", ok))
} else if args.cmd_list {
let accounts = store.accounts();
Expand All @@ -128,14 +145,22 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
let dst = try!(key_dir(&args.flag_dir));
let accounts = try!(import_accounts(src.deref(), dst.deref()));
Ok(format_accounts(&accounts))
} else if args.cmd_import_wallet {
let wallet = try!(PresaleWallet::open(&args.arg_path));
let password = try!(load_password(&args.arg_password));
let kp = try!(wallet.decrypt(&password));
let address = try!(store.insert_account(kp.secret().clone(), &password));
Ok(format!("{}", address))
} else if args.cmd_remove {
let address = try!(Address::from_str(&args.arg_address));
let ok = store.remove_account(&address, &args.arg_password).is_ok();
let password = try!(load_password(&args.arg_password));
let ok = store.remove_account(&address, &password).is_ok();
Ok(format!("{}", ok))
} else if args.cmd_sign {
let address = try!(Address::from_str(&args.arg_address));
let message = try!(Message::from_str(&args.arg_message));
let signature = try!(store.sign(&address, &args.arg_password, &message));
let password = try!(load_password(&args.arg_password));
let signature = try!(store.sign(&address, &password, &message));
Ok(format!("{}", signature))
} else {
unreachable!();
Expand Down
7 changes: 4 additions & 3 deletions ethstore/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl Keccak256<[u8; 32]> 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
Expand All @@ -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(())
}

}
Expand Down
7 changes: 3 additions & 4 deletions ethstore/src/presale.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -58,7 +58,6 @@ impl PresaleWallet {

#[cfg(test)]
mod tests {
use ethkey::Address;
use super::PresaleWallet;
use json;

Expand All @@ -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());
}
}
2 changes: 2 additions & 0 deletions parity/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Usage:
parity daemon <pid-file> [options]
parity account (new | list ) [options]
parity account import <path>... [options]
parity wallet import <path> --password FILE [options]
parity import [ <file> ] [options]
parity export [ <file> ] [options]
parity signer new-token [options]
Expand Down Expand Up @@ -223,6 +224,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,
Expand Down
29 changes: 29 additions & 0 deletions parity/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<PanicHandler>,
_rpc_server: Option<RpcServer>,
Expand Down