diff --git a/Cargo.lock b/Cargo.lock index eeb01529c20..556556786d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1361,7 +1361,6 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-crypto 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-util-mem 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wordlist 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1369,6 +1368,7 @@ dependencies = [ "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3044,6 +3044,7 @@ dependencies = [ "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "time-utils 0.1.0", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4716,6 +4717,25 @@ dependencies = [ "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "zeroize" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zeroize_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zeroize_derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" "checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" @@ -5114,3 +5134,5 @@ dependencies = [ "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xmltree 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8eaee9d17062850f1e6163b509947969242990ee59a35801af437abe041e70" +"checksum zeroize 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2ea4afc22e9497e26b42bf047083c30f7e3ca566f3bcd7187f83d18b327043" +"checksum zeroize_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afd1469e4bbca3b96606d26ba6e9bd6d3aed3b1299c82b92ec94377d22d78dbc" diff --git a/accounts/ethkey/Cargo.toml b/accounts/ethkey/Cargo.toml index a66a74de05a..9c01fa74f58 100644 --- a/accounts/ethkey/Cargo.toml +++ b/accounts/ethkey/Cargo.toml @@ -11,7 +11,6 @@ eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } ethereum-types = "0.6.0" lazy_static = "1.0" log = "0.4" -parity-util-mem = "0.1" parity-wordlist = "1.2" quick-error = "1.2.2" rand = "0.6" @@ -19,3 +18,4 @@ rustc-hex = "1.0" serde = "1.0" serde_derive = "1.0" tiny-keccak = "1.4" +zeroize = "0.9.1" diff --git a/accounts/ethkey/src/lib.rs b/accounts/ethkey/src/lib.rs index 2312f2bcd31..4f55f056d07 100644 --- a/accounts/ethkey/src/lib.rs +++ b/accounts/ethkey/src/lib.rs @@ -19,7 +19,6 @@ extern crate edit_distance; extern crate parity_crypto; extern crate ethereum_types; -extern crate parity_util_mem; extern crate parity_wordlist; #[macro_use] extern crate quick_error; @@ -28,6 +27,7 @@ extern crate rustc_hex; extern crate secp256k1; extern crate serde; extern crate tiny_keccak; +extern crate zeroize; #[macro_use] extern crate lazy_static; diff --git a/accounts/ethkey/src/secret.rs b/accounts/ethkey/src/secret.rs index 25136ee8330..c850fa70ee8 100644 --- a/accounts/ethkey/src/secret.rs +++ b/accounts/ethkey/src/secret.rs @@ -21,17 +21,23 @@ use rustc_hex::ToHex; use secp256k1::constants::{SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE}; use secp256k1::key; use ethereum_types::H256; -use parity_util_mem::Memzero; +use zeroize::Zeroize; use {Error, SECP256K1}; #[derive(Clone, PartialEq, Eq)] pub struct Secret { - inner: Memzero, + inner: H256, +} + +impl Drop for Secret { + fn drop(&mut self) { + self.inner.0.zeroize() + } } impl ToHex for Secret { fn to_hex(&self) -> String { - format!("{:x}", *self.inner) + format!("{:x}", self.inner) } } @@ -61,12 +67,12 @@ impl Secret { } let mut h = H256::zero(); h.as_bytes_mut().copy_from_slice(&key[0..32]); - Some(Secret { inner: Memzero::from(h) }) + Some(Secret { inner: h }) } /// Creates zero key, which is invalid for crypto operations, but valid for math operation. pub fn zero() -> Self { - Secret { inner: Memzero::from(H256::zero()) } + Secret { inner: H256::zero() } } /// Imports and validates the key. @@ -214,7 +220,7 @@ impl FromStr for Secret { impl From<[u8; 32]> for Secret { fn from(k: [u8; 32]) -> Self { - Secret { inner: Memzero::from(H256(k)) } + Secret { inner: H256(k) } } } diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index 46351acc58a..e373b740f8c 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -30,3 +30,4 @@ time-utils = { path = "../util/time-utils" } jsonrpc-core = "10.0.1" jsonrpc-derive = "10.0.2" jsonrpc-pubsub = "10.0.1" +zeroize = "0.9.1" diff --git a/whisper/src/lib.rs b/whisper/src/lib.rs index 7ff7794b77a..550124d13cf 100644 --- a/whisper/src/lib.rs +++ b/whisper/src/lib.rs @@ -35,6 +35,7 @@ extern crate serde; extern crate slab; extern crate smallvec; extern crate tiny_keccak; +extern crate zeroize; extern crate jsonrpc_core; extern crate jsonrpc_derive; diff --git a/whisper/src/rpc/crypto.rs b/whisper/src/rpc/crypto.rs index 3f26e0350a0..ad2b59e2183 100644 --- a/whisper/src/rpc/crypto.rs +++ b/whisper/src/rpc/crypto.rs @@ -20,7 +20,7 @@ use aes_gcm::{Encryptor, Decryptor}; use ethkey::crypto::ecies; use ethereum_types::H256; use ethkey::{self, Public, Secret}; -use parity_util_mem::Memzero; +use zeroize::Zeroizing; /// Length of AES key pub const AES_KEY_LEN: usize = 32; @@ -37,7 +37,7 @@ enum AesEncode { } enum EncryptionInner { - AES(Memzero<[u8; AES_KEY_LEN]>, [u8; AES_NONCE_LEN], AesEncode), + AES(Zeroizing<[u8; AES_KEY_LEN]>, [u8; AES_NONCE_LEN], AesEncode), ECIES(Public), } @@ -59,7 +59,7 @@ impl EncryptionInstance { /// /// If generating nonces with a secure RNG, limit uses such that /// the chance of collision is negligible. - pub fn aes(key: Memzero<[u8; AES_KEY_LEN]>, nonce: [u8; AES_NONCE_LEN]) -> Self { + pub fn aes(key: Zeroizing<[u8; AES_KEY_LEN]>, nonce: [u8; AES_NONCE_LEN]) -> Self { EncryptionInstance(EncryptionInner::AES(key, nonce, AesEncode::AppendedNonce)) } @@ -67,7 +67,7 @@ impl EncryptionInstance { /// /// Key reuse here is extremely dangerous. It should be randomly generated /// with a secure RNG. - pub fn broadcast(key: Memzero<[u8; AES_KEY_LEN]>, topics: Vec) -> Self { + pub fn broadcast(key: Zeroizing<[u8; AES_KEY_LEN]>, topics: Vec) -> Self { EncryptionInstance(EncryptionInner::AES(key, BROADCAST_IV, AesEncode::OnTopics(topics))) } @@ -111,7 +111,7 @@ fn xor(a: &mut [u8; 32], b: &[u8; 32]) { } enum AesExtract { - AppendedNonce(Memzero<[u8; AES_KEY_LEN]>), // extract appended nonce. + AppendedNonce(Zeroizing<[u8; AES_KEY_LEN]>), // extract appended nonce. OnTopics(usize, usize, H256), // number of topics, index we know, topic we know. } @@ -132,7 +132,7 @@ impl DecryptionInstance { } /// 256-bit AES GCM decryption with appended nonce. - pub fn aes(key: Memzero<[u8; AES_KEY_LEN]>) -> Self { + pub fn aes(key: Zeroizing<[u8; AES_KEY_LEN]>) -> Self { DecryptionInstance(DecryptionInner::AES(AesExtract::AppendedNonce(key))) } @@ -167,7 +167,7 @@ impl DecryptionInstance { } let mut salted_topic = H256::zero(); salted_topic.as_bytes_mut().copy_from_slice(&ciphertext[(known_index * 32)..][..32]); - let key = Memzero::from((salted_topic ^ known_topic).0); + let key = Zeroizing::new((salted_topic ^ known_topic).0); let offset = num_topics * 32; Decryptor::aes_256_gcm(&*key).ok()? .decrypt(&BROADCAST_IV, Vec::from(&ciphertext[offset..])) @@ -187,6 +187,7 @@ impl DecryptionInstance { mod tests { use super::*; use rand::{Rng, rngs::OsRng}; + use std::ops::Deref; #[test] @@ -217,9 +218,9 @@ mod tests { fn encrypt_symmetric() { let mut rng = OsRng::new().unwrap(); let mut test_message = move |message: &[u8]| { - let key = Memzero::from(rng.gen::<[u8; 32]>()); + let key = Zeroizing::new(rng.gen::<[u8; 32]>()); - let instance = EncryptionInstance::aes(key.clone(), rng.gen()); + let instance = EncryptionInstance::aes(Zeroizing::new(*key.deref()), rng.gen()); let ciphertext = instance.encrypt(message).unwrap(); if !message.is_empty() { @@ -245,7 +246,7 @@ mod tests { let all_topics = (0..5).map(|_| H256::random_using(&mut rng)).collect::>(); let known_idx = 2; let known_topic = all_topics[2]; - let key = Memzero::from(rng.gen::<[u8; 32]>()); + let key = Zeroizing::new(rng.gen::<[u8; 32]>()); let instance = EncryptionInstance::broadcast(key, all_topics); let ciphertext = instance.encrypt(message).unwrap(); diff --git a/whisper/src/rpc/key_store.rs b/whisper/src/rpc/key_store.rs index 3f84e59ad3a..4d18157880e 100644 --- a/whisper/src/rpc/key_store.rs +++ b/whisper/src/rpc/key_store.rs @@ -23,7 +23,8 @@ use std::collections::HashMap; use ethereum_types::H256; use ethkey::{KeyPair, Public, Secret}; -use parity_util_mem::Memzero; +use zeroize::Zeroizing; +use std::ops::Deref; use rand::{Rng, rngs::OsRng}; use rpc::crypto::{AES_KEY_LEN, EncryptionInstance, DecryptionInstance}; @@ -35,7 +36,7 @@ pub enum Key { /// and signing. Asymmetric(KeyPair), /// AES-256 GCM mode. Suitable for encryption, decryption, but not signing. - Symmetric(Memzero<[u8; AES_KEY_LEN]>), + Symmetric(Zeroizing<[u8; AES_KEY_LEN]>), } impl Key { @@ -49,7 +50,7 @@ impl Key { /// Generate a random symmetric key with the given cryptographic RNG. pub fn new_symmetric(rng: &mut OsRng) -> Self { - Key::Symmetric(Memzero::from(rng.gen::<[u8; 32]>())) + Key::Symmetric(Zeroizing::new(rng.gen::<[u8; 32]>())) } /// From secret asymmetric key. Fails if secret is invalid. @@ -59,7 +60,7 @@ impl Key { /// From raw symmetric key. pub fn from_raw_symmetric(key: [u8; AES_KEY_LEN]) -> Self { - Key::Symmetric(Memzero::from(key)) + Key::Symmetric(Zeroizing::new(key)) } /// Get a handle to the public key if this is an asymmetric key. @@ -138,7 +139,7 @@ impl KeyStore { .map_err(|_| "could not create encryption instance for id"), Key::Symmetric(ref key) => OsRng::new() - .map(|mut rng| EncryptionInstance::aes(key.clone(), rng.gen())) + .map(|mut rng| EncryptionInstance::aes(Zeroizing::new(*key.deref()), rng.gen())) .map_err(|_| "unable to get secure randomness") }) } @@ -149,7 +150,7 @@ impl KeyStore { self.get(id).map(|key| match *key { Key::Asymmetric(ref pair) => DecryptionInstance::ecies(pair.secret().clone()) .expect("all keys stored are valid; qed"), - Key::Symmetric(ref key) => DecryptionInstance::aes(key.clone()), + Key::Symmetric(ref key) => DecryptionInstance::aes(Zeroizing::new(*key.deref())), }) } diff --git a/whisper/src/rpc/mod.rs b/whisper/src/rpc/mod.rs index 61cd14d4b9b..57ec4c6c4f7 100644 --- a/whisper/src/rpc/mod.rs +++ b/whisper/src/rpc/mod.rs @@ -28,7 +28,7 @@ use jsonrpc_derive::rpc; use jsonrpc_pubsub::{Session, PubSubMetadata, SubscriptionId, typed::Subscriber}; use ethereum_types::H256; -use parity_util_mem::Memzero; +use zeroize::Zeroizing; use parking_lot::RwLock; use self::filter::Filter; @@ -284,7 +284,7 @@ impl Whisper for WhisperClien let mut rng = OsRng::new() .map_err(|_| whisper_error("unable to acquire secure randomness"))?; - let key = Memzero::from(rng.gen::<[u8; 32]>()); + let key = Zeroizing::new(rng.gen::<[u8; 32]>()); if req.topics.is_empty() { return Err(whisper_error("must supply at least one topic for broadcast message")); }