Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

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

Merged
merged 5 commits into from
Apr 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 57 additions & 50 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ migration = { path = "util/migration" }
kvdb = { path = "util/kvdb" }
kvdb-rocksdb = { path = "util/kvdb-rocksdb" }
journaldb = { path = "util/journaldb" }
mem = { path = "util/mem" }

parity-dapps = { path = "dapps", optional = true }
ethcore-secretstore = { path = "secret_store", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/snapshot/tests/proof_of_authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const TRANSITION_BLOCK_1: usize = 2; // block at which the contract becomes acti
const TRANSITION_BLOCK_2: usize = 10; // block at which the second contract activates.

macro_rules! secret {
($e: expr) => { Secret::from_slice(&$crate::hash::keccak($e)) }
($e: expr) => { Secret::from($crate::hash::keccak($e).0) }
}

lazy_static! {
Expand Down
2 changes: 1 addition & 1 deletion ethcore/transaction/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl HeapSizeOf for Transaction {
impl From<ethjson::state::Transaction> for SignedTransaction {
fn from(t: ethjson::state::Transaction) -> Self {
let to: Option<ethjson::hash::Address> = t.to.into();
let secret = t.secret.map(|s| Secret::from_slice(&s.0));
let secret = t.secret.map(|s| Secret::from(s.0));
let tx = Transaction {
nonce: t.nonce.into(),
gas_price: t.gas_price.into(),
Expand Down
1 change: 1 addition & 0 deletions ethkey/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
ethereum-types = "0.3"
lazy_static = "1.0"
log = "0.3"
mem = { path = "../util/mem" }
parity-wordlist = "1.2"
rand = "0.4"
rust-crypto = "0.2"
Expand Down
4 changes: 2 additions & 2 deletions ethkey/src/extended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl ExtendedSecret {
pub fn derive<T>(&self, index: Derivation<T>) -> ExtendedSecret where T: Label {
let (derived_key, next_chain_code) = derivation::private(*self.secret, self.chain_code, index);

let derived_secret = Secret::from_slice(&*derived_key);
let derived_secret = Secret::from(derived_key.0);

ExtendedSecret::with_code(derived_secret, next_chain_code)
}
Expand Down Expand Up @@ -399,7 +399,7 @@ mod tests {

fn test_extended<F>(f: F, test_private: H256) where F: Fn(ExtendedSecret) -> ExtendedSecret {
let (private_seed, chain_code) = master_chain_basic();
let extended_secret = ExtendedSecret::with_code(Secret::from_slice(&*private_seed), chain_code);
let extended_secret = ExtendedSecret::with_code(Secret::from(private_seed.0), chain_code);
let derived = f(extended_secret);
assert_eq!(**derived.as_raw(), test_private);
}
Expand Down
1 change: 1 addition & 0 deletions ethkey/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ extern crate byteorder;
extern crate crypto as rcrypto;
extern crate edit_distance;
extern crate ethereum_types;
extern crate mem;
extern crate parity_wordlist;
extern crate rand;
extern crate rustc_hex;
Expand Down
30 changes: 21 additions & 9 deletions ethkey/src/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ use std::fmt;
use std::ops::Deref;
use std::str::FromStr;
use rustc_hex::ToHex;
use secp256k1::constants::{SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE};
use secp256k1::key;
use ethereum_types::H256;
use mem::Memzero;
use {Error, SECP256K1};

#[derive(Clone, PartialEq, Eq)]
pub struct Secret {
inner: H256,
inner: Memzero<H256>,
}

impl ToHex for Secret {
fn to_hex(&self) -> String {
format!("{:x}", self.inner)
format!("{:x}", *self.inner)
}
}

Expand All @@ -52,17 +54,19 @@ impl fmt::Display for Secret {
}

impl Secret {
pub fn from_slice(key: &[u8]) -> Self {
assert_eq!(32, key.len(), "Caller should provide 32-byte length slice");

/// Creates a `Secret` from the given slice, returning `None` if the slice length != 32.
pub fn from_slice(key: &[u8]) -> Option<Self> {
if key.len() != 32 {
return None
}
let mut h = H256::default();
h.copy_from_slice(&key[0..32]);
Secret { inner: h }
Some(Secret { inner: Memzero::from(h) })
}

/// Creates zero key, which is invalid for crypto operations, but valid for math operation.
pub fn zero() -> Self {
Secret { inner: Default::default() }
Secret { inner: Memzero::from(H256::default()) }
}

/// Imports and validates the key.
Expand Down Expand Up @@ -208,9 +212,15 @@ impl FromStr for Secret {
}
}

impl From<[u8; 32]> for Secret {
fn from(k: [u8; 32]) -> Self {
Secret { inner: Memzero::from(H256(k)) }
}
}

impl From<H256> for Secret {
fn from(s: H256) -> Self {
Secret::from_slice(&s)
s.0.into()
}
}

Expand All @@ -222,7 +232,9 @@ impl From<&'static str> for Secret {

impl From<key::SecretKey> for Secret {
fn from(key: key::SecretKey) -> Self {
Self::from_slice(&key[0..32])
let mut a = [0; SECP256K1_SECRET_KEY_SIZE];
a.copy_from_slice(&key[0 .. SECP256K1_SECRET_KEY_SIZE]);
a.into()
}
}

Expand Down
2 changes: 1 addition & 1 deletion rpc/src/v1/tests/mocked/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ fn rpc_eth_submit_hashrate() {
fn rpc_eth_sign() {
let tester = EthTester::default();

let account = tester.accounts_provider.insert_account(Secret::from_slice(&[69u8; 32]), "abcd").unwrap();
let account = tester.accounts_provider.insert_account(Secret::from([69u8; 32]), "abcd").unwrap();
tester.accounts_provider.unlock_account_permanently(account, "abcd".into()).unwrap();
let _message = "0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f".from_hex().unwrap();

Expand Down
2 changes: 1 addition & 1 deletion rpc/src/v1/tests/mocked/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ fn should_sign_if_account_is_unlocked() {
// given
let tester = eth_signing();
let data = vec![5u8];
let acc = tester.accounts.insert_account(Secret::from_slice(&[69u8; 32]), "test").unwrap();
let acc = tester.accounts.insert_account(Secret::from([69u8; 32]), "test").unwrap();
tester.accounts.unlock_account_permanently(acc, "test".into()).unwrap();

// when
Expand Down
8 changes: 4 additions & 4 deletions secret_store/src/key_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,8 @@ pub mod tests {
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 = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &combined_signature).unwrap();
let signature_c = Secret::from_slice(&combined_signature[..32]);
let signature_s = Secret::from_slice(&combined_signature[32..]);
let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap();
let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap();

// check signature
assert_eq!(math::verify_schnorr_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
Expand Down Expand Up @@ -492,8 +492,8 @@ pub mod tests {
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 = crypto::ecies::decrypt(&requestor_secret, &crypto::DEFAULT_MAC, &combined_signature).unwrap();
let signature_c = Secret::from_slice(&combined_signature[..32]);
let signature_s = Secret::from_slice(&combined_signature[32..]);
let signature_c = Secret::from_slice(&combined_signature[..32]).unwrap();
let signature_s = Secret::from_slice(&combined_signature[32..]).unwrap();

// check signature
assert_eq!(math::verify_schnorr_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1272,7 +1272,7 @@ mod tests {
use crypto::DEFAULT_MAC;
use crypto::ecies::decrypt;
let decrypt_shadows: Vec<_> = decrypted_secret.decrypt_shadows.unwrap().into_iter()
.map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()))
.map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap())
.collect();
let decrypted_secret = math::decrypt_with_shadow_coefficients(decrypted_secret.decrypted_secret, decrypted_secret.common_point.unwrap(), decrypt_shadows).unwrap();
assert_eq!(decrypted_secret, SECRET_PLAIN.into());
Expand Down Expand Up @@ -1418,7 +1418,7 @@ mod tests {
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());
let decrypt_shadows: Vec<_> = result.decrypt_shadows.unwrap().into_iter()
.map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()))
.map(|c| Secret::from_slice(&decrypt(key_pair.secret(), &DEFAULT_MAC, &c).unwrap()).unwrap())
.collect();
let decrypted_secret = math::decrypt_with_shadow_coefficients(result.decrypted_secret, result.common_point.unwrap(), decrypt_shadows).unwrap();
assert_eq!(decrypted_secret, SECRET_PLAIN.into());
Expand Down
4 changes: 2 additions & 2 deletions secret_store/src/key_server_cluster/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn zero_scalar() -> Secret {
pub fn to_scalar(hash: H256) -> Result<Secret, Error> {
let scalar: U256 = hash.into();
let scalar: H256 = (scalar % math::curve_order()).into();
let scalar = Secret::from_slice(&*scalar);
let scalar = Secret::from(scalar.0);
scalar.check_validity()?;
Ok(scalar)
}
Expand Down Expand Up @@ -697,7 +697,7 @@ pub mod tests {
// === required to generate shares of inv(x) mod r with out revealing
// === any information about x or inv(x).
// === https://www.researchgate.net/publication/280531698_Robust_Threshold_Elliptic_Curve_Digital_Signature

// generate shared random secret e for given t
let n = artifacts.id_numbers.len();
assert!(t * 2 + 1 <= n);
Expand Down
6 changes: 6 additions & 0 deletions util/mem/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "mem"
version = "0.1.0"
authors = ["Parity Technologies <[email protected]>"]

[dependencies]
57 changes: 57 additions & 0 deletions util/mem/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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 std::ops::{Deref, DerefMut};
use std::ptr;

/// Wrapper to zero out memory when dropped.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Memzero<T: AsMut<[u8]>> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not replace the content in place and just require that T: Default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand. Could you explain this a more fully please?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nvm, actually it's better with AsMut if we have all the supported structs.

mem: T,
}

impl<T: AsMut<[u8]>> From<T> for Memzero<T> {
fn from(mem: T) -> Memzero<T> {
Memzero { mem }
}
}

impl<T: AsMut<[u8]>> Drop for Memzero<T> {
fn drop(&mut self) {
let n = self.mem.as_mut().len();
let p = self.mem.as_mut().as_mut_ptr();
for i in 0..n {
unsafe {
ptr::write_volatile(p.offset(i as isize), 0)
}
}
}
}

impl<T: AsMut<[u8]>> Deref for Memzero<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.mem
}
}

impl<T: AsMut<[u8]>> DerefMut for Memzero<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.mem
}
}

1 change: 1 addition & 0 deletions whisper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions whisper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading