Consolidate crypto functionality in ethcore-crypto
. (#8432)
* Consolidate crypto functionality in `ethcore-crypto`. - Move `ecdh`/`ecies` modules to `ethkey`. - Refactor `ethcore-crypto` to use file per module. - Replace `subtle` with `ethcore_crypto::is_equal`. - Add `aes_gcm` module to `ethcore-crypto`. * Rename `aes::{encrypt,decrypt,decrypt_cbc}` ... ... to `aes::{encrypt_128_ctr,decrypt_128_ctr,decrypt_128_cbc}`.
This commit is contained in:
parent
a4c7843a07
commit
e30839e85f
26
Cargo.lock
generated
26
Cargo.lock
generated
@ -509,6 +509,7 @@ dependencies = [
|
|||||||
"ethash 1.12.0",
|
"ethash 1.12.0",
|
||||||
"ethcore-bloom-journal 0.1.0",
|
"ethcore-bloom-journal 0.1.0",
|
||||||
"ethcore-bytes 0.1.0",
|
"ethcore-bytes 0.1.0",
|
||||||
|
"ethcore-crypto 0.1.0",
|
||||||
"ethcore-io 1.12.0",
|
"ethcore-io 1.12.0",
|
||||||
"ethcore-logger 1.12.0",
|
"ethcore-logger 1.12.0",
|
||||||
"ethcore-miner 1.12.0",
|
"ethcore-miner 1.12.0",
|
||||||
@ -545,7 +546,6 @@ dependencies = [
|
|||||||
"rlp 0.2.1",
|
"rlp 0.2.1",
|
||||||
"rlp_compress 0.1.0",
|
"rlp_compress 0.1.0",
|
||||||
"rlp_derive 0.1.0",
|
"rlp_derive 0.1.0",
|
||||||
"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)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)",
|
"snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)",
|
||||||
"stats 0.1.0",
|
"stats 0.1.0",
|
||||||
@ -576,11 +576,10 @@ version = "0.1.0"
|
|||||||
name = "ethcore-crypto"
|
name = "ethcore-crypto"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)",
|
|
||||||
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethkey 0.3.0",
|
"quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ring 0.12.1 (git+https://github.com/paritytech/ring)",
|
||||||
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -925,13 +924,14 @@ dependencies = [
|
|||||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"edit-distance 2.0.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)",
|
"eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)",
|
||||||
|
"ethcore-crypto 0.1.0",
|
||||||
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethereum-types 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mem 0.1.0",
|
"mem 0.1.0",
|
||||||
"parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (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)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -966,13 +966,11 @@ dependencies = [
|
|||||||
"parity-wordlist 1.2.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.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (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)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -2197,7 +2195,6 @@ dependencies = [
|
|||||||
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rlp 0.2.1",
|
"rlp 0.2.1",
|
||||||
"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)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -2362,7 +2359,6 @@ dependencies = [
|
|||||||
"ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ring 0.12.1 (git+https://github.com/paritytech/ring)",
|
|
||||||
"rlp 0.2.1",
|
"rlp 0.2.1",
|
||||||
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -2621,6 +2617,11 @@ dependencies = [
|
|||||||
"quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@ -3035,11 +3036,6 @@ name = "strsim"
|
|||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "subtle"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
@ -3927,6 +3923,7 @@ dependencies = [
|
|||||||
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
|
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
|
||||||
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
|
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
|
||||||
"checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd"
|
"checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd"
|
||||||
|
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
|
||||||
"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
|
"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
|
||||||
"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
|
"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
|
||||||
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
||||||
@ -3973,7 +3970,6 @@ dependencies = [
|
|||||||
"checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>"
|
"checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>"
|
||||||
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
||||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||||
"checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb"
|
|
||||||
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
|
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
|
||||||
"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e"
|
"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e"
|
||||||
"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c"
|
"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c"
|
||||||
|
@ -20,6 +20,7 @@ fetch = { path = "../util/fetch" }
|
|||||||
hashdb = { path = "../util/hashdb" }
|
hashdb = { path = "../util/hashdb" }
|
||||||
memorydb = { path = "../util/memorydb" }
|
memorydb = { path = "../util/memorydb" }
|
||||||
patricia-trie = { path = "../util/patricia_trie" }
|
patricia-trie = { path = "../util/patricia_trie" }
|
||||||
|
ethcore-crypto = { path = "crypto" }
|
||||||
error-chain = { version = "0.11", default-features = false }
|
error-chain = { version = "0.11", default-features = false }
|
||||||
ethcore-io = { path = "../util/io" }
|
ethcore-io = { path = "../util/io" }
|
||||||
ethcore-logger = { path = "../logger" }
|
ethcore-logger = { path = "../logger" }
|
||||||
@ -56,7 +57,6 @@ util-error = { path = "../util/error" }
|
|||||||
snappy = { git = "https://github.com/paritytech/rust-snappy" }
|
snappy = { git = "https://github.com/paritytech/rust-snappy" }
|
||||||
stop-guard = { path = "../util/stop-guard" }
|
stop-guard = { path = "../util/stop-guard" }
|
||||||
macros = { path = "../util/macros" }
|
macros = { path = "../util/macros" }
|
||||||
rust-crypto = "0.2.34"
|
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
stats = { path = "../util/stats" }
|
stats = { path = "../util/stats" }
|
||||||
trace-time = { path = "../util/trace-time" }
|
trace-time = { path = "../util/trace-time" }
|
||||||
|
@ -20,7 +20,7 @@ extern crate test;
|
|||||||
extern crate ethcore_util as util;
|
extern crate ethcore_util as util;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate bn;
|
extern crate bn;
|
||||||
extern crate crypto;
|
extern crate ethcore_crypto;
|
||||||
extern crate ethkey;
|
extern crate ethkey;
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
extern crate ethcore_bigint;
|
extern crate ethcore_bigint;
|
||||||
@ -61,16 +61,13 @@ fn bn_128_mul(b: &mut Bencher) {
|
|||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn sha256(b: &mut Bencher) {
|
fn sha256(b: &mut Bencher) {
|
||||||
use crypto::sha2::Sha256;
|
use ethcore_crypto::digest::sha256;
|
||||||
use crypto::digest::Digest;
|
|
||||||
|
|
||||||
let mut input: [u8; 256] = [0; 256];
|
let mut input: [u8; 256] = [0; 256];
|
||||||
let mut out = [0; 32];
|
let mut out = [0; 32];
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut sha = Sha256::new();
|
sha256(&input);
|
||||||
sha.input(&input);
|
|
||||||
sha.result(&mut input[0..32]);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,13 +4,9 @@ version = "0.1.0"
|
|||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ethereum-types = "0.3"
|
||||||
|
quick-error = "1.2"
|
||||||
|
ring = "0.12"
|
||||||
rust-crypto = "0.2.36"
|
rust-crypto = "0.2.36"
|
||||||
tiny-keccak = "1.3"
|
tiny-keccak = "1.3"
|
||||||
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", optional = true }
|
|
||||||
ethkey = { path = "../../ethkey", optional = true }
|
|
||||||
ethereum-types = "0.3"
|
|
||||||
subtle = "0.5"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["secp256k1"]
|
|
||||||
secp256k1 = ["eth-secp256k1", "ethkey"]
|
|
||||||
|
54
ethcore/crypto/src/aes.rs
Normal file
54
ethcore/crypto/src/aes.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use error::SymmError;
|
||||||
|
use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding};
|
||||||
|
use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor};
|
||||||
|
use rcrypto::symmetriccipher::{Encryptor, Decryptor};
|
||||||
|
use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer};
|
||||||
|
|
||||||
|
/// Encrypt a message (CTR mode).
|
||||||
|
///
|
||||||
|
/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each.
|
||||||
|
/// An error is returned if the input lengths are invalid.
|
||||||
|
pub fn encrypt_128_ctr(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) -> Result<(), SymmError> {
|
||||||
|
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
|
||||||
|
encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypt a message (CTR mode).
|
||||||
|
///
|
||||||
|
/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each.
|
||||||
|
/// An error is returned if the input lengths are invalid.
|
||||||
|
pub fn decrypt_128_ctr(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmError> {
|
||||||
|
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
|
||||||
|
encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypt a message (CBC mode).
|
||||||
|
///
|
||||||
|
/// Key (`k`) length and initialisation vector (`iv`) length have to be 16 bytes each.
|
||||||
|
/// An error is returned if the input lengths are invalid.
|
||||||
|
pub fn decrypt_128_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<usize, SymmError> {
|
||||||
|
let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec());
|
||||||
|
let len = dest.len();
|
||||||
|
let mut buffer = RefWriteBuffer::new(dest);
|
||||||
|
encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?;
|
||||||
|
Ok(len - buffer.remaining())
|
||||||
|
}
|
||||||
|
|
199
ethcore/crypto/src/aes_gcm.rs
Normal file
199
ethcore/crypto/src/aes_gcm.rs
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use error::SymmError;
|
||||||
|
use ring;
|
||||||
|
|
||||||
|
enum Mode { Aes128Gcm, Aes256Gcm }
|
||||||
|
|
||||||
|
/// AES GCM encryptor.
|
||||||
|
pub struct Encryptor<'a> {
|
||||||
|
mode: Mode,
|
||||||
|
key: ring::aead::SealingKey,
|
||||||
|
ad: &'a [u8],
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Encryptor<'a> {
|
||||||
|
pub fn aes_128_gcm(key: &[u8; 16]) -> Result<Encryptor<'a>, SymmError> {
|
||||||
|
let sk = ring::aead::SealingKey::new(&ring::aead::AES_128_GCM, key)?;
|
||||||
|
Ok(Encryptor {
|
||||||
|
mode: Mode::Aes128Gcm,
|
||||||
|
key: sk,
|
||||||
|
ad: &[],
|
||||||
|
offset: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn aes_256_gcm(key: &[u8; 32]) -> Result<Encryptor<'a>, SymmError> {
|
||||||
|
let sk = ring::aead::SealingKey::new(&ring::aead::AES_256_GCM, key)?;
|
||||||
|
Ok(Encryptor {
|
||||||
|
mode: Mode::Aes256Gcm,
|
||||||
|
key: sk,
|
||||||
|
ad: &[],
|
||||||
|
offset: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Optional associated data which is not encrypted but authenticated.
|
||||||
|
pub fn associate(&mut self, data: &'a [u8]) -> &mut Self {
|
||||||
|
self.ad = data;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Optional offset value. Only the slice `[offset..]` will be encrypted.
|
||||||
|
pub fn offset(&mut self, off: usize) -> &mut Self {
|
||||||
|
self.offset = off;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Please note that the pair (key, nonce) must never be reused. Using random nonces
|
||||||
|
/// limits the number of messages encrypted with the same key to 2^32 (cf. [[1]])
|
||||||
|
///
|
||||||
|
/// [1]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
|
||||||
|
pub fn encrypt(&self, nonce: &[u8; 12], mut data: Vec<u8>) -> Result<Vec<u8>, SymmError> {
|
||||||
|
if self.offset > data.len() {
|
||||||
|
return Err(SymmError::offset_error(self.offset))
|
||||||
|
}
|
||||||
|
let tag_len = match self.mode {
|
||||||
|
Mode::Aes128Gcm => ring::aead::AES_128_GCM.tag_len(),
|
||||||
|
Mode::Aes256Gcm => ring::aead::AES_256_GCM.tag_len(),
|
||||||
|
};
|
||||||
|
data.extend(::std::iter::repeat(0).take(tag_len));
|
||||||
|
let len = ring::aead::seal_in_place(&self.key, nonce, self.ad, &mut data[self.offset ..], tag_len)?;
|
||||||
|
data.truncate(self.offset + len);
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// AES GCM decryptor.
|
||||||
|
pub struct Decryptor<'a> {
|
||||||
|
key: ring::aead::OpeningKey,
|
||||||
|
ad: &'a [u8],
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Decryptor<'a> {
|
||||||
|
pub fn aes_128_gcm(key: &[u8; 16]) -> Result<Decryptor<'a>, SymmError> {
|
||||||
|
let ok = ring::aead::OpeningKey::new(&ring::aead::AES_128_GCM, key)?;
|
||||||
|
Ok(Decryptor {
|
||||||
|
key: ok,
|
||||||
|
ad: &[],
|
||||||
|
offset: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn aes_256_gcm(key: &[u8; 32]) -> Result<Decryptor<'a>, SymmError> {
|
||||||
|
let ok = ring::aead::OpeningKey::new(&ring::aead::AES_256_GCM, key)?;
|
||||||
|
Ok(Decryptor {
|
||||||
|
key: ok,
|
||||||
|
ad: &[],
|
||||||
|
offset: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Optional associated data which is not encrypted but authenticated.
|
||||||
|
pub fn associate(&mut self, data: &'a [u8]) -> &mut Self {
|
||||||
|
self.ad = data;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Optional offset value. Only the slice `[offset..]` will be decrypted.
|
||||||
|
pub fn offset(&mut self, off: usize) -> &mut Self {
|
||||||
|
self.offset = off;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decrypt(&self, nonce: &[u8; 12], mut data: Vec<u8>) -> Result<Vec<u8>, SymmError> {
|
||||||
|
if self.offset > data.len() {
|
||||||
|
return Err(SymmError::offset_error(self.offset))
|
||||||
|
}
|
||||||
|
let len = ring::aead::open_in_place(&self.key, nonce, self.ad, 0, &mut data[self.offset ..])?.len();
|
||||||
|
data.truncate(self.offset + len);
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{Encryptor, Decryptor};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn aes_gcm_128() {
|
||||||
|
let secret = b"1234567890123456";
|
||||||
|
let nonce = b"123456789012";
|
||||||
|
let message = b"So many books, so little time";
|
||||||
|
|
||||||
|
let ciphertext = Encryptor::aes_128_gcm(secret)
|
||||||
|
.unwrap()
|
||||||
|
.encrypt(nonce, message.to_vec())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(ciphertext != message);
|
||||||
|
|
||||||
|
let plaintext = Decryptor::aes_128_gcm(secret)
|
||||||
|
.unwrap()
|
||||||
|
.decrypt(nonce, ciphertext)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(plaintext, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn aes_gcm_256() {
|
||||||
|
let secret = b"12345678901234567890123456789012";
|
||||||
|
let nonce = b"123456789012";
|
||||||
|
let message = b"So many books, so little time";
|
||||||
|
|
||||||
|
let ciphertext = Encryptor::aes_256_gcm(secret)
|
||||||
|
.unwrap()
|
||||||
|
.encrypt(nonce, message.to_vec())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(ciphertext != message);
|
||||||
|
|
||||||
|
let plaintext = Decryptor::aes_256_gcm(secret)
|
||||||
|
.unwrap()
|
||||||
|
.decrypt(nonce, ciphertext)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(plaintext, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn aes_gcm_256_offset() {
|
||||||
|
let secret = b"12345678901234567890123456789012";
|
||||||
|
let nonce = b"123456789012";
|
||||||
|
let message = b"prefix data; So many books, so little time";
|
||||||
|
|
||||||
|
let ciphertext = Encryptor::aes_256_gcm(secret)
|
||||||
|
.unwrap()
|
||||||
|
.offset(13) // length of "prefix data; "
|
||||||
|
.encrypt(nonce, message.to_vec())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(ciphertext != &message[..]);
|
||||||
|
|
||||||
|
let plaintext = Decryptor::aes_256_gcm(secret)
|
||||||
|
.unwrap()
|
||||||
|
.offset(13) // length of "prefix data; "
|
||||||
|
.decrypt(nonce, ciphertext)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(plaintext, &message[..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
109
ethcore/crypto/src/digest.rs
Normal file
109
ethcore/crypto/src/digest.rs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use rcrypto::ripemd160;
|
||||||
|
use ring::digest::{self, Context, SHA256, SHA512};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
/// The message digest.
|
||||||
|
pub struct Digest<T>(InnerDigest, PhantomData<T>);
|
||||||
|
|
||||||
|
enum InnerDigest {
|
||||||
|
Ring(digest::Digest),
|
||||||
|
Ripemd160([u8; 20]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for Digest<T> {
|
||||||
|
type Target = [u8];
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self.0 {
|
||||||
|
InnerDigest::Ring(ref d) => d.as_ref(),
|
||||||
|
InnerDigest::Ripemd160(ref d) => &d[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Single-step sha256 digest computation.
|
||||||
|
pub fn sha256(data: &[u8]) -> Digest<Sha256> {
|
||||||
|
Digest(InnerDigest::Ring(digest::digest(&SHA256, data)), PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Single-step sha512 digest computation.
|
||||||
|
pub fn sha512(data: &[u8]) -> Digest<Sha512> {
|
||||||
|
Digest(InnerDigest::Ring(digest::digest(&SHA512, data)), PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Single-step ripemd160 digest computation.
|
||||||
|
pub fn ripemd160(data: &[u8]) -> Digest<Ripemd160> {
|
||||||
|
let mut hasher = Hasher::ripemd160();
|
||||||
|
hasher.update(data);
|
||||||
|
hasher.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Sha256 {}
|
||||||
|
pub enum Sha512 {}
|
||||||
|
pub enum Ripemd160 {}
|
||||||
|
|
||||||
|
/// Stateful digest computation.
|
||||||
|
pub struct Hasher<T>(Inner, PhantomData<T>);
|
||||||
|
|
||||||
|
enum Inner {
|
||||||
|
Ring(Context),
|
||||||
|
Ripemd160(ripemd160::Ripemd160)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hasher<Sha256> {
|
||||||
|
pub fn sha256() -> Hasher<Sha256> {
|
||||||
|
Hasher(Inner::Ring(Context::new(&SHA256)), PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hasher<Sha512> {
|
||||||
|
pub fn sha512() -> Hasher<Sha512> {
|
||||||
|
Hasher(Inner::Ring(Context::new(&SHA512)), PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hasher<Ripemd160> {
|
||||||
|
pub fn ripemd160() -> Hasher<Ripemd160> {
|
||||||
|
Hasher(Inner::Ripemd160(ripemd160::Ripemd160::new()), PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Hasher<T> {
|
||||||
|
pub fn update(&mut self, data: &[u8]) {
|
||||||
|
match self.0 {
|
||||||
|
Inner::Ring(ref mut ctx) => ctx.update(data),
|
||||||
|
Inner::Ripemd160(ref mut ctx) => {
|
||||||
|
use rcrypto::digest::Digest;
|
||||||
|
ctx.input(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> Digest<T> {
|
||||||
|
match self.0 {
|
||||||
|
Inner::Ring(ctx) => Digest(InnerDigest::Ring(ctx.finish()), PhantomData),
|
||||||
|
Inner::Ripemd160(mut ctx) => {
|
||||||
|
use rcrypto::digest::Digest;
|
||||||
|
let mut d = [0; 20];
|
||||||
|
ctx.result(&mut d);
|
||||||
|
Digest(InnerDigest::Ripemd160(d), PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
ethcore/crypto/src/error.rs
Normal file
83
ethcore/crypto/src/error.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use rcrypto;
|
||||||
|
use ring;
|
||||||
|
|
||||||
|
quick_error! {
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Scrypt(e: ScryptError) {
|
||||||
|
cause(e)
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
Symm(e: SymmError) {
|
||||||
|
cause(e)
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quick_error! {
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ScryptError {
|
||||||
|
// log(N) < r / 16
|
||||||
|
InvalidN {
|
||||||
|
display("Invalid N argument of the scrypt encryption")
|
||||||
|
}
|
||||||
|
// p <= (2^31-1 * 32)/(128 * r)
|
||||||
|
InvalidP {
|
||||||
|
display("Invalid p argument of the scrypt encryption")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quick_error! {
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SymmError wraps PrivSymmErr {
|
||||||
|
RustCrypto(e: rcrypto::symmetriccipher::SymmetricCipherError) {
|
||||||
|
display("symmetric crypto error")
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
Ring(e: ring::error::Unspecified) {
|
||||||
|
display("symmetric crypto error")
|
||||||
|
cause(e)
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
Offset(x: usize) {
|
||||||
|
display("offset {} greater than slice length", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SymmError {
|
||||||
|
pub(crate) fn offset_error(x: usize) -> SymmError {
|
||||||
|
SymmError(PrivSymmErr::Offset(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ring::error::Unspecified> for SymmError {
|
||||||
|
fn from(e: ring::error::Unspecified) -> SymmError {
|
||||||
|
SymmError(PrivSymmErr::Ring(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<rcrypto::symmetriccipher::SymmetricCipherError> for SymmError {
|
||||||
|
fn from(e: rcrypto::symmetriccipher::SymmetricCipherError) -> SymmError {
|
||||||
|
SymmError(PrivSymmErr::RustCrypto(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
89
ethcore/crypto/src/hmac.rs
Normal file
89
ethcore/crypto/src/hmac.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use digest;
|
||||||
|
use ring::digest::{SHA256, SHA512};
|
||||||
|
use ring::hmac::{self, SigningContext};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
/// HMAC signature.
|
||||||
|
pub struct Signature<T>(hmac::Signature, PhantomData<T>);
|
||||||
|
|
||||||
|
impl<T> Deref for Signature<T> {
|
||||||
|
type Target = [u8];
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// HMAC signing key.
|
||||||
|
pub struct SigKey<T>(hmac::SigningKey, PhantomData<T>);
|
||||||
|
|
||||||
|
impl SigKey<digest::Sha256> {
|
||||||
|
pub fn sha256(key: &[u8]) -> SigKey<digest::Sha256> {
|
||||||
|
SigKey(hmac::SigningKey::new(&SHA256, key), PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SigKey<digest::Sha512> {
|
||||||
|
pub fn sha512(key: &[u8]) -> SigKey<digest::Sha512> {
|
||||||
|
SigKey(hmac::SigningKey::new(&SHA512, key), PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute HMAC signature of `data`.
|
||||||
|
pub fn sign<T>(k: &SigKey<T>, data: &[u8]) -> Signature<T> {
|
||||||
|
Signature(hmac::sign(&k.0, data), PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stateful HMAC computation.
|
||||||
|
pub struct Signer<T>(SigningContext, PhantomData<T>);
|
||||||
|
|
||||||
|
impl<T> Signer<T> {
|
||||||
|
pub fn with(key: &SigKey<T>) -> Signer<T> {
|
||||||
|
Signer(hmac::SigningContext::with_key(&key.0), PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, data: &[u8]) {
|
||||||
|
self.0.update(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign(self) -> Signature<T> {
|
||||||
|
Signature(self.0.sign(), PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// HMAC signature verification key.
|
||||||
|
pub struct VerifyKey<T>(hmac::VerificationKey, PhantomData<T>);
|
||||||
|
|
||||||
|
impl VerifyKey<digest::Sha256> {
|
||||||
|
pub fn sha256(key: &[u8]) -> VerifyKey<digest::Sha256> {
|
||||||
|
VerifyKey(hmac::VerificationKey::new(&SHA256, key), PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VerifyKey<digest::Sha512> {
|
||||||
|
pub fn sha512(key: &[u8]) -> VerifyKey<digest::Sha512> {
|
||||||
|
VerifyKey(hmac::VerificationKey::new(&SHA512, key), PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify HMAC signature of `data`.
|
||||||
|
pub fn verify<T>(k: &VerifyKey<T>, data: &[u8], sig: &[u8]) -> bool {
|
||||||
|
hmac::verify(&k.0, data, sig).is_ok()
|
||||||
|
}
|
||||||
|
|
@ -18,23 +18,22 @@
|
|||||||
|
|
||||||
extern crate crypto as rcrypto;
|
extern crate crypto as rcrypto;
|
||||||
extern crate ethereum_types;
|
extern crate ethereum_types;
|
||||||
extern crate subtle;
|
#[macro_use]
|
||||||
|
extern crate quick_error;
|
||||||
|
extern crate ring;
|
||||||
extern crate tiny_keccak;
|
extern crate tiny_keccak;
|
||||||
|
|
||||||
#[cfg(feature = "secp256k1")]
|
pub mod aes;
|
||||||
extern crate secp256k1;
|
pub mod aes_gcm;
|
||||||
#[cfg(feature = "secp256k1")]
|
pub mod error;
|
||||||
extern crate ethkey;
|
pub mod scrypt;
|
||||||
|
pub mod digest;
|
||||||
|
pub mod hmac;
|
||||||
|
pub mod pbkdf2;
|
||||||
|
|
||||||
|
pub use error::Error;
|
||||||
|
|
||||||
use std::fmt;
|
|
||||||
use tiny_keccak::Keccak;
|
use tiny_keccak::Keccak;
|
||||||
use rcrypto::pbkdf2::pbkdf2;
|
|
||||||
use rcrypto::scrypt::{scrypt, ScryptParams};
|
|
||||||
use rcrypto::sha2::Sha256;
|
|
||||||
use rcrypto::hmac::Hmac;
|
|
||||||
|
|
||||||
#[cfg(feature = "secp256k1")]
|
|
||||||
use secp256k1::Error as SecpError;
|
|
||||||
|
|
||||||
pub const KEY_LENGTH: usize = 32;
|
pub const KEY_LENGTH: usize = 32;
|
||||||
pub const KEY_ITERATIONS: usize = 10240;
|
pub const KEY_ITERATIONS: usize = 10240;
|
||||||
@ -43,65 +42,6 @@ pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2;
|
|||||||
/// Default authenticated data to use (in RPC).
|
/// Default authenticated data to use (in RPC).
|
||||||
pub const DEFAULT_MAC: [u8; 2] = [0, 0];
|
pub const DEFAULT_MAC: [u8; 2] = [0, 0];
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
pub enum ScryptError {
|
|
||||||
// log(N) < r / 16
|
|
||||||
InvalidN,
|
|
||||||
// p <= (2^31-1 * 32)/(128 * r)
|
|
||||||
InvalidP,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ScryptError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
||||||
let s = match *self {
|
|
||||||
ScryptError::InvalidN => "Invalid N argument of the scrypt encryption" ,
|
|
||||||
ScryptError::InvalidP => "Invalid p argument of the scrypt encryption",
|
|
||||||
};
|
|
||||||
|
|
||||||
write!(f, "{}", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
#[cfg(feature = "secp256k1")]
|
|
||||||
Secp(SecpError),
|
|
||||||
Scrypt(ScryptError),
|
|
||||||
InvalidMessage,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ScryptError> for Error {
|
|
||||||
fn from(err: ScryptError) -> Self {
|
|
||||||
Error::Scrypt(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
||||||
let s = match *self {
|
|
||||||
#[cfg(feature = "secp256k1")]
|
|
||||||
Error::Secp(ref err) => err.to_string(),
|
|
||||||
Error::Scrypt(ref err) => err.to_string(),
|
|
||||||
Error::InvalidMessage => "Invalid message".into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
write!(f, "{}", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<String> for Error {
|
|
||||||
fn into(self) -> String {
|
|
||||||
format!("{}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "secp256k1")]
|
|
||||||
impl From<SecpError> for Error {
|
|
||||||
fn from(e: SecpError) -> Self {
|
|
||||||
Error::Secp(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Keccak256<T> {
|
pub trait Keccak256<T> {
|
||||||
fn keccak256(&self) -> T where T: Sized;
|
fn keccak256(&self) -> T where T: Sized;
|
||||||
}
|
}
|
||||||
@ -117,33 +57,13 @@ impl<T> Keccak256<[u8; 32]> for T where T: AsRef<[u8]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn derive_key_iterations(password: &str, salt: &[u8; 32], c: u32) -> (Vec<u8>, Vec<u8>) {
|
pub fn derive_key_iterations(password: &str, salt: &[u8; 32], c: u32) -> (Vec<u8>, Vec<u8>) {
|
||||||
let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes());
|
let mut derived_key = [0u8; KEY_LENGTH];
|
||||||
let mut derived_key = vec![0u8; KEY_LENGTH];
|
pbkdf2::sha256(c, pbkdf2::Salt(salt), pbkdf2::Secret(password.as_bytes()), &mut derived_key);
|
||||||
pbkdf2(&mut h_mac, salt, c, &mut derived_key);
|
|
||||||
let derived_right_bits = &derived_key[0..KEY_LENGTH_AES];
|
let derived_right_bits = &derived_key[0..KEY_LENGTH_AES];
|
||||||
let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH];
|
let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH];
|
||||||
(derived_right_bits.to_vec(), derived_left_bits.to_vec())
|
(derived_right_bits.to_vec(), derived_left_bits.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn derive_key_scrypt(password: &str, salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result<(Vec<u8>, Vec<u8>), Error> {
|
|
||||||
// sanity checks
|
|
||||||
let log_n = (32 - n.leading_zeros() - 1) as u8;
|
|
||||||
if log_n as u32 >= r * 16 {
|
|
||||||
return Err(Error::Scrypt(ScryptError::InvalidN));
|
|
||||||
}
|
|
||||||
|
|
||||||
if p as u64 > ((u32::max_value() as u64 - 1) * 32)/(128 * (r as u64)) {
|
|
||||||
return Err(Error::Scrypt(ScryptError::InvalidP));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut derived_key = vec![0u8; KEY_LENGTH];
|
|
||||||
let scrypt_params = ScryptParams::new(log_n, r, p);
|
|
||||||
scrypt(password.as_bytes(), salt, &scrypt_params, &mut derived_key);
|
|
||||||
let derived_right_bits = &derived_key[0..KEY_LENGTH_AES];
|
|
||||||
let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH];
|
|
||||||
Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec<u8> {
|
pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec<u8> {
|
||||||
let mut mac = vec![0u8; KEY_LENGTH_AES + cipher_text.len()];
|
let mut mac = vec![0u8; KEY_LENGTH_AES + cipher_text.len()];
|
||||||
mac[0..KEY_LENGTH_AES].copy_from_slice(derived_left_bits);
|
mac[0..KEY_LENGTH_AES].copy_from_slice(derived_left_bits);
|
||||||
@ -151,194 +71,7 @@ pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec<u8> {
|
|||||||
mac
|
mac
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AES encryption
|
pub fn is_equal(a: &[u8], b: &[u8]) -> bool {
|
||||||
pub mod aes {
|
ring::constant_time::verify_slices_are_equal(a, b).is_ok()
|
||||||
use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding};
|
|
||||||
use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor};
|
|
||||||
use rcrypto::symmetriccipher::{Encryptor, Decryptor, SymmetricCipherError};
|
|
||||||
use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer};
|
|
||||||
|
|
||||||
/// Encrypt a message (CTR mode)
|
|
||||||
pub fn encrypt(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) {
|
|
||||||
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
|
|
||||||
encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decrypt a message (CTR mode)
|
|
||||||
pub fn decrypt(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) {
|
|
||||||
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]) -> Result<usize, SymmetricCipherError> {
|
|
||||||
let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec());
|
|
||||||
let len = dest.len();
|
|
||||||
let mut buffer = RefWriteBuffer::new(dest);
|
|
||||||
encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut buffer, true)?;
|
|
||||||
Ok(len - buffer.remaining())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ECDH functions
|
|
||||||
#[cfg(feature = "secp256k1")]
|
|
||||||
pub mod ecdh {
|
|
||||||
use secp256k1::{ecdh, key, Error as SecpError};
|
|
||||||
use ethkey::{Secret, Public, SECP256K1};
|
|
||||||
use Error;
|
|
||||||
|
|
||||||
/// Agree on a shared secret
|
|
||||||
pub fn agree(secret: &Secret, public: &Public) -> Result<Secret, Error> {
|
|
||||||
let context = &SECP256K1;
|
|
||||||
let pdata = {
|
|
||||||
let mut temp = [4u8; 65];
|
|
||||||
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
|
|
||||||
temp
|
|
||||||
};
|
|
||||||
|
|
||||||
let publ = key::PublicKey::from_slice(context, &pdata)?;
|
|
||||||
let sec = key::SecretKey::from_slice(context, &secret)?;
|
|
||||||
let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
|
|
||||||
|
|
||||||
Secret::from_unsafe_slice(&shared[0..32])
|
|
||||||
.map_err(|_| Error::Secp(SecpError::InvalidSecretKey))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ECIES function
|
|
||||||
#[cfg(feature = "secp256k1")]
|
|
||||||
pub mod ecies {
|
|
||||||
use rcrypto::digest::Digest;
|
|
||||||
use rcrypto::sha2::Sha256;
|
|
||||||
use rcrypto::hmac::Hmac;
|
|
||||||
use rcrypto::mac::Mac;
|
|
||||||
use ethereum_types::H128;
|
|
||||||
use ethkey::{Random, Generator, Public, Secret};
|
|
||||||
use {Error, ecdh, aes};
|
|
||||||
|
|
||||||
/// Encrypt a message with a public key, writing an HMAC covering both
|
|
||||||
/// the plaintext and authenticated data.
|
|
||||||
///
|
|
||||||
/// Authenticated data may be empty.
|
|
||||||
pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
|
|
||||||
let r = Random.generate()
|
|
||||||
.expect("context known to have key-generation capabilities; qed");
|
|
||||||
|
|
||||||
let z = ecdh::agree(r.secret(), public)?;
|
|
||||||
let mut key = [0u8; 32];
|
|
||||||
let mut mkey = [0u8; 32];
|
|
||||||
kdf(&z, &[0u8; 0], &mut key);
|
|
||||||
let mut hasher = Sha256::new();
|
|
||||||
let mkey_material = &key[16..32];
|
|
||||||
hasher.input(mkey_material);
|
|
||||||
hasher.result(&mut mkey);
|
|
||||||
let ekey = &key[0..16];
|
|
||||||
|
|
||||||
let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32];
|
|
||||||
msg[0] = 0x04u8;
|
|
||||||
{
|
|
||||||
let msgd = &mut msg[1..];
|
|
||||||
msgd[0..64].copy_from_slice(r.public());
|
|
||||||
let iv = H128::random();
|
|
||||||
msgd[64..80].copy_from_slice(&iv);
|
|
||||||
{
|
|
||||||
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
|
|
||||||
aes::encrypt(ekey, &iv, plain, cipher);
|
|
||||||
}
|
|
||||||
let mut hmac = Hmac::new(Sha256::new(), &mkey);
|
|
||||||
{
|
|
||||||
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
|
|
||||||
hmac.input(cipher_iv);
|
|
||||||
}
|
|
||||||
hmac.input(auth_data);
|
|
||||||
hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]);
|
|
||||||
}
|
|
||||||
Ok(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decrypt a message with a secret key, checking HMAC for ciphertext
|
|
||||||
/// and authenticated data validity.
|
|
||||||
pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
|
|
||||||
let meta_len = 1 + 64 + 16 + 32;
|
|
||||||
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
|
|
||||||
return Err(Error::InvalidMessage); //invalid message: publickey
|
|
||||||
}
|
|
||||||
|
|
||||||
let e = &encrypted[1..];
|
|
||||||
let p = Public::from_slice(&e[0..64]);
|
|
||||||
let z = ecdh::agree(secret, &p)?;
|
|
||||||
let mut key = [0u8; 32];
|
|
||||||
kdf(&z, &[0u8; 0], &mut key);
|
|
||||||
let ekey = &key[0..16];
|
|
||||||
let mkey_material = &key[16..32];
|
|
||||||
let mut hasher = Sha256::new();
|
|
||||||
let mut mkey = [0u8; 32];
|
|
||||||
hasher.input(mkey_material);
|
|
||||||
hasher.result(&mut mkey);
|
|
||||||
|
|
||||||
let clen = encrypted.len() - meta_len;
|
|
||||||
let cipher_with_iv = &e[64..(64+16+clen)];
|
|
||||||
let cipher_iv = &cipher_with_iv[0..16];
|
|
||||||
let cipher_no_iv = &cipher_with_iv[16..];
|
|
||||||
let msg_mac = &e[(64+16+clen)..];
|
|
||||||
|
|
||||||
// Verify tag
|
|
||||||
let mut hmac = Hmac::new(Sha256::new(), &mkey);
|
|
||||||
hmac.input(cipher_with_iv);
|
|
||||||
hmac.input(auth_data);
|
|
||||||
let mut mac = [0u8; 32];
|
|
||||||
hmac.raw_result(&mut mac);
|
|
||||||
|
|
||||||
// constant time compare to avoid timing attack.
|
|
||||||
if ::subtle::slices_equal(&mac[..], msg_mac) != 1 {
|
|
||||||
return Err(Error::InvalidMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut msg = vec![0u8; clen];
|
|
||||||
aes::decrypt(ekey, cipher_iv, cipher_no_iv, &mut msg[..]);
|
|
||||||
Ok(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
|
|
||||||
let mut hasher = Sha256::new();
|
|
||||||
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
|
|
||||||
// to size of hash output, however, it also notes that
|
|
||||||
// the 4 bytes is okay. NIST specifies 4 bytes.
|
|
||||||
let mut ctr = 1u32;
|
|
||||||
let mut written = 0usize;
|
|
||||||
while written < dest.len() {
|
|
||||||
let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8];
|
|
||||||
hasher.input(&ctrs);
|
|
||||||
hasher.input(secret);
|
|
||||||
hasher.input(s1);
|
|
||||||
hasher.result(&mut dest[written..(written + 32)]);
|
|
||||||
hasher.reset();
|
|
||||||
written += 32;
|
|
||||||
ctr += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use ethkey::{Random, Generator};
|
|
||||||
use ecies;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ecies_shared() {
|
|
||||||
let kp = Random.generate().unwrap();
|
|
||||||
let message = b"So many books, so little time";
|
|
||||||
|
|
||||||
let shared = b"shared";
|
|
||||||
let wrong_shared = b"incorrect";
|
|
||||||
let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap();
|
|
||||||
assert!(encrypted[..] != message[..]);
|
|
||||||
assert_eq!(encrypted[0], 0x04);
|
|
||||||
|
|
||||||
assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err());
|
|
||||||
let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap();
|
|
||||||
assert_eq!(decrypted[..message.len()], message[..]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
ethcore/crypto/src/pbkdf2.rs
Normal file
29
ethcore/crypto/src/pbkdf2.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2018 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use ring;
|
||||||
|
|
||||||
|
pub struct Salt<'a>(pub &'a [u8]);
|
||||||
|
pub struct Secret<'a>(pub &'a [u8]);
|
||||||
|
|
||||||
|
pub fn sha256(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 32]) {
|
||||||
|
ring::pbkdf2::derive(&ring::digest::SHA256, iter, salt.0, sec.0, &mut out[..])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sha512(iter: u32, salt: Salt, sec: Secret, out: &mut [u8; 64]) {
|
||||||
|
ring::pbkdf2::derive(&ring::digest::SHA512, iter, salt.0, sec.0, &mut out[..])
|
||||||
|
}
|
||||||
|
|
39
ethcore/crypto/src/scrypt.rs
Normal file
39
ethcore/crypto/src/scrypt.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use error::ScryptError;
|
||||||
|
use rcrypto::scrypt::{scrypt, ScryptParams};
|
||||||
|
use super::{KEY_LENGTH_AES, KEY_LENGTH};
|
||||||
|
|
||||||
|
pub fn derive_key(pass: &str, salt: &[u8; 32], n: u32, p: u32, r: u32) -> Result<(Vec<u8>, Vec<u8>), ScryptError> {
|
||||||
|
// sanity checks
|
||||||
|
let log_n = (32 - n.leading_zeros() - 1) as u8;
|
||||||
|
if log_n as u32 >= r * 16 {
|
||||||
|
return Err(ScryptError::InvalidN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if p as u64 > ((u32::max_value() as u64 - 1) * 32)/(128 * (r as u64)) {
|
||||||
|
return Err(ScryptError::InvalidP);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut derived_key = vec![0u8; KEY_LENGTH];
|
||||||
|
let scrypt_params = ScryptParams::new(log_n, r, p);
|
||||||
|
scrypt(pass.as_bytes(), salt, &scrypt_params, &mut derived_key);
|
||||||
|
let derived_right_bits = &derived_key[0..KEY_LENGTH_AES];
|
||||||
|
let derived_left_bits = &derived_key[KEY_LENGTH_AES..KEY_LENGTH];
|
||||||
|
Ok((derived_right_bits.to_vec(), derived_left_bits.to_vec()))
|
||||||
|
}
|
||||||
|
|
@ -217,7 +217,8 @@ impl Encryptor for SecretStoreEncryptor {
|
|||||||
// encrypt data
|
// encrypt data
|
||||||
let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.len());
|
let mut cypher = Vec::with_capacity(plain_data.len() + initialisation_vector.len());
|
||||||
cypher.extend(repeat(0).take(plain_data.len()));
|
cypher.extend(repeat(0).take(plain_data.len()));
|
||||||
crypto::aes::encrypt(&key, initialisation_vector, plain_data, &mut cypher);
|
crypto::aes::encrypt_128_ctr(&key, initialisation_vector, plain_data, &mut cypher)
|
||||||
|
.map_err(|e| ErrorKind::Encrypt(e.to_string()))?;
|
||||||
cypher.extend_from_slice(&initialisation_vector);
|
cypher.extend_from_slice(&initialisation_vector);
|
||||||
|
|
||||||
Ok(cypher)
|
Ok(cypher)
|
||||||
@ -243,8 +244,8 @@ impl Encryptor for SecretStoreEncryptor {
|
|||||||
let (cypher, iv) = cypher.split_at(cypher_len - INIT_VEC_LEN);
|
let (cypher, iv) = cypher.split_at(cypher_len - INIT_VEC_LEN);
|
||||||
let mut plain_data = Vec::with_capacity(cypher_len - INIT_VEC_LEN);
|
let mut plain_data = Vec::with_capacity(cypher_len - INIT_VEC_LEN);
|
||||||
plain_data.extend(repeat(0).take(cypher_len - INIT_VEC_LEN));
|
plain_data.extend(repeat(0).take(cypher_len - INIT_VEC_LEN));
|
||||||
crypto::aes::decrypt(&key, &iv, cypher, &mut plain_data);
|
crypto::aes::decrypt_128_ctr(&key, &iv, cypher, &mut plain_data)
|
||||||
|
.map_err(|e| ErrorKind::Decrypt(e.to_string()))?;
|
||||||
Ok(plain_data)
|
Ok(plain_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,7 @@ use std::cmp::{max, min};
|
|||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
|
|
||||||
use byteorder::{ByteOrder, BigEndian};
|
use byteorder::{ByteOrder, BigEndian};
|
||||||
use crypto::sha2::Sha256 as Sha256Digest;
|
use ethcore_crypto::digest;
|
||||||
use crypto::ripemd160::Ripemd160 as Ripemd160Digest;
|
|
||||||
use crypto::digest::Digest;
|
|
||||||
use num::{BigUint, Zero, One};
|
use num::{BigUint, Zero, One};
|
||||||
|
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
@ -295,28 +293,17 @@ impl Impl for EcRecover {
|
|||||||
|
|
||||||
impl Impl for Sha256 {
|
impl Impl for Sha256 {
|
||||||
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> {
|
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> {
|
||||||
let mut sha = Sha256Digest::new();
|
let d = digest::sha256(input);
|
||||||
sha.input(input);
|
output.write(0, &*d);
|
||||||
|
|
||||||
let mut out = [0; 32];
|
|
||||||
sha.result(&mut out);
|
|
||||||
|
|
||||||
output.write(0, &out);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Impl for Ripemd160 {
|
impl Impl for Ripemd160 {
|
||||||
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> {
|
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), Error> {
|
||||||
let mut sha = Ripemd160Digest::new();
|
let hash = digest::ripemd160(input);
|
||||||
sha.input(input);
|
output.write(0, &[0; 12][..]);
|
||||||
|
output.write(12, &hash);
|
||||||
let mut out = [0; 32];
|
|
||||||
sha.result(&mut out[12..32]);
|
|
||||||
|
|
||||||
output.write(0, &out);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,9 @@ extern crate bn;
|
|||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate crossbeam;
|
extern crate crossbeam;
|
||||||
extern crate common_types as types;
|
extern crate common_types as types;
|
||||||
extern crate crypto;
|
|
||||||
extern crate ethash;
|
extern crate ethash;
|
||||||
extern crate ethcore_bloom_journal as bloom_journal;
|
extern crate ethcore_bloom_journal as bloom_journal;
|
||||||
|
extern crate ethcore_crypto;
|
||||||
extern crate ethcore_io as io;
|
extern crate ethcore_io as io;
|
||||||
extern crate ethcore_bytes as bytes;
|
extern crate ethcore_bytes as bytes;
|
||||||
extern crate ethcore_logger;
|
extern crate ethcore_logger;
|
||||||
|
@ -6,13 +6,14 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.0"
|
byteorder = "1.0"
|
||||||
edit-distance = "2.0"
|
edit-distance = "2.0"
|
||||||
|
ethcore-crypto = { path = "../ethcore/crypto" }
|
||||||
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
|
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
|
||||||
ethereum-types = "0.3"
|
ethereum-types = "0.3"
|
||||||
lazy_static = "1.0"
|
lazy_static = "1.0"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
mem = { path = "../util/mem" }
|
mem = { path = "../util/mem" }
|
||||||
parity-wordlist = "1.2"
|
parity-wordlist = "1.2"
|
||||||
|
quick-error = "1.2"
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
rust-crypto = "0.2"
|
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
tiny-keccak = "1.3"
|
tiny-keccak = "1.3"
|
||||||
|
189
ethkey/src/crypto.rs
Normal file
189
ethkey/src/crypto.rs
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use secp256k1;
|
||||||
|
use std::io;
|
||||||
|
use ethcore_crypto::error::SymmError;
|
||||||
|
|
||||||
|
quick_error! {
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Secp(e: secp256k1::Error) {
|
||||||
|
display("secp256k1 error: {}", e)
|
||||||
|
cause(e)
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
Io(e: io::Error) {
|
||||||
|
display("i/o error: {}", e)
|
||||||
|
cause(e)
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
InvalidMessage {
|
||||||
|
display("invalid message")
|
||||||
|
}
|
||||||
|
Symm(e: SymmError) {
|
||||||
|
cause(e)
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ECDH functions
|
||||||
|
pub mod ecdh {
|
||||||
|
use secp256k1::{self, ecdh, key};
|
||||||
|
use super::Error;
|
||||||
|
use {Secret, Public, SECP256K1};
|
||||||
|
|
||||||
|
/// Agree on a shared secret
|
||||||
|
pub fn agree(secret: &Secret, public: &Public) -> Result<Secret, Error> {
|
||||||
|
let context = &SECP256K1;
|
||||||
|
let pdata = {
|
||||||
|
let mut temp = [4u8; 65];
|
||||||
|
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
|
||||||
|
temp
|
||||||
|
};
|
||||||
|
|
||||||
|
let publ = key::PublicKey::from_slice(context, &pdata)?;
|
||||||
|
let sec = key::SecretKey::from_slice(context, &secret)?;
|
||||||
|
let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
|
||||||
|
|
||||||
|
Secret::from_unsafe_slice(&shared[0..32])
|
||||||
|
.map_err(|_| Error::Secp(secp256k1::Error::InvalidSecretKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ECIES function
|
||||||
|
pub mod ecies {
|
||||||
|
use ethcore_crypto::{aes, digest, hmac, is_equal};
|
||||||
|
use ethereum_types::H128;
|
||||||
|
use super::{ecdh, Error};
|
||||||
|
use {Random, Generator, Public, Secret};
|
||||||
|
|
||||||
|
/// Encrypt a message with a public key, writing an HMAC covering both
|
||||||
|
/// the plaintext and authenticated data.
|
||||||
|
///
|
||||||
|
/// Authenticated data may be empty.
|
||||||
|
pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
|
let r = Random.generate()?;
|
||||||
|
let z = ecdh::agree(r.secret(), public)?;
|
||||||
|
let mut key = [0u8; 32];
|
||||||
|
kdf(&z, &[0u8; 0], &mut key);
|
||||||
|
|
||||||
|
let ekey = &key[0..16];
|
||||||
|
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
|
||||||
|
|
||||||
|
let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32];
|
||||||
|
msg[0] = 0x04u8;
|
||||||
|
{
|
||||||
|
let msgd = &mut msg[1..];
|
||||||
|
msgd[0..64].copy_from_slice(r.public());
|
||||||
|
let iv = H128::random();
|
||||||
|
msgd[64..80].copy_from_slice(&iv);
|
||||||
|
{
|
||||||
|
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
|
||||||
|
aes::encrypt_128_ctr(ekey, &iv, plain, cipher)?;
|
||||||
|
}
|
||||||
|
let mut hmac = hmac::Signer::with(&mkey);
|
||||||
|
{
|
||||||
|
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
|
||||||
|
hmac.update(cipher_iv);
|
||||||
|
}
|
||||||
|
hmac.update(auth_data);
|
||||||
|
let sig = hmac.sign();
|
||||||
|
msgd[(64 + 16 + plain.len())..].copy_from_slice(&sig);
|
||||||
|
}
|
||||||
|
Ok(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypt a message with a secret key, checking HMAC for ciphertext
|
||||||
|
/// and authenticated data validity.
|
||||||
|
pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
|
let meta_len = 1 + 64 + 16 + 32;
|
||||||
|
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
|
||||||
|
return Err(Error::InvalidMessage); //invalid message: publickey
|
||||||
|
}
|
||||||
|
|
||||||
|
let e = &encrypted[1..];
|
||||||
|
let p = Public::from_slice(&e[0..64]);
|
||||||
|
let z = ecdh::agree(secret, &p)?;
|
||||||
|
let mut key = [0u8; 32];
|
||||||
|
kdf(&z, &[0u8; 0], &mut key);
|
||||||
|
|
||||||
|
let ekey = &key[0..16];
|
||||||
|
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
|
||||||
|
|
||||||
|
let clen = encrypted.len() - meta_len;
|
||||||
|
let cipher_with_iv = &e[64..(64+16+clen)];
|
||||||
|
let cipher_iv = &cipher_with_iv[0..16];
|
||||||
|
let cipher_no_iv = &cipher_with_iv[16..];
|
||||||
|
let msg_mac = &e[(64+16+clen)..];
|
||||||
|
|
||||||
|
// Verify tag
|
||||||
|
let mut hmac = hmac::Signer::with(&mkey);
|
||||||
|
hmac.update(cipher_with_iv);
|
||||||
|
hmac.update(auth_data);
|
||||||
|
let mac = hmac.sign();
|
||||||
|
|
||||||
|
if !is_equal(&mac.as_ref()[..], msg_mac) {
|
||||||
|
return Err(Error::InvalidMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut msg = vec![0u8; clen];
|
||||||
|
aes::decrypt_128_ctr(ekey, cipher_iv, cipher_no_iv, &mut msg[..])?;
|
||||||
|
Ok(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
|
||||||
|
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
|
||||||
|
// to size of hash output, however, it also notes that
|
||||||
|
// the 4 bytes is okay. NIST specifies 4 bytes.
|
||||||
|
let mut ctr = 1u32;
|
||||||
|
let mut written = 0usize;
|
||||||
|
while written < dest.len() {
|
||||||
|
let mut hasher = digest::Hasher::sha256();
|
||||||
|
let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8];
|
||||||
|
hasher.update(&ctrs);
|
||||||
|
hasher.update(secret);
|
||||||
|
hasher.update(s1);
|
||||||
|
let d = hasher.finish();
|
||||||
|
&mut dest[written..(written + 32)].copy_from_slice(&d);
|
||||||
|
written += 32;
|
||||||
|
ctr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ecies;
|
||||||
|
use {Random, Generator};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ecies_shared() {
|
||||||
|
let kp = Random.generate().unwrap();
|
||||||
|
let message = b"So many books, so little time";
|
||||||
|
|
||||||
|
let shared = b"shared";
|
||||||
|
let wrong_shared = b"incorrect";
|
||||||
|
let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap();
|
||||||
|
assert!(encrypted[..] != message[..]);
|
||||||
|
assert_eq!(encrypted[0], 0x04);
|
||||||
|
|
||||||
|
assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err());
|
||||||
|
let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap();
|
||||||
|
assert_eq!(decrypted[..message.len()], message[..]);
|
||||||
|
}
|
||||||
|
}
|
@ -207,9 +207,7 @@ impl ExtendedKeyPair {
|
|||||||
// Work is based on BIP0032
|
// Work is based on BIP0032
|
||||||
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
||||||
mod derivation {
|
mod derivation {
|
||||||
use rcrypto::hmac::Hmac;
|
use ethcore_crypto::hmac;
|
||||||
use rcrypto::mac::Mac;
|
|
||||||
use rcrypto::sha2::Sha512;
|
|
||||||
use ethereum_types::{U256, U512, H512, H256};
|
use ethereum_types::{U256, U512, H512, H256};
|
||||||
use secp256k1::key::{SecretKey, PublicKey};
|
use secp256k1::key::{SecretKey, PublicKey};
|
||||||
use SECP256K1;
|
use SECP256K1;
|
||||||
@ -242,10 +240,8 @@ mod derivation {
|
|||||||
let private: U256 = private_key.into();
|
let private: U256 = private_key.into();
|
||||||
|
|
||||||
// produces 512-bit derived hmac (I)
|
// produces 512-bit derived hmac (I)
|
||||||
let mut hmac = Hmac::new(Sha512::new(), &*chain_code);
|
let skey = hmac::SigKey::sha512(&*chain_code);
|
||||||
let mut i_512 = [0u8; 64];
|
let i_512 = hmac::sign(&skey, &data[..]);
|
||||||
hmac.input(&data[..]);
|
|
||||||
hmac.raw_result(&mut i_512);
|
|
||||||
|
|
||||||
// left most 256 bits are later added to original private key
|
// left most 256 bits are later added to original private key
|
||||||
let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into();
|
let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into();
|
||||||
@ -321,10 +317,8 @@ mod derivation {
|
|||||||
index.store(&mut data[33..(33 + T::len())]);
|
index.store(&mut data[33..(33 + T::len())]);
|
||||||
|
|
||||||
// HMAC512SHA produces [derived private(256); new chain code(256)]
|
// HMAC512SHA produces [derived private(256); new chain code(256)]
|
||||||
let mut hmac = Hmac::new(Sha512::new(), &*chain_code);
|
let skey = hmac::SigKey::sha512(&*chain_code);
|
||||||
let mut i_512 = [0u8; 64];
|
let i_512 = hmac::sign(&skey, &data[..]);
|
||||||
hmac.input(&data[..]);
|
|
||||||
hmac.raw_result(&mut i_512);
|
|
||||||
|
|
||||||
let new_private = H256::from(&i_512[0..32]);
|
let new_private = H256::from(&i_512[0..32]);
|
||||||
let new_chain_code = H256::from(&i_512[32..64]);
|
let new_chain_code = H256::from(&i_512[32..64]);
|
||||||
@ -369,10 +363,8 @@ mod derivation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn seed_pair(seed: &[u8]) -> (H256, H256) {
|
pub fn seed_pair(seed: &[u8]) -> (H256, H256) {
|
||||||
let mut hmac = Hmac::new(Sha512::new(), b"Bitcoin seed");
|
let skey = hmac::SigKey::sha512(b"Bitcoin seed");
|
||||||
let mut i_512 = [0u8; 64];
|
let i_512 = hmac::sign(&skey, seed);
|
||||||
hmac.input(seed);
|
|
||||||
hmac.raw_result(&mut i_512);
|
|
||||||
|
|
||||||
let master_key = H256::from_slice(&i_512[0..32]);
|
let master_key = H256::from_slice(&i_512[0..32]);
|
||||||
let chain_code = H256::from_slice(&i_512[32..64]);
|
let chain_code = H256::from_slice(&i_512[32..64]);
|
||||||
|
@ -17,11 +17,13 @@
|
|||||||
// #![warn(missing_docs)]
|
// #![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate crypto as rcrypto;
|
|
||||||
extern crate edit_distance;
|
extern crate edit_distance;
|
||||||
|
extern crate ethcore_crypto;
|
||||||
extern crate ethereum_types;
|
extern crate ethereum_types;
|
||||||
extern crate mem;
|
extern crate mem;
|
||||||
extern crate parity_wordlist;
|
extern crate parity_wordlist;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate quick_error;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
extern crate secp256k1;
|
extern crate secp256k1;
|
||||||
@ -44,6 +46,7 @@ mod secret;
|
|||||||
mod extended;
|
mod extended;
|
||||||
|
|
||||||
pub mod brain_recover;
|
pub mod brain_recover;
|
||||||
|
pub mod crypto;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
|
|
||||||
pub use self::parity_wordlist::Error as WordlistError;
|
pub use self::parity_wordlist::Error as WordlistError;
|
||||||
|
@ -12,7 +12,6 @@ serde = "1.0"
|
|||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
rust-crypto = "0.2.36"
|
|
||||||
tiny-keccak = "1.3"
|
tiny-keccak = "1.3"
|
||||||
time = "0.1.34"
|
time = "0.1.34"
|
||||||
itertools = "0.5"
|
itertools = "0.5"
|
||||||
@ -22,7 +21,6 @@ ethereum-types = "0.3"
|
|||||||
dir = { path = "../util/dir" }
|
dir = { path = "../util/dir" }
|
||||||
smallvec = "0.4"
|
smallvec = "0.4"
|
||||||
parity-wordlist = "1.0"
|
parity-wordlist = "1.0"
|
||||||
subtle = "0.5"
|
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -21,7 +21,6 @@ use crypto::Keccak256;
|
|||||||
use random::Random;
|
use random::Random;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use account::{Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf};
|
use account::{Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf};
|
||||||
use subtle;
|
|
||||||
|
|
||||||
/// Encrypted data
|
/// Encrypted data
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@ -74,12 +73,12 @@ impl From<Crypto> for String {
|
|||||||
|
|
||||||
impl Crypto {
|
impl Crypto {
|
||||||
/// Encrypt account secret
|
/// Encrypt account secret
|
||||||
pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Self {
|
pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Result<Self, crypto::Error> {
|
||||||
Crypto::with_plain(&*secret, password, iterations)
|
Crypto::with_plain(&*secret, password, iterations)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypt custom plain data
|
/// Encrypt custom plain data
|
||||||
pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Self {
|
pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Result<Self, crypto::Error> {
|
||||||
let salt: [u8; 32] = Random::random();
|
let salt: [u8; 32] = Random::random();
|
||||||
let iv: [u8; 16] = Random::random();
|
let iv: [u8; 16] = Random::random();
|
||||||
|
|
||||||
@ -93,12 +92,12 @@ impl Crypto {
|
|||||||
let mut ciphertext: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; plain_len]);
|
let mut ciphertext: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; plain_len]);
|
||||||
|
|
||||||
// aes-128-ctr with initial vector of iv
|
// aes-128-ctr with initial vector of iv
|
||||||
crypto::aes::encrypt(&derived_left_bits, &iv, plain, &mut *ciphertext);
|
crypto::aes::encrypt_128_ctr(&derived_left_bits, &iv, plain, &mut *ciphertext)?;
|
||||||
|
|
||||||
// KECCAK(DK[16..31] ++ <ciphertext>), where DK[16..31] - derived_right_bits
|
// KECCAK(DK[16..31] ++ <ciphertext>), where DK[16..31] - derived_right_bits
|
||||||
let mac = crypto::derive_mac(&derived_right_bits, &*ciphertext).keccak256();
|
let mac = crypto::derive_mac(&derived_right_bits, &*ciphertext).keccak256();
|
||||||
|
|
||||||
Crypto {
|
Ok(Crypto {
|
||||||
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
||||||
iv: iv,
|
iv: iv,
|
||||||
}),
|
}),
|
||||||
@ -110,7 +109,7 @@ impl Crypto {
|
|||||||
prf: Prf::HmacSha256,
|
prf: Prf::HmacSha256,
|
||||||
}),
|
}),
|
||||||
mac: mac,
|
mac: mac,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to decrypt and convert result to account secret
|
/// Try to decrypt and convert result to account secret
|
||||||
@ -132,13 +131,13 @@ impl Crypto {
|
|||||||
fn do_decrypt(&self, password: &str, expected_len: usize) -> Result<Vec<u8>, Error> {
|
fn do_decrypt(&self, password: &str, expected_len: usize) -> Result<Vec<u8>, Error> {
|
||||||
let (derived_left_bits, derived_right_bits) = match self.kdf {
|
let (derived_left_bits, derived_right_bits) = match self.kdf {
|
||||||
Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, ¶ms.salt, params.c),
|
Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, ¶ms.salt, params.c),
|
||||||
Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, ¶ms.salt, params.n, params.p, params.r)?,
|
Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(password, ¶ms.salt, params.n, params.p, params.r)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mac = crypto::derive_mac(&derived_right_bits, &self.ciphertext).keccak256();
|
let mac = crypto::derive_mac(&derived_right_bits, &self.ciphertext).keccak256();
|
||||||
|
|
||||||
if subtle::slices_equal(&mac, &self.mac) == 0 {
|
if !crypto::is_equal(&mac, &self.mac) {
|
||||||
return Err(Error::InvalidPassword);
|
return Err(Error::InvalidPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut plain: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; expected_len]);
|
let mut plain: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; expected_len]);
|
||||||
@ -149,7 +148,7 @@ impl Crypto {
|
|||||||
debug_assert!(expected_len >= self.ciphertext.len());
|
debug_assert!(expected_len >= self.ciphertext.len());
|
||||||
|
|
||||||
let from = expected_len - self.ciphertext.len();
|
let from = expected_len - self.ciphertext.len();
|
||||||
crypto::aes::decrypt(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut plain[from..]);
|
crypto::aes::decrypt_128_ctr(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut plain[from..])?;
|
||||||
Ok(plain.into_iter().collect())
|
Ok(plain.into_iter().collect())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -164,7 +163,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_secret_create() {
|
fn crypto_with_secret_create() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240);
|
let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240).unwrap();
|
||||||
let secret = crypto.secret("this is sparta").unwrap();
|
let secret = crypto.secret("this is sparta").unwrap();
|
||||||
assert_eq!(keypair.secret(), &secret);
|
assert_eq!(keypair.secret(), &secret);
|
||||||
}
|
}
|
||||||
@ -172,14 +171,14 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_secret_invalid_password() {
|
fn crypto_with_secret_invalid_password() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240);
|
let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240).unwrap();
|
||||||
assert_matches!(crypto.secret("this is sparta!"), Err(Error::InvalidPassword))
|
assert_matches!(crypto.secret("this is sparta!"), Err(Error::InvalidPassword))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_null_plain_data() {
|
fn crypto_with_null_plain_data() {
|
||||||
let original_data = b"";
|
let original_data = b"";
|
||||||
let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240);
|
let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240).unwrap();
|
||||||
let decrypted_data = crypto.decrypt("this is sparta").unwrap();
|
let decrypted_data = crypto.decrypt("this is sparta").unwrap();
|
||||||
assert_eq!(original_data[..], *decrypted_data);
|
assert_eq!(original_data[..], *decrypted_data);
|
||||||
}
|
}
|
||||||
@ -187,7 +186,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_tiny_plain_data() {
|
fn crypto_with_tiny_plain_data() {
|
||||||
let original_data = b"{}";
|
let original_data = b"{}";
|
||||||
let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240);
|
let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240).unwrap();
|
||||||
let decrypted_data = crypto.decrypt("this is sparta").unwrap();
|
let decrypted_data = crypto.decrypt("this is sparta").unwrap();
|
||||||
assert_eq!(original_data[..], *decrypted_data);
|
assert_eq!(original_data[..], *decrypted_data);
|
||||||
}
|
}
|
||||||
@ -195,7 +194,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_huge_plain_data() {
|
fn crypto_with_huge_plain_data() {
|
||||||
let original_data: Vec<_> = (1..65536).map(|i| (i % 256) as u8).collect();
|
let original_data: Vec<_> = (1..65536).map(|i| (i % 256) as u8).collect();
|
||||||
let crypto = Crypto::with_plain(&original_data, "this is sparta", 10240);
|
let crypto = Crypto::with_plain(&original_data, "this is sparta", 10240).unwrap();
|
||||||
let decrypted_data = crypto.decrypt("this is sparta").unwrap();
|
let decrypted_data = crypto.decrypt("this is sparta").unwrap();
|
||||||
assert_eq!(&original_data, &decrypted_data);
|
assert_eq!(&original_data, &decrypted_data);
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,11 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use ethkey::{KeyPair, sign, Address, Signature, Message, Public, Secret};
|
use ethkey::{self, KeyPair, sign, Address, Signature, Message, Public, Secret};
|
||||||
use crypto::ecdh::agree;
|
use ethkey::crypto::ecdh::agree;
|
||||||
use {json, Error, crypto};
|
use {json, Error};
|
||||||
use account::Version;
|
use account::Version;
|
||||||
|
use crypto;
|
||||||
use super::crypto::Crypto;
|
use super::crypto::Crypto;
|
||||||
|
|
||||||
/// Account representation.
|
/// Account representation.
|
||||||
@ -61,16 +62,16 @@ impl SafeAccount {
|
|||||||
iterations: u32,
|
iterations: u32,
|
||||||
name: String,
|
name: String,
|
||||||
meta: String
|
meta: String
|
||||||
) -> Self {
|
) -> Result<Self, crypto::Error> {
|
||||||
SafeAccount {
|
Ok(SafeAccount {
|
||||||
id: id,
|
id: id,
|
||||||
version: Version::V3,
|
version: Version::V3,
|
||||||
crypto: Crypto::with_secret(keypair.secret(), password, iterations),
|
crypto: Crypto::with_secret(keypair.secret(), password, iterations)?,
|
||||||
address: keypair.address(),
|
address: keypair.address(),
|
||||||
filename: None,
|
filename: None,
|
||||||
name: name,
|
name: name,
|
||||||
meta: meta,
|
meta: meta,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `SafeAccount` from the given `json`; if it was read from a
|
/// Create a new `SafeAccount` from the given `json`; if it was read from a
|
||||||
@ -114,7 +115,7 @@ impl SafeAccount {
|
|||||||
meta: Some(self.meta),
|
meta: Some(self.meta),
|
||||||
};
|
};
|
||||||
let meta_plain = meta_plain.write().map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
let meta_plain = meta_plain.write().map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
||||||
let meta_crypto = Crypto::with_plain(&meta_plain, password, iterations);
|
let meta_crypto = Crypto::with_plain(&meta_plain, password, iterations)?;
|
||||||
|
|
||||||
Ok(json::VaultKeyFile {
|
Ok(json::VaultKeyFile {
|
||||||
id: self.id.into(),
|
id: self.id.into(),
|
||||||
@ -133,7 +134,7 @@ impl SafeAccount {
|
|||||||
/// Decrypt a message.
|
/// Decrypt a message.
|
||||||
pub fn decrypt(&self, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
pub fn decrypt(&self, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
let secret = self.crypto.secret(password)?;
|
let secret = self.crypto.secret(password)?;
|
||||||
crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
|
ethkey::crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Agree on shared key.
|
/// Agree on shared key.
|
||||||
@ -154,7 +155,7 @@ impl SafeAccount {
|
|||||||
let result = SafeAccount {
|
let result = SafeAccount {
|
||||||
id: self.id.clone(),
|
id: self.id.clone(),
|
||||||
version: self.version.clone(),
|
version: self.version.clone(),
|
||||||
crypto: Crypto::with_secret(&secret, new_password, iterations),
|
crypto: Crypto::with_secret(&secret, new_password, iterations)?,
|
||||||
address: self.address.clone(),
|
address: self.address.clone(),
|
||||||
filename: self.filename.clone(),
|
filename: self.filename.clone(),
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
@ -180,7 +181,7 @@ mod tests {
|
|||||||
let password = "hello world";
|
let password = "hello world";
|
||||||
let message = Message::default();
|
let message = Message::default();
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240, "Test".to_owned(), "{}".to_owned());
|
||||||
let signature = account.sign(password, &message).unwrap();
|
let signature = account.unwrap().sign(password, &message).unwrap();
|
||||||
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
|
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +192,7 @@ mod tests {
|
|||||||
let sec_password = "this is sparta";
|
let sec_password = "this is sparta";
|
||||||
let i = 10240;
|
let i = 10240;
|
||||||
let message = Message::default();
|
let message = Message::default();
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i, "Test".to_owned(), "{}".to_owned()).unwrap();
|
||||||
let new_account = account.change_password(first_password, sec_password, i).unwrap();
|
let new_account = account.change_password(first_password, sec_password, i).unwrap();
|
||||||
assert!(account.sign(first_password, &message).is_ok());
|
assert!(account.sign(first_password, &message).is_ok());
|
||||||
assert!(account.sign(sec_password, &message).is_err());
|
assert!(account.sign(sec_password, &message).is_err());
|
||||||
|
@ -319,7 +319,7 @@ mod test {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
|
||||||
let res = directory.insert(account);
|
let res = directory.insert(account.unwrap());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(res.is_ok(), "Should save account succesfuly.");
|
assert!(res.is_ok(), "Should save account succesfuly.");
|
||||||
@ -339,7 +339,7 @@ mod test {
|
|||||||
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned()).unwrap();
|
||||||
let filename = "test".to_string();
|
let filename = "test".to_string();
|
||||||
let dedup = true;
|
let dedup = true;
|
||||||
|
|
||||||
@ -424,7 +424,7 @@ mod test {
|
|||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let password = "test pass";
|
let password = "test pass";
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
|
||||||
directory.insert(account).expect("Account should be inserted ok");
|
directory.insert(account.unwrap()).expect("Account should be inserted ok");
|
||||||
|
|
||||||
let new_hash = directory.files_hash().expect("New files hash should be calculated ok");
|
let new_hash = directory.files_hash().expect("New files hash should be calculated ok");
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ fn check_vault_name(name: &str) -> bool {
|
|||||||
/// Vault can be empty, but still must be pluggable => we store vault password in separate file
|
/// Vault can be empty, but still must be pluggable => we store vault password in separate file
|
||||||
fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef<Path> {
|
fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef<Path> {
|
||||||
let password_hash = key.password.keccak256();
|
let password_hash = key.password.keccak256();
|
||||||
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations);
|
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations)?;
|
||||||
|
|
||||||
let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into();
|
let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into();
|
||||||
vault_file_path.push(VAULT_FILE_NAME);
|
vault_file_path.push(VAULT_FILE_NAME);
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use ethkey::Error as EthKeyError;
|
use ethkey::{self, Error as EthKeyError};
|
||||||
use crypto::Error as EthCryptoError;
|
use crypto::{self, Error as EthCryptoError};
|
||||||
use ethkey::DerivationError;
|
use ethkey::DerivationError;
|
||||||
|
|
||||||
/// Account-related errors.
|
/// Account-related errors.
|
||||||
@ -49,6 +49,8 @@ pub enum Error {
|
|||||||
CreationFailed,
|
CreationFailed,
|
||||||
/// `EthKey` error
|
/// `EthKey` error
|
||||||
EthKey(EthKeyError),
|
EthKey(EthKeyError),
|
||||||
|
/// `ethkey::crypto::Error`
|
||||||
|
EthKeyCrypto(ethkey::crypto::Error),
|
||||||
/// `EthCrypto` error
|
/// `EthCrypto` error
|
||||||
EthCrypto(EthCryptoError),
|
EthCrypto(EthCryptoError),
|
||||||
/// Derivation error
|
/// Derivation error
|
||||||
@ -73,6 +75,7 @@ impl fmt::Display for Error {
|
|||||||
Error::VaultNotFound => "Vault not found".into(),
|
Error::VaultNotFound => "Vault not found".into(),
|
||||||
Error::CreationFailed => "Account creation failed".into(),
|
Error::CreationFailed => "Account creation failed".into(),
|
||||||
Error::EthKey(ref err) => err.to_string(),
|
Error::EthKey(ref err) => err.to_string(),
|
||||||
|
Error::EthKeyCrypto(ref err) => err.to_string(),
|
||||||
Error::EthCrypto(ref err) => err.to_string(),
|
Error::EthCrypto(ref err) => err.to_string(),
|
||||||
Error::Derivation(ref err) => format!("Derivation error: {:?}", err),
|
Error::Derivation(ref err) => format!("Derivation error: {:?}", err),
|
||||||
Error::Custom(ref s) => s.clone(),
|
Error::Custom(ref s) => s.clone(),
|
||||||
@ -94,12 +97,30 @@ impl From<EthKeyError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ethkey::crypto::Error> for Error {
|
||||||
|
fn from(err: ethkey::crypto::Error) -> Self {
|
||||||
|
Error::EthKeyCrypto(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<EthCryptoError> for Error {
|
impl From<EthCryptoError> for Error {
|
||||||
fn from(err: EthCryptoError) -> Self {
|
fn from(err: EthCryptoError) -> Self {
|
||||||
Error::EthCrypto(err)
|
Error::EthCrypto(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<crypto::error::ScryptError> for Error {
|
||||||
|
fn from(err: crypto::error::ScryptError) -> Self {
|
||||||
|
Error::EthCrypto(err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<crypto::error::SymmError> for Error {
|
||||||
|
fn from(err: crypto::error::SymmError) -> Self {
|
||||||
|
Error::EthCrypto(err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<DerivationError> for Error {
|
impl From<DerivationError> for Error {
|
||||||
fn from(err: DerivationError) -> Self {
|
fn from(err: DerivationError) -> Self {
|
||||||
Error::Derivation(err)
|
Error::Derivation(err)
|
||||||
|
@ -458,7 +458,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &str) -> Result<StoreAccountRef, Error> {
|
fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &str) -> Result<StoreAccountRef, Error> {
|
||||||
let keypair = KeyPair::from_secret(secret).map_err(|_| Error::CreationFailed)?;
|
let keypair = KeyPair::from_secret(secret).map_err(|_| Error::CreationFailed)?;
|
||||||
let id: [u8; 16] = Random::random();
|
let id: [u8; 16] = Random::random();
|
||||||
let account = SafeAccount::create(&keypair, id, password, self.iterations, "".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, id, password, self.iterations, "".to_owned(), "{}".to_owned())?;
|
||||||
self.import(vault, account)
|
self.import(vault, account)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate crypto as rcrypto;
|
|
||||||
extern crate dir;
|
extern crate dir;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
@ -28,7 +27,6 @@ extern crate rustc_hex;
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
extern crate subtle;
|
|
||||||
extern crate time;
|
extern crate time;
|
||||||
extern crate tiny_keccak;
|
extern crate tiny_keccak;
|
||||||
extern crate tempdir;
|
extern crate tempdir;
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use rcrypto::pbkdf2::pbkdf2;
|
|
||||||
use rcrypto::sha2::Sha256;
|
|
||||||
use rcrypto::hmac::Hmac;
|
|
||||||
use json;
|
use json;
|
||||||
use ethkey::{Address, Secret, KeyPair};
|
use ethkey::{Address, Secret, KeyPair};
|
||||||
use crypto::Keccak256;
|
use crypto::{Keccak256, pbkdf2};
|
||||||
use {crypto, Error};
|
use {crypto, Error};
|
||||||
|
|
||||||
/// Pre-sale wallet.
|
/// Pre-sale wallet.
|
||||||
@ -42,12 +39,14 @@ impl PresaleWallet {
|
|||||||
|
|
||||||
/// Decrypt the wallet.
|
/// Decrypt the wallet.
|
||||||
pub fn decrypt(&self, password: &str) -> Result<KeyPair, Error> {
|
pub fn decrypt(&self, password: &str) -> Result<KeyPair, Error> {
|
||||||
let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes());
|
let mut derived_key = [0u8; 32];
|
||||||
let mut derived_key = vec![0u8; 16];
|
let salt = pbkdf2::Salt(password.as_bytes());
|
||||||
pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key);
|
let sec = pbkdf2::Secret(password.as_bytes());
|
||||||
|
pbkdf2::sha256(2000, salt, sec, &mut derived_key);
|
||||||
|
|
||||||
let mut key = vec![0; self.ciphertext.len()];
|
let mut key = vec![0; self.ciphertext.len()];
|
||||||
let len = crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key).map_err(|_| Error::InvalidPassword)?;
|
let len = crypto::aes::decrypt_128_cbc(&derived_key[0..16], &self.iv, &self.ciphertext, &mut key)
|
||||||
|
.map_err(|_| Error::InvalidPassword)?;
|
||||||
let unpadded = &key[..len];
|
let unpadded = &key[..len];
|
||||||
|
|
||||||
let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?;
|
let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?;
|
||||||
|
@ -17,7 +17,6 @@ multihash ="0.7"
|
|||||||
order-stat = "0.1"
|
order-stat = "0.1"
|
||||||
parking_lot = "0.5"
|
parking_lot = "0.5"
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
rust-crypto = "0.2"
|
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
semver = "0.9"
|
semver = "0.9"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
|
@ -23,7 +23,6 @@ extern crate futures;
|
|||||||
|
|
||||||
extern crate ansi_term;
|
extern crate ansi_term;
|
||||||
extern crate cid;
|
extern crate cid;
|
||||||
extern crate crypto as rust_crypto;
|
|
||||||
extern crate futures_cpupool;
|
extern crate futures_cpupool;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
extern crate multihash;
|
extern crate multihash;
|
||||||
|
@ -18,21 +18,15 @@
|
|||||||
|
|
||||||
use multihash;
|
use multihash;
|
||||||
use cid::{Cid, Codec, Version};
|
use cid::{Cid, Codec, Version};
|
||||||
use rust_crypto::sha2::Sha256;
|
use crypto::digest;
|
||||||
use rust_crypto::digest::Digest;
|
|
||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use v1::types::Bytes;
|
use v1::types::Bytes;
|
||||||
use super::errors;
|
use super::errors;
|
||||||
|
|
||||||
/// Compute CIDv0 from protobuf encoded bytes.
|
/// Compute CIDv0 from protobuf encoded bytes.
|
||||||
pub fn cid(content: Bytes) -> Result<String, Error> {
|
pub fn cid(content: Bytes) -> Result<String, Error> {
|
||||||
let mut hasher = Sha256::new();
|
let hash = digest::sha256(&content.0);
|
||||||
hasher.input(&content.0);
|
let mh = multihash::encode(multihash::Hash::SHA2256, &*hash).map_err(errors::encoding)?;
|
||||||
let len = hasher.output_bytes();
|
|
||||||
let mut buf = Vec::with_capacity(len);
|
|
||||||
buf.resize(len, 0);
|
|
||||||
hasher.result(&mut buf);
|
|
||||||
let mh = multihash::encode(multihash::Hash::SHA2256, &buf).map_err(errors::encoding)?;
|
|
||||||
let cid = Cid::new(Codec::DagProtobuf, Version::V0, &mh);
|
let cid = Cid::new(Codec::DagProtobuf, Version::V0, &mh);
|
||||||
Ok(cid.to_string().into())
|
Ok(cid.to_string().into())
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use rand::{Rng, OsRng};
|
use rand::{Rng, OsRng};
|
||||||
use ethkey::{Public, Secret, Random, Generator, math};
|
use ethkey::{self, Public, Secret, Random, Generator, math};
|
||||||
use crypto;
|
use crypto;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
@ -36,7 +36,7 @@ pub fn generate_document_key(account_public: Public, server_key_public: Public)
|
|||||||
let (common_point, encrypted_point) = encrypt_secret(document_key.public(), &server_key_public)?;
|
let (common_point, encrypted_point) = encrypt_secret(document_key.public(), &server_key_public)?;
|
||||||
|
|
||||||
// ..and now encrypt document key with account public
|
// ..and now encrypt document key with account public
|
||||||
let encrypted_key = crypto::ecies::encrypt(&account_public, &crypto::DEFAULT_MAC, document_key.public())
|
let encrypted_key = ethkey::crypto::ecies::encrypt(&account_public, &crypto::DEFAULT_MAC, document_key.public())
|
||||||
.map_err(errors::encryption)?;
|
.map_err(errors::encryption)?;
|
||||||
|
|
||||||
Ok(EncryptedDocumentKey {
|
Ok(EncryptedDocumentKey {
|
||||||
@ -57,7 +57,7 @@ pub fn encrypt_document(key: Bytes, document: Bytes) -> Result<Bytes, Error> {
|
|||||||
{
|
{
|
||||||
let (mut encryption_buffer, iv_buffer) = encrypted_document.split_at_mut(document.len());
|
let (mut encryption_buffer, iv_buffer) = encrypted_document.split_at_mut(document.len());
|
||||||
|
|
||||||
crypto::aes::encrypt(&key, &iv, &document, &mut encryption_buffer);
|
crypto::aes::encrypt_128_ctr(&key, &iv, &document, &mut encryption_buffer).map_err(errors::encryption)?;
|
||||||
iv_buffer.copy_from_slice(&iv);
|
iv_buffer.copy_from_slice(&iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ pub fn decrypt_document(key: Bytes, mut encrypted_document: Bytes) -> Result<Byt
|
|||||||
// use symmetric decryption to decrypt document
|
// use symmetric decryption to decrypt document
|
||||||
let iv = encrypted_document.split_off(encrypted_document_len - INIT_VEC_LEN);
|
let iv = encrypted_document.split_off(encrypted_document_len - INIT_VEC_LEN);
|
||||||
let mut document = vec![0; encrypted_document_len - INIT_VEC_LEN];
|
let mut document = vec![0; encrypted_document_len - INIT_VEC_LEN];
|
||||||
crypto::aes::decrypt(&key, &iv, &encrypted_document, &mut document);
|
crypto::aes::decrypt_128_ctr(&key, &iv, &encrypted_document, &mut document).map_err(errors::encryption)?;
|
||||||
|
|
||||||
Ok(document)
|
Ok(document)
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ use std::collections::{BTreeMap, HashSet};
|
|||||||
|
|
||||||
use version::version_data;
|
use version::version_data;
|
||||||
|
|
||||||
use crypto::{ecies, DEFAULT_MAC};
|
use crypto::DEFAULT_MAC;
|
||||||
use ethkey::{Brain, Generator};
|
use ethkey::{crypto::ecies, Brain, Generator};
|
||||||
use ethstore::random_phrase;
|
use ethstore::random_phrase;
|
||||||
use sync::LightSyncProvider;
|
use sync::LightSyncProvider;
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
|
@ -22,8 +22,8 @@ use std::collections::{BTreeMap, HashSet};
|
|||||||
use ethereum_types::Address;
|
use ethereum_types::Address;
|
||||||
use version::version_data;
|
use version::version_data;
|
||||||
|
|
||||||
use crypto::{DEFAULT_MAC, ecies};
|
use crypto::DEFAULT_MAC;
|
||||||
use ethkey::{Brain, Generator};
|
use ethkey::{crypto::ecies, Brain, Generator};
|
||||||
use ethstore::random_phrase;
|
use ethstore::random_phrase;
|
||||||
use sync::{SyncProvider, ManageNetwork};
|
use sync::{SyncProvider, ManageNetwork};
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
|
@ -21,7 +21,8 @@ use std::sync::mpsc;
|
|||||||
use futures::{self, Future};
|
use futures::{self, Future};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use tokio_core::reactor::Core;
|
use tokio_core::reactor::Core;
|
||||||
use crypto;
|
use crypto::DEFAULT_MAC;
|
||||||
|
use ethkey::crypto;
|
||||||
use super::acl_storage::AclStorage;
|
use super::acl_storage::AclStorage;
|
||||||
use super::key_storage::KeyStorage;
|
use super::key_storage::KeyStorage;
|
||||||
use super::key_server_set::KeyServerSet;
|
use super::key_server_set::KeyServerSet;
|
||||||
@ -105,7 +106,7 @@ impl DocumentKeyServer for KeyServerImpl {
|
|||||||
self.store_document_key(key_id, author, encrypted_document_key.common_point, encrypted_document_key.encrypted_point)?;
|
self.store_document_key(key_id, author, encrypted_document_key.common_point, encrypted_document_key.encrypted_point)?;
|
||||||
|
|
||||||
// encrypt document key with requestor public key
|
// encrypt document key with requestor public key
|
||||||
let document_key = crypto::ecies::encrypt(&public, &crypto::DEFAULT_MAC, &document_key)
|
let document_key = crypto::ecies::encrypt(&public, &DEFAULT_MAC, &document_key)
|
||||||
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
|
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
|
||||||
Ok(document_key)
|
Ok(document_key)
|
||||||
}
|
}
|
||||||
@ -122,7 +123,7 @@ impl DocumentKeyServer for KeyServerImpl {
|
|||||||
.decrypted_secret;
|
.decrypted_secret;
|
||||||
|
|
||||||
// encrypt document key with requestor public key
|
// encrypt document key with requestor public key
|
||||||
let document_key = crypto::ecies::encrypt(&public, &crypto::DEFAULT_MAC, &document_key)
|
let document_key = crypto::ecies::encrypt(&public, &DEFAULT_MAC, &document_key)
|
||||||
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
|
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
|
||||||
Ok(document_key)
|
Ok(document_key)
|
||||||
}
|
}
|
||||||
@ -152,7 +153,7 @@ impl MessageSigner for KeyServerImpl {
|
|||||||
combined_signature[32..].clone_from_slice(&**message_signature.1);
|
combined_signature[32..].clone_from_slice(&**message_signature.1);
|
||||||
|
|
||||||
// encrypt combined signature with requestor public key
|
// encrypt combined signature with requestor public key
|
||||||
let message_signature = crypto::ecies::encrypt(&public, &crypto::DEFAULT_MAC, &combined_signature)
|
let message_signature = crypto::ecies::encrypt(&public, &DEFAULT_MAC, &combined_signature)
|
||||||
.map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?;
|
.map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?;
|
||||||
Ok(message_signature)
|
Ok(message_signature)
|
||||||
}
|
}
|
||||||
@ -167,7 +168,7 @@ impl MessageSigner for KeyServerImpl {
|
|||||||
let message_signature = signing_session.wait()?;
|
let message_signature = signing_session.wait()?;
|
||||||
|
|
||||||
// encrypt combined signature with requestor public key
|
// encrypt combined signature with requestor public key
|
||||||
let message_signature = crypto::ecies::encrypt(&public, &crypto::DEFAULT_MAC, &*message_signature)
|
let message_signature = crypto::ecies::encrypt(&public, &DEFAULT_MAC, &*message_signature)
|
||||||
.map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?;
|
.map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?;
|
||||||
Ok(message_signature)
|
Ok(message_signature)
|
||||||
}
|
}
|
||||||
@ -229,8 +230,8 @@ pub mod tests {
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use crypto;
|
use crypto::DEFAULT_MAC;
|
||||||
use ethkey::{self, Secret, Random, Generator, verify_public};
|
use ethkey::{self, crypto, Secret, Random, Generator, verify_public};
|
||||||
use acl_storage::DummyAclStorage;
|
use acl_storage::DummyAclStorage;
|
||||||
use key_storage::KeyStorage;
|
use key_storage::KeyStorage;
|
||||||
use key_storage::tests::DummyKeyStorage;
|
use key_storage::tests::DummyKeyStorage;
|
||||||
@ -358,12 +359,12 @@ pub mod tests {
|
|||||||
let secret = Random.generate().unwrap().secret().clone();
|
let secret = Random.generate().unwrap().secret().clone();
|
||||||
let signature = ethkey::sign(&secret, &document).unwrap();
|
let signature = ethkey::sign(&secret, &document).unwrap();
|
||||||
let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap();
|
let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap();
|
||||||
let generated_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &generated_key).unwrap();
|
let generated_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &generated_key).unwrap();
|
||||||
|
|
||||||
// now let's try to retrieve key back
|
// now let's try to retrieve key back
|
||||||
for key_server in key_servers.iter() {
|
for key_server in key_servers.iter() {
|
||||||
let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap();
|
let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap();
|
||||||
let retrieved_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &retrieved_key).unwrap();
|
let retrieved_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &retrieved_key).unwrap();
|
||||||
assert_eq!(retrieved_key, generated_key);
|
assert_eq!(retrieved_key, generated_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -380,12 +381,12 @@ pub mod tests {
|
|||||||
let secret = Random.generate().unwrap().secret().clone();
|
let secret = Random.generate().unwrap().secret().clone();
|
||||||
let signature = ethkey::sign(&secret, &document).unwrap();
|
let signature = ethkey::sign(&secret, &document).unwrap();
|
||||||
let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), *threshold).unwrap();
|
let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), *threshold).unwrap();
|
||||||
let generated_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &generated_key).unwrap();
|
let generated_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &generated_key).unwrap();
|
||||||
|
|
||||||
// now let's try to retrieve key back
|
// now let's try to retrieve key back
|
||||||
for (i, key_server) in key_servers.iter().enumerate() {
|
for (i, key_server) in key_servers.iter().enumerate() {
|
||||||
let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap();
|
let retrieved_key = key_server.restore_document_key(&document, &signature.clone().into()).unwrap();
|
||||||
let retrieved_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &retrieved_key).unwrap();
|
let retrieved_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &retrieved_key).unwrap();
|
||||||
assert_eq!(retrieved_key, generated_key);
|
assert_eq!(retrieved_key, generated_key);
|
||||||
|
|
||||||
let key_share = key_storages[i].get(&document).unwrap().unwrap();
|
let key_share = key_storages[i].get(&document).unwrap().unwrap();
|
||||||
@ -419,7 +420,7 @@ pub mod tests {
|
|||||||
// now let's try to retrieve key back
|
// now let's try to retrieve key back
|
||||||
for key_server in key_servers.iter() {
|
for key_server in key_servers.iter() {
|
||||||
let retrieved_key = key_server.restore_document_key(&server_key_id, &signature.clone().into()).unwrap();
|
let retrieved_key = key_server.restore_document_key(&server_key_id, &signature.clone().into()).unwrap();
|
||||||
let retrieved_key = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &retrieved_key).unwrap();
|
let retrieved_key = crypto::ecies::decrypt(&requestor_secret, &DEFAULT_MAC, &retrieved_key).unwrap();
|
||||||
let retrieved_key = Public::from_slice(&retrieved_key);
|
let retrieved_key = Public::from_slice(&retrieved_key);
|
||||||
assert_eq!(retrieved_key, generated_key);
|
assert_eq!(retrieved_key, generated_key);
|
||||||
}
|
}
|
||||||
@ -442,7 +443,7 @@ pub mod tests {
|
|||||||
// sign message
|
// sign message
|
||||||
let message_hash = H256::from(42);
|
let message_hash = H256::from(42);
|
||||||
let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap();
|
let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap();
|
||||||
let combined_signature = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &combined_signature).unwrap();
|
let combined_signature = crypto::ecies::decrypt(&requestor_secret, &DEFAULT_MAC, &combined_signature).unwrap();
|
||||||
let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap();
|
let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap();
|
||||||
let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap();
|
let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap();
|
||||||
|
|
||||||
@ -462,14 +463,14 @@ pub mod tests {
|
|||||||
let secret = Random.generate().unwrap().secret().clone();
|
let secret = Random.generate().unwrap().secret().clone();
|
||||||
let signature = ethkey::sign(&secret, &document).unwrap();
|
let signature = ethkey::sign(&secret, &document).unwrap();
|
||||||
let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap();
|
let generated_key = key_servers[0].generate_document_key(&document, &signature.clone().into(), threshold).unwrap();
|
||||||
let generated_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &generated_key).unwrap();
|
let generated_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &generated_key).unwrap();
|
||||||
|
|
||||||
// remove key from node0
|
// remove key from node0
|
||||||
key_servers[0].cluster().key_storage().remove(&document).unwrap();
|
key_servers[0].cluster().key_storage().remove(&document).unwrap();
|
||||||
|
|
||||||
// now let's try to retrieve key back by requesting it from node0, so that session must be delegated
|
// now let's try to retrieve key back by requesting it from node0, so that session must be delegated
|
||||||
let retrieved_key = key_servers[0].restore_document_key(&document, &signature.into()).unwrap();
|
let retrieved_key = key_servers[0].restore_document_key(&document, &signature.into()).unwrap();
|
||||||
let retrieved_key = crypto::ecies::decrypt(&secret, &crypto::DEFAULT_MAC, &retrieved_key).unwrap();
|
let retrieved_key = crypto::ecies::decrypt(&secret, &DEFAULT_MAC, &retrieved_key).unwrap();
|
||||||
assert_eq!(retrieved_key, generated_key);
|
assert_eq!(retrieved_key, generated_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,7 +492,7 @@ pub mod tests {
|
|||||||
// sign message
|
// sign message
|
||||||
let message_hash = H256::from(42);
|
let message_hash = H256::from(42);
|
||||||
let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap();
|
let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature.into(), message_hash.clone()).unwrap();
|
||||||
let combined_signature = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &combined_signature).unwrap();
|
let combined_signature = crypto::ecies::decrypt(&requestor_secret, &DEFAULT_MAC, &combined_signature).unwrap();
|
||||||
let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap();
|
let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap();
|
||||||
let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap();
|
let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap();
|
||||||
|
|
||||||
@ -517,7 +518,7 @@ pub mod tests {
|
|||||||
// sign message
|
// sign message
|
||||||
let message_hash = H256::random();
|
let message_hash = H256::random();
|
||||||
let signature = key_servers[0].sign_message_ecdsa(&server_key_id, &signature.into(), message_hash.clone()).unwrap();
|
let signature = key_servers[0].sign_message_ecdsa(&server_key_id, &signature.into(), message_hash.clone()).unwrap();
|
||||||
let signature = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &signature).unwrap();
|
let signature = crypto::ecies::decrypt(&requestor_secret, &DEFAULT_MAC, &signature).unwrap();
|
||||||
let signature: H520 = signature[0..65].into();
|
let signature: H520 = signature[0..65].into();
|
||||||
|
|
||||||
// check signature
|
// check signature
|
||||||
|
@ -1279,7 +1279,7 @@ mod tests {
|
|||||||
assert!(decrypted_secret.decrypt_shadows.is_some());
|
assert!(decrypted_secret.decrypt_shadows.is_some());
|
||||||
// check that KS client is able to restore original secret
|
// check that KS client is able to restore original secret
|
||||||
use crypto::DEFAULT_MAC;
|
use crypto::DEFAULT_MAC;
|
||||||
use crypto::ecies::decrypt;
|
use ethkey::crypto::ecies::decrypt;
|
||||||
let decrypt_shadows: Vec<_> = decrypted_secret.decrypt_shadows.unwrap().into_iter()
|
let decrypt_shadows: Vec<_> = decrypted_secret.decrypt_shadows.unwrap().into_iter()
|
||||||
.map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap())
|
.map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap())
|
||||||
.collect();
|
.collect();
|
||||||
@ -1423,7 +1423,7 @@ mod tests {
|
|||||||
|
|
||||||
// 4 nodes must be able to recover original secret
|
// 4 nodes must be able to recover original secret
|
||||||
use crypto::DEFAULT_MAC;
|
use crypto::DEFAULT_MAC;
|
||||||
use crypto::ecies::decrypt;
|
use ethkey::crypto::ecies::decrypt;
|
||||||
let result = sessions[0].decrypted_secret().unwrap().unwrap();
|
let result = sessions[0].decrypted_secret().unwrap().unwrap();
|
||||||
assert_eq!(3, sessions.iter().skip(1).filter(|s| s.decrypted_secret() == Some(Ok(result.clone()))).count());
|
assert_eq!(3, sessions.iter().skip(1).filter(|s| s.decrypted_secret() == Some(Ok(result.clone()))).count());
|
||||||
let decrypt_shadows: Vec<_> = result.decrypt_shadows.unwrap().into_iter()
|
let decrypt_shadows: Vec<_> = result.decrypt_shadows.unwrap().into_iter()
|
||||||
|
@ -37,7 +37,7 @@ use std::sync::Arc;
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use futures::{Future, Poll, Async};
|
use futures::{Future, Poll, Async};
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
use crypto::ecdh::agree;
|
use ethkey::crypto::ecdh::agree;
|
||||||
use ethkey::{Random, Generator, KeyPair, Public, Signature, verify_public, sign, recover};
|
use ethkey::{Random, Generator, KeyPair, Public, Signature, verify_public, sign, recover};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use key_server_cluster::{NodeId, Error, NodeKeyPair};
|
use key_server_cluster::{NodeId, Error, NodeKeyPair};
|
||||||
|
@ -19,7 +19,7 @@ use std::u16;
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use crypto::ecies;
|
use ethkey::crypto::ecies;
|
||||||
use ethkey::{Secret, KeyPair};
|
use ethkey::{Secret, KeyPair};
|
||||||
use ethkey::math::curve_order;
|
use ethkey::math::curve_order;
|
||||||
use ethereum_types::{H256, U256};
|
use ethereum_types::{H256, U256};
|
||||||
@ -306,7 +306,7 @@ pub mod tests {
|
|||||||
use futures::Poll;
|
use futures::Poll;
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
use ethkey::{Random, Generator, KeyPair};
|
use ethkey::{Random, Generator, KeyPair};
|
||||||
use crypto::ecdh::agree;
|
use ethkey::crypto::ecdh::agree;
|
||||||
use key_server_cluster::Error;
|
use key_server_cluster::Error;
|
||||||
use key_server_cluster::message::Message;
|
use key_server_cluster::message::Message;
|
||||||
use super::{MESSAGE_HEADER_SIZE, CURRENT_HEADER_VERSION, MessageHeader, fix_shared_key, encrypt_message,
|
use super::{MESSAGE_HEADER_SIZE, CURRENT_HEADER_VERSION, MessageHeader, fix_shared_key, encrypt_message,
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
use std::collections::{BTreeSet, BTreeMap};
|
use std::collections::{BTreeSet, BTreeMap};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use ethkey::{Public, Secret};
|
use ethkey::{Public, Secret};
|
||||||
use crypto::ecies::encrypt;
|
|
||||||
use crypto::DEFAULT_MAC;
|
use crypto::DEFAULT_MAC;
|
||||||
|
use ethkey::crypto::ecies::encrypt;
|
||||||
use key_server_cluster::{Error, NodeId, DocumentKeyShare, EncryptedDocumentKeyShadow};
|
use key_server_cluster::{Error, NodeId, DocumentKeyShare, EncryptedDocumentKeyShadow};
|
||||||
use key_server_cluster::math;
|
use key_server_cluster::math;
|
||||||
use key_server_cluster::jobs::job_session::{JobPartialRequestAction, JobPartialResponseAction, JobExecutor};
|
use key_server_cluster::jobs::job_session::{JobPartialRequestAction, JobPartialResponseAction, JobExecutor};
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crypto::ecdh::agree;
|
use ethkey::crypto::ecdh::agree;
|
||||||
use ethkey::{KeyPair, Public, Signature, Error as EthKeyError, sign, public_to_address};
|
use ethkey::{KeyPair, Public, Signature, Error as EthKeyError, sign, public_to_address};
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
use ethereum_types::{H256, Address};
|
use ethereum_types::{H256, Address};
|
||||||
@ -54,7 +54,8 @@ impl NodeKeyPair for PlainNodeKeyPair {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compute_shared_key(&self, peer_public: &Public) -> Result<KeyPair, EthKeyError> {
|
fn compute_shared_key(&self, peer_public: &Public) -> Result<KeyPair, EthKeyError> {
|
||||||
agree(self.key_pair.secret(), peer_public).map_err(|e| EthKeyError::Custom(e.into()))
|
agree(self.key_pair.secret(), peer_public)
|
||||||
|
.map_err(|e| EthKeyError::Custom(e.to_string()))
|
||||||
.and_then(KeyPair::from_secret)
|
.and_then(KeyPair::from_secret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,12 @@ impl From<ethkey::Error> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ethkey::crypto::Error> for Error {
|
||||||
|
fn from(err: ethkey::crypto::Error) -> Self {
|
||||||
|
Error::EthKey(err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<kvdb::Error> for Error {
|
impl From<kvdb::Error> for Error {
|
||||||
fn from(err: kvdb::Error) -> Self {
|
fn from(err: kvdb::Error) -> Self {
|
||||||
Error::Database(err.to_string())
|
Error::Database(err.to_string())
|
||||||
@ -176,7 +182,7 @@ impl From<kvdb::Error> for Error {
|
|||||||
|
|
||||||
impl From<crypto::Error> for Error {
|
impl From<crypto::Error> for Error {
|
||||||
fn from(err: crypto::Error) -> Self {
|
fn from(err: crypto::Error) -> Self {
|
||||||
Error::EthKey(err.into())
|
Error::EthKey(err.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ use rcrypto::symmetriccipher::*;
|
|||||||
use rcrypto::buffer::*;
|
use rcrypto::buffer::*;
|
||||||
use tiny_keccak::Keccak;
|
use tiny_keccak::Keccak;
|
||||||
use bytes::{Buf, BufMut};
|
use bytes::{Buf, BufMut};
|
||||||
use crypto;
|
use ethkey::crypto;
|
||||||
use network::{Error, ErrorKind};
|
use network::{Error, ErrorKind};
|
||||||
|
|
||||||
const ENCRYPTED_HEADER_LEN: usize = 32;
|
const ENCRYPTED_HEADER_LEN: usize = 32;
|
||||||
|
@ -25,7 +25,7 @@ use connection::{Connection};
|
|||||||
use node_table::NodeId;
|
use node_table::NodeId;
|
||||||
use io::{IoContext, StreamToken};
|
use io::{IoContext, StreamToken};
|
||||||
use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random};
|
use ethkey::{KeyPair, Public, Secret, recover, sign, Generator, Random};
|
||||||
use crypto::{ecdh, ecies};
|
use ethkey::crypto::{ecdh, ecies};
|
||||||
use network::{Error, ErrorKind, HostInfo};
|
use network::{Error, ErrorKind, HostInfo};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
|
@ -151,8 +151,14 @@ impl From<ethkey::Error> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<crypto::Error> for Error {
|
impl From<ethkey::crypto::Error> for Error {
|
||||||
fn from(_err: crypto::Error) -> Self {
|
fn from(_err: ethkey::crypto::Error) -> Self {
|
||||||
|
ErrorKind::Auth.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<crypto::error::SymmError> for Error {
|
||||||
|
fn from(_err: crypto::error::SymmError) -> Self {
|
||||||
ErrorKind::Auth.into()
|
ErrorKind::Auth.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,11 +174,11 @@ fn test_errors() {
|
|||||||
|
|
||||||
match *<Error as From<rlp::DecoderError>>::from(rlp::DecoderError::RlpIsTooBig).kind() {
|
match *<Error as From<rlp::DecoderError>>::from(rlp::DecoderError::RlpIsTooBig).kind() {
|
||||||
ErrorKind::Auth => {},
|
ErrorKind::Auth => {},
|
||||||
_ => panic!("Unexpeceted error"),
|
_ => panic!("Unexpected error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
match *<Error as From<crypto::Error>>::from(crypto::Error::InvalidMessage).kind() {
|
match *<Error as From<ethkey::crypto::Error>>::from(ethkey::crypto::Error::InvalidMessage).kind() {
|
||||||
ErrorKind::Auth => {},
|
ErrorKind::Auth => {},
|
||||||
_ => panic!("Unexpeceted error"),
|
_ => panic!("Unexpected error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ mem = { path = "../util/mem" }
|
|||||||
ordered-float = "0.5"
|
ordered-float = "0.5"
|
||||||
parking_lot = "0.5"
|
parking_lot = "0.5"
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
ring = "0.12"
|
|
||||||
rlp = { path = "../util/rlp" }
|
rlp = { path = "../util/rlp" }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
@ -28,7 +28,6 @@ extern crate ordered_float;
|
|||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate rlp;
|
extern crate rlp;
|
||||||
extern crate ring;
|
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate slab;
|
extern crate slab;
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
//! Encryption schemes supported by RPC layer.
|
//! Encryption schemes supported by RPC layer.
|
||||||
|
|
||||||
use crypto;
|
use crypto::aes_gcm::{Encryptor, Decryptor};
|
||||||
|
use ethkey::crypto::ecies;
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use ethkey::{self, Public, Secret};
|
use ethkey::{self, Public, Secret};
|
||||||
use mem::Memzero;
|
use mem::Memzero;
|
||||||
use ring::aead::{self, AES_256_GCM, SealingKey, OpeningKey};
|
|
||||||
|
|
||||||
/// Length of AES key
|
/// Length of AES key
|
||||||
pub const AES_KEY_LEN: usize = 32;
|
pub const AES_KEY_LEN: usize = 32;
|
||||||
@ -72,38 +72,15 @@ impl EncryptionInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypt the supplied plaintext
|
/// Encrypt the supplied plaintext
|
||||||
pub fn encrypt(self, plain: &[u8]) -> Vec<u8> {
|
pub fn encrypt(self, plain: &[u8]) -> Option<Vec<u8>> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
EncryptionInner::AES(key, nonce, encode) => {
|
EncryptionInner::AES(key, nonce, encode) => {
|
||||||
let sealing_key = SealingKey::new(&AES_256_GCM, &*key)
|
|
||||||
.expect("key is of correct len; qed");
|
|
||||||
|
|
||||||
let encrypt_plain = move |buf: &mut Vec<u8>| {
|
|
||||||
let out_suffix_capacity = AES_256_GCM.tag_len();
|
|
||||||
|
|
||||||
let prepend_len = buf.len();
|
|
||||||
buf.extend(plain);
|
|
||||||
|
|
||||||
buf.resize(prepend_len + plain.len() + out_suffix_capacity, 0);
|
|
||||||
|
|
||||||
let out_size = aead::seal_in_place(
|
|
||||||
&sealing_key,
|
|
||||||
&nonce,
|
|
||||||
&[], // no authenticated data.
|
|
||||||
&mut buf[prepend_len..],
|
|
||||||
out_suffix_capacity,
|
|
||||||
).expect("key, nonce, buf are valid and out suffix large enough; qed");
|
|
||||||
|
|
||||||
// truncate to the output size and return.
|
|
||||||
buf.truncate(prepend_len + out_size);
|
|
||||||
};
|
|
||||||
|
|
||||||
match encode {
|
match encode {
|
||||||
AesEncode::AppendedNonce => {
|
AesEncode::AppendedNonce => {
|
||||||
let mut buf = Vec::new();
|
let mut enc = Encryptor::aes_256_gcm(&*key).ok()?;
|
||||||
encrypt_plain(&mut buf);
|
let mut buf = enc.encrypt(&nonce, plain.to_vec()).ok()?;
|
||||||
buf.extend(&nonce[..]);
|
buf.extend(&nonce[..]);
|
||||||
buf
|
Some(buf)
|
||||||
}
|
}
|
||||||
AesEncode::OnTopics(topics) => {
|
AesEncode::OnTopics(topics) => {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
@ -111,14 +88,16 @@ impl EncryptionInstance {
|
|||||||
xor(&mut t.0, &key);
|
xor(&mut t.0, &key);
|
||||||
buf.extend(&t.0);
|
buf.extend(&t.0);
|
||||||
}
|
}
|
||||||
encrypt_plain(&mut buf);
|
let mut enc = Encryptor::aes_256_gcm(&*key).ok()?;
|
||||||
buf
|
enc.offset(buf.len());
|
||||||
|
buf.extend(plain);
|
||||||
|
let ciphertext = enc.encrypt(&nonce, buf).ok()?;
|
||||||
|
Some(ciphertext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EncryptionInner::ECIES(valid_public) => {
|
EncryptionInner::ECIES(valid_public) => {
|
||||||
crypto::ecies::encrypt(&valid_public, &[], plain)
|
ecies::encrypt(&valid_public, &[], plain).ok()
|
||||||
.expect("validity of public key an invariant of the type; qed")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,58 +148,36 @@ impl DecryptionInstance {
|
|||||||
pub fn decrypt(self, ciphertext: &[u8]) -> Option<Vec<u8>> {
|
pub fn decrypt(self, ciphertext: &[u8]) -> Option<Vec<u8>> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
DecryptionInner::AES(extract) => {
|
DecryptionInner::AES(extract) => {
|
||||||
let decrypt = |
|
|
||||||
key: Memzero<[u8; AES_KEY_LEN]>,
|
|
||||||
nonce: [u8; AES_NONCE_LEN],
|
|
||||||
ciphertext: &[u8]
|
|
||||||
| {
|
|
||||||
if ciphertext.len() < AES_256_GCM.tag_len() { return None }
|
|
||||||
|
|
||||||
let opening_key = OpeningKey::new(&AES_256_GCM, &*key)
|
|
||||||
.expect("key length is valid for mode; qed");
|
|
||||||
|
|
||||||
let mut buf = ciphertext.to_vec();
|
|
||||||
|
|
||||||
// decrypted plaintext always ends up at the
|
|
||||||
// front of the buffer.
|
|
||||||
let maybe_decrypted = aead::open_in_place(
|
|
||||||
&opening_key,
|
|
||||||
&nonce,
|
|
||||||
&[], // no authenticated data
|
|
||||||
0, // no header.
|
|
||||||
&mut buf,
|
|
||||||
).ok().map(|plain_slice| plain_slice.len());
|
|
||||||
|
|
||||||
maybe_decrypted.map(move |len| { buf.truncate(len); buf })
|
|
||||||
};
|
|
||||||
|
|
||||||
match extract {
|
match extract {
|
||||||
AesExtract::AppendedNonce(key) => {
|
AesExtract::AppendedNonce(key) => {
|
||||||
if ciphertext.len() < AES_NONCE_LEN { return None }
|
if ciphertext.len() < AES_NONCE_LEN {
|
||||||
|
return None
|
||||||
|
}
|
||||||
// nonce is the suffix of ciphertext.
|
// nonce is the suffix of ciphertext.
|
||||||
let mut nonce = [0; AES_NONCE_LEN];
|
let mut nonce = [0; AES_NONCE_LEN];
|
||||||
let nonce_offset = ciphertext.len() - AES_NONCE_LEN;
|
let nonce_offset = ciphertext.len() - AES_NONCE_LEN;
|
||||||
|
|
||||||
nonce.copy_from_slice(&ciphertext[nonce_offset..]);
|
nonce.copy_from_slice(&ciphertext[nonce_offset..]);
|
||||||
decrypt(key, nonce, &ciphertext[..nonce_offset])
|
Decryptor::aes_256_gcm(&*key).ok()?
|
||||||
|
.decrypt(&nonce, Vec::from(&ciphertext[..nonce_offset]))
|
||||||
|
.ok()
|
||||||
}
|
}
|
||||||
AesExtract::OnTopics(num_topics, known_index, known_topic) => {
|
AesExtract::OnTopics(num_topics, known_index, known_topic) => {
|
||||||
if ciphertext.len() < num_topics * 32 { return None }
|
if ciphertext.len() < num_topics * 32 {
|
||||||
|
return None
|
||||||
|
}
|
||||||
let mut salted_topic = H256::new();
|
let mut salted_topic = H256::new();
|
||||||
salted_topic.copy_from_slice(&ciphertext[(known_index * 32)..][..32]);
|
salted_topic.copy_from_slice(&ciphertext[(known_index * 32)..][..32]);
|
||||||
|
|
||||||
let key = Memzero::from((salted_topic ^ known_topic).0);
|
let key = Memzero::from((salted_topic ^ known_topic).0);
|
||||||
|
|
||||||
let offset = num_topics * 32;
|
let offset = num_topics * 32;
|
||||||
decrypt(key, BROADCAST_IV, &ciphertext[offset..])
|
Decryptor::aes_256_gcm(&*key).ok()?
|
||||||
|
.decrypt(&BROADCAST_IV, Vec::from(&ciphertext[offset..]))
|
||||||
|
.ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DecryptionInner::ECIES(secret) => {
|
DecryptionInner::ECIES(secret) => {
|
||||||
// secret is checked for validity, so only fails on invalid message.
|
// secret is checked for validity, so only fails on invalid message.
|
||||||
crypto::ecies::decrypt(&secret, &[], ciphertext).ok()
|
ecies::decrypt(&secret, &[], ciphertext).ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,16 +187,6 @@ impl DecryptionInstance {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn aes_key_len_should_be_equal_to_constant() {
|
|
||||||
assert_eq!(::ring::aead::AES_256_GCM.key_len(), AES_KEY_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn aes_nonce_len_should_be_equal_to_constant() {
|
|
||||||
assert_eq!(::ring::aead::AES_256_GCM.nonce_len(), AES_NONCE_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encrypt_asymmetric() {
|
fn encrypt_asymmetric() {
|
||||||
use ethkey::{Generator, Random};
|
use ethkey::{Generator, Random};
|
||||||
@ -247,7 +194,7 @@ mod tests {
|
|||||||
let key_pair = Random.generate().unwrap();
|
let key_pair = Random.generate().unwrap();
|
||||||
let test_message = move |message: &[u8]| {
|
let test_message = move |message: &[u8]| {
|
||||||
let instance = EncryptionInstance::ecies(key_pair.public().clone()).unwrap();
|
let instance = EncryptionInstance::ecies(key_pair.public().clone()).unwrap();
|
||||||
let ciphertext = instance.encrypt(&message);
|
let ciphertext = instance.encrypt(&message).unwrap();
|
||||||
|
|
||||||
if !message.is_empty() {
|
if !message.is_empty() {
|
||||||
assert!(&ciphertext[..message.len()] != message)
|
assert!(&ciphertext[..message.len()] != message)
|
||||||
@ -273,7 +220,7 @@ mod tests {
|
|||||||
let key = Memzero::from(rng.gen::<[u8; 32]>());
|
let key = Memzero::from(rng.gen::<[u8; 32]>());
|
||||||
|
|
||||||
let instance = EncryptionInstance::aes(key.clone(), rng.gen());
|
let instance = EncryptionInstance::aes(key.clone(), rng.gen());
|
||||||
let ciphertext = instance.encrypt(message);
|
let ciphertext = instance.encrypt(message).unwrap();
|
||||||
|
|
||||||
if !message.is_empty() {
|
if !message.is_empty() {
|
||||||
assert!(&ciphertext[..message.len()] != message)
|
assert!(&ciphertext[..message.len()] != message)
|
||||||
@ -303,7 +250,7 @@ mod tests {
|
|||||||
let key = Memzero::from(rng.gen::<[u8; 32]>());
|
let key = Memzero::from(rng.gen::<[u8; 32]>());
|
||||||
|
|
||||||
let instance = EncryptionInstance::broadcast(key, all_topics);
|
let instance = EncryptionInstance::broadcast(key, all_topics);
|
||||||
let ciphertext = instance.encrypt(message);
|
let ciphertext = instance.encrypt(message).unwrap();
|
||||||
|
|
||||||
if !message.is_empty() {
|
if !message.is_empty() {
|
||||||
assert!(&ciphertext[..message.len()] != message)
|
assert!(&ciphertext[..message.len()] != message)
|
||||||
|
@ -402,7 +402,7 @@ mod tests {
|
|||||||
sign_with: Some(signing_pair.secret().unwrap())
|
sign_with: Some(signing_pair.secret().unwrap())
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
|
||||||
let encrypted = encryption_instance.encrypt(&payload);
|
let encrypted = encryption_instance.encrypt(&payload).unwrap();
|
||||||
|
|
||||||
let message = Message::create(CreateParams {
|
let message = Message::create(CreateParams {
|
||||||
ttl: 100,
|
ttl: 100,
|
||||||
|
@ -25,7 +25,6 @@ use ethereum_types::H256;
|
|||||||
use ethkey::{KeyPair, Public, Secret};
|
use ethkey::{KeyPair, Public, Secret};
|
||||||
use mem::Memzero;
|
use mem::Memzero;
|
||||||
use rand::{Rng, OsRng};
|
use rand::{Rng, OsRng};
|
||||||
use ring::error::Unspecified;
|
|
||||||
|
|
||||||
use rpc::crypto::{AES_KEY_LEN, EncryptionInstance, DecryptionInstance};
|
use rpc::crypto::{AES_KEY_LEN, EncryptionInstance, DecryptionInstance};
|
||||||
|
|
||||||
@ -54,10 +53,8 @@ impl Key {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// From secret asymmetric key. Fails if secret is invalid.
|
/// From secret asymmetric key. Fails if secret is invalid.
|
||||||
pub fn from_secret(secret: Secret) -> Result<Self, Unspecified> {
|
pub fn from_secret(secret: Secret) -> Option<Self> {
|
||||||
KeyPair::from_secret(secret)
|
KeyPair::from_secret(secret).map(Key::Asymmetric).ok()
|
||||||
.map(Key::Asymmetric)
|
|
||||||
.map_err(|_| Unspecified)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// From raw symmetric key.
|
/// From raw symmetric key.
|
||||||
@ -179,7 +176,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rejects_invalid_secret() {
|
fn rejects_invalid_secret() {
|
||||||
let bad_secret = ::ethkey::Secret::from([0xff; 32]);
|
let bad_secret = ::ethkey::Secret::from([0xff; 32]);
|
||||||
assert!(Key::from_secret(bad_secret).is_err());
|
assert!(Key::from_secret(bad_secret).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -226,7 +226,7 @@ impl<P: PoolHandle + 'static, M: Send + Sync + 'static> Whisper for WhisperClien
|
|||||||
|
|
||||||
fn add_private_key(&self, private: types::Private) -> Result<types::Identity, Error> {
|
fn add_private_key(&self, private: types::Private) -> Result<types::Identity, Error> {
|
||||||
let key_pair = Key::from_secret(private.into_inner().into())
|
let key_pair = Key::from_secret(private.into_inner().into())
|
||||||
.map_err(|_| whisper_error("Invalid private key"))?;
|
.ok_or_else(|| whisper_error("Invalid private key"))?;
|
||||||
|
|
||||||
Ok(HexEncode(self.store.write().insert(key_pair)))
|
Ok(HexEncode(self.store.write().insert(key_pair)))
|
||||||
}
|
}
|
||||||
@ -317,7 +317,7 @@ impl<P: PoolHandle + 'static, M: Send + Sync + 'static> Whisper for WhisperClien
|
|||||||
sign_with: sign_with.as_ref(),
|
sign_with: sign_with.as_ref(),
|
||||||
}).map_err(whisper_error)?;
|
}).map_err(whisper_error)?;
|
||||||
|
|
||||||
encryption.encrypt(&payload)
|
encryption.encrypt(&payload).ok_or(whisper_error("encryption error"))?
|
||||||
};
|
};
|
||||||
|
|
||||||
// mining the packet is the heaviest item of work by far.
|
// mining the packet is the heaviest item of work by far.
|
||||||
|
Loading…
Reference in New Issue
Block a user