parsec_interface/operations/
psa_aead_decrypt.rs

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