Skip to content

Commit

Permalink
Merge pull request parallaxsecond#37 from sbailey-arm/add-asym-encryp…
Browse files Browse the repository at this point in the history
…tion

Added asymmetric encrypt and decrypt to psa-crypto and psa-crypto-sys
  • Loading branch information
ionut-arm authored Jul 6, 2020
2 parents 5288f88 + b93fd93 commit 44486bb
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 15 deletions.
28 changes: 28 additions & 0 deletions psa-crypto-sys/src/c/shim.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ shim_PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(psa_algorithm_t alg) {
return PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg);
}

int
shim_PSA_ALG_IS_RSA_OAEP(psa_algorithm_t alg) {
return PSA_ALG_IS_RSA_OAEP(alg);
}

int
shim_PSA_ALG_IS_KEY_AGREEMENT(psa_algorithm_t alg) {
return PSA_ALG_IS_KEY_AGREEMENT(alg);
Expand Down Expand Up @@ -157,6 +162,11 @@ shim_PSA_ALG_SIGN_GET_HASH(psa_algorithm_t alg) {
return PSA_ALG_SIGN_GET_HASH(alg);
}

psa_algorithm_t
shim_PSA_ALG_RSA_OAEP_GET_HASH(psa_algorithm_t alg) {
return PSA_ALG_RSA_OAEP_GET_HASH(alg);
}

psa_algorithm_t
shim_PSA_ALG_RSA_PKCS1V15_SIGN(psa_algorithm_t hash_alg) {
return PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg);
Expand Down Expand Up @@ -201,6 +211,12 @@ shim_PSA_KEY_TYPE_IS_DH_KEY_PAIR(psa_key_type_t key_type)
return PSA_KEY_TYPE_IS_DH_KEY_PAIR(key_type);
}

psa_algorithm_t
shim_PSA_ALG_RSA_OAEP(psa_algorithm_t alg_type)
{
return PSA_ALG_RSA_OAEP(alg_type);
}

psa_ecc_curve_t
shim_PSA_KEY_TYPE_GET_CURVE(psa_key_type_t key_type)
{
Expand Down Expand Up @@ -249,6 +265,18 @@ shim_PSA_SIGN_OUTPUT_SIZE(psa_key_type_t key_type, size_t key_bits, psa_algorith
return PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, alg);
}

size_t
shim_PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(psa_key_type_t key_type, size_t key_bits, psa_algorithm_t alg)
{
return PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(key_type, key_bits, alg);
}

size_t
shim_PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(psa_key_type_t key_type, size_t key_bits, psa_algorithm_t alg)
{
return PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(key_type, key_bits, alg);
}

size_t
shim_PSA_KEY_EXPORT_MAX_SIZE(psa_key_type_t key_type, size_t key_bits)
{
Expand Down
5 changes: 5 additions & 0 deletions psa-crypto-sys/src/c/shim.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,20 @@ int shim_PSA_ALG_IS_CIPHER(psa_algorithm_t alg);
int shim_PSA_ALG_IS_AEAD(psa_algorithm_t alg);
int shim_PSA_ALG_IS_SIGN(psa_algorithm_t alg);
int shim_PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(psa_algorithm_t alg);
int shim_PSA_ALG_IS_RSA_OAEP(psa_algorithm_t alg);
int shim_PSA_ALG_IS_KEY_AGREEMENT(psa_algorithm_t alg);
int shim_PSA_ALG_IS_KEY_DERIVATION(psa_algorithm_t alg);
int shim_PSA_ALG_IS_RSA_PKCS1V15_SIGN(psa_algorithm_t alg);
int shim_PSA_ALG_IS_RSA_PSS(psa_algorithm_t alg);
int shim_PSA_ALG_IS_ECDSA(psa_algorithm_t alg);
int shim_PSA_ALG_IS_DETERMINISTIC_ECDSA(psa_algorithm_t alg);
psa_algorithm_t shim_PSA_ALG_RSA_OAEP(psa_algorithm_t alg);
psa_algorithm_t shim_PSA_ALG_RSA_PKCS1V15_SIGN(psa_algorithm_t hash_alg);
psa_algorithm_t shim_PSA_ALG_RSA_PSS(psa_algorithm_t hash_alg);
psa_algorithm_t shim_PSA_ALG_ECDSA(psa_algorithm_t hash_alg);
psa_algorithm_t shim_PSA_ALG_DETERMINISTIC_ECDSA(psa_algorithm_t hash_alg);
psa_algorithm_t shim_PSA_ALG_SIGN_GET_HASH(psa_algorithm_t alg);
psa_algorithm_t shim_PSA_ALG_RSA_OAEP_GET_HASH(psa_algorithm_t alg);
int shim_PSA_KEY_TYPE_IS_ECC_KEY_PAIR(psa_key_type_t key_type);
int shim_PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(psa_key_type_t key_type);
int shim_PSA_KEY_TYPE_IS_DH_PUBLIC_KEY(psa_key_type_t key_type);
Expand All @@ -117,4 +120,6 @@ psa_key_type_t shim_PSA_KEY_TYPE_DH_KEY_PAIR(psa_dh_group_t group);
psa_key_type_t shim_PSA_KEY_TYPE_DH_PUBLIC_KEY(psa_dh_group_t group);
psa_key_type_t shim_PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(psa_key_type_t key_type);
size_t shim_PSA_SIGN_OUTPUT_SIZE(psa_key_type_t key_type, size_t key_bits, psa_algorithm_t alg);
size_t shim_PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(psa_key_type_t key_type, size_t key_bits, psa_algorithm_t alg);
size_t shim_PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(psa_key_type_t key_type, size_t key_bits, psa_algorithm_t alg);
size_t shim_PSA_KEY_EXPORT_MAX_SIZE(psa_key_type_t key_type, size_t key_bits);
7 changes: 4 additions & 3 deletions psa-crypto-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ pub use types::*;

#[cfg(feature = "implementation-defined")]
pub use psa_crypto_binding::{
psa_close_key, psa_crypto_init, psa_destroy_key, psa_export_public_key, psa_generate_key,
psa_get_key_attributes, psa_import_key, psa_key_attributes_t, psa_open_key,
psa_reset_key_attributes, psa_sign_hash, psa_verify_hash,
psa_asymmetric_decrypt, psa_asymmetric_encrypt, psa_close_key, psa_crypto_init,
psa_destroy_key, psa_export_public_key, psa_generate_key, psa_get_key_attributes,
psa_import_key, psa_key_attributes_t, psa_open_key, psa_reset_key_attributes, psa_sign_hash,
psa_verify_hash,
};

// Secure Element Driver definitions
Expand Down
28 changes: 28 additions & 0 deletions psa-crypto-sys/src/shim_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ pub fn PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg: psa_algorithm_t) -> bool {
unsafe { psa_crypto_binding::shim_PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg) == 1 }
}

pub unsafe fn PSA_ALG_IS_RSA_OAEP(alg: psa_algorithm_t) -> bool {
psa_crypto_binding::shim_PSA_ALG_IS_RSA_OAEP(alg) == 1
}

pub fn PSA_ALG_IS_KEY_AGREEMENT(alg: psa_algorithm_t) -> bool {
unsafe { psa_crypto_binding::shim_PSA_ALG_IS_KEY_AGREEMENT(alg) == 1 }
}
Expand Down Expand Up @@ -116,6 +120,10 @@ pub fn PSA_ALG_SIGN_GET_HASH(alg: psa_algorithm_t) -> psa_algorithm_t {
unsafe { psa_crypto_binding::shim_PSA_ALG_SIGN_GET_HASH(alg) }
}

pub fn PSA_ALG_RSA_OAEP_GET_HASH(alg: psa_algorithm_t) -> psa_algorithm_t {
unsafe { psa_crypto_binding::shim_PSA_ALG_RSA_OAEP_GET_HASH(alg) }
}

pub fn PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg: psa_algorithm_t) -> psa_algorithm_t {
unsafe { psa_crypto_binding::shim_PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg) }
}
Expand All @@ -132,6 +140,10 @@ pub fn PSA_ALG_DETERMINISTIC_ECDSA(hash_alg: psa_algorithm_t) -> psa_algorithm_t
unsafe { psa_crypto_binding::shim_PSA_ALG_DETERMINISTIC_ECDSA(hash_alg) }
}

pub unsafe fn PSA_ALG_RSA_OAEP(hash_alg: psa_algorithm_t) -> psa_algorithm_t {
psa_crypto_binding::shim_PSA_ALG_RSA_OAEP(hash_alg)
}

pub fn PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type: psa_key_type_t) -> bool {
unsafe { psa_crypto_binding::shim_PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type) == 1 }
}
Expand Down Expand Up @@ -184,6 +196,22 @@ pub unsafe fn PSA_SIGN_OUTPUT_SIZE(
psa_crypto_binding::shim_PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, alg)
}

pub unsafe fn PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(
key_type: psa_key_type_t,
key_bits: usize,
alg: psa_algorithm_t,
) -> usize {
psa_crypto_binding::shim_PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(key_type, key_bits, alg)
}

pub unsafe fn PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(
key_type: psa_key_type_t,
key_bits: usize,
alg: psa_algorithm_t,
) -> usize {
psa_crypto_binding::shim_PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(key_type, key_bits, alg)
}

pub unsafe fn PSA_EXPORT_KEY_OUTPUT_SIZE(key_type: psa_key_type_t, key_bits: usize) -> usize {
psa_crypto_binding::shim_PSA_KEY_EXPORT_MAX_SIZE(key_type, key_bits)
}
4 changes: 4 additions & 0 deletions psa-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ log = "0.4.8"
serde = { version = "1.0.110", features = ["derive"] }
zeroize = { version = "1.1.0", features = ["zeroize_derive"] }

[dev-dependencies]
rsa = "0.3.0"
rand = "0.7.3"

[features]
default = ["with-mbed-crypto", "no-std"]
with-mbed-crypto = ["psa-crypto-sys/implementation-defined"]
Expand Down
170 changes: 170 additions & 0 deletions psa-crypto/src/operations/asym_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,173 @@
// SPDX-License-Identifier: Apache-2.0

//! # Asymmetric Encryption operations
//!
//! See the PSA Crypto API for the format of the different parameters used in this module.
use crate::initialized;
use crate::types::algorithm::AsymmetricEncryption;
use crate::types::key::Id;
use crate::types::status::{Result, Status};

/// Encrypt a short message with a key pair or public key
///
/// The encrypted message is written in `ciphertext`. The function returns the number of bytes written.
///
/// # Example
///
/// ```
/// # use psa_crypto::operations::key_management::generate;
/// # use psa_crypto::operations::asym_encryption::encrypt;
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// # use psa_crypto::types::algorithm::{AsymmetricEncryption, Hash};
/// #
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags: UsageFlags {
/// # encrypt: true,
/// # ..Default::default()
/// # },
/// # permitted_algorithms: AsymmetricEncryption::RsaPkcs1v15Crypt.into(),
/// # },
/// # };
/// # const MESSAGE: [u8; 32] = [
/// # 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2,
/// # 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78,
/// # ];
/// psa_crypto::init().unwrap();
/// let my_key = generate(attributes, None).unwrap();
/// let alg = AsymmetricEncryption::RsaPkcs1v15Crypt;
/// let buffer_size = attributes.asymmetric_encrypt_output_size(alg).unwrap();
/// let mut encrypted_message = vec![0; buffer_size];
///
/// let size = encrypt(my_key,
/// alg,
/// &MESSAGE,
/// None,
/// &mut encrypted_message).unwrap();
/// encrypted_message.resize(size, 0);
/// ```
pub fn encrypt(
key_id: Id,
alg: AsymmetricEncryption,
plaintext: &[u8],
salt: Option<&[u8]>,
ciphertext: &mut [u8],
) -> Result<usize> {
initialized()?;

let handle = key_id.handle()?;

let mut output_length = 0;
let (salt_ptr, salt_len) = match salt {
Some(salt) => (salt.as_ptr(), salt.len()),
None => (core::ptr::null(), 0),
};

let encrypt_res = Status::from(unsafe {
psa_crypto_sys::psa_asymmetric_encrypt(
handle,
alg.into(),
plaintext.as_ptr(),
plaintext.len(),
salt_ptr,
salt_len,
ciphertext.as_mut_ptr(),
ciphertext.len(),
&mut output_length,
)
})
.to_result();
let close_key_handle_res = key_id.close_handle(handle);
encrypt_res?;
close_key_handle_res?;
Ok(output_length)
}

/// Decrypt a short message with a key pair or private key
///
/// The decrypted message is written in `plaintext`. The function returns the number of bytes written.
///
/// # Example
///
/// ```
/// # use psa_crypto::operations::key_management::{generate, export_public};
/// # use psa_crypto::operations::asym_encryption::decrypt;
/// # use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags};
/// # use psa_crypto::types::algorithm::{AsymmetricEncryption, Hash};
/// # use rsa::{RSAPublicKey, PaddingScheme, PublicKey};
/// # use rand::rngs::OsRng;
/// # let mut attributes = Attributes {
/// # key_type: Type::RsaKeyPair,
/// # bits: 1024,
/// # lifetime: Lifetime::Volatile,
/// # policy: Policy {
/// # usage_flags: UsageFlags {
/// # decrypt: true,
/// # ..Default::default()
/// # },
/// # permitted_algorithms: AsymmetricEncryption::RsaPkcs1v15Crypt.into()
/// # },
/// # };
/// # const MESSAGE: [u8; 64] = [ 0x4e, 0x31, 0x74, 0x96, 0x8f, 0xe4, 0xba, 0xb3, 0xaf, 0x77, 0x75,
/// # 0x76, 0x61, 0xde, 0xe5, 0xb8, 0x2c, 0x4f, 0x2a, 0x77, 0x6f, 0x2a, 0x86, 0x36, 0x13, 0xc3, 0xd1,
/// # 0x26, 0x77, 0x30, 0x64, 0x9c, 0xb9, 0x95, 0x84, 0x73, 0x54, 0xfd, 0x6d, 0x2f, 0xba, 0x7e, 0x6c,
/// # 0xb5, 0x0a, 0xe1, 0x09, 0x4e, 0x57, 0x3e, 0xeb, 0x7c, 0x64, 0xcc, 0x9d, 0xf2, 0xf2, 0x37, 0x2e,
/// # 0xb1, 0xe9, 0x92, 0xb7, 0x7b];
/// psa_crypto::init().unwrap();
///
/// let key_id = generate(attributes, None).unwrap();
/// let mut pub_key = vec![0; attributes.export_public_key_output_size().unwrap()];
/// let _pub_key_length = export_public(key_id.clone(), &mut pub_key);
/// let rsa_pub_key = RSAPublicKey::from_pkcs1(&pub_key).unwrap();
/// let ciphertext = rsa_pub_key.encrypt(&mut OsRng, PaddingScheme::new_pkcs1v15_encrypt(), &MESSAGE).unwrap();
///
/// let alg = AsymmetricEncryption::RsaPkcs1v15Crypt;
/// let buffer_size = attributes.asymmetric_decrypt_output_size(alg).unwrap();
/// let mut decrypted_message = vec![0; buffer_size];
/// let size = decrypt(key_id,
/// alg,
/// &ciphertext,
/// None,
/// &mut decrypted_message).unwrap();
/// decrypted_message.resize(size, 0);
/// ```
pub fn decrypt(
key_id: Id,
alg: AsymmetricEncryption,
encrypted_message: &[u8],
salt: Option<&[u8]>,
plaintext: &mut [u8],
) -> Result<usize> {
initialized()?;

let handle = key_id.handle()?;

let mut output_length = 0;
let (salt_ptr, salt_len) = match salt {
Some(salt) => (salt.as_ptr(), salt.len()),
None => (core::ptr::null(), 0),
};

let decrypt_res = Status::from(unsafe {
psa_crypto_sys::psa_asymmetric_decrypt(
handle,
alg.into(),
encrypted_message.as_ptr(),
encrypted_message.len(),
salt_ptr,
salt_len,
plaintext.as_mut_ptr(),
plaintext.len(),
&mut output_length,
)
})
.to_result();
let close_handle_res = key_id.close_handle(handle);
decrypt_res?;
close_handle_res?;
Ok(output_length)
}
37 changes: 35 additions & 2 deletions psa-crypto/src/types/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,8 +560,8 @@ impl TryFrom<psa_crypto_sys::psa_algorithm_t> for Algorithm {
let asym_sign: AsymmetricSignature = alg.try_into()?;
Ok(asym_sign.into())
} else if psa_crypto_sys::PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg) {
error!("Asymmetric Encryption algorithms are not supported.");
Err(Error::NotSupported)
let asym_encryption: AsymmetricEncryption = alg.try_into()?;
Ok(asym_encryption.into())
} else if psa_crypto_sys::PSA_ALG_IS_KEY_AGREEMENT(alg) {
error!("Key Agreement algorithms are not supported.");
Err(Error::NotSupported)
Expand All @@ -583,6 +583,7 @@ impl TryFrom<Algorithm> for psa_crypto_sys::psa_algorithm_t {
Algorithm::None => Ok(0),
Algorithm::Hash(hash) => Ok(hash.into()),
Algorithm::AsymmetricSignature(asym_sign) => Ok(asym_sign.into()),
Algorithm::AsymmetricEncryption(asym_encrypt) => Ok(asym_encrypt.into()),
_ => {
error!("Algorithm not supported: {:?}.", alg);
Err(Error::NotSupported)
Expand Down Expand Up @@ -722,6 +723,38 @@ impl From<AsymmetricSignature> for psa_crypto_sys::psa_algorithm_t {
}
}

#[cfg(feature = "with-mbed-crypto")]
impl TryFrom<psa_crypto_sys::psa_algorithm_t> for AsymmetricEncryption {
type Error = Error;
fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
if alg == psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_CRYPT {
Ok(AsymmetricEncryption::RsaPkcs1v15Crypt)
} else if unsafe { psa_crypto_sys::PSA_ALG_IS_RSA_OAEP(alg) } {
Ok(AsymmetricEncryption::RsaOaep {
hash_alg: psa_crypto_sys::PSA_ALG_RSA_OAEP_GET_HASH(alg).try_into()?,
})
} else {
error!(
"Can not find a valid AsymmetricEncryption algorithm for {}.",
alg
);
Err(Error::InvalidArgument)
}
}
}

#[cfg(feature = "with-mbed-crypto")]
impl From<AsymmetricEncryption> for psa_crypto_sys::psa_algorithm_t {
fn from(asym_encrypt: AsymmetricEncryption) -> Self {
match asym_encrypt {
AsymmetricEncryption::RsaPkcs1v15Crypt => psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_CRYPT,
AsymmetricEncryption::RsaOaep { hash_alg } => unsafe {
psa_crypto_sys::PSA_ALG_RSA_OAEP(hash_alg.into())
},
}
}
}

#[cfg(test)]
mod test {
use crate::types::algorithm::{Algorithm, AsymmetricSignature, Hash, SignHash};
Expand Down
Loading

0 comments on commit 44486bb

Please sign in to comment.