From 3ff738c529260077ff71e77572d37c1dae809d80 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Tue, 22 Sep 2020 14:10:19 -0400 Subject: [PATCH 1/3] Mnemonic and seed implement zeroize. --- Cargo.toml | 1 + src/language.rs | 6 ++++-- src/mnemonic.rs | 16 ++++++++++++---- src/seed.rs | 6 +++++- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c864faf..555712b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ pbkdf2 = { version = "0.3.0", default-features = false } rand = "0.7.2" once_cell = { version = "1.2.0", features = [ "parking_lot" ] } unicode-normalization = "0.1.12" +zeroize = { version = "1.1.1", features = ["zeroize_derive"] } [dev-dependencies] hex = "0.4.0" diff --git a/src/language.rs b/src/language.rs index 49e5ca6..76e738a 100644 --- a/src/language.rs +++ b/src/language.rs @@ -2,6 +2,7 @@ use crate::error::ErrorKind; use crate::util::{Bits, Bits11}; use failure::Error; use rustc_hash::FxHashMap; +use zeroize::Zeroize; pub struct WordMap { inner: FxHashMap<&'static str, Bits11>, @@ -32,7 +33,7 @@ impl WordList { let count = self.inner[start..].iter() .take_while(|word| word.starts_with(prefix)) .count(); - + &self.inner[start..start + count] } } @@ -113,7 +114,8 @@ mod lazy { /// /// [Mnemonic]: ./mnemonic/struct.Mnemonic.html /// [Seed]: ./seed/struct.Seed.html -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Zeroize)] +#[zeroize(drop)] pub enum Language { English, #[cfg(feature = "chinese-simplified")] diff --git a/src/mnemonic.rs b/src/mnemonic.rs index 9b676fe..ebd4c82 100644 --- a/src/mnemonic.rs +++ b/src/mnemonic.rs @@ -1,6 +1,8 @@ use std::fmt; use failure::Error; +use std::mem; use unicode_normalization::UnicodeNormalization; +use zeroize::Zeroize; use crate::crypto::{gen_random_bytes, sha256_first_byte}; use crate::error::ErrorKind; use crate::language::Language; @@ -22,6 +24,8 @@ use crate::util::{checksum, BitWriter, IterExt}; /// but beware that the entropy value is **not the same thing** as an HD wallet seed, and should /// *never* be used that way. /// +/// [`Mnemonic`][Mnemonic] implements [`Zeroize`][Zeroize], so it's bytes will be zeroed when it's dropped. +/// /// [Mnemonic]: ./mnemonic/struct.Mnemonic.html /// [Mnemonic::new()]: ./mnemonic/struct.Mnemonic.html#method.new /// [Mnemonic::from_phrase()]: ./mnemonic/struct.Mnemonic.html#method.from_phrase @@ -30,7 +34,8 @@ use crate::util::{checksum, BitWriter, IterExt}; /// [Seed::new()]: ./seed/struct.Seed.html#method.new /// [Seed::as_bytes()]: ./seed/struct.Seed.html#method.as_bytes /// -#[derive(Clone)] +#[derive(Clone, Zeroize)] +#[zeroize(drop)] pub struct Mnemonic { phrase: String, lang: Language, @@ -221,9 +226,12 @@ impl Mnemonic { /// Consume the `Mnemonic` and return the phrase as a `String`. /// - /// This operation doesn't perform any allocations. - pub fn into_phrase(self) -> String { - self.phrase + /// This operation creates an empty string and swaps values with the mnemonic's phrase. This + /// allows `Mnemonic` to implement `Drop`, while still returning the phrase. + pub fn into_phrase(mut self) -> String { + let mut phrase = String::new(); + mem::swap(&mut self.phrase, &mut phrase); + phrase } /// Get the original entropy value of the mnemonic phrase as a slice. diff --git a/src/seed.rs b/src/seed.rs index babba88..e2bdae7 100644 --- a/src/seed.rs +++ b/src/seed.rs @@ -1,5 +1,6 @@ use std::fmt; use unicode_normalization::UnicodeNormalization; +use zeroize::Zeroize; use crate::crypto::pbkdf2; use crate::mnemonic::Mnemonic; @@ -13,11 +14,14 @@ use crate::mnemonic::Mnemonic; /// HD wallet addresses using another crate (deriving HD wallet addresses is outside the scope of this /// crate and the BIP39 standard). /// +/// [`Seed`][Seed] implements [`Zeroize`][Zeroize], so it's bytes will be zeroed when it's dropped. +/// /// [Mnemonic]: ./mnemonic/struct.Mnemonic.html /// [Seed]: ./seed/struct.Seed.html /// [Seed::as_bytes()]: ./seed/struct.Seed.html#method.as_bytes -#[derive(Clone)] +#[derive(Clone, Zeroize)] +#[zeroize(drop)] pub struct Seed { bytes: Vec, } From 4d5e542b39008678d07df9cf1e4cd670d92ce179 Mon Sep 17 00:00:00 2001 From: realbigsean Date: Thu, 24 Sep 2020 21:15:20 -0400 Subject: [PATCH 2/3] Comment update. --- src/mnemonic.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mnemonic.rs b/src/mnemonic.rs index ebd4c82..4ff911b 100644 --- a/src/mnemonic.rs +++ b/src/mnemonic.rs @@ -225,10 +225,9 @@ impl Mnemonic { } /// Consume the `Mnemonic` and return the phrase as a `String`. - /// - /// This operation creates an empty string and swaps values with the mnemonic's phrase. This - /// allows `Mnemonic` to implement `Drop`, while still returning the phrase. pub fn into_phrase(mut self) -> String { + // Create an empty string and swap values with the mnemonic's phrase. + // This allows `Mnemonic` to implement `Drop`, while still returning the phrase. let mut phrase = String::new(); mem::swap(&mut self.phrase, &mut phrase); phrase From 6d3e8f356b29ea2cc98278cbac02c3432a875b86 Mon Sep 17 00:00:00 2001 From: Maciej Hirsz <1096222+maciejhirsz@users.noreply.github.com> Date: Mon, 9 Nov 2020 09:28:48 +0100 Subject: [PATCH 3/3] mem::swap -> mem::replace --- src/mnemonic.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mnemonic.rs b/src/mnemonic.rs index 4ff911b..12ff4c2 100644 --- a/src/mnemonic.rs +++ b/src/mnemonic.rs @@ -228,8 +228,7 @@ impl Mnemonic { pub fn into_phrase(mut self) -> String { // Create an empty string and swap values with the mnemonic's phrase. // This allows `Mnemonic` to implement `Drop`, while still returning the phrase. - let mut phrase = String::new(); - mem::swap(&mut self.phrase, &mut phrase); + mem::replace(&mut self.phrase, String:new()); phrase }