parsec_interface/operations/
psa_asymmetric_encrypt.rs

1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! # PsaAsymmetricEncrypt operation
4//!
5//! Encrypt a short message with a public key.
6
7use super::psa_key_attributes::Attributes;
8use crate::operations::psa_algorithm::AsymmetricEncryption;
9use crate::requests::ResponseStatus;
10use derivative::Derivative;
11
12/// Native object for asymmetric 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 asymmetric encryption algorithm that is compatible with the key type
19    pub alg: AsymmetricEncryption,
20    /// The short message to be encrypted.
21    #[derivative(Debug = "ignore")]
22    pub plaintext: zeroize::Zeroizing<Vec<u8>>,
23    /// Salt to use during encryption, if supported by the algorithm.
24    #[derivative(Debug = "ignore")]
25    pub salt: Option<zeroize::Zeroizing<Vec<u8>>>,
26}
27
28impl Operation {
29    /// Validate the contents of the operation against the attributes of the key it targets
30    ///
31    /// This method checks that:
32    /// * the key policy allows encrypting messages
33    /// * the key policy allows the encryption algorithm requested in the operation
34    /// * the key type is compatible with the requested algorithm
35    /// * if the algorithm is RsaPkcs1v15Crypt, it has no salt (it is not compatible with salt)
36    /// * the message to encrypt is valid (not length 0)
37    pub fn validate(&self, key_attributes: Attributes) -> crate::requests::Result<()> {
38        key_attributes.can_encrypt_message()?;
39        key_attributes.permits_alg(self.alg.into())?;
40        key_attributes.compatible_with_alg(self.alg.into())?;
41        if (self.alg == AsymmetricEncryption::RsaPkcs1v15Crypt && self.salt.is_some())
42            || self.plaintext.is_empty()
43        {
44            return Err(ResponseStatus::PsaErrorInvalidArgument);
45        }
46        Ok(())
47    }
48}
49
50/// Native object for asymmetric encrypt result.
51#[derive(Derivative)]
52#[derivative(Debug)]
53pub struct Result {
54    /// The `ciphertext` field contains the encrypted short message.
55    #[derivative(Debug = "ignore")]
56    pub ciphertext: zeroize::Zeroizing<Vec<u8>>,
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::operations::psa_algorithm::{AsymmetricEncryption, Hash};
63    use crate::operations::psa_key_attributes::{Lifetime, Policy, Type, UsageFlags};
64
65    fn get_attrs() -> Attributes {
66        let mut usage_flags = UsageFlags::default();
67        let _ = usage_flags.set_encrypt();
68        Attributes {
69            lifetime: Lifetime::Persistent,
70            key_type: Type::RsaKeyPair,
71            bits: 256,
72            policy: Policy {
73                usage_flags,
74                permitted_algorithms: AsymmetricEncryption::RsaPkcs1v15Crypt.into(),
75            },
76        }
77    }
78
79    #[test]
80    fn validate_success() {
81        (Operation {
82            key_name: String::from("some key"),
83            alg: AsymmetricEncryption::RsaPkcs1v15Crypt,
84            plaintext: vec![0xff, 32].into(),
85            salt: None,
86        })
87        .validate(get_attrs())
88        .unwrap();
89    }
90
91    #[test]
92    fn cannot_encrypt() {
93        let mut attrs = get_attrs();
94        attrs.policy.usage_flags = UsageFlags::default();
95        assert_eq!(
96            (Operation {
97                key_name: String::from("some key"),
98                alg: AsymmetricEncryption::RsaPkcs1v15Crypt,
99                plaintext: vec![0xff, 32].into(),
100                salt: None,
101            })
102            .validate(attrs)
103            .unwrap_err(),
104            ResponseStatus::PsaErrorNotPermitted
105        );
106    }
107
108    #[test]
109    fn wrong_algorithm() {
110        assert_eq!(
111            (Operation {
112                key_name: String::from("some key"),
113                alg: AsymmetricEncryption::RsaOaep {
114                    hash_alg: Hash::Sha256,
115                },
116                plaintext: vec![0xff, 32].into(),
117                salt: None,
118            })
119            .validate(get_attrs())
120            .unwrap_err(),
121            ResponseStatus::PsaErrorNotPermitted
122        );
123    }
124
125    #[test]
126    fn invalid_plaintext() {
127        assert_eq!(
128            (Operation {
129                key_name: String::from("some key"),
130                alg: AsymmetricEncryption::RsaPkcs1v15Crypt,
131                plaintext: vec![].into(),
132                salt: None,
133            })
134            .validate(get_attrs())
135            .unwrap_err(),
136            ResponseStatus::PsaErrorInvalidArgument
137        );
138    }
139
140    #[test]
141    fn salt_with_rsapkcs1v15crypt() {
142        assert_eq!(
143            (Operation {
144                key_name: String::from("some key"),
145                alg: AsymmetricEncryption::RsaPkcs1v15Crypt,
146                plaintext: vec![0xff, 32].into(),
147                salt: Some(zeroize::Zeroizing::new(vec![0xff, 32])),
148            })
149            .validate(get_attrs())
150            .unwrap_err(),
151            ResponseStatus::PsaErrorInvalidArgument
152        );
153    }
154}