Skip to content

Commit

Permalink
all: best-effort at zeroization of secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
conradoplg committed Feb 20, 2025
1 parent df39100 commit 58b9e6d
Show file tree
Hide file tree
Showing 13 changed files with 53 additions and 13 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ zcash_keys = "0.6.0"
zcash_primitives = "0.21.0"
zcash_proofs = "0.21.0"
zcash_protocol = "0.4.3"
zeroize = "1.8.1"

[patch.crates-io]
# TODO: remove this when https://github.com/zcash/orchard/issues/430 is fully
Expand Down
1 change: 1 addition & 0 deletions dkg/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ xeddsa = { workspace = true }
reqwest = { workspace = true, features = ["json", "rustls-tls-native-roots"] }
tokio = { workspace = true, features = ["full"] }
snow = { workspace = true }
zeroize = { workspace = true, features = ["serde", "zeroize_derive"] }

[features]
default = []
7 changes: 6 additions & 1 deletion dkg/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::rc::Rc;

use clap::Parser;
use frost_core::{Ciphersuite, Identifier};
use zeroize::{Zeroize, ZeroizeOnDrop};

#[derive(Parser, Debug, Default)]
#[command(author, version, about, long_about = None)]
Expand All @@ -10,7 +11,7 @@ pub struct Args {
pub ciphersuite: String,
}

#[derive(Clone)]
#[derive(Clone, Zeroize)]
pub struct ProcessedArgs<C: Ciphersuite> {
/// CLI mode. If enabled, it will prompt for inputs from stdin
/// and print values to stdout, ignoring other flags.
Expand Down Expand Up @@ -38,6 +39,7 @@ pub struct ProcessedArgs<C: Ciphersuite> {
// using `fn()` would preclude using closures and using generics would
// require a lot of code change for something simple.
#[allow(clippy::type_complexity)]
#[zeroize(skip)]
pub comm_participant_pubkey_getter: Option<Rc<dyn Fn(&Vec<u8>) -> Option<Vec<u8>>>>,

/// The threshold to use for the shares
Expand All @@ -51,9 +53,12 @@ pub struct ProcessedArgs<C: Ciphersuite> {
pub participants: Vec<Vec<u8>>,

/// Identifier to use for the participant. Only needed for CLI mode.
#[zeroize(skip)]
pub identifier: Option<Identifier<C>>,
}

impl<C> ZeroizeOnDrop for ProcessedArgs<C> where C: Ciphersuite {}

impl<C> ProcessedArgs<C>
where
C: Ciphersuite,
Expand Down
2 changes: 2 additions & 0 deletions dkg/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use reddsa::frost::redpallas::keys::EvenY;
use std::collections::HashMap;
use std::error::Error;
use std::io::{BufRead, Write};
use zeroize::Zeroizing;

use crate::args::ProcessedArgs;
use crate::comms::cli::CLIComms;
Expand Down Expand Up @@ -102,6 +103,7 @@ pub async fn cli_for_processed_args<C: Ciphersuite + 'static + MaybeIntoEvenY>(

let (round2_secret_package, round2_packages) =
frost::keys::dkg::part2(round1_secret_package, &received_round1_packages)?;
let round2_secret_package = Zeroizing::new(round2_secret_package);

let received_round2_packages = comms
.get_round2_packages(input, logger, round2_packages)
Expand Down
1 change: 1 addition & 0 deletions frost-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ rand = { workspace = true }
stable-eyre = { workspace = true }
itertools = { workspace = true }
xeddsa = { workspace = true }
zeroize = { workspace = true, features = ["serde", "zeroize_derive"] }
20 changes: 16 additions & 4 deletions frost-client/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::{
use eyre::{eyre, OptionExt};
use frost_core::{Ciphersuite, Identifier};
use serde::{Deserialize, Serialize};
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};

use crate::{ciphersuite_helper::ciphersuite_helper, contact::Contact, write_atomic};

Expand All @@ -29,6 +30,14 @@ pub struct Config {
pub group: BTreeMap<String, Group>,
}

impl Zeroize for Config {
fn zeroize(&mut self) {
self.group.iter_mut().for_each(|(_, g)| g.zeroize());
}
}

impl ZeroizeOnDrop for Config {}

impl Config {
pub fn contact_by_pubkey(&self, pubkey: &[u8]) -> Result<Contact, Box<dyn Error>> {
if Some(pubkey) == self.communication_key.as_ref().map(|c| c.pubkey.as_slice()) {
Expand All @@ -48,7 +57,7 @@ impl Config {
}

/// The communication key pair for the user.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, ZeroizeOnDrop)]
pub struct CommunicationKey {
/// The private key.
#[serde(
Expand All @@ -65,7 +74,7 @@ pub struct CommunicationKey {
}

/// A FROST group the user belongs to.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, Zeroize)]
pub struct Group {
/// A human-readable description of the group to make it easier to select
/// groups
Expand All @@ -87,9 +96,12 @@ pub struct Group {
/// The default server the participants are using, if any.
pub server_url: Option<String>,
/// The group participants, keyed by hex-encoded identifier
#[zeroize(skip)]
pub participant: BTreeMap<String, Participant>,
}

impl ZeroizeOnDrop for Group {}

impl Group {
/// Returns a human-readable summary of the contact; used when it is
/// printed to the terminal.
Expand Down Expand Up @@ -176,7 +188,7 @@ impl Config {
..Default::default()
});
}
let bytes = std::fs::read(&path)?;
let bytes = Zeroizing::new(std::fs::read(&path)?);
let s = str::from_utf8(&bytes)?;
let mut config: Config = toml::from_str(s)?;
config.path = Some(path);
Expand All @@ -185,7 +197,7 @@ impl Config {

/// Write the config to path it was loaded from.
pub fn write(&self) -> Result<(), Box<dyn Error>> {
let s = toml::to_string_pretty(self)?;
let s = Zeroizing::new(toml::to_string_pretty(self)?);
let bytes = s.as_bytes();
Ok(write_atomic::write_file(
self.path
Expand Down
3 changes: 2 additions & 1 deletion frost-client/src/contact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ pub(crate) fn export(args: &Command) -> Result<(), Box<dyn Error>> {
pubkey: config
.communication_key
.ok_or(eyre!("pubkey not generated yet"))?
.pubkey,
.pubkey
.clone(),
};

eprintln!("Exporting this information:");
Expand Down
8 changes: 6 additions & 2 deletions frost-client/src/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use dkg::cli::MaybeIntoEvenY;
use frost_core::Ciphersuite;
use frost_ed25519::Ed25519Sha512;
use reqwest::Url;
use zeroize::Zeroizing;

use crate::{
args::Command,
Expand Down Expand Up @@ -57,7 +58,8 @@ pub(crate) async fn dkg_for_ciphersuite<C: Ciphersuite + MaybeIntoEvenY + 'stati
.communication_key
.clone()
.ok_or_eyre("user not initialized")?
.pubkey;
.pubkey
.clone();

let mut participants = participants
.iter()
Expand All @@ -83,7 +85,8 @@ pub(crate) async fn dkg_for_ciphersuite<C: Ciphersuite + MaybeIntoEvenY + 'stati
.communication_key
.clone()
.ok_or_eyre("user not initialized")?
.privkey,
.privkey
.clone(),
),
comm_pubkey: Some(comm_pubkey),
comm_participant_pubkey_getter: Some(Rc::new(move |participant_pubkey| {
Expand All @@ -101,6 +104,7 @@ pub(crate) async fn dkg_for_ciphersuite<C: Ciphersuite + MaybeIntoEvenY + 'stati
// Generate key shares
let (key_package, public_key_package, pubkey_map) =
dkg::cli::cli_for_processed_args::<C>(dkg_config, &mut input, &mut output).await?;
let key_package = Zeroizing::new(key_package);

// Reverse pubkey_map
let pubkey_map = pubkey_map
Expand Down
4 changes: 3 additions & 1 deletion frost-client/src/trusted_dealer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rand::thread_rng;
use frost_core::{keys::KeyPackage, Ciphersuite};
use frost_ed25519::Ed25519Sha512;
use trusted_dealer::MaybeIntoEvenY;
use zeroize::Zeroizing;

use crate::{
args::Command,
Expand Down Expand Up @@ -72,7 +73,8 @@ pub(crate) fn trusted_dealer_for_ciphersuite<C: Ciphersuite + MaybeIntoEvenY + '
let pubkey = config
.communication_key
.ok_or_eyre("config not initialized")?
.pubkey;
.pubkey
.clone();
let participant = Participant {
identifier: identifier.serialize(),
pubkey: pubkey.clone(),
Expand Down
1 change: 1 addition & 0 deletions participant/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ frostd = { workspace = true }
rpassword = { workspace = true }
snow = { workspace = true }
xeddsa = { workspace = true }
zeroize = { workspace = true, features = ["serde", "zeroize_derive"] }

[features]
default = []
6 changes: 5 additions & 1 deletion participant/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use frost_core::{
keys::{KeyPackage, SecretShare},
Ciphersuite,
};
use zeroize::{Zeroize, ZeroizeOnDrop};

use crate::input::read_from_file_or_stdin;

Expand Down Expand Up @@ -45,7 +46,7 @@ pub struct Args {
pub session_id: String,
}

#[derive(Clone)]
#[derive(Clone, Zeroize)]
pub struct ProcessedArgs<C: Ciphersuite> {
/// CLI mode. If enabled, it will prompt for inputs from stdin
/// and print values to stdout, ignoring other flags.
Expand Down Expand Up @@ -82,9 +83,12 @@ pub struct ProcessedArgs<C: Ciphersuite> {
// using `fn()` would preclude using closures and using generics would
// require a lot of code change for something simple.
#[allow(clippy::type_complexity)]
#[zeroize(skip)]
pub comm_coordinator_pubkey_getter: Option<Rc<dyn Fn(&Vec<u8>) -> Option<Vec<u8>>>>,
}

impl<C> ZeroizeOnDrop for ProcessedArgs<C> where C: Ciphersuite {}

impl<C: Ciphersuite + 'static> ProcessedArgs<C> {
/// Create a ProcessedArgs from a Args.
///
Expand Down
8 changes: 5 additions & 3 deletions participant/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use frost_rerandomized::RandomizedCiphersuite;
use rand::thread_rng;
use reddsa::frost::redpallas::PallasBlake2b512;
use std::io::{BufRead, Write};
use zeroize::Zeroizing;

pub async fn cli<C: RandomizedCiphersuite + 'static>(
args: &Args,
Expand All @@ -40,10 +41,11 @@ pub async fn cli_for_processed_args<C: RandomizedCiphersuite + 'static>(

// Round 1

let key_package = pargs.key_package;
let key_package = &pargs.key_package;

let mut rng = thread_rng();
let (nonces, commitments) = generate_nonces_and_commitments(&key_package, &mut rng);
let (nonces, commitments) = generate_nonces_and_commitments(key_package, &mut rng);
let nonces = Zeroizing::new(nonces);

if pargs.cli {
print_values(commitments, logger)?;
Expand Down Expand Up @@ -80,7 +82,7 @@ pub async fn cli_for_processed_args<C: RandomizedCiphersuite + 'static>(
return Err(eyre!("signing cancelled").into());
}

let signature = generate_signature(round_2_config, &key_package, &nonces)?;
let signature = generate_signature(round_2_config, key_package, &nonces)?;

comms
.send_signature_share(*key_package.identifier(), signature)
Expand Down

0 comments on commit 58b9e6d

Please sign in to comment.