use alloc::vec::Vec;
use crate::cryptomat::{
CryptoAlg,
Pk,
SearchableKey,
SearchableKeyGen,
Sig,
SignK,
SignKeyPair,
Sk,
SkComposer,
SortableKey,
SortableKeyGen,
StaticKeyPair,
SymKey,
SymKeyComposer,
SymKeyGen,
VerifyK,
};
use crate::Error;
pub struct CreateGroupOutput<P: Pk, V: VerifyK, S: Sig, GS: Sig>
{
pub encrypted_group_key: Vec<u8>, pub group_key_alg: &'static str, pub encrypted_group_key_alg: &'static str, pub encrypted_private_group_key: Vec<u8>,
pub public_group_key: P,
pub keypair_encrypt_alg: &'static str,
pub encrypted_hmac_key: Vec<u8>,
pub encrypted_hmac_alg: &'static str,
pub encrypted_sortable_key: Vec<u8>,
pub encrypted_sortable_key_alg: &'static str,
pub group_key_sig: Option<GS>,
pub verify_key: Option<V>,
pub encrypted_sign_key: Option<Vec<u8>>,
pub keypair_sign_alg: Option<&'static str>,
pub public_key_sig: Option<S>,
}
pub struct KeyRotationOutput<P: Pk, V: VerifyK, S: Sig, GS: Sig>
{
pub encrypted_group_key_by_user: Vec<u8>, pub group_key_alg: &'static str,
pub encrypted_group_key_alg: &'static str, pub encrypted_private_group_key: Vec<u8>,
pub public_group_key: P,
pub keypair_encrypt_alg: &'static str,
pub encrypted_group_key_by_ephemeral: Vec<u8>,
pub ephemeral_alg: &'static str,
pub encrypted_ephemeral_key: Vec<u8>, pub group_key_sig: Option<GS>,
pub verify_key: Option<V>,
pub encrypted_sign_key: Option<Vec<u8>>,
pub keypair_sign_alg: Option<&'static str>,
pub public_key_sig: Option<S>,
}
pub struct PrepareGroupKeysForNewMemberOutput
{
pub alg: &'static str,
pub encrypted_group_key: Vec<u8>,
pub encrypted_group_key_alg: &'static str,
}
#[allow(clippy::type_complexity)]
fn prepare_keys<Sign: SignKeyPair, GSign: SignK>(
creators_public_key: &impl Pk,
user_group: bool,
group_key: &impl SymKey,
group_sk: &impl Sk,
group_pk: &impl Pk,
sign_key: Option<&GSign>,
) -> Result<
(
Vec<u8>,
Vec<u8>,
&'static str,
Option<Sign::VerifyKey>,
Option<Vec<u8>>,
Option<<<Sign>::SignKey as SignK>::Signature>,
Option<&'static str>,
Option<GSign::Signature>,
),
Error,
>
{
let encrypted_private_group_key = group_sk.encrypt_by_master_key(group_key)?;
let encrypted_group_key = group_key.encrypt_key_with_master_key(creators_public_key)?;
let group_key_sig = if let Some(s) = sign_key { Some(group_key.sign_key(s)?) } else { None };
let (verify_key, encrypted_sign_key, public_key_sig, keypair_sign_alg) = if !user_group {
(None, None, None, None)
} else {
let (sign_key, verify_key) = Sign::generate_key_pair()?;
let encrypted_sign_key = sign_key.encrypt_by_master_key(group_key)?;
let public_key_sig = group_pk.sign_public_key(&sign_key)?;
(
Some(verify_key),
Some(encrypted_sign_key),
Some(public_key_sig),
Some(sign_key.get_alg_str()),
)
};
Ok((
encrypted_private_group_key,
encrypted_group_key,
creators_public_key.get_alg_str(),
verify_key,
encrypted_sign_key,
public_key_sig,
keypair_sign_alg,
group_key_sig,
))
}
#[allow(clippy::type_complexity)]
pub fn prepare_create<S, St, Sign, Search, Sort, GSign: SignK>(
creators_public_key: &impl Pk,
user_group: bool,
sign_key: Option<&GSign>,
) -> Result<
(
CreateGroupOutput<St::PublicKey, Sign::VerifyKey, <<Sign>::SignKey as SignK>::Signature, GSign::Signature>,
S::SymmetricKey,
),
Error,
>
where
S: SymKeyGen,
St: StaticKeyPair,
Sign: SignKeyPair,
Search: SearchableKeyGen,
Sort: SortableKeyGen,
{
let group_key = S::generate()?;
let (sk, public_group_key) = St::generate_static_keypair()?;
let (
encrypted_private_group_key,
encrypted_group_key,
encrypted_group_key_alg,
verify_key,
encrypted_sign_key,
public_key_sig,
keypair_sign_alg,
group_key_sig,
) = prepare_keys::<Sign, GSign>(
creators_public_key,
user_group,
&group_key,
&sk,
&public_group_key,
sign_key,
)?;
let searchable_encryption = Search::generate()?;
let encrypted_hmac_key = searchable_encryption.encrypt_key_with_master_key(&group_key)?;
let sortable_encryption = Sort::generate()?;
let encrypted_sortable_key = sortable_encryption.encrypt_key_with_master_key(&group_key)?;
Ok((
CreateGroupOutput {
encrypted_group_key,
encrypted_private_group_key,
public_group_key,
group_key_alg: group_key.get_alg_str(),
keypair_encrypt_alg: sk.get_alg_str(),
encrypted_hmac_key,
encrypted_hmac_alg: searchable_encryption.get_alg_str(),
encrypted_sortable_key,
encrypted_sortable_key_alg: sortable_encryption.get_alg_str(),
encrypted_group_key_alg,
verify_key,
encrypted_sign_key,
keypair_sign_alg,
public_key_sig,
group_key_sig,
},
group_key, ))
}
#[allow(clippy::type_complexity)]
pub fn key_rotation<S: SymKeyGen, St: StaticKeyPair, Sign: SignKeyPair, GSign: SignK>(
previous_group_key: &impl SymKey,
invoker_public_key: &impl Pk,
user_group: bool,
sign_key: Option<&GSign>,
) -> Result<KeyRotationOutput<St::PublicKey, Sign::VerifyKey, <<Sign as SignKeyPair>::SignKey as SignK>::Signature, GSign::Signature>, Error>
{
let group_key = S::generate()?;
let (sk, public_group_key) = St::generate_static_keypair()?;
let (
encrypted_private_group_key,
encrypted_group_key_by_user,
encrypted_group_key_alg,
verify_key,
encrypted_sign_key,
public_key_sig,
keypair_sign_alg,
group_key_sig,
) = prepare_keys::<Sign, GSign>(
invoker_public_key,
user_group,
&group_key,
&sk,
&public_group_key,
sign_key,
)?;
let ephemeral_key = S::generate()?;
let encrypted_group_key_by_ephemeral = group_key.encrypt_with_sym_key(&ephemeral_key)?;
let encrypted_ephemeral_key = ephemeral_key.encrypt_with_sym_key(previous_group_key)?;
Ok(KeyRotationOutput {
encrypted_group_key_by_user,
encrypted_group_key_alg,
encrypted_private_group_key,
group_key_alg: group_key.get_alg_str(),
keypair_encrypt_alg: sk.get_alg_str(),
encrypted_group_key_by_ephemeral,
public_group_key,
encrypted_ephemeral_key,
group_key_sig,
verify_key,
encrypted_sign_key,
keypair_sign_alg,
public_key_sig,
ephemeral_alg: ephemeral_key.get_alg_str(),
})
}
pub fn done_key_rotation<SymC: SymKeyComposer>(
private_key: &impl Sk,
public_key: &impl Pk,
previous_group_key: &impl SymKey,
encrypted_ephemeral_key_by_group_key_and_public_key: &[u8],
encrypted_group_key_by_ephemeral: &[u8],
ephemeral_alg: &str,
) -> Result<Vec<u8>, Error>
{
let decrypted_encrypted_ephemeral_key = private_key.decrypt(encrypted_ephemeral_key_by_group_key_and_public_key)?;
let ephemeral_key = SymC::decrypt_key_by_sym_key(previous_group_key, &decrypted_encrypted_ephemeral_key, ephemeral_alg)?;
let new_group_key = ephemeral_key.decrypt(encrypted_group_key_by_ephemeral)?;
let encrypted_new_group_key = public_key.encrypt(&new_group_key)?;
Ok(encrypted_new_group_key)
}
pub fn get_group<SymC: SymKeyComposer, SkC: SkComposer, VK: VerifyK>(
private_key: &impl Sk,
encrypted_group_key: &[u8],
encrypted_private_group_key: &[u8],
group_key_alg: &str,
key_pair_alg: &str,
verify_key: Option<&VK>,
group_key_sig: Option<&VK::Signature>,
) -> Result<(SymC::SymmetricKey, SkC::SecretKey), Error>
{
let decrypted_group_key = SymC::decrypt_key_by_master_key(private_key, encrypted_group_key, group_key_alg)?;
if let (Some(vk), Some(sig)) = (verify_key, group_key_sig) {
if !decrypted_group_key.verify_key(vk, sig)? {
return Err(Error::KeyDecryptionVerifyFailed);
}
}
let decrypted_private_group_key = SkC::decrypt_by_master_key(&decrypted_group_key, encrypted_private_group_key, key_pair_alg)?;
Ok((decrypted_group_key, decrypted_private_group_key))
}
pub fn prepare_group_keys_for_new_member<P: Pk>(
requester_public_key: &P,
group_keys: &[&impl SymKey],
) -> Result<Vec<PrepareGroupKeysForNewMemberOutput>, Error>
{
let encrypted_group_key_alg = requester_public_key.get_alg_str();
let encrypted_group_keys = group_keys
.iter()
.map(|group_key| {
let encrypted_group_key = group_key.encrypt_key_with_master_key(requester_public_key)?;
Ok(PrepareGroupKeysForNewMemberOutput {
encrypted_group_key,
alg: group_key.get_alg_str(),
encrypted_group_key_alg,
})
})
.collect::<Result<Vec<PrepareGroupKeysForNewMemberOutput>, Error>>()?;
Ok(encrypted_group_keys)
}