parsec_interface/operations/
psa_cipher_encrypt.rs

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