diff --git a/Cargo.lock b/Cargo.lock index b98284b0d..f66727d95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -398,6 +398,11 @@ name = "dtoa" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "edit-distance" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "either" version = "1.1.0" @@ -488,8 +493,8 @@ dependencies = [ "ethcore-stratum 1.9.0", "ethcore-util 1.9.0", "ethjson 0.1.0", - "ethkey 0.2.0", - "ethstore 0.1.0", + "ethkey 0.3.0", + "ethstore 0.2.0", "evm 0.1.0", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "hardware-wallet 1.9.0", @@ -512,7 +517,7 @@ dependencies = [ "migration 0.1.0", "native-contracts 0.1.0", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-machine 0.1.0", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie 0.1.0", @@ -645,7 +650,7 @@ dependencies = [ "ethcore-logger 1.9.0", "ethcore-util 1.9.0", "ethcrypto 0.1.0", - "ethkey 0.2.0", + "ethkey 0.3.0", "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -677,7 +682,7 @@ dependencies = [ "ethcore-logger 1.9.0", "ethcore-util 1.9.0", "ethcrypto 0.1.0", - "ethkey 0.2.0", + "ethkey 0.3.0", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -757,7 +762,7 @@ version = "0.1.0" dependencies = [ "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", "ethcore-bigint 0.2.1", - "ethkey 0.2.0", + "ethkey 0.3.0", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -777,12 +782,15 @@ dependencies = [ [[package]] name = "ethkey" -version = "0.2.0" +version = "0.3.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", "ethcore-bigint 0.2.1", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -794,24 +802,27 @@ name = "ethkey-cli" version = "0.1.0" dependencies = [ "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethkey 0.2.0", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethkey 0.3.0", "panic_hook 0.1.0", + "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ethstore" -version = "0.1.0" +version = "0.2.0" dependencies = [ "ethcore-bigint 0.2.1", "ethcrypto 0.1.0", - "ethkey 0.2.0", + "ethkey 0.3.0", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-wordlist 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -830,8 +841,10 @@ name = "ethstore-cli" version = "0.1.0" dependencies = [ "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethstore 0.1.0", + "ethstore 0.2.0", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -850,7 +863,7 @@ dependencies = [ "ethcore-light 1.9.0", "ethcore-network 1.9.0", "ethcore-util 1.9.0", - "ethkey 0.2.0", + "ethkey 0.3.0", "heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.0", @@ -970,7 +983,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1013,7 +1026,7 @@ name = "hardware-wallet" version = "1.9.0" dependencies = [ "ethcore-bigint 0.2.1", - "ethkey 0.2.0", + "ethkey 0.3.0", "hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)", "libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1095,7 +1108,7 @@ dependencies = [ "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1817,7 +1830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1920,7 +1933,7 @@ dependencies = [ "ethcore-secretstore 1.0.0", "ethcore-stratum 1.9.0", "ethcore-util 1.9.0", - "ethkey 0.2.0", + "ethkey 0.3.0", "ethsync 1.9.0", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1936,7 +1949,7 @@ dependencies = [ "migration 0.1.0", "node-filter 1.9.0", "node-health 0.1.0", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", "parity-dapps 1.9.0", @@ -2074,7 +2087,7 @@ version = "0.1.0" dependencies = [ "ethcore 1.9.0", "ethcore-io 1.9.0", - "ethkey 0.2.0", + "ethkey 0.3.0", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2119,8 +2132,8 @@ dependencies = [ "ethcore-util 1.9.0", "ethcrypto 0.1.0", "ethjson 0.1.0", - "ethkey 0.2.0", - "ethstore 0.1.0", + "ethkey 0.3.0", + "ethstore 0.2.0", "ethsync 1.9.0", "fetch 0.1.0", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2274,7 +2287,7 @@ dependencies = [ "ethcore-bigint 0.2.1", "ethcore-network 1.9.0", "ethcrypto 0.1.0", - "ethkey 0.2.0", + "ethkey 0.3.0", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.9)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.9)", @@ -2296,7 +2309,7 @@ dependencies = [ [[package]] name = "parity-wordlist" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2570,7 +2583,7 @@ dependencies = [ "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3111,6 +3124,14 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "threadpool" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "time" version = "0.1.38" @@ -3571,6 +3592,7 @@ dependencies = [ "checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" "checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" +"checksum edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a34f5204fbc13582de418611cf3a7dcdd07c6d312a5b631597ba72c06b9d9c9" "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" "checksum elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "258ff6a9a94f648d0379dbd79110e057edbb53eb85cc237e33eadf8e5a30df85" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" @@ -3656,7 +3678,7 @@ dependencies = [ "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" "checksum num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "288629c76fac4b33556f4b7ab57ba21ae202da65ba8b77466e6d598e31990790" "checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" -"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" +"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" "checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" @@ -3670,7 +3692,7 @@ dependencies = [ "checksum parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-v1.git)" = "" "checksum parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-shell.git)" = "" "checksum parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8431a184ad88cfbcd71a792aaca319cc7203a94300c26b8dce2d0df0681ea87d" -"checksum parity-wordlist 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81451bfab101d186f8fc4a0aa13cb5539b31b02c4ed96425a0842e2a413daba6" +"checksum parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0dec124478845b142f68b446cbee953d14d4b41f1bc0425024417720dce693" "checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" @@ -3758,6 +3780,7 @@ dependencies = [ "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" "checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" +"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52d12ad79e4063e0cb0ca5efa202ed7244b6ce4d25f4d3abe410b2a66128292" "checksum tokio-core 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e85d419699ec4b71bfe35bbc25bb8771e52eff0471a7f75c853ad06e200b4f86" diff --git a/ethkey/Cargo.toml b/ethkey/Cargo.toml index 519accadf..7307fe0e9 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -1,14 +1,17 @@ [package] name = "ethkey" -version = "0.2.0" +version = "0.3.0" authors = ["Parity Technologies "] [dependencies] -rand = "0.3.14" -lazy_static = "0.2" -tiny-keccak = "1.3" -eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } -rustc-hex = "1.0" -ethcore-bigint = { path = "../util/bigint" } -rust-crypto = "0.2" byteorder = "1.0" +edit-distance = "2.0" +eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } +ethcore-bigint = { path = "../util/bigint" } +lazy_static = "0.2" +log = "0.3" +parity-wordlist = "1.2" +rand = "0.3.14" +rust-crypto = "0.2" +rustc-hex = "1.0" +tiny-keccak = "1.3" diff --git a/ethkey/README.md b/ethkey/README.md index 3886338ea..12161b377 100644 --- a/ethkey/README.md +++ b/ethkey/README.md @@ -16,13 +16,13 @@ Ethereum keys generator. Copyright 2016, 2017 Parity Technologies (UK) Ltd Usage: - ethkey info [options] + ethkey info [options] ethkey generate random [options] - ethkey generate prefix [options] - ethkey generate brain [options] + ethkey generate prefix [options] ethkey sign ethkey verify public ethkey verify address
+ ethkey recover
ethkey [-h | --help] Options: @@ -30,15 +30,15 @@ Options: -s, --secret Display only the secret. -p, --public Display only the public. -a, --address Display only the address. + -b, --brain Use parity brain wallet algorithm. Commands: info Display public and address of the secret. - generate Generates new ethereum key. - random Random generation. - prefix Random generation, but address must start with a prefix - brain Generate new key from string seed. + generate random Generates new random ethereum key. + generate prefix Random generation, but address must start with a prefix. sign Sign message using secret. verify Verify signer of the signature. + recover Try to find brain phrase matching given address from partial phrase. ``` ### Examples @@ -60,20 +60,22 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5 -- -#### `generate brain ` -*Generate new brain-wallet keypair using 16384 iterations.* -- `` - brain-wallet seed, any string +#### `info --brain ` +*Display info about private key generate from brain wallet recovery phrase.* +- `` - Parity recovery phrase, 12 words ``` -ethkey generate brain "this is sparta" +ethkey info --brain "this is sparta" ``` ``` -secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55 -public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124 -address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5 +The recover phrase was not generated by Parity: The word 'this' does not come from the dictionary. + +secret: aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2 +public: c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4 +address: 006e27b6a72e1f34c626762f3c4761547aff1421 ``` -- @@ -93,14 +95,30 @@ address: a8fa5dd30a87bb9e3288d604eb74949c515ab66e -- -#### `generate prefix ` +#### `generate random --brain` +*Generate new keypair with recovery phrase randomly.* + +``` +ethkey generate random --brain +``` + +``` +recovery phrase: thwarting scandal creamer nuzzle asparagus blast crouch trusting anytime elixir frenzied octagon +secret: 001ce488d50d2f7579dc190c4655f32918d505cee3de63bddc7101bc91c0c2f0 +public: 4e19a5fdae82596e1485c69b687c9cc52b5078e5b0668ef3ce8543cd90e712cb00df822489bc1f1dcb3623538a54476c7b3def44e1a51dc174e86448b63f42d0 +address: 00cf3711cbd3a1512570639280758118ba0b2bcb +``` + + +-- + +#### `generate prefix ` *Generate new keypair randomly with address starting with prefix.* - `` - desired address prefix, 0 - 32 bytes long. -- `` - maximum number of tries before generation is assumed to be a failure. ``` -ethkey generate prefix ff 1000 +ethkey generate prefix ff ``` ``` @@ -111,6 +129,24 @@ address: fff7e25dff2aa60f61f9d98130c8646a01f31649 -- +#### `generate prefix --brain ` +*Generate new keypair with recovery phrase randomly with address starting with prefix.* + +- `` - desired address prefix, 0 - 32 bytes long. + +``` +ethkey generate prefix --brain 00cf +``` + +``` +recovery phrase: thwarting scandal creamer nuzzle asparagus blast crouch trusting anytime elixir frenzied octagon +secret: 001ce488d50d2f7579dc190c4655f32918d505cee3de63bddc7101bc91c0c2f0 +public: 4e19a5fdae82596e1485c69b687c9cc52b5078e5b0668ef3ce8543cd90e712cb00df822489bc1f1dcb3623538a54476c7b3def44e1a51dc174e86448b63f42d0 +address: 00cf3711cbd3a1512570639280758118ba0b2bcb +``` + +-- + #### `sign ` *Sign a message with a secret.* @@ -159,9 +195,32 @@ ethkey verify address 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6 true ``` +-- -# Ethcore toolchain -*this project is a part of the ethcore toolchain* +#### `recover
` +*Try to recover an account given expected address and partial (too short or with invalid words) recovery phrase.* + +- `
` - ethereum address, 20 bytes long +- `` - known phrase, can be in a form of `thwarting * creamer` + +``` +RUST_LOG="info" ethkey recover "00cf3711cbd3a1512570639280758118ba0b2bcb" "thwarting scandal creamer nuzzle asparagus blast crouch trusting anytime elixir frenzied octag" +``` + +``` +INFO:ethkey::brain_recover: Invalid word 'octag', looking for potential substitutions. +INFO:ethkey::brain_recover: Closest words: ["ocean", "octagon", "octane", "outage", "tag", "acting", "acts", "aorta", "cage", "chug"] +INFO:ethkey::brain_recover: Starting to test 7776 possible combinations. + +thwarting scandal creamer nuzzle asparagus blast crouch trusting anytime elixir frenzied octagon +secret: 001ce488d50d2f7579dc190c4655f32918d505cee3de63bddc7101bc91c0c2f0 +public: 4e19a5fdae82596e1485c69b687c9cc52b5078e5b0668ef3ce8543cd90e712cb00df822489bc1f1dcb3623538a54476c7b3def44e1a51dc174e86448b63f42d0 +address: 00cf3711cbd3a1512570639280758118ba0b2bcb +``` + + +# Parity toolchain +*this project is a part of the parity toolchain* - [**ethkey**](https://github.com/paritytech/ethkey) - Ethereum keys generator and signer. - [**ethstore**](https://github.com/paritytech/ethstore) - Ethereum key management. diff --git a/ethkey/cli/Cargo.toml b/ethkey/cli/Cargo.toml index 6921af745..67c784f08 100644 --- a/ethkey/cli/Cargo.toml +++ b/ethkey/cli/Cargo.toml @@ -4,12 +4,15 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] +docopt = "0.8" +env_logger = "0.4" ethkey = { path = "../" } +panic_hook = { path = "../../panic_hook" } +parity-wordlist="1.2" +rustc-hex = "1.0" serde = "1.0" serde_derive = "1.0" -rustc-hex = "1.0" -docopt = "0.8" -panic_hook = { path = "../../panic_hook" } +threadpool = "1.7" [[bin]] name = "ethkey" diff --git a/ethkey/cli/src/main.rs b/ethkey/cli/src/main.rs index e60b4583a..1c9b748a9 100644 --- a/ethkey/cli/src/main.rs +++ b/ethkey/cli/src/main.rs @@ -15,32 +15,36 @@ // along with Parity. If not, see . extern crate docopt; -extern crate rustc_hex; -extern crate serde; -#[macro_use] -extern crate serde_derive; +extern crate env_logger; extern crate ethkey; extern crate panic_hook; +extern crate parity_wordlist; +extern crate rustc_hex; +extern crate serde; +extern crate threadpool; + +#[macro_use] +extern crate serde_derive; -use std::{env, fmt, process}; use std::num::ParseIntError; +use std::{env, fmt, process, io, sync}; + use docopt::Docopt; +use ethkey::{KeyPair, Random, Brain, BrainPrefix, Prefix, Error as EthkeyError, Generator, sign, verify_public, verify_address, brain_recover}; use rustc_hex::{ToHex, FromHex, FromHexError}; -use ethkey::{KeyPair, Random, Brain, Prefix, Error as EthkeyError, Generator, sign, verify_public, verify_address}; -use std::io; pub const USAGE: &'static str = r#" Ethereum keys generator. Copyright 2016, 2017 Parity Technologies (UK) Ltd Usage: - ethkey info [options] + ethkey info [options] ethkey generate random [options] - ethkey generate prefix [options] - ethkey generate brain [options] + ethkey generate prefix [options] ethkey sign ethkey verify public ethkey verify address
+ ethkey recover
ethkey [-h | --help] Options: @@ -48,15 +52,15 @@ Options: -s, --secret Display only the secret. -p, --public Display only the public. -a, --address Display only the address. + -b, --brain Use parity brain wallet algorithm. Commands: info Display public and address of the secret. - generate Generates new ethereum key. - random Random generation. - prefix Random generation, but address must start with a prefix - brain Generate new key from string seed. + generate random Generates new random ethereum key. + generate prefix Random generation, but address must start with a prefix. sign Sign message using secret. verify Verify signer of the signature. + recover Try to find brain phrase matching given address from partial phrase. "#; #[derive(Debug, Deserialize)] @@ -65,15 +69,15 @@ struct Args { cmd_generate: bool, cmd_random: bool, cmd_prefix: bool, - cmd_brain: bool, cmd_sign: bool, cmd_verify: bool, cmd_public: bool, cmd_address: bool, + cmd_recover: bool, arg_prefix: String, - arg_iterations: String, - arg_seed: String, arg_secret: String, + arg_secret_or_phrase: String, + arg_known_phrase: String, arg_message: String, arg_public: String, arg_address: String, @@ -81,6 +85,7 @@ struct Args { flag_secret: bool, flag_public: bool, flag_address: bool, + flag_brain: bool, } #[derive(Debug)] @@ -157,6 +162,7 @@ impl DisplayMode { fn main() { panic_hook::set(); + env_logger::init().expect("Logger initialized only once."); match execute(env::args()) { Ok(ok) => println!("{}", ok), @@ -167,9 +173,13 @@ fn main() { } } -fn display(keypair: KeyPair, mode: DisplayMode) -> String { +fn display(result: (KeyPair, Option), mode: DisplayMode) -> String { + let keypair = result.0; match mode { - DisplayMode::KeyPair => format!("{}", keypair), + DisplayMode::KeyPair => match result.1 { + Some(extra_data) => format!("{}\n{}", extra_data, keypair), + None => format!("{}", keypair) + }, DisplayMode::Secret => format!("{}", keypair.secret().to_hex()), DisplayMode::Public => format!("{:?}", keypair.public()), DisplayMode::Address => format!("{:?}", keypair.address()), @@ -182,23 +192,53 @@ fn execute(command: I) -> Result where I: IntoIterator(command: I) -> Result where I: IntoIterator= 1024 { + return Ok(None) + } + } + + Err(EthkeyError::Custom("Couldn't find any results.".into())) + } + })?; + Ok(display((keypair, Some(phrase)), display_mode)) } else { - unreachable!(); + Ok(format!("{}", USAGE)) } } +const BRAIN_WORDS: usize = 12; + +fn validate_phrase(phrase: &str) -> String { + match Brain::validate_phrase(phrase, BRAIN_WORDS) { + Ok(()) => format!("The recovery phrase looks correct.\n"), + Err(err) => format!("The recover phrase was not generated by Parity: {}", err) + } +} + +fn in_threads(prepare: F) -> Result where + O: Send + 'static, + X: Send + 'static, + F: Fn() -> X, + X: FnMut() -> Result, EthkeyError>, +{ + let pool = threadpool::Builder::new().build(); + + let (tx, rx) = sync::mpsc::sync_channel(1); + let is_done = sync::Arc::new(sync::atomic::AtomicBool::default()); + + for _ in 0..pool.max_count() { + let is_done = is_done.clone(); + let tx = tx.clone(); + let mut task = prepare(); + pool.execute(move || { + loop { + if is_done.load(sync::atomic::Ordering::SeqCst) { + return; + } + + let res = match task() { + Ok(None) => continue, + Ok(Some(v)) => Ok(v), + Err(err) => Err(err), + }; + + // We are interested only in the first response. + let _ = tx.send(res); + } + }); + } + + if let Ok(solution) = rx.recv() { + is_done.store(true, sync::atomic::Ordering::SeqCst); + return solution; + } + + Err(EthkeyError::Custom("No results found.".into())) +} + #[cfg(test)] mod tests { use super::execute; @@ -242,13 +357,15 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned(); #[test] fn brain() { - let command = vec!["ethkey", "generate", "brain", "this is sparta"] + let command = vec!["ethkey", "info", "--brain", "this is sparta"] .into_iter() .map(Into::into) .collect::>(); let expected = -"secret: aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2 +"The recover phrase was not generated by Parity: The word 'this' does not come from the dictionary. + +secret: aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2 public: c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4 address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned(); assert_eq!(execute(command).unwrap(), expected); @@ -256,7 +373,7 @@ address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned(); #[test] fn secret() { - let command = vec!["ethkey", "generate", "brain", "this is sparta", "--secret"] + let command = vec!["ethkey", "info", "--brain", "this is sparta", "--secret"] .into_iter() .map(Into::into) .collect::>(); @@ -267,7 +384,7 @@ address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned(); #[test] fn public() { - let command = vec!["ethkey", "generate", "brain", "this is sparta", "--public"] + let command = vec!["ethkey", "info", "--brain", "this is sparta", "--public"] .into_iter() .map(Into::into) .collect::>(); @@ -278,7 +395,7 @@ address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned(); #[test] fn address() { - let command = vec!["ethkey", "generate", "brain", "this is sparta", "--address"] + let command = vec!["ethkey", "info", "-b", "this is sparta", "--address"] .into_iter() .map(Into::into) .collect::>(); diff --git a/ethkey/src/brain.rs b/ethkey/src/brain.rs index 8bc9d2cd7..fffae0bed 100644 --- a/ethkey/src/brain.rs +++ b/ethkey/src/brain.rs @@ -16,6 +16,7 @@ use keccak::Keccak256; use super::{KeyPair, Generator, Secret}; +use parity_wordlist; /// Simple brainwallet. pub struct Brain(String); @@ -24,13 +25,17 @@ impl Brain { pub fn new(s: String) -> Self { Brain(s) } + + pub fn validate_phrase(phrase: &str, expected_words: usize) -> Result<(), ::WordlistError> { + parity_wordlist::validate_phrase(phrase, expected_words) + } } impl Generator for Brain { type Error = ::Void; - fn generate(self) -> Result { - let seed = self.0; + fn generate(&mut self) -> Result { + let seed = self.0.clone(); let mut secret = seed.into_bytes().keccak256(); let mut i = 0; @@ -43,7 +48,10 @@ impl Generator for Brain { if let Ok(pair) = Secret::from_unsafe_slice(&secret) .and_then(KeyPair::from_secret) { - if pair.address()[0] == 0 { return Ok(pair) } + if pair.address()[0] == 0 { + trace!("Testing: {}, got: {:?}", self.0, pair.address()); + return Ok(pair) + } } }, } diff --git a/ethkey/src/brain_prefix.rs b/ethkey/src/brain_prefix.rs new file mode 100644 index 000000000..a4e31e989 --- /dev/null +++ b/ethkey/src/brain_prefix.rs @@ -0,0 +1,70 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use super::{Generator, KeyPair, Error, Brain}; +use parity_wordlist as wordlist; + +/// Tries to find brain-seed keypair with address starting with given prefix. +pub struct BrainPrefix { + prefix: Vec, + iterations: usize, + no_of_words: usize, + last_phrase: String, +} + +impl BrainPrefix { + pub fn new(prefix: Vec, iterations: usize, no_of_words: usize) -> Self { + BrainPrefix { + prefix, + iterations, + no_of_words, + last_phrase: String::new(), + } + } + + pub fn phrase(&self) -> &str { + &self.last_phrase + } +} + +impl Generator for BrainPrefix { + type Error = Error; + + fn generate(&mut self) -> Result { + for _ in 0..self.iterations { + let phrase = wordlist::random_phrase(self.no_of_words); + let keypair = Brain::new(phrase.clone()).generate().unwrap(); + if keypair.address().starts_with(&self.prefix) { + self.last_phrase = phrase; + return Ok(keypair) + } + } + + Err(Error::Custom("Could not find keypair".into())) + } +} + +#[cfg(test)] +mod tests { + use {Generator, BrainPrefix}; + + #[test] + fn prefix_generator() { + let prefix = vec![0x00u8]; + let keypair = BrainPrefix::new(prefix.clone(), usize::max_value(), 12).generate().unwrap(); + assert!(keypair.address().starts_with(&prefix)); + } +} diff --git a/ethkey/src/brain_recover.rs b/ethkey/src/brain_recover.rs new file mode 100644 index 000000000..f064c6fd0 --- /dev/null +++ b/ethkey/src/brain_recover.rs @@ -0,0 +1,175 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::HashSet; + +use edit_distance::edit_distance; +use parity_wordlist; + +use super::{Address, Brain, Generator}; + + +/// Tries to find a phrase for address, given the number +/// of expected words and a partial phrase. +/// +/// Returns `None` if phrase couldn't be found. +pub fn brain_recover( + address: &Address, + known_phrase: &str, + expected_words: usize, +) -> Option { + let it = PhrasesIterator::from_known_phrase(known_phrase, expected_words); + for phrase in it { + let keypair = Brain::new(phrase.clone()).generate().expect("Brain wallets are infallible; qed"); + trace!("Testing: {}, got: {:?}", phrase, keypair.address()); + if &keypair.address() == address { + return Some(phrase); + } + } + + None +} + +fn generate_substitutions(word: &str) -> Vec<&'static str> { + let mut words = parity_wordlist::WORDS.iter().cloned() + .map(|w| (edit_distance(w, word), w)) + .collect::>(); + words.sort_by(|a, b| a.0.cmp(&b.0)); + + words.into_iter() + .map(|pair| pair.1) + .collect() +} + +/// Iterator over possible +pub struct PhrasesIterator { + words: Vec>, + combinations: u64, + indexes: Vec, + has_next: bool, +} + +impl PhrasesIterator { + pub fn from_known_phrase(known_phrase: &str, expected_words: usize) -> Self { + let known_words = parity_wordlist::WORDS.iter().cloned().collect::>(); + let mut words = known_phrase.split(' ') + .map(|word| match known_words.get(word) { + None => { + info!("Invalid word '{}', looking for potential substitutions.", word); + let substitutions = generate_substitutions(word); + info!("Closest words: {:?}", &substitutions[..10]); + substitutions + }, + Some(word) => vec![*word], + }) + .collect::>(); + + // add missing words + if words.len() < expected_words { + let to_add = expected_words - words.len(); + info!("Number of words is insuficcient adding {} more.", to_add); + for _ in 0..to_add { + words.push(parity_wordlist::WORDS.iter().cloned().collect()); + } + } + + // start searching + PhrasesIterator::new(words) + } + + pub fn new(words: Vec>) -> Self { + let combinations = words.iter().fold(1u64, |acc, x| acc * x.len() as u64); + let indexes = words.iter().map(|_| 0).collect(); + info!("Starting to test {} possible combinations.", combinations); + + PhrasesIterator { + words, + combinations, + indexes, + has_next: combinations > 0, + } + } + + pub fn combinations(&self) -> u64 { + self.combinations + } + + fn current(&self) -> String { + let mut s = self.words[0][self.indexes[0]].to_owned(); + for i in 1..self.indexes.len() { + s.push(' '); + s.push_str(self.words[i][self.indexes[i]]); + } + s + } + + fn next_index(&mut self) -> bool { + let mut pos = self.indexes.len(); + while pos > 0 { + pos -= 1; + self.indexes[pos] += 1; + if self.indexes[pos] >= self.words[pos].len() { + self.indexes[pos] = 0; + } else { + return true; + } + } + + false + } +} + +impl Iterator for PhrasesIterator { + type Item = String; + + fn next(&mut self) -> Option { + if !self.has_next { + return None; + } + + let phrase = self.current(); + self.has_next = self.next_index(); + Some(phrase) + } +} + +#[cfg(test)] +mod tests { + use super::PhrasesIterator; + + + #[test] + fn should_generate_possible_combinations() { + let mut it = PhrasesIterator::new(vec![ + vec!["1", "2", "3"], + vec!["test"], + vec!["a", "b", "c"], + ]); + + assert_eq!(it.combinations(), 9); + assert_eq!(it.next(), Some("1 test a".to_owned())); + assert_eq!(it.next(), Some("1 test b".to_owned())); + assert_eq!(it.next(), Some("1 test c".to_owned())); + assert_eq!(it.next(), Some("2 test a".to_owned())); + assert_eq!(it.next(), Some("2 test b".to_owned())); + assert_eq!(it.next(), Some("2 test c".to_owned())); + assert_eq!(it.next(), Some("3 test a".to_owned())); + assert_eq!(it.next(), Some("3 test b".to_owned())); + assert_eq!(it.next(), Some("3 test c".to_owned())); + assert_eq!(it.next(), None); + } + +} diff --git a/ethkey/src/lib.rs b/ethkey/src/lib.rs index 271a5f166..8753c0177 100644 --- a/ethkey/src/lib.rs +++ b/ethkey/src/lib.rs @@ -14,18 +14,25 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -extern crate rand; -extern crate tiny_keccak; -extern crate secp256k1; -extern crate rustc_hex; -extern crate ethcore_bigint as bigint; -extern crate crypto as rcrypto; +// #![warn(missing_docs)] + extern crate byteorder; +extern crate crypto as rcrypto; +extern crate edit_distance; +extern crate ethcore_bigint as bigint; +extern crate parity_wordlist; +extern crate rand; +extern crate rustc_hex; +extern crate secp256k1; +extern crate tiny_keccak; #[macro_use] extern crate lazy_static; +#[macro_use] +extern crate log; mod brain; +mod brain_prefix; mod error; mod keypair; mod keccak; @@ -35,9 +42,12 @@ mod signature; mod secret; mod extended; +pub mod brain_recover; pub mod math; +pub use self::parity_wordlist::Error as WordlistError; pub use self::brain::Brain; +pub use self::brain_prefix::BrainPrefix; pub use self::error::Error; pub use self::keypair::{KeyPair, public_to_address}; pub use self::math::public_is_valid; @@ -62,7 +72,7 @@ pub trait Generator { type Error; /// Should be called to generate new keypair. - fn generate(self) -> Result; + fn generate(&mut self) -> Result; } pub type Address = H160; diff --git a/ethkey/src/prefix.rs b/ethkey/src/prefix.rs index 25b1ab3f7..f2ef0f0ff 100644 --- a/ethkey/src/prefix.rs +++ b/ethkey/src/prefix.rs @@ -34,7 +34,7 @@ impl Prefix { impl Generator for Prefix { type Error = Error; - fn generate(self) -> Result { + fn generate(&mut self) -> Result { for _ in 0..self.iterations { let keypair = Random.generate()?; if keypair.address().starts_with(&self.prefix) { diff --git a/ethkey/src/random.rs b/ethkey/src/random.rs index 715dd3cb5..b44a4b2ca 100644 --- a/ethkey/src/random.rs +++ b/ethkey/src/random.rs @@ -23,7 +23,7 @@ pub struct Random; impl Generator for Random { type Error = ::std::io::Error; - fn generate(self) -> Result { + fn generate(&mut self) -> Result { let mut rng = OsRng::new()?; match rng.generate() { Ok(pair) => Ok(pair), @@ -32,10 +32,10 @@ impl Generator for Random { } } -impl<'a> Generator for &'a mut OsRng { +impl Generator for OsRng { type Error = ::Void; - fn generate(self) -> Result { + fn generate(&mut self) -> Result { let (sec, publ) = SECP256K1.generate_keypair(self) .expect("context always created with full capabilities; qed"); diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index 200dec366..23c02973f 100755 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ethstore" -version = "0.1.0" +version = "0.2.0" authors = ["Parity Technologies "] [dependencies] diff --git a/ethstore/README.md b/ethstore/README.md index 4f7daf4e2..c56a24a93 100644 --- a/ethstore/README.md +++ b/ethstore/README.md @@ -21,6 +21,7 @@ Usage: ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore import [--src DIR] [--dir DIR] ethstore import-wallet [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] + ethstore find-wallet-pass ethstore remove
[--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore sign
[--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore public
[--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] @@ -50,6 +51,7 @@ Commands: list List accounts. import Import accounts from src. import-wallet Import presale wallet. + find-wallet-pass Tries to open a wallet with list of passwords given. remove Remove account. sign Sign message. public Displays public key for an address. @@ -164,6 +166,25 @@ ethstore import-wallet ethwallet.json password.txt e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb ``` + +-- + +#### `find-wallet-pass ` +Try to open presale wallet given a list of passwords from a file. +The list of passwords can be generated using e.g. [Phildo/brutedist](https://github.com/Phildo/brutedist). + +- `` - presale wallet path +- `` - possible passwords, file path + +``` +ethstore find-wallet-pass ethwallet.json passwords.txt +``` + +``` +Found password: test +``` + + -- #### `remove
[--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]` @@ -318,8 +339,8 @@ OK -- -# Ethcore toolchain -*this project is a part of the ethcore toolchain* +# Parity toolchain +*this project is a part of the parity toolchain* - [**ethkey**](https://github.com/paritytech/ethkey) - Ethereum keys generator and signer. - [**ethstore**](https://github.com/paritytech/ethstore) - Ethereum key management. diff --git a/ethstore/cli/Cargo.toml b/ethstore/cli/Cargo.toml index 71215fefe..24d1c9a8f 100644 --- a/ethstore/cli/Cargo.toml +++ b/ethstore/cli/Cargo.toml @@ -4,10 +4,12 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] +docopt = "0.8" +num_cpus = "1.6" rustc-hex = "1.0" serde = "1.0" serde_derive = "1.0" -docopt = "0.8" +parking_lot = "0.4" ethstore = { path = "../" } panic_hook = { path = "../../panic_hook" } diff --git a/ethstore/cli/src/crack.rs b/ethstore/cli/src/crack.rs new file mode 100644 index 000000000..64eda66e5 --- /dev/null +++ b/ethstore/cli/src/crack.rs @@ -0,0 +1,50 @@ +use std::{cmp, thread}; +use std::sync::Arc; +use std::collections::VecDeque; +use parking_lot::Mutex; + +use ethstore::{PresaleWallet, Error}; +use num_cpus; + +pub fn run(passwords: VecDeque, wallet_path: &str) -> Result<(), Error> { + let passwords = Arc::new(Mutex::new(passwords)); + + let mut handles = Vec::new(); + + for _ in 0..num_cpus::get() { + let passwords = passwords.clone(); + let wallet = PresaleWallet::open(&wallet_path)?; + handles.push(thread::spawn(move || { + look_for_password(passwords, wallet); + })); + } + + for handle in handles { + handle.join().map_err(|err| Error::Custom(format!("Error finishing thread: {:?}", err)))?; + } + + Ok(()) +} + +fn look_for_password(passwords: Arc>>, wallet: PresaleWallet) { + let mut counter = 0; + while !passwords.lock().is_empty() { + let package = { + let mut passwords = passwords.lock(); + let len = passwords.len(); + passwords.split_off(cmp::min(len, 32)) + }; + for pass in package { + counter += 1; + match wallet.decrypt(&pass) { + Ok(_) => { + println!("Found password: {}", &pass); + passwords.lock().clear(); + return; + }, + _ if counter % 100 == 0 => print!("."), + _ => {}, + } + } + } +} diff --git a/ethstore/cli/src/main.rs b/ethstore/cli/src/main.rs index 849985167..798c7e599 100644 --- a/ethstore/cli/src/main.rs +++ b/ethstore/cli/src/main.rs @@ -14,21 +14,27 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -extern crate rustc_hex; extern crate docopt; +extern crate ethstore; +extern crate num_cpus; +extern crate panic_hook; +extern crate parking_lot; +extern crate rustc_hex; extern crate serde; + #[macro_use] extern crate serde_derive; -extern crate ethstore; -extern crate panic_hook; -use std::{env, process, fs, fmt}; +use std::collections::VecDeque; use std::io::Read; +use std::{env, process, fs, fmt}; + use docopt::Docopt; -use ethstore::ethkey::Address; use ethstore::dir::{paths, KeyDirectory, RootDiskDirectory}; -use ethstore::{EthStore, SimpleSecretStore, SecretStore, import_accounts, PresaleWallet, - SecretVaultRef, StoreAccountRef}; +use ethstore::ethkey::Address; +use ethstore::{EthStore, SimpleSecretStore, SecretStore, import_accounts, PresaleWallet, SecretVaultRef, StoreAccountRef}; + +mod crack; pub const USAGE: &'static str = r#" Ethereum key management. @@ -40,6 +46,7 @@ Usage: ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore import [--src DIR] [--dir DIR] ethstore import-wallet [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] + ethstore find-wallet-pass ethstore remove
[--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore sign
[--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore public
[--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] @@ -69,6 +76,7 @@ Commands: list List accounts. import Import accounts from src. import-wallet Import presale wallet. + find-wallet-pass Tries to open a wallet with list of passwords given. remove Remove account. sign Sign message. public Displays public key for an address. @@ -86,6 +94,7 @@ struct Args { cmd_list: bool, cmd_import: bool, cmd_import_wallet: bool, + cmd_find_wallet_pass: bool, cmd_remove: bool, cmd_sign: bool, cmd_public: bool, @@ -239,6 +248,11 @@ fn execute(command: I) -> Result where I: IntoIterator>(); + crack::run(passwords, &args.arg_path)?; + Ok(format!("Password not found.")) } else if args.cmd_remove { let address = args.arg_address.parse().map_err(|_| ethstore::Error::InvalidAccount)?; let password = load_password(&args.arg_password)?;