parsec_interface/operations/
psa_cipher_decrypt.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! # PsaCipherDecrypt operation
4//!
5//! Decrypt a short message with a symmetric cipher
6
7use super::psa_key_attributes::Attributes;
8use crate::operations::psa_algorithm::Cipher;
9use crate::requests::ResponseStatus;
10use derivative::Derivative;
11
12/// Native object for cipher 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 cipher encryption algorithm to be used for decryption, that is compatible with the type of key.
19    pub alg: Cipher,
20    /// The short encrypted message to be decrypted.
21    #[derivative(Debug = "ignore")]
22    pub ciphertext: zeroize::Zeroizing<Vec<u8>>,
23}
24
25impl Operation {
26    /// Validate the contents of the operation against the attributes of the key it targets
27    ///
28    /// This method checks that:
29    /// * the key policy allows decrypting messages
30    /// * the key policy allows the decryption algorithm requested in the operation
31    /// * the key type is compatible with the requested algorithm
32    /// * the message to decrypt is valid (not length 0)
33    pub fn validate(&self, key_attributes: Attributes) -> crate::requests::Result<()> {
34        key_attributes.can_decrypt_message()?;
35        key_attributes.permits_alg(self.alg.into())?;
36        key_attributes.compatible_with_alg(self.alg.into())?;
37        if self.ciphertext.is_empty() {
38            return Err(ResponseStatus::PsaErrorInvalidArgument);
39        }
40        Ok(())
41    }
42}
43
44/// Native object for cipher decrypt result.
45// Debug derived as NativeResult enum requires it, even though nothing inside this Result is debuggable
46// as `plaintext` is sensitive.
47#[derive(Derivative)]
48#[derivative(Debug)]
49pub struct Result {
50    /// Decrypted message
51    #[derivative(Debug = "ignore")]
52    pub plaintext: zeroize::Zeroizing<Vec<u8>>,
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use crate::operations::psa_algorithm::Cipher;
59    use crate::operations::psa_key_attributes::{Lifetime, Policy, Type, UsageFlags};
60
61    fn get_attrs() -> Attributes {
62        let mut usage_flags = UsageFlags::default();
63        let _ = usage_flags.set_decrypt();
64        Attributes {
65            lifetime: Lifetime::Persistent,
66            key_type: Type::Arc4,
67            bits: 256,
68            policy: Policy {
69                usage_flags,
70                permitted_algorithms: Cipher::StreamCipher.into(),
71            },
72        }
73    }
74
75    #[test]
76    fn validate_success() {
77        (Operation {
78            key_name: String::from("some key"),
79            alg: Cipher::StreamCipher,
80            ciphertext: vec![0xff, 32].into(),
81        })
82        .validate(get_attrs())
83        .unwrap();
84    }
85
86    #[test]
87    fn cannot_decrypt() {
88        let mut attrs = get_attrs();
89        attrs.policy.usage_flags = UsageFlags::default();
90        assert_eq!(
91            (Operation {
92                key_name: String::from("some key"),
93                alg: Cipher::StreamCipher,
94                ciphertext: vec![0xff, 32].into(),
95            })
96            .validate(attrs)
97            .unwrap_err(),
98            ResponseStatus::PsaErrorNotPermitted
99        );
100    }
101
102    #[test]
103    fn wrong_algorithm() {
104        assert_eq!(
105            (Operation {
106                key_name: String::from("some key"),
107                alg: Cipher::Cfb,
108                ciphertext: vec![0xff, 32].into(),
109            })
110            .validate(get_attrs())
111            .unwrap_err(),
112            ResponseStatus::PsaErrorNotPermitted
113        );
114    }
115
116    #[test]
117    fn invalid_ciphertext() {
118        assert_eq!(
119            (Operation {
120                key_name: String::from("some key"),
121                alg: Cipher::StreamCipher,
122                ciphertext: vec![].into(),
123            })
124            .validate(get_attrs())
125            .unwrap_err(),
126            ResponseStatus::PsaErrorInvalidArgument
127        );
128    }
129}