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

importing presale wallet #1368

Merged
merged 2 commits into from
Jun 21, 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
11 changes: 9 additions & 2 deletions ethstore/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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");
}

}

8 changes: 8 additions & 0 deletions ethstore/src/ethkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@ impl From<json::H160> 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)
}
}
27 changes: 26 additions & 1 deletion ethstore/src/json/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

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};
Expand All @@ -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<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
Expand Down Expand Up @@ -85,3 +109,4 @@ macro_rules! impl_hash {
impl_hash!(H128, 16);
impl_hash!(H160, 20);
impl_hash!(H256, 32);
impl_hash!(H768, 96);
4 changes: 3 additions & 1 deletion ethstore/src/json/mod.rs.in
Original file line number Diff line number Diff line change
Expand Up @@ -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;

42 changes: 42 additions & 0 deletions ethstore/src/json/presale.rs
Original file line number Diff line number Diff line change
@@ -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<R>(reader: R) -> Result<Self, serde_json::Error> 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": "[email protected]",
"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);
}
}
2 changes: 2 additions & 0 deletions ethstore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ mod crypto;
mod error;
mod ethstore;
mod import;
mod presale;
mod random;
mod secret_store;

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;

80 changes: 80 additions & 0 deletions ethstore/src/presale.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use std::fs;
use std::path::Path;
use rcrypto::pbkdf2::pbkdf2;
use rcrypto::sha2::Sha256;
use rcrypto::hmac::Hmac;
use json;
use ethkey::{Address, Secret, KeyPair};
use crypto::Keccak256;
use {crypto, Error};

pub struct PresaleWallet {
iv: [u8; 16],
ciphertext: [u8; 80],
address: Address,
}

impl From<json::PresaleWallet> for PresaleWallet {
fn from(wallet: json::PresaleWallet) -> Self {
let mut iv = [0u8; 16];
iv.copy_from_slice(&wallet.encseed[..16]);

let mut ciphertext = [0u8; 80];
ciphertext.copy_from_slice(&wallet.encseed[16..]);

PresaleWallet {
iv: iv,
ciphertext: ciphertext,
address: Address::from(wallet.address),
}
}
}

impl PresaleWallet {
pub fn open<P>(path: P) -> Result<Self, Error> where P: AsRef<Path> {
let file = try!(fs::File::open(path));
let presale = json::PresaleWallet::load(file).unwrap();
Ok(PresaleWallet::from(presale))
}

pub fn decrypt(&self, password: &str) -> Result<KeyPair, Error> {
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::Address;
use super::PresaleWallet;
use json;

#[test]
fn test() {
let json = r#"
{
"encseed": "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066",
"ethaddr": "ede84640d1a1d3e06902048e67aa7db8d52c2ce1",
"email": "[email protected]",
"btcaddr": "1JvqEc6WLhg6GnyrLBe2ztPAU28KRfuseH"
} "#;

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));
}
}