Skip to content

Commit

Permalink
Update pqc_kyber from 0.4 to 0.7 (security advisory on 0.4)
Browse files Browse the repository at this point in the history
  • Loading branch information
ThibsG committed Feb 12, 2024
1 parent 33229df commit aac4805
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 46 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Security fix

- Update Kyber dependecy due to a [timing vulnerability](https://github.com/Argyle-Software/kyber/issues/108)

### Features

- Change `Axis` to `Dimension` with a clear distinction between `Ordered` and `Unordered`.
Expand Down
17 changes: 12 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@ hybridized_bench = []

[dependencies]
base64 = { version = "0.21.0", optional = true }
cosmian_crypto_core = { version = "9.2.0", default-features = false, features = ["ser", "sha3", "aes", "curve25519"] }
pqc_kyber = { version = "0.4", features = ["std", "hazmat"] }
cosmian_crypto_core = { version = "9.3", default-features = false, features = [
"ser",
"sha3",
"aes",
"curve25519",
] }
pqc_kyber = { version = "0.7", features = ["std", "hazmat"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tiny-keccak = { version = "2.0.2", features = ["shake", "kmac"] }
tiny-keccak = { version = "2.0", features = ["shake", "kmac"] }
zeroize = "1.6.0"

[dev-dependencies]
base64 = { version = "0.21.0" }
criterion = { version = "0.4", features = ["html_reports"], default_features = false }
base64 = { version = "0.21" }
criterion = { version = "0.5", features = [
"html_reports",
], default_features = false }
4 changes: 2 additions & 2 deletions src/core/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ impl Covercrypt {
&self,
policy: &Policy,
) -> Result<(MasterSecretKey, MasterPublicKey), Error> {
Ok(setup(
setup(
&mut *self.rng.lock().expect("Mutex lock failed!"),
policy.generate_all_partitions()?,
))
)
}

/// Updates the master keys according to this new policy.
Expand Down
8 changes: 4 additions & 4 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{
};

use cosmian_crypto_core::{R25519PrivateKey, R25519PublicKey, SymmetricKey};
use pqc_kyber::{KYBER_INDCPA_BYTES, KYBER_INDCPA_PUBLICKEYBYTES, KYBER_INDCPA_SECRETKEYBYTES};
use pqc_kyber::{KYBER_CIPHERTEXTBYTES, KYBER_PUBLICKEYBYTES, KYBER_SECRETKEYBYTES};
use zeroize::ZeroizeOnDrop;

use crate::{
Expand Down Expand Up @@ -41,7 +41,7 @@ type Tag = [u8; TAG_LENGTH];

/// Kyber public key length
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct KyberPublicKey([u8; KYBER_INDCPA_PUBLICKEYBYTES]);
pub struct KyberPublicKey([u8; KYBER_PUBLICKEYBYTES]);

impl Deref for KyberPublicKey {
type Target = [u8];
Expand All @@ -53,7 +53,7 @@ impl Deref for KyberPublicKey {

/// Kyber secret key length
#[derive(Debug, Clone, PartialEq, Eq, Hash, ZeroizeOnDrop)]
pub struct KyberSecretKey([u8; KYBER_INDCPA_SECRETKEYBYTES]);
pub struct KyberSecretKey([u8; KYBER_SECRETKEYBYTES]);

impl Deref for KyberSecretKey {
type Target = [u8];
Expand Down Expand Up @@ -94,7 +94,7 @@ pub struct UserSecretKey {
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
enum KeyEncapsulation {
ClassicEncapsulation(Box<[u8; SYM_KEY_LENGTH]>),
HybridEncapsulation(Box<[u8; KYBER_INDCPA_BYTES]>),
HybridEncapsulation(Box<[u8; KYBER_CIPHERTEXTBYTES]>),
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
66 changes: 37 additions & 29 deletions src/core/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use cosmian_crypto_core::{
};
use pqc_kyber::{
indcpa::{indcpa_dec, indcpa_enc, indcpa_keypair},
KYBER_INDCPA_BYTES, KYBER_INDCPA_PUBLICKEYBYTES, KYBER_INDCPA_SECRETKEYBYTES, KYBER_SYMBYTES,
KYBER_CIPHERTEXTBYTES, KYBER_PUBLICKEYBYTES, KYBER_SECRETKEYBYTES, KYBER_SYMBYTES,
};
use tiny_keccak::{Hasher, IntoXof, Kmac, Xof};
use zeroize::Zeroizing;
Expand Down Expand Up @@ -77,13 +77,16 @@ fn verify_user_key_kmac(msk: &MasterSecretKey, usk: &UserSecretKey) -> Result<()
}

/// Returns newly generated public and private Kyber key pair.
fn create_kyber_key_pair(rng: &mut impl CryptoRngCore) -> (KyberPublicKey, KyberSecretKey) {
fn create_kyber_key_pair(
rng: &mut impl CryptoRngCore,
) -> Result<(KyberPublicKey, KyberSecretKey), Error> {
let (mut sk, mut pk) = (
KyberSecretKey([0; KYBER_INDCPA_SECRETKEYBYTES]),
KyberPublicKey([0; KYBER_INDCPA_PUBLICKEYBYTES]),
KyberSecretKey([0; KYBER_SECRETKEYBYTES]),
KyberPublicKey([0; KYBER_PUBLICKEYBYTES]),
);
indcpa_keypair(&mut pk.0, &mut sk.0, None, rng);
(pk, sk)
indcpa_keypair(&mut pk.0, &mut sk.0, None, rng)
.map_err(|e| Error::KeyError(format!("Unable to generate kyber key pair: {e}")))?;
Ok((pk, sk))
}

/// Returns a newly generated pair of public and private subkeys with optional
Expand All @@ -92,17 +95,17 @@ fn create_subkey_pair(
rng: &mut impl CryptoRngCore,
h: &R25519CurvePoint,
is_hybridized: EncryptionHint,
) -> (PublicSubkey, SecretSubkey) {
) -> Result<(PublicSubkey, SecretSubkey), Error> {
let sk_i = R25519PrivateKey::new(rng);
let pk_i = h * &sk_i;

let (pk_pq, sk_pq) = if is_hybridized.into() {
let (pk, sk) = create_kyber_key_pair(rng);
let (pk, sk) = create_kyber_key_pair(rng)?;
(Some(pk), Some(sk))
} else {
(None, None)
};
((pk_pq, pk_i), (sk_pq, sk_i))
Ok(((pk_pq, pk_i), (sk_pq, sk_i)))
}

/// Update a pair of public and private subkeys of a `ReadWrite` partition.
Expand All @@ -124,7 +127,7 @@ fn update_subkey_pair(
match (&pk_pq, &sk_pq) {
(None, _) => {
// generate a new Kyber key pair
let (pk, sk) = create_kyber_key_pair(rng);
let (pk, sk) = create_kyber_key_pair(rng)?;
pk_pq.replace(pk);
sk_pq.replace(sk);
}
Expand All @@ -145,13 +148,14 @@ fn update_master_subkey(
_h: &R25519CurvePoint,
msk: &mut SecretSubkey,
is_hybridized: EncryptionHint,
) {
) -> Result<(), Error> {
let (sk_pq, _) = msk;
// Add Kyber key if needed
if is_hybridized.into() && sk_pq.is_none() {
let (_, sk) = create_kyber_key_pair(rng);
let (_, sk) = create_kyber_key_pair(rng)?;
sk_pq.replace(sk);
}
Ok(())
}

/// Generates the master secret key and master public key of the `Covercrypt`
Expand All @@ -164,7 +168,7 @@ fn update_master_subkey(
pub fn setup(
rng: &mut impl CryptoRngCore,
partitions: HashMap<Partition, (EncryptionHint, AttributeStatus)>,
) -> (MasterSecretKey, MasterPublicKey) {
) -> Result<(MasterSecretKey, MasterPublicKey), Error> {
let s = R25519PrivateKey::new(rng);
let s1 = R25519PrivateKey::new(rng);
let s2 = R25519PrivateKey::new(rng);
Expand All @@ -176,7 +180,7 @@ pub fn setup(
let mut sub_pk = HashMap::with_capacity(partitions.len());

for (partition, (is_hybridized, write_status)) in partitions {
let (public_subkey, secret_subkey) = create_subkey_pair(rng, &h, is_hybridized);
let (public_subkey, secret_subkey) = create_subkey_pair(rng, &h, is_hybridized)?;
sub_sk.insert(partition.clone(), secret_subkey);
if write_status == EncryptDecrypt {
sub_pk.insert(partition, public_subkey);
Expand All @@ -185,7 +189,7 @@ pub fn setup(

let kmac_key = Some(SymmetricKey::<KMAC_KEY_LENGTH>::new(rng));

(
Ok((
MasterSecretKey {
s,
s1,
Expand All @@ -198,7 +202,7 @@ pub fn setup(
g2,
subkeys: sub_pk,
},
)
))
}

/// Generates a user secret key for the given decryption set.
Expand Down Expand Up @@ -264,7 +268,7 @@ pub fn encaps(
kdf256!(&mut e_i, &(h_i * &r).to_bytes());
xor_in_place(&mut e_i, &seed);
if let Some(pk_i) = pk_i {
let mut epq_i = [0; KYBER_INDCPA_BYTES];
let mut epq_i = [0; KYBER_CIPHERTEXTBYTES];
let mut coin = Zeroizing::new([0; KYBER_SYMBYTES]);
rng.fill_bytes(&mut *coin);
indcpa_enc(&mut epq_i, &e_i, pk_i, &*coin);
Expand Down Expand Up @@ -382,15 +386,15 @@ pub fn update(
(EncryptDecrypt, Some(public_subkey)) => {
update_subkey_pair(rng, &h, public_subkey, secret_subkey, is_hybridized)?;
}
(DecryptOnly, None) => update_master_subkey(rng, &h, secret_subkey, is_hybridized),
(DecryptOnly, None) => update_master_subkey(rng, &h, secret_subkey, is_hybridized)?,
(DecryptOnly, Some(_)) => {
mpk.subkeys.remove(&partition);
update_master_subkey(rng, &h, secret_subkey, is_hybridized);
update_master_subkey(rng, &h, secret_subkey, is_hybridized)?;
}
}
} else {
// generate new keys
let (public_subkey, secret_subkey) = create_subkey_pair(rng, &h, is_hybridized);
let (public_subkey, secret_subkey) = create_subkey_pair(rng, &h, is_hybridized)?;
msk.subkeys.insert(partition.clone(), secret_subkey);
if write_status == EncryptDecrypt {
mpk.subkeys.insert(partition, public_subkey);
Expand Down Expand Up @@ -423,7 +427,7 @@ pub fn rekey(
.and_then(|(sk_i, _)| sk_i.as_ref())
.is_some(),
);
let (public_subkey, secret_subkey) = create_subkey_pair(rng, &h, is_hybridized);
let (public_subkey, secret_subkey) = create_subkey_pair(rng, &h, is_hybridized)?;
msk.subkeys.insert(coordinate.clone(), secret_subkey);

// update public subkey if partition is not read only
Expand Down Expand Up @@ -510,16 +514,18 @@ pub fn refresh(

#[cfg(test)]
mod tests {
use cosmian_crypto_core::{
bytes_ser_de::Serializable, reexport::rand_core::SeedableRng, CsRng,
};

#[cfg(feature = "serialization")]
use cosmian_crypto_core::bytes_ser_de::Serializable;

use cosmian_crypto_core::{reexport::rand_core::SeedableRng, CsRng};

use super::*;

#[test]
fn test_kyber() {
let mut rng = CsRng::from_entropy();
let keypair = pqc_kyber::keypair(&mut rng);
let keypair = pqc_kyber::keypair(&mut rng).unwrap();
let (ct, ss) = pqc_kyber::encapsulate(&keypair.public, &mut rng).unwrap();
let res = pqc_kyber::decapsulate(&ct, &keypair.secret).unwrap();
assert_eq!(ss, res, "Decapsulation failed!");
Expand Down Expand Up @@ -550,7 +556,7 @@ mod tests {
// secure random number generator
let mut rng = CsRng::from_entropy();
// setup scheme
let (mut msk, mut mpk) = setup(&mut rng, partitions_set);
let (mut msk, mut mpk) = setup(&mut rng, partitions_set)?;

// The admin partition matches a hybridized sub-key.
let admin_secret_subkeys = msk.subkeys.get_latest(&admin_partition);
Expand Down Expand Up @@ -673,7 +679,7 @@ mod tests {
// secure random number generator
let mut rng = CsRng::from_entropy();
// setup scheme
let (mut msk, mut mpk) = setup(&mut rng, partitions_set);
let (mut msk, mut mpk) = setup(&mut rng, partitions_set)?;

// now remove partition 1 and add partition 3
let partition_3 = Partition(b"3".to_vec());
Expand All @@ -698,6 +704,7 @@ mod tests {
}

#[test]
#[cfg(feature = "serialization")]
fn test_user_key_refresh() -> Result<(), Error> {
let partition_1 = Partition(b"1".to_vec());
let partition_2 = Partition(b"2".to_vec());
Expand All @@ -720,7 +727,7 @@ mod tests {
// secure random number generator
let mut rng = CsRng::from_entropy();
// setup scheme
let (mut msk, mut mpk) = setup(&mut rng, partitions_set);
let (mut msk, mut mpk) = setup(&mut rng, partitions_set)?;
// create a user key with access to partition 1 and 2
let mut usk = keygen(
&mut rng,
Expand Down Expand Up @@ -787,6 +794,7 @@ mod tests {
}

#[test]
#[cfg(feature = "serialization")]
fn test_user_key_kmac() -> Result<(), Error> {
let partition_1 = Partition(b"1".to_vec());
let partition_2 = Partition(b"2".to_vec());
Expand All @@ -804,7 +812,7 @@ mod tests {
// secure random number generator
let mut rng = CsRng::from_entropy();
// setup scheme
let (msk, _) = setup(&mut rng, partitions_set);
let (msk, _) = setup(&mut rng, partitions_set)?;
// create a user key with access to partition 1 and 2
let mut usk = keygen(&mut rng, &msk, &HashSet::from([partition_1, partition_2]))?;

Expand Down
10 changes: 5 additions & 5 deletions src/core/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use cosmian_crypto_core::{
bytes_ser_de::{to_leb128_len, Deserializer, Serializable, Serializer},
FixedSizeCBytes, R25519PrivateKey, R25519PublicKey, RandomFixedSizeCBytes, SymmetricKey,
};
use pqc_kyber::{KYBER_INDCPA_PUBLICKEYBYTES, KYBER_INDCPA_SECRETKEYBYTES};
use pqc_kyber::{KYBER_PUBLICKEYBYTES, KYBER_SECRETKEYBYTES};

use super::{KyberPublicKey, KyberSecretKey, KMAC_KEY_LENGTH, KMAC_LENGTH, TAG_LENGTH};
use crate::{
Expand Down Expand Up @@ -66,7 +66,7 @@ impl Serializable for MasterPublicKey {
+ self.subkeys.len() * R25519PublicKey::LENGTH;
for (partition, (pk_i, _)) in &self.subkeys {
length += to_leb128_len(partition.len()) + partition.len();
length += serialize_len_option!(pk_i, _value, KYBER_INDCPA_PUBLICKEYBYTES);
length += serialize_len_option!(pk_i, _value, KYBER_PUBLICKEYBYTES);
}
length
}
Expand Down Expand Up @@ -112,7 +112,7 @@ impl Serializable for MasterSecretKey {
length += to_leb128_len(partition.len()) + partition.len();
length += to_leb128_len(chain.len());
for (sk_i, _) in chain {
let x = serialize_len_option!(sk_i, _value, KYBER_INDCPA_SECRETKEYBYTES);
let x = serialize_len_option!(sk_i, _value, KYBER_SECRETKEYBYTES);
length += x;
}
}
Expand Down Expand Up @@ -189,7 +189,7 @@ impl Serializable for UserSecretKey {
length += to_leb128_len(partition.len()) + partition.len();
length += to_leb128_len(chain.len());
for (sk_i, _) in chain {
length += serialize_len_option!(sk_i, _value, KYBER_INDCPA_SECRETKEYBYTES);
length += serialize_len_option!(sk_i, _value, KYBER_SECRETKEYBYTES);
}
}
length
Expand Down Expand Up @@ -434,7 +434,7 @@ mod tests {
let target_set = HashSet::from([admin_partition, dev_partition]);
let mut rng = CsRng::from_entropy();

let (msk, mpk) = setup(&mut rng, partitions_set);
let (msk, mpk) = setup(&mut rng, partitions_set)?;

// Check Covercrypt `MasterSecretKey` serialization.
let bytes = msk.serialize()?;
Expand Down
7 changes: 6 additions & 1 deletion src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@ pub fn policy() -> Result<Policy, Error> {

#[cfg(test)]
mod tests {
#[cfg(feature = "serialization")]
use cosmian_crypto_core::bytes_ser_de::Serializable;

#[cfg(feature = "serialization")]
use crate::UserSecretKey;

use super::*;
use crate::{
abe_policy::{AccessPolicy, Attribute, LegacyPolicy, Partition},
Covercrypt, EncryptedHeader, UserSecretKey,
Covercrypt, EncryptedHeader,
};

#[test]
Expand Down Expand Up @@ -139,6 +143,7 @@ mod tests {
}

#[test]
#[cfg(feature = "serialization")]
fn test_refresh_user_key() -> Result<(), Error> {
let policy = policy()?;
let cover_crypt = Covercrypt::default();
Expand Down

0 comments on commit aac4805

Please sign in to comment.