parsec_service/providers/cryptoauthlib/
cipher.rs1use super::Provider;
4use crate::authenticators::ApplicationIdentity;
5use crate::key_info_managers::KeyIdentity;
6use log::error;
7use parsec_interface::operations::psa_algorithm::Cipher;
8use parsec_interface::operations::{psa_cipher_decrypt, psa_cipher_encrypt, psa_generate_random};
9use parsec_interface::requests::{ResponseStatus, Result};
10use std::convert::TryInto;
11
12const CIPHER_IV_SIZE: usize = 16;
13const CIPHER_CTR_SIZE: u8 = 4;
14
15impl Provider {
16 pub(super) fn algorithm_need_iv(&self, alg: &Cipher) -> bool {
18 !matches!(alg, Cipher::EcbNoPadding)
19 }
20
21 pub(super) fn get_cipher_algorithm(
23 &self,
24 mut cipher_params: rust_cryptoauthlib::CipherParam,
25 alg: &Cipher,
26 ) -> Result<rust_cryptoauthlib::CipherAlgorithm> {
27 match alg {
28 Cipher::Cfb => Ok(rust_cryptoauthlib::CipherAlgorithm::Cfb(cipher_params)),
29 Cipher::Ctr => {
30 cipher_params.counter_size = Some(CIPHER_CTR_SIZE);
31 Ok(rust_cryptoauthlib::CipherAlgorithm::Ctr(cipher_params))
32 }
33 Cipher::Ofb => Ok(rust_cryptoauthlib::CipherAlgorithm::Ofb(cipher_params)),
34 Cipher::EcbNoPadding => Ok(rust_cryptoauthlib::CipherAlgorithm::Ecb(cipher_params)),
35 Cipher::CbcNoPadding => Ok(rust_cryptoauthlib::CipherAlgorithm::Cbc(cipher_params)),
36 Cipher::CbcPkcs7 => Ok(rust_cryptoauthlib::CipherAlgorithm::CbcPkcs7(cipher_params)),
37 _ => {
38 error!("Cipher encryption failed: given algorithm is not supported.");
39 Err(ResponseStatus::PsaErrorNotSupported)
40 }
41 }
42 }
43
44 pub fn generate_iv(&self) -> Result<Vec<u8>> {
46 let random_op = psa_generate_random::Operation {
47 size: CIPHER_IV_SIZE,
48 };
49 let random_bytes = self
50 .psa_generate_random_internal(random_op)?
51 .random_bytes
52 .to_vec();
53 Ok(random_bytes)
54 }
55
56 pub(super) fn psa_cipher_encrypt_internal(
57 &self,
58 application_identity: &ApplicationIdentity,
59 op: psa_cipher_encrypt::Operation,
60 ) -> Result<psa_cipher_encrypt::Result> {
61 let key_identity = KeyIdentity::new(
62 application_identity.clone(),
63 self.provider_identity.clone(),
64 op.key_name.clone(),
65 );
66 let key_attributes = self.key_info_store.get_key_attributes(&key_identity)?;
67 op.validate(key_attributes)?;
68
69 let mut cipher_param = rust_cryptoauthlib::CipherParam {
70 ..Default::default()
71 };
72 let mut generated_iv = vec![0u8; 0];
73 if self.algorithm_need_iv(&op.alg) {
74 generated_iv = self.generate_iv()?;
75 cipher_param.iv = Some(generated_iv[..].try_into()?);
76 }
77
78 let mut plaintext = op.plaintext.to_vec();
79 let key_id = self.key_info_store.get_key_id::<u8>(&key_identity)?;
80
81 let result = self.device.cipher_encrypt(
82 self.get_cipher_algorithm(cipher_param, &op.alg)?,
83 key_id,
84 &mut plaintext,
85 );
86 match result {
87 rust_cryptoauthlib::AtcaStatus::AtcaSuccess => {
88 generated_iv.append(&mut plaintext);
89 let ciphertext = zeroize::Zeroizing::new(generated_iv);
90 Ok(psa_cipher_encrypt::Result { ciphertext })
91 }
92 rust_cryptoauthlib::AtcaStatus::AtcaInvalidSize
93 | rust_cryptoauthlib::AtcaStatus::AtcaInvalidId
94 | rust_cryptoauthlib::AtcaStatus::AtcaBadParam => {
95 error!("Cipher encryption failed: given plaintext is invalid.");
96 Err(ResponseStatus::PsaErrorInvalidArgument)
97 }
98 _ => Err(ResponseStatus::PsaErrorGenericError),
99 }
100 }
101
102 pub(super) fn psa_cipher_decrypt_internal(
103 &self,
104 application_identity: &ApplicationIdentity,
105 op: psa_cipher_decrypt::Operation,
106 ) -> Result<psa_cipher_decrypt::Result> {
107 let key_identity = KeyIdentity::new(
108 application_identity.clone(),
109 self.provider_identity.clone(),
110 op.key_name.clone(),
111 );
112 let key_attributes = self.key_info_store.get_key_attributes(&key_identity)?;
113 op.validate(key_attributes)?;
114
115 let mut cipher_param = rust_cryptoauthlib::CipherParam {
116 ..Default::default()
117 };
118 let mut ciphertext = op.ciphertext.to_vec();
119
120 if self.algorithm_need_iv(&op.alg) {
121 if ciphertext.len() < CIPHER_IV_SIZE {
122 error!(
123 "Cipher decryption failed: given ciphertext is too short to contain initialization vector."
124 );
125 return Err(ResponseStatus::PsaErrorInvalidArgument);
126 }
127 let mut iv = ciphertext;
128 ciphertext = iv.split_off(CIPHER_IV_SIZE);
129 cipher_param.iv = Some(iv[..].try_into()?);
130 }
131
132 let key_id = self.key_info_store.get_key_id::<u8>(&key_identity)?;
133
134 let result = self.device.cipher_decrypt(
135 self.get_cipher_algorithm(cipher_param, &op.alg)?,
136 key_id,
137 &mut ciphertext,
138 );
139
140 match result {
141 rust_cryptoauthlib::AtcaStatus::AtcaSuccess => {
142 let plaintext = zeroize::Zeroizing::new(ciphertext);
143 Ok(psa_cipher_decrypt::Result { plaintext })
144 }
145 rust_cryptoauthlib::AtcaStatus::AtcaInvalidSize
146 | rust_cryptoauthlib::AtcaStatus::AtcaInvalidId
147 | rust_cryptoauthlib::AtcaStatus::AtcaBadParam => {
148 error!("Cipher decryption failed: given ciphertext is invalid.");
149 Err(ResponseStatus::PsaErrorInvalidArgument)
150 }
151 _ => Err(ResponseStatus::PsaErrorGenericError),
152 }
153 }
154}