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:
Toralf Wittner 2018-05-05 11:02:33 +02:00 committed by Marek Kotewicz
parent a4c7843a07
commit e30839e85f
50 changed files with 1003 additions and 542 deletions

26
Cargo.lock generated
View File

@ -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"

View File

@ -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" }

View File

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

View File

@ -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
View 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())
}

View 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[..])
}
}

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

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

View 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()
}

View File

@ -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[..]);
}
} }

View 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[..])
}

View 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()))
}

View File

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

View File

@ -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(())
} }
} }

View File

@ -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;

View File

@ -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
View 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[..]);
}
}

View File

@ -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]);

View File

@ -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;

View File

@ -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]

View File

@ -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, &params.salt, params.c), Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, &params.salt, params.c),
Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, &params.salt, params.n, params.p, params.r)?, Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(password, &params.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, &params.iv, &self.ciphertext, &mut plain[from..]); crypto::aes::decrypt_128_ctr(&derived_left_bits, &params.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);
} }

View File

@ -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());

View File

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

View File

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

View File

@ -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)

View File

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

View File

@ -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;

View File

@ -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())?;

View File

@ -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"

View File

@ -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;

View File

@ -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())
} }

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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()

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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())
} }
} }

View File

@ -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;

View File

@ -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)]

View File

@ -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"),
} }
} }

View File

@ -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"

View File

@ -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;

View File

@ -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)

View File

@ -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,

View File

@ -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]

View File

@ -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.