Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ subtle = { version = "2.6.1", default-features = false }
tiny-keccak = { version = "2.0.2", features = ["sha3", "shake"] }
# aes-gcm >= 0.10.3 fixes RUSTSEC-2023-0096 / CVE-2023-42811.
aes-gcm = { version = "0.10.3", optional = true }
zeroize = { version = "1.7", default-features = false, features = ["derive"], optional = true }

[target.wasm32-unknown-unknown.dependencies]
getrandom = { version = "0.2", features = ["js"] }
Expand All @@ -43,6 +44,7 @@ kv1 = []
waters = []
waters_naccache = []
mkem = ["aes-gcm"]
zeroize = ["dep:zeroize", "pg-curve/zeroize"]

[lib]
bench = false
Expand Down
45 changes: 44 additions & 1 deletion src/ibe/boyen_waters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,15 @@ pub struct PublicKey {
}

/// Secret key parameter generated by the PKG used to extract user secret keys.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct SecretKey {
alpha: Scalar,
t1: Scalar,
Expand All @@ -75,7 +83,15 @@ impl PartialEq for SecretKey {
}

/// Points on the paired curves that form the user secret key.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
Comment thread
dobby-coder[bot] marked this conversation as resolved.
pub struct UserSecretKey {
d: [G2Affine; 5],
}
Expand All @@ -102,7 +118,15 @@ pub struct CipherText {
/// A point on the paired curve that can be encrypted and decrypted.
///
/// You can use the byte representation to derive an AES key.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct SharedSecret(Gt);

/// A message that can be encrypted using the PKE.
Expand Down Expand Up @@ -227,7 +251,7 @@ impl IBE for BoyenWaters {
}
}

/// Decrypt ciphertext to a SharedSecret using a user secret key.
/// Decrypt ciphertext to a message using a user secret key.
fn decrypt(usk: &UserSecretKey, ct: &CipherText) -> Msg {
ct.cprime
+ multi_miller_loop(&[
Expand Down Expand Up @@ -466,4 +490,23 @@ impl Compress for CipherText {
#[cfg(test)]
mod tests {
test_ibe!(BoyenWaters);

#[cfg(feature = "zeroize")]
#[test]
fn shared_secret_zeroize() {
use group::Group;
use zeroize::Zeroize;

let mut rng = rand::thread_rng();
let mut ss = SharedSecret(Gt::random(&mut rng));
let before = ss;

ss.zeroize();
assert_ne!(ss, before, "SharedSecret did not zeroize");

// Zeroization is deterministic: two independently-wiped values match.
let mut ss2 = SharedSecret(Gt::random(&mut rng));
ss2.zeroize();
assert_eq!(ss, ss2, "zeroized SharedSecrets should be identical");
}
}
16 changes: 16 additions & 0 deletions src/ibe/cgw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,15 @@ pub struct PublicKey {

/// Secret key parameter generated by the PKG used to extract user secret keys.
/// Also known as MSK.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct SecretKey {
b: [Scalar; 2],
k: [Scalar; 2],
Expand All @@ -58,7 +66,15 @@ pub struct SecretKey {

/// User secret key. Can be used to decrypt the corresponding ciphertext.
/// Also known as USK_{id}.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct UserSecretKey {
d0: [G2Affine; 2],
d1: [G2Affine; 2],
Expand Down
16 changes: 16 additions & 0 deletions src/ibe/waters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,15 @@ pub struct PublicKey {
}

/// Secret key parameter generated by the PKG used to extract user secret keys.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct SecretKey {
g1prime: G1Affine,
}
Expand All @@ -66,7 +74,15 @@ impl PartialEq for SecretKey {
}

/// Points on the paired curves that form the user secret key.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct UserSecretKey {
d1: G1Affine,
d2: G2Affine,
Expand Down
16 changes: 16 additions & 0 deletions src/ibe/waters_naccache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,15 @@ pub struct PublicKey {
pub struct Identity([Scalar; CHUNKS]);

/// Secret key parameter generated by the PKG used to extract user secret keys.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct SecretKey {
g2prime: G2Affine,
}
Expand All @@ -76,7 +84,15 @@ impl PartialEq for SecretKey {
}

/// Points on the paired curves that form the user secret key.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct UserSecretKey {
d1: G2Affine,
d2: G1Affine,
Expand Down
8 changes: 8 additions & 0 deletions src/kem/cgw_fo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@ pub const USK_BYTES: usize = CPA_USK_BYTES + ID_BYTES;

/// User secret key. Can be used to decaps the corresponding ciphertext.
/// Also known as USK_{id}.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct UserSecretKey {
usk: crate::ibe::cgw::UserSecretKey,
id: Identity,
Expand Down
49 changes: 49 additions & 0 deletions src/kem/cgw_kv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,15 @@ pub struct PublicKey {

/// Secret key parameter generated by the PKG used to extract user secret keys.
/// Also known as MSK.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct SecretKey {
b: [Scalar; 2],
k: [Scalar; 2],
Expand All @@ -58,7 +66,15 @@ pub struct SecretKey {

/// User secret key. Can be used to decaps the corresponding ciphertext.
/// Also known as USK_{id}.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct UserSecretKey {
d0: [G2Affine; 2],
d1: [G2Affine; 2],
Expand Down Expand Up @@ -516,4 +532,37 @@ mod tests {

#[cfg(feature = "mkem")]
test_multi_kem!(CGWKV);

#[cfg(feature = "zeroize")]
#[test]
fn secret_types_zeroize() {
use zeroize::Zeroize;
let mut rng = rand::thread_rng();
let id = <CGWKV as IBKEM>::Id::derive_str("alice@example.com");
let (pk, mut sk) = CGWKV::setup(&mut rng);
let mut usk = CGWKV::extract_usk(Some(&pk), &sk, &id, &mut rng);
let (_ct, mut ss) = CGWKV::encaps(&pk, &id, &mut rng);

// Snapshot serialized form so we can assert zeroization actually blanks it.
let sk_bytes_before = sk.to_bytes();
let usk_bytes_before = usk.to_bytes();
let ss_bytes_before = ss.0;

sk.zeroize();
usk.zeroize();
ss.zeroize();

assert_ne!(sk.to_bytes(), sk_bytes_before, "SecretKey did not zeroize");
assert_ne!(
usk.to_bytes(),
usk_bytes_before,
"UserSecretKey did not zeroize"
);
assert_ne!(ss.0, ss_bytes_before, "SharedSecret did not zeroize");
assert_eq!(
ss.0,
[0u8; crate::kem::SS_BYTES],
"SharedSecret bytes should be zero"
);
}
}
16 changes: 16 additions & 0 deletions src/kem/kiltz_vahlis_one.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,29 @@ pub struct PublicKey {
}

/// Secret key parameter generated by the PKG used to extract user secret keys.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct SecretKey {
alpha: G1Affine,
}

/// Points on the paired curves that form the user secret key.
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct UserSecretKey {
d1: G1Affine,
d2: G2Affine,
Expand Down
8 changes: 8 additions & 0 deletions src/kem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,15 @@ pub const SS_BYTES: usize = 32;
///
/// This shared secret has roughly a 127 bits of security.
/// This is due to the fact that BLS12-381 targets this security level (optimistically).
///
/// # Zeroization
///
/// With the `zeroize` feature enabled this type derives `Zeroize` but **not**
/// `ZeroizeOnDrop` (it is `Copy`). Secret material is **not** cleared on drop —
/// you **MUST** call `.zeroize()` explicitly once done. See the
/// [crate-level docs](crate#zeroizing-secret-material).
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct SharedSecret(pub [u8; SS_BYTES]);

impl ConstantTimeEq for SharedSecret {
Expand Down
37 changes: 37 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,43 @@
//!
//! assert_eq!(k, k2);
//! ```
//!
//! # Zeroizing secret material
//!
//! When the `zeroize` feature is enabled, the secret types in this crate — the
//! [`SharedSecret`](crate::kem::SharedSecret) produced by the KEMs, and the
//! `SecretKey` and `UserSecretKey` of every scheme — derive
//! [`Zeroize`](https://docs.rs/zeroize), but **not** `ZeroizeOnDrop`.
//!
//! These types are `Copy`, and a `Copy` type cannot implement `Drop` (Rust
//! forbids `Copy` and `Drop` on the same type), so `ZeroizeOnDrop` cannot be
//! derived for them. As a consequence **secret key material is not wiped from
//! memory automatically when a value goes out of scope**. If you care about
//! clearing secrets, you **MUST** call `.zeroize()` explicitly once you are
//! done with each secret value:
//!
//! ```ignore
//! use ibe::kem::{IBKEM, cgw_kv::CGWKV};
//! use ibe::Derive;
//! use zeroize::Zeroize;
//!
//! let mut rng = rand::thread_rng();
//! let id = <CGWKV as IBKEM>::Id::derive_str("alice@example.com");
//! let (pk, mut sk) = CGWKV::setup(&mut rng);
//! let mut usk = CGWKV::extract_usk(Some(&pk), &sk, &id, &mut rng);
//! let (_ct, mut ss) = CGWKV::encaps(&pk, &id, &mut rng);
//!
//! // ... use sk / usk / ss ...
//!
//! // Wipe the secret material once you are done with it.
//! sk.zeroize();
//! usk.zeroize();
//! ss.zeroize();
//! ```
//!
//! Making these types `!Copy` so that `ZeroizeOnDrop` can be derived (and the
//! wiping happens automatically) is a breaking API change; it is deferred to a
//! future major release.

#![no_std]
#![deny(missing_debug_implementations, rust_2018_idioms, missing_docs)]
Expand Down
1 change: 1 addition & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub fn rpc<Gr: UncompressedEncoding>(k: &[u8; 32], gs: &[Gr]) -> Scalar {
///
/// This identity is obtained by hashing using sha3_512.
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize))]
pub struct Identity(pub [u8; ID_BYTES]);

impl Default for Identity {
Expand Down
Loading