quantcrypt/cms/asn1/
auth_enveloped_data_builder.rsuse crate::cea::common::cea_trait::Cea;
use cms::authenticated_data::MessageAuthenticationCode;
use cms::builder::Error;
use cms::content_info::CmsVersion;
use cms::enveloped_data::{EncryptedContentInfo, RecipientInfo, RecipientInfos};
use cms::{builder::RecipientInfoBuilder, enveloped_data::OriginatorInfo};
use const_oid::db::rfc5911::{ID_AES_128_GCM, ID_AES_192_GCM, ID_AES_256_GCM};
use der::{Decode, Encode};
use spki::ObjectIdentifier;
use x509_cert::attr::Attributes;
use zeroize::Zeroize;
use crate::cea::cea_manager::CeaManager;
use crate::cea::common::cea_type::CeaType;
use crate::QuantCryptError;
use crate::cms::asn1::auth_env_data::AuthEnvelopedData;
type Result<T> = std::result::Result<T, QuantCryptError>;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ContentEncryptionAlgorithmAead {
Aes128Gcm,
Aes192Gcm,
Aes256Gcm,
}
pub struct AuthEnvelopedDataBuilder<'c> {
content_id: Option<ObjectIdentifier>,
originator_info: Option<OriginatorInfo>,
recipient_infos: Vec<Box<dyn RecipientInfoBuilder + 'c>>,
unencrypted_content: &'c [u8],
content_encryption_algorithm: ContentEncryptionAlgorithmAead,
auth_attributes: Option<Attributes>,
unauth_attributes: Option<Attributes>,
}
impl ContentEncryptionAlgorithmAead {
pub fn oid(&self) -> ObjectIdentifier {
match self {
ContentEncryptionAlgorithmAead::Aes128Gcm => ID_AES_128_GCM,
ContentEncryptionAlgorithmAead::Aes192Gcm => ID_AES_192_GCM,
ContentEncryptionAlgorithmAead::Aes256Gcm => ID_AES_256_GCM,
}
}
}
impl<'c> AuthEnvelopedDataBuilder<'c> {
pub fn new(
content_id: Option<ObjectIdentifier>,
originator_info: Option<OriginatorInfo>,
unencrypted_content: &'c [u8],
content_encryption_algorithm: ContentEncryptionAlgorithmAead,
auth_attributes: Option<Attributes>,
unauth_attributes: Option<Attributes>,
) -> Result<AuthEnvelopedDataBuilder<'c>> {
Ok(AuthEnvelopedDataBuilder {
content_id,
originator_info,
recipient_infos: Vec::new(),
unencrypted_content,
content_encryption_algorithm,
auth_attributes,
unauth_attributes,
})
}
pub fn add_recipient_info(
&mut self,
recipient_info_builder: impl RecipientInfoBuilder + 'c,
) -> Result<&mut Self> {
self.recipient_infos.push(Box::new(recipient_info_builder));
Ok(self)
}
pub fn build(&mut self) -> Result<AuthEnvelopedData> {
let aad = match &self.auth_attributes {
Some(attrs) => Some(attrs.to_der().map_err(|_| QuantCryptError::Unknown)?),
None => None,
};
let oid = self.content_encryption_algorithm.oid().to_string();
let cea_type = if let Some(oid) = CeaType::from_oid(&oid) {
oid
} else {
return Err(QuantCryptError::Unknown);
};
let mut cea = CeaManager::new(cea_type)?;
let mut cek = cea.key_gen()?;
let nonce = cea.nonce_gen()?;
let content_id = self.content_id.map(|oid| oid.to_string());
let (tag, eci) = cea.encrypt(
&cek,
Some(&nonce),
self.unencrypted_content,
aad.as_deref(),
content_id.as_deref(),
)?;
type Result<T> = core::result::Result<T, Error>;
let recipient_infos_vec = self
.recipient_infos
.iter_mut()
.map(|ri| ri.build(&cek))
.collect::<Result<Vec<RecipientInfo>>>()
.map_err(|_| QuantCryptError::Unknown)?;
cek.zeroize();
let recip_infos =
RecipientInfos::try_from(recipient_infos_vec).map_err(|_| QuantCryptError::Unknown)?;
let mac = MessageAuthenticationCode::new(tag).map_err(|_| QuantCryptError::Unknown)?;
let eci = EncryptedContentInfo::from_der(&eci).map_err(|_| QuantCryptError::Unknown)?;
Ok(AuthEnvelopedData {
version: self.calculate_version(),
originator_info: self.originator_info.clone(),
recip_infos,
auth_encrypted_content: eci,
auth_attrs: self.auth_attributes.clone(),
mac,
unauth_attrs: self.unauth_attributes.clone(),
})
}
fn calculate_version(&self) -> CmsVersion {
CmsVersion::V0
}
}