Add util/mem to zero out memory on drop. (#8356)

* Add `util/mem` to zero out memory on drop.

* Remove nonsense.

* Remove `Into` impls for `Memzero`.

* Update ethereum-types and remove H256Mut.
This commit is contained in:
Toralf Wittner
2018-04-11 13:57:12 +02:00
committed by Marek Kotewicz
parent dd2c27958c
commit 2b05eb43a9
20 changed files with 190 additions and 95 deletions

View File

@@ -13,6 +13,7 @@ ethcore-crypto = { path = "../ethcore/crypto" }
ethkey = { path = "../ethkey" }
hex = "0.2"
log = "0.3"
mem = { path = "../util/mem" }
ordered-float = "0.5"
parking_lot = "0.5"
rand = "0.4"

View File

@@ -23,6 +23,7 @@ extern crate ethcore_network as network;
extern crate ethereum_types;
extern crate ethkey;
extern crate hex;
extern crate mem;
extern crate ordered_float;
extern crate parking_lot;
extern crate rand;

View File

@@ -19,6 +19,7 @@
use crypto;
use ethereum_types::H256;
use ethkey::{self, Public, Secret};
use mem::Memzero;
use ring::aead::{self, AES_256_GCM, SealingKey, OpeningKey};
/// Length of AES key
@@ -36,7 +37,7 @@ enum AesEncode {
}
enum EncryptionInner {
AES([u8; AES_KEY_LEN], [u8; AES_NONCE_LEN], AesEncode),
AES(Memzero<[u8; AES_KEY_LEN]>, [u8; AES_NONCE_LEN], AesEncode),
ECIES(Public),
}
@@ -58,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: [u8; AES_KEY_LEN], nonce: [u8; AES_NONCE_LEN]) -> Self {
pub fn aes(key: Memzero<[u8; AES_KEY_LEN]>, nonce: [u8; AES_NONCE_LEN]) -> Self {
EncryptionInstance(EncryptionInner::AES(key, nonce, AesEncode::AppendedNonce))
}
@@ -66,7 +67,7 @@ impl EncryptionInstance {
///
/// Key reuse here is extremely dangerous. It should be randomly generated
/// with a secure RNG.
pub fn broadcast(key: [u8; AES_KEY_LEN], topics: Vec<H256>) -> Self {
pub fn broadcast(key: Memzero<[u8; AES_KEY_LEN]>, topics: Vec<H256>) -> Self {
EncryptionInstance(EncryptionInner::AES(key, BROADCAST_IV, AesEncode::OnTopics(topics)))
}
@@ -74,7 +75,7 @@ impl EncryptionInstance {
pub fn encrypt(self, plain: &[u8]) -> Vec<u8> {
match self.0 {
EncryptionInner::AES(key, nonce, encode) => {
let sealing_key = SealingKey::new(&AES_256_GCM, &key)
let sealing_key = SealingKey::new(&AES_256_GCM, &*key)
.expect("key is of correct len; qed");
let encrypt_plain = move |buf: &mut Vec<u8>| {
@@ -106,12 +107,10 @@ impl EncryptionInstance {
}
AesEncode::OnTopics(topics) => {
let mut buf = Vec::new();
let key = H256(key);
for topic in topics {
buf.extend(&*(topic ^ key));
for mut t in topics {
xor(&mut t.0, &key);
buf.extend(&t.0);
}
encrypt_plain(&mut buf);
buf
}
@@ -125,8 +124,15 @@ impl EncryptionInstance {
}
}
#[inline]
fn xor(a: &mut [u8; 32], b: &[u8; 32]) {
for i in 0 .. 32 {
a[i] ^= b[i]
}
}
enum AesExtract {
AppendedNonce([u8; AES_KEY_LEN]), // extract appended nonce.
AppendedNonce(Memzero<[u8; AES_KEY_LEN]>), // extract appended nonce.
OnTopics(usize, usize, H256), // number of topics, index we know, topic we know.
}
@@ -147,7 +153,7 @@ impl DecryptionInstance {
}
/// 256-bit AES GCM decryption with appended nonce.
pub fn aes(key: [u8; AES_KEY_LEN]) -> Self {
pub fn aes(key: Memzero<[u8; AES_KEY_LEN]>) -> Self {
DecryptionInstance(DecryptionInner::AES(AesExtract::AppendedNonce(key)))
}
@@ -164,13 +170,13 @@ impl DecryptionInstance {
match self.0 {
DecryptionInner::AES(extract) => {
let decrypt = |
key: [u8; AES_KEY_LEN],
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)
let opening_key = OpeningKey::new(&AES_256_GCM, &*key)
.expect("key length is valid for mode; qed");
let mut buf = ciphertext.to_vec();
@@ -205,7 +211,7 @@ impl DecryptionInstance {
let mut salted_topic = H256::new();
salted_topic.copy_from_slice(&ciphertext[(known_index * 32)..][..32]);
let key = (salted_topic ^ known_topic).0;
let key = Memzero::from((salted_topic ^ known_topic).0);
let offset = num_topics * 32;
decrypt(key, BROADCAST_IV, &ciphertext[offset..])
@@ -264,9 +270,9 @@ mod tests {
let mut rng = OsRng::new().unwrap();
let mut test_message = move |message: &[u8]| {
let key = rng.gen();
let key = Memzero::from(rng.gen::<[u8; 32]>());
let instance = EncryptionInstance::aes(key, rng.gen());
let instance = EncryptionInstance::aes(key.clone(), rng.gen());
let ciphertext = instance.encrypt(message);
if !message.is_empty() {
@@ -294,7 +300,7 @@ mod tests {
let all_topics = (0..5).map(|_| rng.gen()).collect::<Vec<_>>();
let known_idx = 2;
let known_topic = all_topics[2];
let key = rng.gen();
let key = Memzero::from(rng.gen::<[u8; 32]>());
let instance = EncryptionInstance::broadcast(key, all_topics);
let ciphertext = instance.encrypt(message);

View File

@@ -23,6 +23,7 @@ use std::collections::HashMap;
use ethereum_types::H256;
use ethkey::{KeyPair, Public, Secret};
use mem::Memzero;
use rand::{Rng, OsRng};
use ring::error::Unspecified;
@@ -35,7 +36,7 @@ pub enum Key {
/// and signing.
Asymmetric(KeyPair),
/// AES-256 GCM mode. Suitable for encryption, decryption, but not signing.
Symmetric([u8; AES_KEY_LEN]),
Symmetric(Memzero<[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(rng.gen())
Key::Symmetric(Memzero::from(rng.gen::<[u8; 32]>()))
}
/// From secret asymmetric key. Fails if secret is invalid.
@@ -61,7 +62,7 @@ impl Key {
/// From raw symmetric key.
pub fn from_raw_symmetric(key: [u8; AES_KEY_LEN]) -> Self {
Key::Symmetric(key)
Key::Symmetric(Memzero::from(key))
}
/// Get a handle to the public key if this is an asymmetric key.
@@ -177,7 +178,7 @@ mod tests {
#[test]
fn rejects_invalid_secret() {
let bad_secret = ::ethkey::Secret::from_slice(&[0xff; 32]);
let bad_secret = ::ethkey::Secret::from([0xff; 32]);
assert!(Key::from_secret(bad_secret).is_err());
}

View File

@@ -28,6 +28,7 @@ use jsonrpc_pubsub::{Session, PubSubMetadata, SubscriptionId};
use jsonrpc_macros::pubsub;
use ethereum_types::H256;
use mem::Memzero;
use parking_lot::RwLock;
use self::filter::Filter;
@@ -286,7 +287,7 @@ impl<P: PoolHandle + 'static, M: Send + Sync + 'static> Whisper for WhisperClien
let mut rng = OsRng::new()
.map_err(|_| whisper_error("unable to acquire secure randomness"))?;
let key = rng.gen();
let key = Memzero::from(rng.gen::<[u8; 32]>());
if req.topics.is_empty() {
return Err(whisper_error("must supply at least one topic for broadcast message"));
}