use super::psa_key_attributes::Attributes;
use crate::operations::psa_algorithm::Aead;
use crate::requests::ResponseStatus;
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Operation {
pub key_name: String,
pub alg: Aead,
#[derivative(Debug = "ignore")]
pub nonce: zeroize::Zeroizing<Vec<u8>>,
#[derivative(Debug = "ignore")]
pub additional_data: zeroize::Zeroizing<Vec<u8>>,
#[derivative(Debug = "ignore")]
pub ciphertext: zeroize::Zeroizing<Vec<u8>>,
}
impl Operation {
pub fn validate(&self, key_attributes: Attributes) -> crate::requests::Result<()> {
key_attributes.can_decrypt_message()?;
key_attributes.permits_alg(self.alg.into())?;
key_attributes.compatible_with_alg(self.alg.into())?;
if self.ciphertext.is_empty() || self.nonce.is_empty() {
return Err(ResponseStatus::PsaErrorInvalidArgument);
}
Ok(())
}
}
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Result {
#[derivative(Debug = "ignore")]
pub plaintext: zeroize::Zeroizing<Vec<u8>>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::operations::psa_algorithm::AeadWithDefaultLengthTag;
use crate::operations::psa_key_attributes::{Lifetime, Policy, Type, UsageFlags};
use psa_crypto::types::algorithm::Aead;
fn get_attrs() -> Attributes {
let mut usage_flags = UsageFlags::default();
let _ = usage_flags.set_decrypt();
Attributes {
lifetime: Lifetime::Persistent,
key_type: Type::Aes,
bits: 0,
policy: Policy {
usage_flags,
permitted_algorithms: Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm)
.into(),
},
}
}
#[test]
fn validate_success() {
(Operation {
key_name: String::from("some key"),
alg: AeadWithDefaultLengthTag::Ccm.into(),
ciphertext: vec![0xff, 32].into(),
nonce: vec![0xaa, 12].into(),
additional_data: vec![0xff, 16].into(),
})
.validate(get_attrs())
.unwrap();
}
#[test]
fn cannot_decrypt() {
let mut attrs = get_attrs();
attrs.policy.usage_flags = UsageFlags::default();
assert_eq!(
(Operation {
key_name: String::from("some key"),
alg: AeadWithDefaultLengthTag::Ccm.into(),
ciphertext: vec![0xff, 32].into(),
nonce: vec![0xaa, 12].into(),
additional_data: vec![0xff, 16].into()
})
.validate(attrs)
.unwrap_err(),
ResponseStatus::PsaErrorNotPermitted
);
}
#[test]
fn wrong_algorithm() {
assert_eq!(
(Operation {
key_name: String::from("some key"),
alg: AeadWithDefaultLengthTag::Gcm.into(),
ciphertext: vec![0xff, 32].into(),
nonce: vec![0xaa, 12].into(),
additional_data: vec![0xff, 16].into()
})
.validate(get_attrs())
.unwrap_err(),
ResponseStatus::PsaErrorNotPermitted
);
}
#[test]
fn invalid_plaintext() {
assert_eq!(
(Operation {
key_name: String::from("some key"),
alg: AeadWithDefaultLengthTag::Ccm.into(),
ciphertext: vec![].into(),
nonce: vec![0xaa, 12].into(),
additional_data: vec![0xff, 16].into()
})
.validate(get_attrs())
.unwrap_err(),
ResponseStatus::PsaErrorInvalidArgument
);
}
#[test]
fn invalid_nonce() {
assert_eq!(
(Operation {
key_name: String::from("some key"),
alg: AeadWithDefaultLengthTag::Ccm.into(),
ciphertext: vec![0xff, 32].into(),
nonce: vec![].into(),
additional_data: vec![0xff, 16].into()
})
.validate(get_attrs())
.unwrap_err(),
ResponseStatus::PsaErrorInvalidArgument
);
}
}