diff --git a/emerald-cli/usage.txt b/emerald-cli/usage.txt index b04a5994..3537508e 100644 --- a/emerald-cli/usage.txt +++ b/emerald-cli/usage.txt @@ -16,5 +16,5 @@ Options: + Mac OS X: ~/Library/Emerald + Linux: ~/.emerald + Windows: %USERDIR%\.emerald - --security-level Level of security for cryptographic operations [default: normal] + --security-level Level of security for cryptographic operations [default: ultra] -c, --chain Chain name [default: mainnet] \ No newline at end of file diff --git a/emerald-core/src/hdwallet/mod.rs b/emerald-core/src/hdwallet/mod.rs index 4432b0da..1507864f 100644 --- a/emerald-core/src/hdwallet/mod.rs +++ b/emerald-core/src/hdwallet/mod.rs @@ -15,10 +15,10 @@ pub use self::error::Error; pub use self::keystore::HdwalletCrypto; use super::{Address, ECDSA_SIGNATURE_BYTES, Signature, to_arr, to_bytes}; use hidapi::{HidApi, HidDevice, HidDeviceInfo}; +use regex::Regex; use std::{thread, time}; use std::str::{FromStr, from_utf8}; - const GET_ETH_ADDRESS: u8 = 0x02; const SIGN_ETH_TRANSACTION: u8 = 0x04; const CHUNK_SIZE: usize = 255; @@ -86,11 +86,19 @@ impl From for Device { /// Parse HD path into byte array pub fn path_to_arr(hd_str: &str) -> Result, Error> { - let mut buf = Vec::new(); + lazy_static! { + static ref INVALID_PATH_RE: Regex = Regex::new(r#"[^0-9'/]"#).unwrap(); + } - hd_str - .split("/") - .map(|s| { + if INVALID_PATH_RE.is_match(hd_str) { + return Err(Error::HDWalletError( + format!("Invalid `hd_path` format: {}", hd_str), + )); + } + + let mut buf = Vec::new(); + { + let parse = |s: &str| { let mut str = s.to_string(); let mut v: u64 = 0; @@ -98,9 +106,8 @@ pub fn path_to_arr(hd_str: &str) -> Result, Error> { v += 0x80000000; str.remove(s.len() - 1); } - - match str.parse::() { - Ok(d) => v += d as u64, + match str.parse::() { + Ok(d) => v += d, Err(_) => { return Err(Error::HDWalletError( format!("Invalid `hd_path` format: {}", hd_str), @@ -109,8 +116,10 @@ pub fn path_to_arr(hd_str: &str) -> Result, Error> { } buf.extend(to_bytes(v, 4)); Ok(()) - }) - .collect::>(); + }; + + hd_str.split("/").map(parse).collect::>(); + } Ok(buf) } @@ -468,7 +477,7 @@ mod tests { #[test] pub fn should_parse_hd_path() { - let path_str = "44\'/60\'/160720\'/0\'/0"; + let path_str = "44'/60'/160720'/0'/0"; assert_eq!( ETC_DERIVATION_PATH[1..].to_vec(), path_to_arr(&path_str).unwrap() @@ -476,18 +485,17 @@ mod tests { } #[test] - #[ignore] pub fn should_fail_parse_hd_path() { - let mut path_str = "44\'/60\'/160A+_0\'/0\'/0"; + let mut path_str = "44'/60'/160A+_0'/0'/0"; assert!(path_to_arr(&path_str).is_err()); - path_str = "44\'/60\'/16011_11111111111111111zz1111111111111111111111111111111\'/0\'/0"; + path_str = "44'/60'/16011_11111111111111111zz1111111111111111111111111111111'/0'/0"; assert!(path_to_arr(&path_str).is_err()); } #[test] - pub fn should_parse_hd_path_prefixed() { - let path_str = "44\'/60\'/160720\'/0\'/0"; + pub fn should_parse_hd_path_into_prefixed() { + let path_str = "44'/60'/160720'/0'/0"; assert_eq!( ETC_DERIVATION_PATH.to_vec(), to_prefixed_path(&path_str).unwrap() diff --git a/emerald-core/src/keystore/mod.rs b/emerald-core/src/keystore/mod.rs index 2ce05d38..ea7b0db7 100644 --- a/emerald-core/src/keystore/mod.rs +++ b/emerald-core/src/keystore/mod.rs @@ -11,7 +11,7 @@ mod serialize; pub use self::cipher::Cipher; pub use self::error::Error; -pub use self::kdf::{Kdf, KdfDepthLevel}; +pub use self::kdf::{Kdf, KdfDepthLevel, PBKDF2_KDF_NAME}; pub use self::prf::Prf; pub use self::serialize::{CoreCrypto, Iv, Mac, Salt, decode_str, hide, list_accounts, unhide}; use super::core::{self, Address, PrivateKey}; @@ -20,6 +20,7 @@ pub use hdwallet::HdwalletCrypto; use rand::{OsRng, Rng}; use std::{cmp, fmt}; use std::convert::From; +use std::str::FromStr; use uuid::Uuid; /// Key derivation function salt length in bytes @@ -76,10 +77,17 @@ impl KeyFile { ) -> Result { let mut rng = os_random(); + let kdf; + if cfg!(target_os = "windows") { + kdf = Kdf::from_str(PBKDF2_KDF_NAME)?; + } else { + kdf = Kdf::from(*sec_level); + } + Self::new_custom( PrivateKey::gen_custom(&mut rng), passphrase, - Kdf::from(*sec_level), + kdf, &mut rng, name, description, diff --git a/emerald-core/tests/keystore_test.rs b/emerald-core/tests/keystore_test.rs index 3573da98..68aa7b9f 100644 --- a/emerald-core/tests/keystore_test.rs +++ b/emerald-core/tests/keystore_test.rs @@ -260,6 +260,8 @@ fn should_decode_hd_wallet_keyfile() { } #[test] +//TODO:1 remove condition after fix for `scrypt` on Windows +#[cfg(not(target_os = "windows"))] fn should_use_security_level() { let sec = KdfDepthLevel::Normal; let kf = KeyFile::new("1234567890", &sec, None, None).unwrap();