Skip to content

key-wallet: ExtendedBLSPrivKey and ExtendedEd25519PrivKey are not zeroized on drop #858

Closed

Description

@QuantumExplorer

Summary

In key-wallet, the two non-secp256k1 extended private key types hold raw secret key material but have no Drop / Zeroize implementation, so their secret bytes are left in freed heap when the value is dropped. Their secp256k1 sibling types (ExtendedPrivKey, RootExtendedPrivKey) do zeroize on drop, so this is an inconsistency in an otherwise disciplined secret-handling story.

Observed at rev 647fa9820f3614090e4e5f5f2b709961d68e538b.

Details

ExtendedBLSPrivKey — key-wallet/src/derivation_bls_bip32.rs

#[derive(Clone)]
pub struct ExtendedBLSPrivKey {
    pub network: Network,
    pub depth: u8,
    pub parent_fingerprint: Fingerprint,
    pub child_number: ChildNumber,
    pub private_key: BlsSecretKey<Bls12381G2Impl>,
    // ...
}

No impl Drop and no impl Zeroize for this type.

ExtendedEd25519PrivKey — key-wallet/src/derivation_slip10.rs

#[derive(Clone, PartialEq, Eq)]
pub struct ExtendedEd25519PrivKey {
    // ...
    pub private_key: [u8; 32],
}

No impl Drop and no impl Zeroize.

Contrast with the secp256k1 types (correct behavior)

ExtendedPrivKey (key-wallet/src/bip32.rs) and RootExtendedPrivKey (key-wallet/src/wallet/root_extended_keys.rs) both hand-implement Zeroize (calling SecretKey::non_secure_erase() on the key and zeroizing the chain code) plus an impl Drop that calls zeroize(). So an intermediate secp256k1 xpriv created during path derivation is wiped automatically on scope exit; the BLS and Ed25519 equivalents are not.

Impact

Any code that derives BLS operator keys or Ed25519 platform-node keys — e.g. masternode provider-operator key material and platform node keys — builds intermediate ExtendedBLSPrivKey / ExtendedEd25519PrivKey masters and children. Those secret bytes linger in reclaimed memory after the derivation call returns, until overwritten by later allocations. Downstream callers that carefully wrap the final scalar in Zeroizing still can't wipe these library-internal intermediates.

(Surfaced while auditing the memory-safety of BLS/Ed25519 provider-key derivation in dashpay/platform.)

Suggested fix

Mirror the secp256k1 types: implement Zeroize for both (BlsSecretKey — zeroize/overwrite its scalar bytes; [u8; 32] — zeroize() directly, plus the derivation metadata as the sibling types do), and add an impl Drop calling zeroize(). Note #[derive(Zeroize)] won't work directly for the BLS type if BlsSecretKey lacks a Zeroize impl (same reason the secp256k1 types are hand-written — SecretKey only exposes non_secure_erase()), so a manual impl is likely needed.

Note ExtendedEd25519PrivKey also derives PartialEq, Eq over a raw [u8; 32] secret, i.e. non-constant-time secret comparison — worth considering a constant-time Eq while touching this type, though that's secondary to the zeroization gap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions