From 4d01909dc2f95672f202297cf1a8b41671629f99 Mon Sep 17 00:00:00 2001 From: Hugo Rosenkranz-Costa Date: Wed, 29 Nov 2023 15:23:18 +0100 Subject: [PATCH] feat: store MPK subkeys in regular HashMap --- src/core/api.rs | 20 +++++++++++++++++--- src/core/mod.rs | 8 ++++++-- src/core/primitives.rs | 32 +++++++++++++++++++------------- src/core/serialization.rs | 37 +++++++++++++------------------------ 4 files changed, 55 insertions(+), 42 deletions(-) diff --git a/src/core/api.rs b/src/core/api.rs index 7ae8204c..ea9bb101 100644 --- a/src/core/api.rs +++ b/src/core/api.rs @@ -10,7 +10,7 @@ use cosmian_crypto_core::{ use crate::{ abe_policy::{AccessPolicy, Policy}, core::{ - primitives::{decaps, encaps, keygen, refresh, setup, update}, + primitives::{decaps, encaps, keygen, refresh, rekey, setup, update}, Encapsulation, MasterPublicKey, MasterSecretKey, UserSecretKey, SYM_KEY_LENGTH, }, Error, @@ -74,6 +74,22 @@ impl Covercrypt { ) } + /// Generates new key pairs for a given AccessPolicy + pub fn rekey_master_keys( + &self, + access_policy: &AccessPolicy, + policy: &Policy, + msk: &mut MasterSecretKey, + mpk: &mut MasterPublicKey, + ) -> Result<(), Error> { + rekey( + &mut *self.rng.lock().expect("Mutex lock failed!"), + msk, + mpk, + &policy.access_policy_to_partitions(access_policy, false)?, + ) + } + /// Generates a user secret key. /// /// A new user secret key does NOT include to old (i.e. rotated) partitions. @@ -103,7 +119,6 @@ impl Covercrypt { /// /// - `usk` : the user key to refresh /// - `msk` : master secret key - /// - `policy` : global policy of the master secret key /// - `keep_old_accesses` : whether access to old partitions (i.e. before /// rotation) should be kept pub fn refresh_user_secret_key( @@ -112,7 +127,6 @@ impl Covercrypt { msk: &MasterSecretKey, keep_old_rights: bool, ) -> Result<(), Error> { - // TODO: use keep_old_rotations refresh(msk, usk, keep_old_rights) } diff --git a/src/core/mod.rs b/src/core/mod.rs index 2e705cea..adad9688 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,6 +1,10 @@ //! Implements the core functionalities of `Covercrypt`. -use std::{collections::HashSet, hash::Hash, ops::Deref}; +use std::{ + collections::{HashMap, HashSet}, + hash::Hash, + ops::Deref, +}; use cosmian_crypto_core::{R25519PrivateKey, R25519PublicKey, SymmetricKey}; use pqc_kyber::{KYBER_INDCPA_BYTES, KYBER_INDCPA_PUBLICKEYBYTES, KYBER_INDCPA_SECRETKEYBYTES}; @@ -63,7 +67,7 @@ impl Deref for KyberSecretKey { pub struct MasterPublicKey { g1: R25519PublicKey, g2: R25519PublicKey, - pub(crate) subkeys: RevisionMap, R25519PublicKey)>, + pub(crate) subkeys: HashMap, R25519PublicKey)>, } type Subkey = (Option, R25519PrivateKey); diff --git a/src/core/primitives.rs b/src/core/primitives.rs index 6354593a..6530d541 100644 --- a/src/core/primitives.rs +++ b/src/core/primitives.rs @@ -112,7 +112,7 @@ pub fn setup( let g2 = R25519PublicKey::from(&s2); let mut sub_sk = RevisionMap::with_capacity(partitions.len()); - let mut sub_pk = RevisionMap::with_capacity(partitions.len()); + let mut sub_pk = HashMap::with_capacity(partitions.len()); for (partition, &(is_hybridized, _)) in partitions { let ((pk_i, pk_pq), (sk_i, sk_pq)) = create_key_pair(rng, &h, is_hybridized); @@ -197,7 +197,7 @@ pub fn encaps( let c2 = &mpk.g2 * &r; let mut encs = HashSet::with_capacity(encryption_set.len()); for partition in encryption_set { - if let Some((pk_i, h_i)) = mpk.subkeys.get_current_revision(partition) { + if let Some((pk_i, h_i)) = mpk.subkeys.get(partition) { let mut e_i = [0; SYM_KEY_LENGTH]; kdf256!(&mut e_i, &(h_i * &r).to_bytes()); xor_in_place(&mut e_i, &seed); @@ -306,11 +306,11 @@ pub fn update( partitions_set: &HashMap, ) -> Result<(), Error> { let mut new_sub_sk = RevisionMap::with_capacity(partitions_set.len()); - let mut new_sub_pk = RevisionMap::with_capacity(partitions_set.len()); + let mut new_sub_pk = HashMap::with_capacity(partitions_set.len()); let h = R25519PublicKey::from(&msk.s); for (partition, &(is_hybridized, write_status)) in partitions_set { - // TODO: get all revisions + // only regenerate public subkey for current subkey in master secret key if let Some((sk_i, x_i)) = msk.subkeys.get_current_revision(partition) { // regenerate the public sub-key. let h_i = &h * x_i; @@ -319,7 +319,7 @@ pub fn update( if sk_i.is_some() { let pk_i = mpk .subkeys - .get_current_revision(partition) + .get(partition) .map(|(pk_i, _)| pk_i) .unwrap_or(&None); (sk_i.clone(), pk_i.clone()) @@ -373,20 +373,26 @@ pub fn update( Ok(()) } -pub fn rotate( +pub fn rekey( rng: &mut impl CryptoRngCore, msk: &mut MasterSecretKey, mpk: &mut MasterPublicKey, - partitions_to_rotate: &HashMap, + partitions_to_rotate: &HashSet, ) -> Result<(), Error> { - // let partitions_to_rotate = - // self.access_policy_to_partitions(&AccessPolicy::Attr(attr.clone()), - // false)?; let h = R25519PublicKey::from(&msk.s); - for (partition, (is_hybridized, write_status)) in partitions_to_rotate { - let ((pk_i, pk_pq), (sk_i, sk_pq)) = create_key_pair(rng, &h, *is_hybridized); + for partition in partitions_to_rotate { + // write a `get_encryption`` function in a dedicated Subkey class? + let is_hybridized = EncryptionHint::new( + msk.subkeys + .get_current_revision(partition) + .and_then(|(sk_i, _)| sk_i.as_ref()) + .is_some(), + ); + let ((pk_i, pk_pq), (sk_i, sk_pq)) = create_key_pair(rng, &h, is_hybridized); msk.subkeys.insert(partition.clone(), (sk_pq, sk_i)); - if *write_status == AttributeStatus::EncryptDecrypt { + + // update public subkey if partition is not read only + if mpk.subkeys.contains_key(partition) { mpk.subkeys.insert(partition.clone(), (pk_pq, pk_i)); } } diff --git a/src/core/serialization.rs b/src/core/serialization.rs index 94c8119e..caa24cde 100644 --- a/src/core/serialization.rs +++ b/src/core/serialization.rs @@ -1,6 +1,6 @@ //! Implements the serialization methods for the `Covercrypt` objects. -use std::collections::{HashSet, LinkedList}; +use std::collections::{HashMap, HashSet, LinkedList}; use cosmian_crypto_core::{ bytes_ser_de::{to_leb128_len, Deserializer, Serializable, Serializer}, @@ -61,14 +61,11 @@ impl Serializable for MasterPublicKey { fn length(&self) -> usize { let mut length = 2 * R25519PublicKey::LENGTH // subkeys serialization - + to_leb128_len(self.subkeys.nb_chains()) + + to_leb128_len(self.subkeys.len()) + self.subkeys.len() * R25519PublicKey::LENGTH; - for (partition, chain) in &self.subkeys.map { + for (partition, (pk_i, _)) in &self.subkeys { length += to_leb128_len(partition.len()) + partition.len(); - length += to_leb128_len(chain.len()); - for (pk_i, _) in chain { - length += serialize_len_option!(pk_i, _value, KYBER_INDCPA_PUBLICKEYBYTES); - } + length += serialize_len_option!(pk_i, _value, KYBER_INDCPA_PUBLICKEYBYTES); } length } @@ -76,14 +73,11 @@ impl Serializable for MasterPublicKey { fn write(&self, ser: &mut Serializer) -> Result { let mut n = ser.write_array(&self.g1.to_bytes())?; n += ser.write_array(&self.g2.to_bytes())?; - n += ser.write_leb128_u64(self.subkeys.nb_chains() as u64)?; - for (partition, chain) in &self.subkeys.map { + n += ser.write_leb128_u64(self.subkeys.len() as u64)?; + for (partition, (pk_i, h_i)) in &self.subkeys { n += ser.write_vec(partition)?; - n += ser.write_leb128_u64(chain.len() as u64)?; - for (pk_i, h_i) in chain { - serialize_option!(ser, n, pk_i, value, ser.write_array(value)); - n += ser.write_array(&h_i.to_bytes())?; - } + serialize_option!(ser, n, pk_i, value, ser.write_array(value)); + n += ser.write_array(&h_i.to_bytes())?; } Ok(n) } @@ -92,18 +86,13 @@ impl Serializable for MasterPublicKey { let g1 = R25519PublicKey::try_from_bytes(de.read_array::<{ R25519PublicKey::LENGTH }>()?)?; let g2 = R25519PublicKey::try_from_bytes(de.read_array::<{ R25519PublicKey::LENGTH }>()?)?; let n_partitions = ::try_from(de.read_leb128_u64()?)?; - let mut subkeys = RevisionMap::with_capacity(n_partitions); + let mut subkeys = HashMap::with_capacity(n_partitions); for _ in 0..n_partitions { let partition = Partition::from(de.read_vec()?); - let n_keys = ::try_from(de.read_leb128_u64()?)?; - let chain: Result, Self::Error> = (0..n_keys) - .map(|_| { - let pk_i = deserialize_option!(de, KyberPublicKey(de.read_array()?)); - let h_i = de.read_array::<{ R25519PublicKey::LENGTH }>()?; - Ok((pk_i, R25519PublicKey::try_from_bytes(h_i)?)) - }) - .collect(); - subkeys.map.insert(partition, chain?); + let pk_i = deserialize_option!(de, KyberPublicKey(de.read_array()?)); + let h_i = + R25519PublicKey::try_from_bytes(de.read_array::<{ R25519PublicKey::LENGTH }>()?)?; + subkeys.insert(partition, (pk_i, h_i)); } Ok(Self { g1, g2, subkeys }) }