diff --git a/psa-crypto-sys/src/c/shim.c b/psa-crypto-sys/src/c/shim.c index c89ebda..de7e20e 100644 --- a/psa-crypto-sys/src/c/shim.c +++ b/psa-crypto-sys/src/c/shim.c @@ -49,6 +49,12 @@ shim_key_attributes_init(void) return psa_key_attributes_init(); } +psa_cipher_operation_t +shim_cipher_operation_init(void) +{ + return psa_cipher_operation_init(); +} + psa_key_derivation_operation_t shim_key_derivation_operation_init(void) { diff --git a/psa-crypto-sys/src/c/shim.h b/psa-crypto-sys/src/c/shim.h index 854a658..323fe9d 100644 --- a/psa-crypto-sys/src/c/shim.h +++ b/psa-crypto-sys/src/c/shim.h @@ -19,6 +19,7 @@ psa_key_lifetime_t shim_get_key_lifetime(const psa_key_attributes_t *attributes) psa_key_type_t shim_get_key_type(const psa_key_attributes_t *attributes); psa_key_usage_t shim_get_key_usage_flags(const psa_key_attributes_t *attributes); psa_key_attributes_t shim_key_attributes_init(void); +psa_cipher_operation_t shim_cipher_operation_init(void); psa_key_derivation_operation_t shim_key_derivation_operation_init(void); void shim_set_key_algorithm(psa_key_attributes_t *attributes, psa_algorithm_t alg); diff --git a/psa-crypto-sys/src/lib.rs b/psa-crypto-sys/src/lib.rs index 9039fb9..14b84d8 100644 --- a/psa-crypto-sys/src/lib.rs +++ b/psa-crypto-sys/src/lib.rs @@ -39,17 +39,20 @@ pub use types::*; #[cfg(feature = "operations")] pub use psa_crypto_binding::{ psa_aead_decrypt, psa_aead_encrypt, psa_asymmetric_decrypt, psa_asymmetric_encrypt, - psa_close_key, psa_copy_key, psa_crypto_init, psa_destroy_key, psa_export_key, - psa_export_public_key, psa_generate_key, psa_generate_random, psa_get_key_attributes, - psa_hash_compare, psa_hash_compute, psa_import_key, psa_key_derivation_abort, - psa_key_derivation_input_bytes, psa_key_derivation_input_key, psa_key_derivation_key_agreement, - psa_key_derivation_output_key, psa_key_derivation_set_capacity, psa_key_derivation_setup, - psa_mac_compute, psa_mac_verify, psa_open_key, psa_raw_key_agreement, psa_reset_key_attributes, - psa_sign_hash, psa_verify_hash, + psa_cipher_abort, psa_cipher_decrypt_setup, psa_cipher_encrypt_setup, psa_cipher_finish, + psa_cipher_set_iv, psa_cipher_update, psa_close_key, psa_copy_key, psa_crypto_init, + psa_destroy_key, psa_export_key, psa_export_public_key, psa_generate_key, psa_generate_random, + psa_get_key_attributes, psa_hash_compare, psa_hash_compute, psa_import_key, + psa_key_derivation_abort, psa_key_derivation_input_bytes, psa_key_derivation_input_key, + psa_key_derivation_key_agreement, psa_key_derivation_output_key, + psa_key_derivation_set_capacity, psa_key_derivation_setup, psa_mac_compute, psa_mac_verify, + psa_open_key, psa_raw_key_agreement, psa_reset_key_attributes, psa_sign_hash, psa_verify_hash, }; #[cfg(feature = "interface")] -pub use psa_crypto_binding::{psa_key_attributes_t, psa_key_derivation_operation_t}; +pub use psa_crypto_binding::{ + psa_cipher_operation_t, psa_key_attributes_t, psa_key_derivation_operation_t, +}; // Secure Element Driver definitions #[cfg(feature = "interface")] diff --git a/psa-crypto-sys/src/shim.rs b/psa-crypto-sys/src/shim.rs index ee1e7de..ae86b4c 100644 --- a/psa-crypto-sys/src/shim.rs +++ b/psa-crypto-sys/src/shim.rs @@ -5,9 +5,9 @@ //! generated by bindgen, such as #define or static inline functions. use super::psa_crypto_binding::{ - self, psa_algorithm_t, psa_dh_family_t, psa_ecc_family_t, psa_key_attributes_t, - psa_key_derivation_operation_t, psa_key_derivation_step_t, psa_key_id_t, psa_key_lifetime_t, - psa_key_type_t, psa_key_usage_t, + self, psa_algorithm_t, psa_cipher_operation_t, psa_dh_family_t, psa_ecc_family_t, + psa_key_attributes_t, psa_key_derivation_operation_t, psa_key_derivation_step_t, psa_key_id_t, + psa_key_lifetime_t, psa_key_type_t, psa_key_usage_t, }; pub const PSA_KEY_DERIVATION_INPUT_SECRET: psa_key_derivation_step_t = @@ -45,6 +45,10 @@ pub unsafe fn psa_key_attributes_init() -> psa_key_attributes_t { psa_crypto_binding::shim_key_attributes_init() } +pub unsafe fn psa_cipher_operation_init() -> psa_cipher_operation_t { + psa_crypto_binding::shim_cipher_operation_init() +} + pub fn psa_key_derivation_operation_init() -> psa_key_derivation_operation_t { unsafe { psa_crypto_binding::shim_key_derivation_operation_init() } } diff --git a/psa-crypto/src/operations/cipher.rs b/psa-crypto/src/operations/cipher.rs index a817844..b61ada7 100644 --- a/psa-crypto/src/operations/cipher.rs +++ b/psa-crypto/src/operations/cipher.rs @@ -2,3 +2,157 @@ // SPDX-License-Identifier: Apache-2.0 //! # Unauthenticated Ciphers operations + +use crate::initialized; +use crate::types::algorithm::Cipher; +use crate::types::key::Id; +use crate::types::status::{Result, Status}; + +fn crypt( + encrypt: bool, + key_id: Id, + alg: Cipher, + plaintext: &[u8], + iv: &[u8], + ciphertext: &mut [u8], +) -> Result { + initialized()?; + + let mut operation: psa_crypto_sys::psa_cipher_operation_t = + unsafe { psa_crypto_sys::psa_cipher_operation_init() }; + + Status::from(unsafe { + (if encrypt { + psa_crypto_sys::psa_cipher_encrypt_setup + } else { + psa_crypto_sys::psa_cipher_decrypt_setup + })(&mut operation, key_id.0, alg.into()) + }) + .to_result()?; + + let mut output_length = 0; + let mut output_length_finish = 0; + match (|| { + Status::from(unsafe { + psa_crypto_sys::psa_cipher_set_iv(&mut operation, iv.as_ptr(), iv.len()) + }) + .to_result()?; + + Status::from(unsafe { + psa_crypto_sys::psa_cipher_update( + &mut operation, + plaintext.as_ptr(), + plaintext.len(), + ciphertext.as_mut_ptr(), + ciphertext.len(), + &mut output_length, + ) + }) + .to_result()?; + + Status::from(unsafe { + psa_crypto_sys::psa_cipher_finish( + &mut operation, + ciphertext.as_mut_ptr().add(output_length), + ciphertext.len() - output_length, + &mut output_length_finish, + ) + }) + .to_result()?; + + Ok(()) + })() { + Ok(()) => (), + Err(x) => { + Status::from(unsafe { psa_crypto_sys::psa_cipher_abort(&mut operation) }) + .to_result()?; + return Err(x); + } + } + + Ok(output_length + output_length_finish) +} + +/// Encrypt a short message with a key +/// +/// The encrypted message is written in `ciphertext`. The function returns the number of bytes written. +/// +/// # Example +/// +/// ``` +/// # use psa_crypto::operations::cipher::encrypt; +/// # use psa_crypto::operations::key_management::generate; +/// # use psa_crypto::types::algorithm::Cipher; +/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags}; +/// # +/// # let mut usage_flags: UsageFlags = Default::default(); +/// # usage_flags.set_encrypt(); +/// # let mut attributes = Attributes { +/// # key_type: Type::Aes, +/// # bits: 128, +/// # lifetime: Lifetime::Volatile, +/// # policy: Policy { +/// # usage_flags, +/// # permitted_algorithms: Cipher::CbcNoPadding.into(), +/// # }, +/// # }; +/// # const MESSAGE: [u8; 16] = [0; 16]; +/// psa_crypto::init().unwrap(); +/// let my_key = generate(attributes, None).unwrap(); +/// let alg = Cipher::CbcNoPadding; +/// let iv = vec![0; 16]; +/// let mut encrypted_message = vec![0; MESSAGE.len()]; +/// +/// let size = encrypt(my_key, alg, &MESSAGE, &iv, &mut encrypted_message).unwrap(); +/// ``` +pub fn encrypt( + key_id: Id, + alg: Cipher, + plaintext: &[u8], + iv: &[u8], + ciphertext: &mut [u8], +) -> Result { + crypt(true, key_id, alg, plaintext, iv, ciphertext) +} + +/// Decrypt a short message with a key +/// +/// The decrypted message is written in `plaintext`. The function returns the number of bytes written. +/// +/// # Example +/// +/// ``` +/// # use psa_crypto::operations::cipher::decrypt; +/// # use psa_crypto::operations::key_management::generate; +/// # use psa_crypto::types::algorithm::Cipher; +/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags}; +/// # +/// # let mut usage_flags: UsageFlags = Default::default(); +/// # usage_flags.set_decrypt(); +/// # let mut attributes = Attributes { +/// # key_type: Type::Aes, +/// # bits: 128, +/// # lifetime: Lifetime::Volatile, +/// # policy: Policy { +/// # usage_flags, +/// # permitted_algorithms: Cipher::Ctr.into(), +/// # }, +/// # }; +/// # const MESSAGE: [u8; 13] = [0; 13]; +/// psa_crypto::init().unwrap(); +/// let my_key = generate(attributes, None).unwrap(); +/// let alg = Cipher::Ctr; +/// let iv = vec![0; 16]; +/// let mut decrypted_message = vec![0; MESSAGE.len()]; +/// +/// let size = decrypt(my_key, alg, &MESSAGE, &iv, &mut decrypted_message).unwrap(); +/// ``` +pub fn decrypt( + key_id: Id, + alg: Cipher, + ciphertext: &[u8], + iv: &[u8], + plaintext: &mut [u8], +) -> Result { + crypt(false, key_id, alg, ciphertext, iv, plaintext) +} diff --git a/psa-crypto/src/types/algorithm.rs b/psa-crypto/src/types/algorithm.rs index ee73842..667dbe5 100644 --- a/psa-crypto/src/types/algorithm.rs +++ b/psa-crypto/src/types/algorithm.rs @@ -599,10 +599,7 @@ impl TryFrom for psa_crypto_sys::psa_algorithm_t { Algorithm::KeyAgreement(key_agreement) => Ok(key_agreement.into()), Algorithm::KeyDerivation(key_derivation) => Ok(key_derivation.into()), Algorithm::Aead(aead) => Ok(aead.into()), - _ => { - error!("Algorithm not supported: {:?}.", alg); - Err(Error::NotSupported) - } + Algorithm::Cipher(cipher) => Ok(cipher.into()), } } } @@ -770,6 +767,22 @@ impl From for psa_crypto_sys::psa_algorithm_t { } } +#[cfg(feature = "interface")] +impl From for psa_crypto_sys::psa_algorithm_t { + fn from(cipher: Cipher) -> Self { + match cipher { + Cipher::StreamCipher => psa_crypto_sys::PSA_ALG_STREAM_CIPHER, + Cipher::Ctr => psa_crypto_sys::PSA_ALG_CTR, + Cipher::Cfb => psa_crypto_sys::PSA_ALG_CFB, + Cipher::Ofb => psa_crypto_sys::PSA_ALG_OFB, + Cipher::Xts => psa_crypto_sys::PSA_ALG_XTS, + Cipher::EcbNoPadding => psa_crypto_sys::PSA_ALG_ECB_NO_PADDING, + Cipher::CbcNoPadding => psa_crypto_sys::PSA_ALG_CBC_NO_PADDING, + Cipher::CbcPkcs7 => psa_crypto_sys::PSA_ALG_CBC_PKCS7, + } + } +} + #[cfg(feature = "interface")] impl TryFrom for Mac { type Error = Error;