Skip to content

Commit 5c4e8b6

Browse files
committed
Added asymmetric encrypt and decrypt
Signed-off-by: Samuel Bailey <[email protected]>
1 parent 6ca5f87 commit 5c4e8b6

File tree

2 files changed

+119
-3
lines changed

2 files changed

+119
-3
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ edition = "2018"
1313
documentation = "https://docs.rs/crate/parsec-client"
1414

1515
[dependencies]
16-
parsec-interface = "0.17.1"
16+
parsec-interface = "0.17.2"
1717
num = "0.2.1"
1818
rand = "0.7.3"
1919
log = "0.4.8"

src/core/basic_client.rs

+118-2
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ use crate::error::{ClientErrorKind, Error, Result};
77
use parsec_interface::operations::list_opcodes::Operation as ListOpcodes;
88
use parsec_interface::operations::list_providers::{Operation as ListProviders, ProviderInfo};
99
use parsec_interface::operations::ping::Operation as Ping;
10-
use parsec_interface::operations::psa_algorithm::AsymmetricSignature;
10+
use parsec_interface::operations::psa_algorithm::{AsymmetricSignature, AsymmetricEncryption};
1111
use parsec_interface::operations::psa_destroy_key::Operation as PsaDestroyKey;
1212
use parsec_interface::operations::psa_export_public_key::Operation as PsaExportPublicKey;
1313
use parsec_interface::operations::psa_generate_key::Operation as PsaGenerateKey;
1414
use parsec_interface::operations::psa_import_key::Operation as PsaImportKey;
1515
use parsec_interface::operations::psa_key_attributes::Attributes;
1616
use parsec_interface::operations::psa_sign_hash::Operation as PsaSignHash;
1717
use parsec_interface::operations::psa_verify_hash::Operation as PsaVerifyHash;
18+
use parsec_interface::operations::psa_asymmetric_encrypt::Operation as PsaAsymEncrypt;
19+
use parsec_interface::operations::psa_asymmetric_decrypt::Operation as PsaAsymDecrypt;
1820
use parsec_interface::operations::{NativeOperation, NativeResult};
1921
use parsec_interface::requests::{Opcode, ProviderID};
2022
use parsec_interface::secrecy::Secret;
@@ -229,7 +231,6 @@ impl BasicClient {
229231
ProviderID::Core,
230232
&self.auth_data,
231233
)?;
232-
233234
if let NativeResult::ListProviders(res) = res {
234235
Ok(res.providers)
235236
} else {
@@ -522,6 +523,121 @@ impl BasicClient {
522523
Ok(())
523524
}
524525

526+
/// **[Cryptographic Operation]** Encrypt a short message.
527+
///
528+
/// The key intended for encrypting **must** have its `encrypt` flag set
529+
/// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
530+
///
531+
/// The encryption will be performed with the algorithm defined in `alg`,
532+
/// but only after checking that the key policy and type conform with it.
533+
///
534+
/// `salt` can be provided if supported by the algorithm. If the algorithm does not support salt, pass
535+
// an empty vector. If the algorithm supports optional salt, pass an empty vector to indicate no
536+
// salt. For RSA PKCS#1 v1.5 encryption, no salt is supported.
537+
///
538+
/// # Errors
539+
///
540+
/// If the implicit client provider is `ProviderID::Core`, a client error
541+
/// of `InvalidProvider` type is returned.
542+
///
543+
/// If the implicit client provider has not been set, a client error of
544+
/// `NoProvider` type is returned.
545+
///
546+
/// See the operation-specific response codes returned by the service
547+
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_asymmetric_encrypt.html#specific-response-status-codes).
548+
pub fn psa_asymmetric_encrypt(
549+
&self,
550+
key_name: String,
551+
encrypt_alg: AsymmetricEncryption,
552+
plaintext: &[u8],
553+
salt: Option<&[u8]>,
554+
) -> Result<Vec<u8>> {
555+
let plaintext = Secret::new(plaintext.to_vec());
556+
let salt = match salt {
557+
Some(salt) => Some(Zeroizing::new(salt.to_vec())),
558+
None=> None,
559+
};
560+
let crypto_provider = self.can_provide_crypto()?;
561+
562+
let op = PsaAsymEncrypt {
563+
key_name,
564+
alg: encrypt_alg,
565+
plaintext,
566+
salt,
567+
};
568+
569+
let encrypt_res = self.op_client.process_operation(
570+
NativeOperation::PsaAsymmetricEncrypt(op),
571+
crypto_provider,
572+
&self.auth_data,
573+
)?;
574+
575+
if let NativeResult::PsaAsymmetricEncrypt(res) = encrypt_res {
576+
Ok(res.ciphertext.to_vec())
577+
} else {
578+
// Should really not be reached given the checks we do, but it's not impossible if some
579+
// changes happen in the interface
580+
Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
581+
}
582+
}
583+
584+
/// **[Cryptographic Operation]** Decrypt a short message.
585+
///
586+
/// The key intended for decrypting **must** have its `decrypt` flag set
587+
/// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
588+
///
589+
/// The decryption will be performed with the algorithm defined in `alg`,
590+
/// but only after checking that the key policy and type conform with it.
591+
///
592+
/// `salt` can be provided if supported by the algorithm. If the algorithm does not support salt, pass
593+
// an empty vector. If the algorithm supports optional salt, pass an empty vector to indicate no
594+
// salt. For RSA PKCS#1 v1.5 encryption, no salt is supported.
595+
///
596+
/// # Errors
597+
///
598+
/// If the implicit client provider is `ProviderID::Core`, a client error
599+
/// of `InvalidProvider` type is returned.
600+
///
601+
/// If the implicit client provider has not been set, a client error of
602+
/// `NoProvider` type is returned.
603+
///
604+
/// See the operation-specific response codes returned by the service
605+
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_asymmetric_decrypt.html#specific-response-status-codes).
606+
pub fn psa_asymmetric_decrypt(
607+
&self,
608+
key_name: String,
609+
encrypt_alg: AsymmetricEncryption,
610+
ciphertext: &[u8],
611+
salt: Option<&[u8]>,
612+
) -> Result<Vec<u8>> {
613+
let salt = match salt {
614+
Some(salt) => Some(Zeroizing::new(salt.to_vec())),
615+
None => None,
616+
};
617+
let crypto_provider = self.can_provide_crypto()?;
618+
619+
let op = PsaAsymDecrypt {
620+
key_name,
621+
alg: encrypt_alg,
622+
ciphertext: Zeroizing::new(ciphertext.to_vec()),
623+
salt,
624+
};
625+
626+
let decrypt_res = self.op_client.process_operation(
627+
NativeOperation::PsaAsymmetricDecrypt(op),
628+
crypto_provider,
629+
&self.auth_data,
630+
)?;
631+
632+
if let NativeResult::PsaAsymmetricDecrypt(res) = decrypt_res {
633+
Ok(res.plaintext)
634+
} else {
635+
// Should really not be reached given the checks we do, but it's not impossible if some
636+
// changes happen in the interface
637+
Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
638+
}
639+
}
640+
525641
fn can_provide_crypto(&self) -> Result<ProviderID> {
526642
match self.implicit_provider {
527643
None => Err(Error::Client(ClientErrorKind::NoProvider)),

0 commit comments

Comments
 (0)