From 2625f9005360e73dbef44c10b7f9f1b83319fc45 Mon Sep 17 00:00:00 2001 From: Oleksii Filonenko Date: Tue, 10 Oct 2023 20:14:23 +0300 Subject: [PATCH] feat: securely zero out `SecretKey`s from memory (#1161) Co-authored-by: Ahmed Sagdati <37515857+segfault-magnet@users.noreply.github.com> --- Cargo.toml | 1 + packages/fuels-accounts/Cargo.toml | 1 + packages/fuels-accounts/src/wallet.rs | 13 +++++++++---- packages/fuels-core/Cargo.toml | 1 + .../fuels-core/src/types/transaction_builders.rs | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 21e96446c6..6de72615fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ thiserror = { version = "1.0.47", default-features = false } tokio = { version = "1.31.0", default-features = false } trybuild = "1.0.82" which = { version = "4.4.0", default-features = false } +zeroize = "1.6.0" # Dependencies from the `fuel-core` repository: fuel-core = { version = "0.20.4", default-features = false } diff --git a/packages/fuels-accounts/Cargo.toml b/packages/fuels-accounts/Cargo.toml index f4603e084a..8ec391efd2 100644 --- a/packages/fuels-accounts/Cargo.toml +++ b/packages/fuels-accounts/Cargo.toml @@ -26,6 +26,7 @@ rand = { workspace = true, default-features = false } tai64 = { workspace = true, features = ["serde"] } thiserror = { workspace = true, default-features = false } tokio = { workspace = true, features = ["full"] } +zeroize = { workspace = true, features = ["derive"] } [dev-dependencies] hex = { workspace = true, default-features = false, features = ["std"] } diff --git a/packages/fuels-accounts/src/wallet.rs b/packages/fuels-accounts/src/wallet.rs index 907abc63f1..1c587e3f2a 100644 --- a/packages/fuels-accounts/src/wallet.rs +++ b/packages/fuels-accounts/src/wallet.rs @@ -16,6 +16,7 @@ use fuels_core::{ }; use rand::{CryptoRng, Rng}; use thiserror::Error; +use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::{ accounts_utils::{adjust_inputs, adjust_outputs, calculate_base_amount_with_fee}, @@ -71,8 +72,11 @@ pub struct Wallet { /// A `WalletUnlocked` is equivalent to a [`Wallet`] whose private key is known and stored /// alongside in-memory. Knowing the private key allows a `WalletUlocked` to sign operations, send /// transactions, and more. -#[derive(Clone, Debug)] +/// +/// `private_key` will be zeroed out on calling `lock()` or `drop`ping a `WalletUnlocked`. +#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)] pub struct WalletUnlocked { + #[zeroize(skip)] wallet: Wallet, pub(crate) private_key: SecretKey, } @@ -118,9 +122,10 @@ impl ViewOnlyAccount for Wallet { } impl WalletUnlocked { - /// Lock the wallet by `drop`ping the private key from memory. - pub fn lock(self) -> Wallet { - self.wallet + /// Lock the wallet by securely `zeroize`-ing and `drop`ping the private key from memory. + pub fn lock(mut self) -> Wallet { + self.private_key.zeroize(); + self.wallet.clone() } // NOTE: Rather than providing a `DerefMut` implementation, we wrap the `set_provider` method diff --git a/packages/fuels-core/Cargo.toml b/packages/fuels-core/Cargo.toml index 9afe9a7172..615d9f3d83 100644 --- a/packages/fuels-core/Cargo.toml +++ b/packages/fuels-core/Cargo.toml @@ -28,6 +28,7 @@ serde_json = { workspace = true, default-features = true } sha2 = { workspace = true } thiserror = { workspace = true, default-features = false } uint = { version = "0.9.5", default-features = false } +zeroize = { workspace = true, features = ["derive"] } [dev-dependencies] fuels-macros = { workspace = true } diff --git a/packages/fuels-core/src/types/transaction_builders.rs b/packages/fuels-core/src/types/transaction_builders.rs index 1d58b5bda6..1c9639c43e 100644 --- a/packages/fuels-core/src/types/transaction_builders.rs +++ b/packages/fuels-core/src/types/transaction_builders.rs @@ -11,6 +11,7 @@ use fuel_tx::{ }; use fuel_types::{bytes::padded_len_usize, Bytes32, ChainId, MemLayout, Salt}; use fuel_vm::{checked_transaction::EstimatePredicates, gas::GasCosts}; +use zeroize::{Zeroize, ZeroizeOnDrop}; use super::{chain_info::ChainInfo, node_info::NodeInfo}; use crate::{ @@ -52,8 +53,9 @@ impl NetworkInfo { } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, Zeroize, ZeroizeOnDrop)] struct UnresolvedSignatures { + #[zeroize(skip)] addr_idx_offset_map: HashMap, secret_keys: Vec, }