use super::{
DataEncryptionAlgorithm, DecryptionKeyResolver, KeyCandidateBudget, KeyEncryptionKeySource,
KeyWrapAlgorithm, XmlEncError,
};
use crate::provider::{CryptoProvider, KeyDecapsulationKey, RecoveredContentKey};
pub struct EncapsulationDecryptor<'a> {
key: RecipientKey<'a>,
}
enum RecipientKey<'a> {
Borrowed(&'a dyn KeyDecapsulationKey),
Owned(std::sync::Arc<dyn KeyDecapsulationKey>),
}
impl RecipientKey<'_> {
fn as_ref(&self) -> &dyn KeyDecapsulationKey {
match self {
Self::Borrowed(key) => *key,
Self::Owned(key) => key.as_ref(),
}
}
}
impl<'a> EncapsulationDecryptor<'a> {
pub fn new(key: &'a dyn KeyDecapsulationKey) -> Self {
Self {
key: RecipientKey::Borrowed(key),
}
}
pub fn provider_key(key: std::sync::Arc<dyn KeyDecapsulationKey>) -> Self {
Self {
key: RecipientKey::Owned(key),
}
}
fn recover(
&self,
provider: &dyn CryptoProvider,
width: usize,
descriptor: &crate::key_establishment::EncapsulationMechanism,
policy: &crate::policy::DecryptionPolicy,
budget: &mut KeyCandidateBudget,
) -> Result<Vec<RecoveredContentKey>, XmlEncError> {
if width == 0 || width > 32 {
return Err(crate::key_establishment::KeyEstablishmentError::Structure(
"consuming key exceeds KEM secret width",
)
.into());
}
budget.consume(1)?;
budget.key_establishment.commit_all(
&policy.key_establishment,
0,
0,
(width + core::mem::size_of::<RecoveredContentKey>()) as u128,
)?;
let secret = budget.key_establishment.decapsulate(
&policy.key_establishment,
provider,
self.key.as_ref(),
descriptor.algorithm,
&descriptor.ciphertext,
)?;
Ok(vec![RecoveredContentKey::confirmed(
secret[..width].to_vec(),
)])
}
}
impl DecryptionKeyResolver for EncapsulationDecryptor<'_> {
fn resolve_key(
&self,
_: &dyn CryptoProvider,
_: DataEncryptionAlgorithm,
_: Option<&super::EncryptedKey>,
) -> Result<Vec<u8>, XmlEncError> {
Err(XmlEncError::KeyNotFound)
}
fn resolve_encapsulation_content_keys_with_policy(
&self,
provider: &dyn CryptoProvider,
algorithm: DataEncryptionAlgorithm,
descriptor: &crate::key_establishment::EncapsulationMechanism,
policy: &crate::policy::DecryptionPolicy,
budget: &mut KeyCandidateBudget,
) -> Result<Vec<RecoveredContentKey>, XmlEncError> {
policy.key_establishment.check_kem_content(algorithm)?;
self.recover(provider, algorithm.key_len(), descriptor, policy, budget)
}
fn resolve_key_encryption_keys_with_policy(
&self,
provider: &dyn CryptoProvider,
algorithm: KeyWrapAlgorithm,
source: KeyEncryptionKeySource<'_>,
policy: &crate::policy::DecryptionPolicy,
budget: &mut KeyCandidateBudget,
) -> Result<Vec<RecoveredContentKey>, XmlEncError> {
let KeyEncryptionKeySource::Encapsulation(descriptor) = source else {
return Err(XmlEncError::KeyNotFound);
};
self.recover(provider, algorithm.key_len(), descriptor, policy, budget)
}
}