parsec_interface/operations/
psa_aead_encrypt.rs

1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! # PsaAeadEncrypt operation
4//!
5//! Process an authenticated encryption operation.
6
7use super::psa_key_attributes::Attributes;
8use crate::operations::psa_algorithm::Aead;
9use crate::requests::ResponseStatus;
10use derivative::Derivative;
11
12/// Native object for AEAD encryption operations.
13#[derive(Derivative)]
14#[derivative(Debug)]
15pub struct Operation {
16    /// Defines which key should be used for the encryption operation.
17    pub key_name: String,
18    /// An AEAD encryption algorithm that is compatible with the key type.
19    pub alg: Aead,
20    /// Nonce or IV to use.
21    #[derivative(Debug = "ignore")]
22    pub nonce: zeroize::Zeroizing<Vec<u8>>,
23    /// Additional data that will be authenticated but not encrypted.
24    #[derivative(Debug = "ignore")]
25    pub additional_data: zeroize::Zeroizing<Vec<u8>>,
26    /// Data that will be authenticated and encrypted.
27    #[derivative(Debug = "ignore")]
28    pub plaintext: zeroize::Zeroizing<Vec<u8>>,
29}
30
31impl Operation {
32    /// Validate the contents of the operation against the attributes of the key it targets
33    ///
34    /// This method checks that:
35    /// * the key policy allows encrypting messages
36    /// * the key policy allows the encryption algorithm requested in the operation
37    /// * the key type is compatible with the requested algorithm
38    /// * the message to encrypt is valid (not length 0)
39    /// * the nonce is valid (not length 0)
40    pub fn validate(&self, key_attributes: Attributes) -> crate::requests::Result<()> {
41        key_attributes.can_encrypt_message()?;
42        key_attributes.permits_alg(self.alg.into())?;
43        key_attributes.compatible_with_alg(self.alg.into())?;
44        if self.plaintext.is_empty() || self.nonce.is_empty() {
45            return Err(ResponseStatus::PsaErrorInvalidArgument);
46        }
47        Ok(())
48    }
49}
50
51/// Native object for AEAD encrypt result.
52#[derive(Derivative)]
53#[derivative(Debug)]
54pub struct Result {
55    /// The `ciphertext` field contains the encrypted and authenticated data.For algorithms where
56    /// the encrypted data and the authentication tag are defined as separate outputs, the authentication
57    /// tag is appended to the encrypted data.
58    #[derivative(Debug = "ignore")]
59    pub ciphertext: zeroize::Zeroizing<Vec<u8>>,
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use crate::operations::psa_algorithm::AeadWithDefaultLengthTag;
66    use crate::operations::psa_key_attributes::{Lifetime, Policy, Type, UsageFlags};
67    use psa_crypto::types::algorithm::Aead;
68
69    fn get_attrs() -> Attributes {
70        let mut usage_flags = UsageFlags::default();
71        let _ = usage_flags.set_encrypt();
72        Attributes {
73            lifetime: Lifetime::Persistent,
74            key_type: Type::Aes,
75            bits: 0,
76            policy: Policy {
77                usage_flags,
78                permitted_algorithms: Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm)
79                    .into(),
80            },
81        }
82    }
83
84    #[test]
85    fn validate_success() {
86        (Operation {
87            key_name: String::from("some key"),
88            alg: AeadWithDefaultLengthTag::Ccm.into(),
89            plaintext: vec![0xff, 32].into(),
90            nonce: vec![0xaa, 12].into(),
91            additional_data: vec![0xff, 16].into(),
92        })
93        .validate(get_attrs())
94        .unwrap();
95    }
96
97    #[test]
98    fn cannot_encrypt() {
99        let mut attrs = get_attrs();
100        attrs.policy.usage_flags = UsageFlags::default();
101        assert_eq!(
102            (Operation {
103                key_name: String::from("some key"),
104                alg: AeadWithDefaultLengthTag::Ccm.into(),
105                plaintext: vec![0xff, 32].into(),
106                nonce: vec![0xaa, 12].into(),
107                additional_data: vec![0xff, 16].into()
108            })
109            .validate(attrs)
110            .unwrap_err(),
111            ResponseStatus::PsaErrorNotPermitted
112        );
113    }
114
115    #[test]
116    fn wrong_algorithm() {
117        assert_eq!(
118            (Operation {
119                key_name: String::from("some key"),
120                alg: AeadWithDefaultLengthTag::Gcm.into(),
121                plaintext: vec![0xff, 32].into(),
122                nonce: vec![0xaa, 12].into(),
123                additional_data: vec![0xff, 16].into()
124            })
125            .validate(get_attrs())
126            .unwrap_err(),
127            ResponseStatus::PsaErrorNotPermitted
128        );
129    }
130
131    #[test]
132    fn invalid_plaintext() {
133        assert_eq!(
134            (Operation {
135                key_name: String::from("some key"),
136                alg: AeadWithDefaultLengthTag::Ccm.into(),
137                plaintext: vec![].into(),
138                nonce: vec![0xaa, 12].into(),
139                additional_data: vec![0xff, 16].into()
140            })
141            .validate(get_attrs())
142            .unwrap_err(),
143            ResponseStatus::PsaErrorInvalidArgument
144        );
145    }
146
147    #[test]
148    fn invalid_nonce() {
149        assert_eq!(
150            (Operation {
151                key_name: String::from("some key"),
152                alg: AeadWithDefaultLengthTag::Ccm.into(),
153                plaintext: vec![0xff, 32].into(),
154                nonce: vec![].into(),
155                additional_data: vec![0xff, 16].into()
156            })
157            .validate(get_attrs())
158            .unwrap_err(),
159            ResponseStatus::PsaErrorInvalidArgument
160        );
161    }
162}