-
Notifications
You must be signed in to change notification settings - Fork 18
Added asymmetric encrypt and decrypt #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ionut-arm
merged 1 commit into
parallaxsecond:master
from
sbailey-arm:add-asym-encrypt-decrypt
Jul 7, 2020
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule parsec-operations
updated
2 files
+18 −0 | protobuf/psa_asymmetric_decrypt.proto | |
+18 −0 | protobuf/psa_asymmetric_encrypt.proto |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
// Copyright 2020 Contributors to the Parsec project. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
//! # PsaAsymmetricDecrypt operation | ||
//! | ||
//! Decrypt a short message with a public key. | ||
|
||
use super::psa_key_attributes::Attributes; | ||
use crate::operations::psa_algorithm::AsymmetricEncryption; | ||
use crate::requests::ResponseStatus; | ||
#[cfg(feature = "fuzz")] | ||
use arbitrary::Arbitrary; | ||
use derivative::Derivative; | ||
|
||
/// Native object for asymmetric decryption operations. | ||
#[derive(Derivative)] | ||
#[derivative(Debug)] | ||
pub struct Operation { | ||
/// Defines which key should be used for the signing operation. | ||
pub key_name: String, | ||
/// An asymmetric encryption algorithm to be used for decryption, that is compatible with the type of key. | ||
pub alg: AsymmetricEncryption, | ||
/// The short encrypted message to be decrypted. | ||
#[derivative(Debug = "ignore")] | ||
pub ciphertext: zeroize::Zeroizing<Vec<u8>>, | ||
/// Salt to use during decryption, if supported by the algorithm. | ||
#[derivative(Debug = "ignore")] | ||
pub salt: Option<zeroize::Zeroizing<Vec<u8>>>, | ||
} | ||
|
||
impl Operation { | ||
/// Validate the contents of the operation against the attributes of the key it targets | ||
/// | ||
/// This method checks that: | ||
/// * the key policy allows decrypting messages | ||
/// * the key policy allows the decryption algorithm requested in the operation | ||
/// * the key type is compatible with the requested algorithm | ||
/// * if the algorithm is RsaPkcs1v15Crypt, it has no salt (it is not compatible with salt) | ||
/// * the message to decrypt is valid (not length 0) | ||
pub fn validate(&self, key_attributes: Attributes) -> crate::requests::Result<()> { | ||
key_attributes.can_decrypt_message()?; | ||
key_attributes.permits_alg(self.alg.into())?; | ||
key_attributes.compatible_with_alg(self.alg.into())?; | ||
if (self.alg == AsymmetricEncryption::RsaPkcs1v15Crypt && self.salt != None) | ||
|| self.ciphertext.is_empty() | ||
{ | ||
return Err(ResponseStatus::PsaErrorInvalidArgument); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
/// Native object for asymmetric decrypt result. | ||
// Debug derived as NativeResult enum requires it, even though nothing inside this Result is debuggable | ||
// as `plaintext` is sensitive. | ||
#[derive(Derivative)] | ||
#[derivative(Debug)] | ||
pub struct Result { | ||
/// Decrypted message | ||
#[derivative(Debug = "ignore")] | ||
pub plaintext: zeroize::Zeroizing<Vec<u8>>, | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::operations::psa_algorithm::{AsymmetricEncryption, Hash}; | ||
use crate::operations::psa_key_attributes::{Lifetime, Policy, Type, UsageFlags}; | ||
use zeroize::Zeroizing; | ||
|
||
fn get_attrs() -> Attributes { | ||
Attributes { | ||
lifetime: Lifetime::Persistent, | ||
key_type: Type::RsaKeyPair, | ||
bits: 256, | ||
policy: Policy { | ||
usage_flags: UsageFlags { | ||
export: false, | ||
copy: false, | ||
cache: false, | ||
encrypt: false, | ||
decrypt: true, | ||
sign_message: false, | ||
verify_message: false, | ||
sign_hash: false, | ||
verify_hash: false, | ||
derive: false, | ||
}, | ||
permitted_algorithms: AsymmetricEncryption::RsaPkcs1v15Crypt.into(), | ||
}, | ||
} | ||
} | ||
|
||
#[test] | ||
fn validate_success() { | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaPkcs1v15Crypt, | ||
ciphertext: Zeroizing::new(vec![0xff, 32]), | ||
salt: None, | ||
}) | ||
.validate(get_attrs()) | ||
.unwrap(); | ||
} | ||
|
||
#[test] | ||
fn cannot_decrypt() { | ||
let mut attrs = get_attrs(); | ||
attrs.policy.usage_flags.decrypt = false; | ||
assert_eq!( | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaPkcs1v15Crypt, | ||
ciphertext: Zeroizing::new(vec![0xff, 32]), | ||
salt: None, | ||
}) | ||
.validate(attrs) | ||
.unwrap_err(), | ||
ResponseStatus::PsaErrorNotPermitted | ||
); | ||
} | ||
|
||
#[test] | ||
fn wrong_algorithm() { | ||
assert_eq!( | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaOaep { | ||
hash_alg: Hash::Sha256, | ||
}, | ||
ciphertext: Zeroizing::new(vec![0xff, 32]), | ||
salt: None, | ||
}) | ||
.validate(get_attrs()) | ||
.unwrap_err(), | ||
ResponseStatus::PsaErrorNotPermitted | ||
); | ||
} | ||
|
||
#[test] | ||
fn invalid_ciphertext() { | ||
assert_eq!( | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaPkcs1v15Crypt, | ||
ciphertext: Zeroizing::new(vec![]), | ||
salt: None, | ||
}) | ||
.validate(get_attrs()) | ||
.unwrap_err(), | ||
ResponseStatus::PsaErrorInvalidArgument | ||
); | ||
} | ||
|
||
#[test] | ||
fn salt_with_rsapkcs1v15crypt() { | ||
assert_eq!( | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaPkcs1v15Crypt, | ||
ciphertext: Zeroizing::new(vec![0xff, 32]), | ||
salt: Some(zeroize::Zeroizing::new(vec![0xff, 32])), | ||
}) | ||
.validate(get_attrs()) | ||
.unwrap_err(), | ||
ResponseStatus::PsaErrorInvalidArgument | ||
); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
// Copyright 2020 Contributors to the Parsec project. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
//! # PsaAsymmetricEncrypt operation | ||
//! | ||
//! Encrypt a short message with a public key. | ||
|
||
use super::psa_key_attributes::Attributes; | ||
use crate::operations::psa_algorithm::AsymmetricEncryption; | ||
use crate::requests::ResponseStatus; | ||
use derivative::Derivative; | ||
|
||
/// Native object for asymmetric encryption operations. | ||
#[derive(Derivative)] | ||
#[derivative(Debug)] | ||
pub struct Operation { | ||
/// Defines which key should be used for the encryption operation. | ||
pub key_name: String, | ||
/// An asymmetric encryption algorithm that is compatible with the key type | ||
pub alg: AsymmetricEncryption, | ||
/// The short message to be encrypted. | ||
#[derivative(Debug = "ignore")] | ||
pub plaintext: zeroize::Zeroizing<Vec<u8>>, | ||
/// Salt to use during encryption, if supported by the algorithm. | ||
#[derivative(Debug = "ignore")] | ||
pub salt: Option<zeroize::Zeroizing<Vec<u8>>>, | ||
} | ||
|
||
impl Operation { | ||
/// Validate the contents of the operation against the attributes of the key it targets | ||
/// | ||
/// This method checks that: | ||
/// * the key policy allows encrypting messages | ||
/// * the key policy allows the encryption algorithm requested in the operation | ||
/// * the key type is compatible with the requested algorithm | ||
/// * if the algorithm is RsaPkcs1v15Crypt, it has no salt (it is not compatible with salt) | ||
/// * the message to encrypt is valid (not length 0) | ||
pub fn validate(&self, key_attributes: Attributes) -> crate::requests::Result<()> { | ||
key_attributes.can_encrypt_message()?; | ||
key_attributes.permits_alg(self.alg.into())?; | ||
key_attributes.compatible_with_alg(self.alg.into())?; | ||
if (self.alg == AsymmetricEncryption::RsaPkcs1v15Crypt && self.salt != None) | ||
|| self.plaintext.is_empty() | ||
{ | ||
return Err(ResponseStatus::PsaErrorInvalidArgument); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
/// Native object for asymmetric encrypt result. | ||
#[derive(Derivative)] | ||
#[derivative(Debug)] | ||
pub struct Result { | ||
/// The `ciphertext` field contains the encrypted short message. | ||
#[derivative(Debug = "ignore")] | ||
pub ciphertext: zeroize::Zeroizing<Vec<u8>>, | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::operations::psa_algorithm::{AsymmetricEncryption, Hash}; | ||
use crate::operations::psa_key_attributes::{Lifetime, Policy, Type, UsageFlags}; | ||
|
||
fn get_attrs() -> Attributes { | ||
Attributes { | ||
lifetime: Lifetime::Persistent, | ||
key_type: Type::RsaKeyPair, | ||
bits: 256, | ||
policy: Policy { | ||
usage_flags: UsageFlags { | ||
export: false, | ||
copy: false, | ||
cache: false, | ||
encrypt: true, | ||
decrypt: false, | ||
sign_message: false, | ||
verify_message: false, | ||
sign_hash: false, | ||
verify_hash: false, | ||
derive: false, | ||
}, | ||
permitted_algorithms: AsymmetricEncryption::RsaPkcs1v15Crypt.into(), | ||
}, | ||
} | ||
} | ||
|
||
#[test] | ||
fn validate_success() { | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaPkcs1v15Crypt, | ||
plaintext: vec![0xff, 32].into(), | ||
salt: None, | ||
}) | ||
.validate(get_attrs()) | ||
.unwrap(); | ||
} | ||
|
||
#[test] | ||
fn cannot_encrypt() { | ||
let mut attrs = get_attrs(); | ||
attrs.policy.usage_flags.encrypt = false; | ||
assert_eq!( | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaPkcs1v15Crypt, | ||
plaintext: vec![0xff, 32].into(), | ||
salt: None, | ||
}) | ||
.validate(attrs) | ||
.unwrap_err(), | ||
ResponseStatus::PsaErrorNotPermitted | ||
); | ||
} | ||
|
||
#[test] | ||
fn wrong_algorithm() { | ||
assert_eq!( | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaOaep { | ||
hash_alg: Hash::Sha256, | ||
}, | ||
plaintext: vec![0xff, 32].into(), | ||
salt: None, | ||
}) | ||
.validate(get_attrs()) | ||
.unwrap_err(), | ||
ResponseStatus::PsaErrorNotPermitted | ||
); | ||
} | ||
|
||
#[test] | ||
fn invalid_plaintext() { | ||
assert_eq!( | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaPkcs1v15Crypt, | ||
plaintext: vec![].into(), | ||
salt: None, | ||
}) | ||
.validate(get_attrs()) | ||
.unwrap_err(), | ||
ResponseStatus::PsaErrorInvalidArgument | ||
); | ||
} | ||
|
||
#[test] | ||
fn salt_with_rsapkcs1v15crypt() { | ||
assert_eq!( | ||
(Operation { | ||
key_name: String::from("some key"), | ||
alg: AsymmetricEncryption::RsaPkcs1v15Crypt, | ||
plaintext: vec![0xff, 32].into(), | ||
salt: Some(zeroize::Zeroizing::new(vec![0xff, 32])), | ||
}) | ||
.validate(get_attrs()) | ||
.unwrap_err(), | ||
ResponseStatus::PsaErrorInvalidArgument | ||
); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just an idea: would it be wrong to include the
salt
inside theAsymmetricEncryption
structure (in theRsaOaep
structure)? That way this condition would be checked statically. But that seems to be a big deviation from the PSA API.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a good idea, even if it deviates from the PSA API a bit. It sounds more 'Rusty' to me 😉.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do that, we need to have separate implementations of
RsaOaep
for policy and for operations - it doesn't make any sense to have asalt
for a policy. Then, if we do have an operation-specific enum for algorithms, I don't see why we couldn't include algorithm-specific fields inside those structures/variants.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, would be good but probably not as part of this PR.