Skip to content

Commit

Permalink
Merge pull request #406 from iotaledger/security/clear-mnemonic-from-…
Browse files Browse the repository at this point in the history
…bip39-procedure

Security/clear mnemonic from bip39 procedure
  • Loading branch information
felsweg-iota authored Jul 15, 2022
2 parents e9c3ebc + 9a85cab commit e4162c9
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changes/bip39clear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"iota-stronghold" : patch
---

Bip39 mnemonic will now be cleared before the procedure will be dropped
33 changes: 31 additions & 2 deletions client/src/procedures/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crypto::{
use engine::runtime::memories::buffer::{Buffer, Ref};
use serde::{Deserialize, Serialize};
use stronghold_utils::GuardDebug;
use zeroize::Zeroize;

/// Enum that wraps all cryptographic procedures that are supported by Stronghold.
///
Expand Down Expand Up @@ -360,9 +361,11 @@ impl GenerateSecret for BIP39Generate {
let mnemonic = bip39::wordlist::encode(&entropy, &wordlist).unwrap();

let mut seed = [0u8; 64];
let passphrase = self.passphrase.unwrap_or_else(|| "".into());
let mut passphrase = self.passphrase.clone().unwrap_or_else(|| "".into());
bip39::mnemonic_to_seed(&mnemonic, &passphrase, &mut seed);

passphrase.zeroize();

Ok(Products {
secret: seed.to_vec(),
output: mnemonic,
Expand All @@ -374,6 +377,12 @@ impl GenerateSecret for BIP39Generate {
}
}

impl Drop for BIP39Generate {
fn drop(&mut self) {
self.passphrase.zeroize();
}
}

/// Use a BIP39 mnemonic sentence (optionally protected by a passphrase) to create or recover
/// a BIP39 seed and store it in the `output` location
#[derive(Debug, Clone, Serialize, Deserialize)]
Expand All @@ -388,8 +397,12 @@ impl GenerateSecret for BIP39Recover {

fn generate(self) -> Result<Products<Self::Output>, FatalProcedureError> {
let mut seed = [0u8; 64];
let passphrase = self.passphrase.unwrap_or_else(|| "".into());
let mut passphrase = self.passphrase.clone().unwrap_or_else(|| "".into());
bip39::mnemonic_to_seed(&self.mnemonic, &passphrase, &mut seed);

// explicitly clear passphrase
passphrase.zeroize();

Ok(Products {
secret: seed.to_vec(),
output: (),
Expand All @@ -401,6 +414,15 @@ impl GenerateSecret for BIP39Recover {
}
}

impl Drop for BIP39Recover {
fn drop(&mut self) {
self.mnemonic.zeroize();
if let Some(ref mut p) = &mut self.passphrase {
p.zeroize();
}
}
}

/// Generate a raw SLIP10 seed of the specified size (in bytes, defaults to 64 bytes/512 bits) and store it in
/// the `output` location
///
Expand Down Expand Up @@ -745,6 +767,13 @@ impl GenerateSecret for Pbkdf2Hmac {
}
}

impl Drop for Pbkdf2Hmac {
fn drop(&mut self) {
self.password.zeroize();
self.salt.zeroize();
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AeadEncrypt {
pub cipher: AeadCipher,
Expand Down
35 changes: 35 additions & 0 deletions client/src/tests/procedure_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,3 +769,38 @@ async fn usecase_move_record() -> Result<(), Box<dyn std::error::Error>> {

Ok(())
}

#[tokio::test]
async fn test_bip39_recover_zeroize() -> Result<(), Box<dyn std::error::Error>> {
let client_path = "client-path";
let vault_path = b"vault-path";
let record_path = b"record_path";
let location_a = Location::const_generic(vault_path.to_vec(), record_path.to_vec());
let location_b = Location::const_generic(vault_path.to_vec(), record_path.to_vec());
let passphrase = "PASSPHRASEPASSHRASE".to_string();

let stronghold = Stronghold::default();

let client = stronghold.create_client(client_path)?;

let bip39_generate = BIP39Generate {
language: MnemonicLanguage::English,
output: location_a,
passphrase: Some(passphrase.clone()),
};

let mnemonic = client.execute_procedure(bip39_generate)?;

let bip39_recover = BIP39Recover {
passphrase: Some(passphrase),
mnemonic,
output: location_b,
};

let pid = std::process::id();

let result = client.execute_procedure(bip39_recover);
assert!(result.is_ok());

Ok(())
}

0 comments on commit e4162c9

Please sign in to comment.