diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml index 4169c55..7f38a86 100644 --- a/x25519-dalek/Cargo.toml +++ b/x25519-dalek/Cargo.toml @@ -41,7 +41,7 @@ features = ["getrandom", "reusable_secrets", "serde", "static_secrets"] curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false } rand_core = { version = "0.6", default-features = false } serde = { version = "1", default-features = false, optional = true, features = ["derive"] } -zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] } +zeroize = { version = "1", default-features = false, optional = true } [dev-dependencies] bincode = "1" diff --git a/x25519-dalek/src/x25519.rs b/x25519-dalek/src/x25519.rs index 6ee76eb..cdbc025 100644 --- a/x25519-dalek/src/x25519.rs +++ b/x25519-dalek/src/x25519.rs @@ -29,7 +29,6 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; /// (in this crate) does *not* automatically happen, but either must be derived /// for Drop or explicitly called. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "zeroize", derive(Zeroize))] #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] pub struct PublicKey(pub(crate) MontgomeryPoint); @@ -62,6 +61,13 @@ impl AsRef<[u8]> for PublicKey { } } +#[cfg(feature = "zeroize")] +impl Zeroize for PublicKey { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + /// A short-lived Diffie-Hellman secret key that can only be used to compute a single /// [`SharedSecret`]. /// @@ -70,7 +76,6 @@ impl AsRef<[u8]> for PublicKey { /// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be /// generated from fresh randomness where the compiler statically checks that the resulting /// secret is used at most once. -#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))] pub struct EphemeralSecret(pub(crate) [u8; 32]); impl EphemeralSecret { @@ -111,6 +116,23 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { } } +impl Drop for EphemeralSecret { + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + self.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl Zeroize for EphemeralSecret { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for EphemeralSecret {} + /// A Diffie-Hellman secret key which may be used more than once, but is /// purposefully not serialiseable in order to discourage key-reuse. This is /// implemented to facilitate protocols such as Noise (e.g. Noise IK key usage, @@ -130,7 +152,6 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { /// secret keys are never reused, which can have very serious security /// implications for many protocols. #[cfg(feature = "reusable_secrets")] -#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))] #[derive(Clone)] pub struct ReusableSecret(pub(crate) [u8; 32]); @@ -174,6 +195,24 @@ impl<'a> From<&'a ReusableSecret> for PublicKey { } } +#[cfg(feature = "reusable_secrets")] +impl Drop for ReusableSecret { + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + self.zeroize(); + } +} + +#[cfg(all(feature = "reusable_secrets", feature = "zeroize"))] +impl Zeroize for ReusableSecret { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +#[cfg(all(feature = "reusable_secrets", feature = "zeroize"))] +impl ZeroizeOnDrop for ReusableSecret {} + /// A Diffie-Hellman secret key that can be used to compute multiple [`SharedSecret`]s. /// /// This type is identical to the [`EphemeralSecret`] type, except that the @@ -190,7 +229,6 @@ impl<'a> From<&'a ReusableSecret> for PublicKey { /// implications for many protocols. #[cfg(feature = "static_secrets")] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))] #[derive(Clone)] pub struct StaticSecret([u8; 32]); @@ -263,11 +301,28 @@ impl AsRef<[u8]> for StaticSecret { } } +#[cfg(feature = "static_secrets")] +impl Drop for StaticSecret { + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + self.zeroize(); + } +} + +#[cfg(all(feature = "static_secrets", feature = "zeroize"))] +impl Zeroize for StaticSecret { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +#[cfg(all(feature = "static_secrets", feature = "zeroize"))] +impl ZeroizeOnDrop for StaticSecret {} + /// The result of a Diffie-Hellman key exchange. /// /// Each party computes this using their [`EphemeralSecret`] or [`StaticSecret`] and their /// counterparty's [`PublicKey`]. -#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))] pub struct SharedSecret(pub(crate) MontgomeryPoint); impl SharedSecret { @@ -330,6 +385,23 @@ impl AsRef<[u8]> for SharedSecret { } } +impl Drop for SharedSecret { + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + self.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl Zeroize for SharedSecret { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for SharedSecret {} + /// The bare, byte-oriented x25519 function, exactly as specified in RFC7748. /// /// This can be used with [`X25519_BASEPOINT_BYTES`] for people who