| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| // Ensure only one crypto provider is selected | |
| #[cfg(all(feature = "crypto-rust", feature = "crypto-openssl"))] | |
| compile_error!("Features `crypto-rust` and `crypto-openssl` are mutually exclusive"); | |
| #[cfg(all(feature = "crypto-rust", feature = "crypto-ring"))] | |
| compile_error!("Features `crypto-rust` and `crypto-ring` are mutually exclusive"); | |
| #[cfg(all(feature = "crypto-rust", feature = "crypto-graviola"))] | |
| compile_error!("Features `crypto-rust` and `crypto-graviola` are mutually exclusive"); | |
| #[cfg(all(feature = "crypto-ring", feature = "crypto-openssl"))] | |
| compile_error!("Features `crypto-ring` and `crypto-openssl` are mutually exclusive"); | |
| #[cfg(all(feature = "crypto-ring", feature = "crypto-graviola"))] | |
| compile_error!("Features `crypto-ring` and `crypto-graviola` are mutually exclusive"); | |
| #[cfg(all(feature = "crypto-openssl", feature = "crypto-graviola"))] | |
| compile_error!("Features `crypto-openssl` and `crypto-graviola` are mutually exclusive"); | |
| #[cfg(all(feature = "crypto-ring-rust", feature = "crypto-graviola-rust"))] | |
| compile_error!("Features `crypto-ring-rust` and `crypto-graviola-rust` are mutually exclusive"); | |
| #[cfg(any(feature = "crypto-graviola", feature = "crypto-graviola-rust"))] | |
| mod graviola; | |
| #[cfg(feature = "crypto-openssl")] | |
| mod openssl; | |
| #[cfg(any(feature = "crypto-ring", feature = "crypto-ring-rust"))] | |
| mod ring; | |
| #[cfg(feature = "_rustcrypto")] | |
| mod rust; | |
| use crate::hash::HashAlgorithm; | |
| use crate::subtle::EllipticCurve; | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub struct RsaImportResult { | |
| pub key_data: Vec<u8>, | |
| pub modulus_length: u32, | |
| pub public_exponent: Vec<u8>, | |
| pub is_private: bool, | |
| } | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub struct EcImportResult { | |
| pub key_data: Vec<u8>, | |
| pub is_private: bool, | |
| } | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub struct OkpImportResult { | |
| pub key_data: Vec<u8>, | |
| pub is_private: bool, | |
| } | |
| /// RSA JWK components for import (all values are raw bytes, not base64) | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub struct RsaJwkImport<'a> { | |
| pub n: &'a [u8], // modulus | |
| pub e: &'a [u8], // public exponent | |
| pub d: Option<&'a [u8]>, // private exponent | |
| pub p: Option<&'a [u8]>, // first prime | |
| pub q: Option<&'a [u8]>, // second prime | |
| pub dp: Option<&'a [u8]>, // first factor CRT exponent | |
| pub dq: Option<&'a [u8]>, // second factor CRT exponent | |
| pub qi: Option<&'a [u8]>, // first CRT coefficient | |
| } | |
| /// RSA JWK components for export | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub struct RsaJwkExport { | |
| pub n: Vec<u8>, | |
| pub e: Vec<u8>, | |
| pub d: Option<Vec<u8>>, | |
| pub p: Option<Vec<u8>>, | |
| pub q: Option<Vec<u8>>, | |
| pub dp: Option<Vec<u8>>, | |
| pub dq: Option<Vec<u8>>, | |
| pub qi: Option<Vec<u8>>, | |
| } | |
| /// EC JWK components for import (all values are raw bytes) | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub struct EcJwkImport<'a> { | |
| pub x: &'a [u8], | |
| pub y: &'a [u8], | |
| pub d: Option<&'a [u8]>, | |
| } | |
| /// EC JWK components for export | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub struct EcJwkExport { | |
| pub x: Vec<u8>, | |
| pub y: Vec<u8>, | |
| pub d: Option<Vec<u8>>, | |
| } | |
| /// OKP (Ed25519/X25519) JWK components for import | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub struct OkpJwkImport<'a> { | |
| pub x: &'a [u8], // public key | |
| pub d: Option<&'a [u8]>, // private key | |
| } | |
| /// OKP JWK components for export | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub struct OkpJwkExport { | |
| pub x: Vec<u8>, | |
| pub d: Option<Vec<u8>>, | |
| } | |
| pub trait SimpleDigest: Send { | |
| fn update(&mut self, data: &[u8]); | |
| fn finalize(self) -> Vec<u8> | |
| where | |
| Self: Sized; | |
| } | |
| #[derive(Debug, Clone, Copy)] | |
| #[allow(dead_code)] | |
| pub enum AesMode { | |
| Ctr { counter_length: u32 }, | |
| Cbc, | |
| Gcm { tag_length: u8 }, | |
| } | |
| #[allow(dead_code)] | |
| pub trait CryptoProvider { | |
| type Digest: SimpleDigest; | |
| type Hmac: HmacProvider; | |
| // Digest operations | |
| fn digest(&self, algorithm: HashAlgorithm) -> Self::Digest; | |
| // HMAC operations | |
| fn hmac(&self, algorithm: HashAlgorithm, key: &[u8]) -> Self::Hmac; | |
| // ECDSA operations | |
| fn ecdsa_sign( | |
| &self, | |
| curve: EllipticCurve, | |
| private_key_der: &[u8], | |
| digest: &[u8], | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn ecdsa_verify( | |
| &self, | |
| curve: EllipticCurve, | |
| public_key_sec1: &[u8], | |
| signature: &[u8], | |
| digest: &[u8], | |
| ) -> Result<bool, CryptoError>; | |
| // EdDSA operations | |
| fn ed25519_sign(&self, private_key_der: &[u8], data: &[u8]) -> Result<Vec<u8>, CryptoError>; | |
| fn ed25519_verify( | |
| &self, | |
| public_key_bytes: &[u8], | |
| signature: &[u8], | |
| data: &[u8], | |
| ) -> Result<bool, CryptoError>; | |
| // RSA operations | |
| fn rsa_pss_sign( | |
| &self, | |
| private_key_der: &[u8], | |
| digest: &[u8], | |
| salt_length: usize, | |
| hash_alg: HashAlgorithm, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn rsa_pss_verify( | |
| &self, | |
| public_key_der: &[u8], | |
| signature: &[u8], | |
| digest: &[u8], | |
| salt_length: usize, | |
| hash_alg: HashAlgorithm, | |
| ) -> Result<bool, CryptoError>; | |
| fn rsa_pkcs1v15_sign( | |
| &self, | |
| private_key_der: &[u8], | |
| digest: &[u8], | |
| hash_alg: HashAlgorithm, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn rsa_pkcs1v15_verify( | |
| &self, | |
| public_key_der: &[u8], | |
| signature: &[u8], | |
| digest: &[u8], | |
| hash_alg: HashAlgorithm, | |
| ) -> Result<bool, CryptoError>; | |
| fn rsa_oaep_encrypt( | |
| &self, | |
| public_key_der: &[u8], | |
| data: &[u8], | |
| hash_alg: HashAlgorithm, | |
| label: Option<&[u8]>, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn rsa_oaep_decrypt( | |
| &self, | |
| private_key_der: &[u8], | |
| data: &[u8], | |
| hash_alg: HashAlgorithm, | |
| label: Option<&[u8]>, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| // ECDH operations | |
| fn ecdh_derive_bits( | |
| &self, | |
| curve: EllipticCurve, | |
| private_key_der: &[u8], | |
| public_key_sec1: &[u8], | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| // X25519 operations | |
| fn x25519_derive_bits( | |
| &self, | |
| private_key: &[u8], | |
| public_key: &[u8], | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| // AES operations | |
| fn aes_encrypt( | |
| &self, | |
| mode: AesMode, | |
| key: &[u8], | |
| iv: &[u8], | |
| data: &[u8], | |
| additional_data: Option<&[u8]>, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn aes_decrypt( | |
| &self, | |
| mode: AesMode, | |
| key: &[u8], | |
| iv: &[u8], | |
| data: &[u8], | |
| additional_data: Option<&[u8]>, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| // AES-KW operations | |
| fn aes_kw_wrap(&self, kek: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError>; | |
| fn aes_kw_unwrap(&self, kek: &[u8], wrapped_key: &[u8]) -> Result<Vec<u8>, CryptoError>; | |
| // KDF operations | |
| fn hkdf_derive_key( | |
| &self, | |
| key: &[u8], | |
| salt: &[u8], | |
| info: &[u8], | |
| length: usize, | |
| hash_alg: HashAlgorithm, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn pbkdf2_derive_key( | |
| &self, | |
| password: &[u8], | |
| salt: &[u8], | |
| iterations: u32, | |
| length: usize, | |
| hash_alg: HashAlgorithm, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn generate_aes_key(&self, length_bits: u16) -> Result<Vec<u8>, CryptoError>; | |
| fn generate_hmac_key( | |
| &self, | |
| hash_alg: HashAlgorithm, | |
| length_bits: u16, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn generate_ec_key(&self, curve: EllipticCurve) -> Result<(Vec<u8>, Vec<u8>), CryptoError>; // (private, public) | |
| fn generate_ed25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError>; | |
| fn generate_x25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError>; | |
| fn generate_rsa_key( | |
| &self, | |
| modulus_length: u32, | |
| public_exponent: &[u8], | |
| ) -> Result<(Vec<u8>, Vec<u8>), CryptoError>; | |
| // RSA key import from DER formats | |
| fn import_rsa_public_key_pkcs1(&self, der: &[u8]) -> Result<RsaImportResult, CryptoError>; | |
| fn import_rsa_private_key_pkcs1(&self, der: &[u8]) -> Result<RsaImportResult, CryptoError>; | |
| fn import_rsa_public_key_spki(&self, der: &[u8]) -> Result<RsaImportResult, CryptoError>; | |
| fn import_rsa_private_key_pkcs8(&self, der: &[u8]) -> Result<RsaImportResult, CryptoError>; | |
| // RSA key export to DER formats | |
| fn export_rsa_public_key_pkcs1(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError>; | |
| fn export_rsa_public_key_spki(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError>; | |
| fn export_rsa_private_key_pkcs8(&self, key_data: &[u8]) -> Result<Vec<u8>, CryptoError>; | |
| // EC key import from DER formats | |
| fn import_ec_public_key_sec1( | |
| &self, | |
| data: &[u8], | |
| curve: EllipticCurve, | |
| ) -> Result<EcImportResult, CryptoError>; | |
| fn import_ec_public_key_spki( | |
| &self, | |
| der: &[u8], | |
| curve: EllipticCurve, | |
| ) -> Result<EcImportResult, CryptoError>; | |
| fn import_ec_private_key_pkcs8(&self, der: &[u8]) -> Result<EcImportResult, CryptoError>; | |
| fn import_ec_private_key_sec1( | |
| &self, | |
| data: &[u8], | |
| curve: EllipticCurve, | |
| ) -> Result<EcImportResult, CryptoError>; | |
| // EC key export | |
| fn export_ec_public_key_sec1( | |
| &self, | |
| key_data: &[u8], | |
| curve: EllipticCurve, | |
| is_private: bool, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn export_ec_public_key_spki( | |
| &self, | |
| key_data: &[u8], | |
| curve: EllipticCurve, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn export_ec_private_key_pkcs8( | |
| &self, | |
| key_data: &[u8], | |
| curve: EllipticCurve, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| // OKP (Ed25519/X25519) key import | |
| fn import_okp_public_key_raw(&self, data: &[u8]) -> Result<OkpImportResult, CryptoError>; | |
| fn import_okp_public_key_spki( | |
| &self, | |
| der: &[u8], | |
| expected_oid: &[u8], | |
| ) -> Result<OkpImportResult, CryptoError>; | |
| fn import_okp_private_key_pkcs8( | |
| &self, | |
| der: &[u8], | |
| expected_oid: &[u8], | |
| ) -> Result<OkpImportResult, CryptoError>; | |
| // OKP key export | |
| fn export_okp_public_key_raw( | |
| &self, | |
| key_data: &[u8], | |
| is_private: bool, | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn export_okp_public_key_spki( | |
| &self, | |
| key_data: &[u8], | |
| oid: &[u8], | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| fn export_okp_private_key_pkcs8( | |
| &self, | |
| key_data: &[u8], | |
| oid: &[u8], | |
| ) -> Result<Vec<u8>, CryptoError>; | |
| // JWK import/export | |
| fn import_rsa_jwk(&self, jwk: RsaJwkImport<'_>) -> Result<RsaImportResult, CryptoError>; | |
| fn export_rsa_jwk( | |
| &self, | |
| key_data: &[u8], | |
| is_private: bool, | |
| ) -> Result<RsaJwkExport, CryptoError>; | |
| fn import_ec_jwk( | |
| &self, | |
| jwk: EcJwkImport<'_>, | |
| curve: EllipticCurve, | |
| ) -> Result<EcImportResult, CryptoError>; | |
| fn export_ec_jwk( | |
| &self, | |
| key_data: &[u8], | |
| curve: EllipticCurve, | |
| is_private: bool, | |
| ) -> Result<EcJwkExport, CryptoError>; | |
| // OKP JWK import/export | |
| fn import_okp_jwk( | |
| &self, | |
| jwk: OkpJwkImport<'_>, | |
| is_ed25519: bool, | |
| ) -> Result<OkpImportResult, CryptoError>; | |
| fn export_okp_jwk( | |
| &self, | |
| key_data: &[u8], | |
| is_private: bool, | |
| is_ed25519: bool, | |
| ) -> Result<OkpJwkExport, CryptoError>; | |
| } | |
| pub trait HmacProvider: Send { | |
| fn update(&mut self, data: &[u8]); | |
| fn finalize(self) -> Vec<u8> | |
| where | |
| Self: Sized; | |
| } | |
| #[derive(Debug)] | |
| #[allow(dead_code)] | |
| pub enum CryptoError { | |
| InvalidKey(Option<Box<str>>), | |
| InvalidData(Option<Box<str>>), | |
| InvalidSignature(Option<Box<str>>), | |
| InvalidLength, | |
| SigningFailed(Option<Box<str>>), | |
| VerificationFailed, | |
| OperationFailed(Option<Box<str>>), | |
| UnsupportedAlgorithm, | |
| DerivationFailed(Option<Box<str>>), | |
| EncryptionFailed(Option<Box<str>>), | |
| DecryptionFailed(Option<Box<str>>), | |
| InvalidAccess(Option<Box<str>>), | |
| } | |
| impl std::fmt::Display for CryptoError { | |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
| match self { | |
| CryptoError::InvalidKey(None) => write!(f, "Invalid key"), | |
| CryptoError::InvalidKey(Some(msg)) => write!(f, "Invalid key: {}", msg), | |
| CryptoError::InvalidData(None) => write!(f, "Invalid data"), | |
| CryptoError::InvalidData(Some(msg)) => write!(f, "Invalid data: {}", msg), | |
| CryptoError::InvalidSignature(None) => write!(f, "Invalid signature"), | |
| CryptoError::InvalidSignature(Some(msg)) => write!(f, "Invalid signature: {}", msg), | |
| CryptoError::InvalidLength => write!(f, "Invalid length"), | |
| CryptoError::SigningFailed(None) => write!(f, "Signing failed"), | |
| CryptoError::SigningFailed(Some(msg)) => write!(f, "Signing failed: {}", msg), | |
| CryptoError::VerificationFailed => write!(f, "Verification failed"), | |
| CryptoError::OperationFailed(None) => write!(f, "Operation failed"), | |
| CryptoError::OperationFailed(Some(msg)) => write!(f, "Operation failed: {}", msg), | |
| CryptoError::UnsupportedAlgorithm => write!(f, "Unsupported algorithm"), | |
| CryptoError::DerivationFailed(None) => write!(f, "Derivation failed"), | |
| CryptoError::DerivationFailed(Some(msg)) => write!(f, "Derivation failed: {}", msg), | |
| CryptoError::EncryptionFailed(None) => write!(f, "Encryption failed"), | |
| CryptoError::EncryptionFailed(Some(msg)) => write!(f, "Encryption failed: {}", msg), | |
| CryptoError::DecryptionFailed(None) => write!(f, "Decryption failed"), | |
| CryptoError::DecryptionFailed(Some(msg)) => write!(f, "Decryption failed: {}", msg), | |
| CryptoError::InvalidAccess(None) => write!(f, "Invalid access"), | |
| CryptoError::InvalidAccess(Some(msg)) => write!(f, "Invalid access: {}", msg), | |
| } | |
| } | |
| } | |
| impl std::error::Error for CryptoError {} | |
| pub fn parse_rsa_public_exponent(public_exponent: &[u8]) -> Result<u64, CryptoError> { | |
| match public_exponent { | |
| [0x01, 0x00, 0x01] => Ok(65537), | |
| [0x03] => Ok(3), | |
| bytes if bytes.ends_with(&[0x03]) && bytes[..bytes.len() - 1].iter().all(|&b| b == 0) => { | |
| Ok(3) | |
| }, | |
| _ => Err(CryptoError::OperationFailed(None)), | |
| } | |
| } | |
| #[cfg(feature = "crypto-openssl")] | |
| pub type DefaultProvider = openssl::OpenSslProvider; | |
| #[cfg(feature = "crypto-rust")] | |
| pub type DefaultProvider = rust::RustCryptoProvider; | |
| #[cfg(feature = "crypto-ring")] | |
| pub type DefaultProvider = ring::RingProvider; | |
| #[cfg(feature = "crypto-ring-rust")] | |
| pub type DefaultProvider = RingRustProvider; | |
| #[cfg(all(feature = "crypto-graviola", not(feature = "crypto-graviola-rust")))] | |
| pub type DefaultProvider = graviola::GraviolaProvider; | |
| #[cfg(feature = "crypto-graviola-rust")] | |
| pub type DefaultProvider = GraviolaRustProvider; | |
| // Macro to generate hybrid providers that delegate to RustCrypto | |
| #[cfg(any(feature = "crypto-ring-rust", feature = "crypto-graviola-rust"))] | |
| macro_rules! impl_hybrid_provider { | |
| ($name:ident, $digest:ty, $hmac:ty, $digest_fn:expr, $hmac_fn:expr, $aes_encrypt:expr, $aes_decrypt:expr) => { | |
| pub struct $name; | |
| impl CryptoProvider for $name { | |
| type Digest = $digest; | |
| type Hmac = $hmac; | |
| fn digest(&self, alg: HashAlgorithm) -> Self::Digest { | |
| $digest_fn(alg) | |
| } | |
| fn hmac(&self, alg: HashAlgorithm, key: &[u8]) -> Self::Hmac { | |
| $hmac_fn(alg, key) | |
| } | |
| fn ecdsa_sign( | |
| &self, | |
| c: EllipticCurve, | |
| k: &[u8], | |
| d: &[u8], | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.ecdsa_sign(c, k, d) | |
| } | |
| fn ecdsa_verify( | |
| &self, | |
| c: EllipticCurve, | |
| k: &[u8], | |
| s: &[u8], | |
| d: &[u8], | |
| ) -> Result<bool, CryptoError> { | |
| rust::RustCryptoProvider.ecdsa_verify(c, k, s, d) | |
| } | |
| fn ed25519_sign(&self, k: &[u8], d: &[u8]) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.ed25519_sign(k, d) | |
| } | |
| fn ed25519_verify(&self, k: &[u8], s: &[u8], d: &[u8]) -> Result<bool, CryptoError> { | |
| rust::RustCryptoProvider.ed25519_verify(k, s, d) | |
| } | |
| fn rsa_pss_sign( | |
| &self, | |
| k: &[u8], | |
| d: &[u8], | |
| s: usize, | |
| a: HashAlgorithm, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.rsa_pss_sign(k, d, s, a) | |
| } | |
| fn rsa_pss_verify( | |
| &self, | |
| k: &[u8], | |
| s: &[u8], | |
| d: &[u8], | |
| sl: usize, | |
| a: HashAlgorithm, | |
| ) -> Result<bool, CryptoError> { | |
| rust::RustCryptoProvider.rsa_pss_verify(k, s, d, sl, a) | |
| } | |
| fn rsa_pkcs1v15_sign( | |
| &self, | |
| k: &[u8], | |
| d: &[u8], | |
| a: HashAlgorithm, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.rsa_pkcs1v15_sign(k, d, a) | |
| } | |
| fn rsa_pkcs1v15_verify( | |
| &self, | |
| k: &[u8], | |
| s: &[u8], | |
| d: &[u8], | |
| a: HashAlgorithm, | |
| ) -> Result<bool, CryptoError> { | |
| rust::RustCryptoProvider.rsa_pkcs1v15_verify(k, s, d, a) | |
| } | |
| fn rsa_oaep_encrypt( | |
| &self, | |
| k: &[u8], | |
| d: &[u8], | |
| a: HashAlgorithm, | |
| l: Option<&[u8]>, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.rsa_oaep_encrypt(k, d, a, l) | |
| } | |
| fn rsa_oaep_decrypt( | |
| &self, | |
| k: &[u8], | |
| d: &[u8], | |
| a: HashAlgorithm, | |
| l: Option<&[u8]>, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.rsa_oaep_decrypt(k, d, a, l) | |
| } | |
| fn ecdh_derive_bits( | |
| &self, | |
| c: EllipticCurve, | |
| pk: &[u8], | |
| pubk: &[u8], | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.ecdh_derive_bits(c, pk, pubk) | |
| } | |
| fn x25519_derive_bits(&self, pk: &[u8], pubk: &[u8]) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.x25519_derive_bits(pk, pubk) | |
| } | |
| fn aes_encrypt( | |
| &self, | |
| m: AesMode, | |
| k: &[u8], | |
| iv: &[u8], | |
| d: &[u8], | |
| aad: Option<&[u8]>, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| $aes_encrypt(m, k, iv, d, aad) | |
| } | |
| fn aes_decrypt( | |
| &self, | |
| m: AesMode, | |
| k: &[u8], | |
| iv: &[u8], | |
| d: &[u8], | |
| aad: Option<&[u8]>, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| $aes_decrypt(m, k, iv, d, aad) | |
| } | |
| fn aes_kw_wrap(&self, kek: &[u8], k: &[u8]) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.aes_kw_wrap(kek, k) | |
| } | |
| fn aes_kw_unwrap(&self, kek: &[u8], w: &[u8]) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.aes_kw_unwrap(kek, w) | |
| } | |
| fn hkdf_derive_key( | |
| &self, | |
| k: &[u8], | |
| s: &[u8], | |
| i: &[u8], | |
| l: usize, | |
| a: HashAlgorithm, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.hkdf_derive_key(k, s, i, l, a) | |
| } | |
| fn pbkdf2_derive_key( | |
| &self, | |
| p: &[u8], | |
| s: &[u8], | |
| i: u32, | |
| l: usize, | |
| a: HashAlgorithm, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.pbkdf2_derive_key(p, s, i, l, a) | |
| } | |
| fn generate_aes_key(&self, b: u16) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.generate_aes_key(b) | |
| } | |
| fn generate_hmac_key(&self, a: HashAlgorithm, b: u16) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.generate_hmac_key(a, b) | |
| } | |
| fn generate_ec_key(&self, c: EllipticCurve) -> Result<(Vec<u8>, Vec<u8>), CryptoError> { | |
| rust::RustCryptoProvider.generate_ec_key(c) | |
| } | |
| fn generate_ed25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> { | |
| rust::RustCryptoProvider.generate_ed25519_key() | |
| } | |
| fn generate_x25519_key(&self) -> Result<(Vec<u8>, Vec<u8>), CryptoError> { | |
| rust::RustCryptoProvider.generate_x25519_key() | |
| } | |
| fn generate_rsa_key( | |
| &self, | |
| b: u32, | |
| e: &[u8], | |
| ) -> Result<(Vec<u8>, Vec<u8>), CryptoError> { | |
| rust::RustCryptoProvider.generate_rsa_key(b, e) | |
| } | |
| fn import_rsa_public_key_pkcs1( | |
| &self, | |
| d: &[u8], | |
| ) -> Result<RsaImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_rsa_public_key_pkcs1(d) | |
| } | |
| fn import_rsa_private_key_pkcs1( | |
| &self, | |
| d: &[u8], | |
| ) -> Result<RsaImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_rsa_private_key_pkcs1(d) | |
| } | |
| fn import_rsa_public_key_spki(&self, d: &[u8]) -> Result<RsaImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_rsa_public_key_spki(d) | |
| } | |
| fn import_rsa_private_key_pkcs8( | |
| &self, | |
| d: &[u8], | |
| ) -> Result<RsaImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_rsa_private_key_pkcs8(d) | |
| } | |
| fn export_rsa_public_key_pkcs1(&self, d: &[u8]) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.export_rsa_public_key_pkcs1(d) | |
| } | |
| fn export_rsa_public_key_spki(&self, d: &[u8]) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.export_rsa_public_key_spki(d) | |
| } | |
| fn export_rsa_private_key_pkcs8(&self, d: &[u8]) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.export_rsa_private_key_pkcs8(d) | |
| } | |
| fn import_ec_public_key_sec1( | |
| &self, | |
| d: &[u8], | |
| c: EllipticCurve, | |
| ) -> Result<EcImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_ec_public_key_sec1(d, c) | |
| } | |
| fn import_ec_public_key_spki( | |
| &self, | |
| d: &[u8], | |
| c: EllipticCurve, | |
| ) -> Result<EcImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_ec_public_key_spki(d, c) | |
| } | |
| fn import_ec_private_key_pkcs8(&self, d: &[u8]) -> Result<EcImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_ec_private_key_pkcs8(d) | |
| } | |
| fn import_ec_private_key_sec1( | |
| &self, | |
| d: &[u8], | |
| c: EllipticCurve, | |
| ) -> Result<EcImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_ec_private_key_sec1(d, c) | |
| } | |
| fn export_ec_public_key_sec1( | |
| &self, | |
| d: &[u8], | |
| c: EllipticCurve, | |
| p: bool, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.export_ec_public_key_sec1(d, c, p) | |
| } | |
| fn export_ec_public_key_spki( | |
| &self, | |
| d: &[u8], | |
| c: EllipticCurve, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.export_ec_public_key_spki(d, c) | |
| } | |
| fn export_ec_private_key_pkcs8( | |
| &self, | |
| d: &[u8], | |
| c: EllipticCurve, | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.export_ec_private_key_pkcs8(d, c) | |
| } | |
| fn import_okp_public_key_raw(&self, d: &[u8]) -> Result<OkpImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_okp_public_key_raw(d) | |
| } | |
| fn import_okp_public_key_spki( | |
| &self, | |
| d: &[u8], | |
| o: &[u8], | |
| ) -> Result<OkpImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_okp_public_key_spki(d, o) | |
| } | |
| fn import_okp_private_key_pkcs8( | |
| &self, | |
| d: &[u8], | |
| o: &[u8], | |
| ) -> Result<OkpImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_okp_private_key_pkcs8(d, o) | |
| } | |
| fn export_okp_public_key_raw(&self, d: &[u8], p: bool) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.export_okp_public_key_raw(d, p) | |
| } | |
| fn export_okp_public_key_spki( | |
| &self, | |
| d: &[u8], | |
| o: &[u8], | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.export_okp_public_key_spki(d, o) | |
| } | |
| fn export_okp_private_key_pkcs8( | |
| &self, | |
| d: &[u8], | |
| o: &[u8], | |
| ) -> Result<Vec<u8>, CryptoError> { | |
| rust::RustCryptoProvider.export_okp_private_key_pkcs8(d, o) | |
| } | |
| fn import_rsa_jwk(&self, j: RsaJwkImport<'_>) -> Result<RsaImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_rsa_jwk(j) | |
| } | |
| fn export_rsa_jwk(&self, d: &[u8], p: bool) -> Result<RsaJwkExport, CryptoError> { | |
| rust::RustCryptoProvider.export_rsa_jwk(d, p) | |
| } | |
| fn import_ec_jwk( | |
| &self, | |
| j: EcJwkImport<'_>, | |
| c: EllipticCurve, | |
| ) -> Result<EcImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_ec_jwk(j, c) | |
| } | |
| fn export_ec_jwk( | |
| &self, | |
| d: &[u8], | |
| c: EllipticCurve, | |
| p: bool, | |
| ) -> Result<EcJwkExport, CryptoError> { | |
| rust::RustCryptoProvider.export_ec_jwk(d, c, p) | |
| } | |
| fn import_okp_jwk( | |
| &self, | |
| j: OkpJwkImport<'_>, | |
| is_ed25519: bool, | |
| ) -> Result<OkpImportResult, CryptoError> { | |
| rust::RustCryptoProvider.import_okp_jwk(j, is_ed25519) | |
| } | |
| fn export_okp_jwk( | |
| &self, | |
| d: &[u8], | |
| is_private: bool, | |
| is_ed25519: bool, | |
| ) -> Result<OkpJwkExport, CryptoError> { | |
| rust::RustCryptoProvider.export_okp_jwk(d, is_private, is_ed25519) | |
| } | |
| } | |
| }; | |
| } | |
| #[cfg(feature = "crypto-ring-rust")] | |
| impl_hybrid_provider!( | |
| RingRustProvider, | |
| ring::RingDigestType, | |
| ring::RingHmacType, | |
| |a| ring::RingProvider.digest(a), | |
| |a, k| ring::RingProvider.hmac(a, k), | |
| |m, k, iv, d, aad| rust::RustCryptoProvider.aes_encrypt(m, k, iv, d, aad), | |
| |m, k, iv, d, aad| rust::RustCryptoProvider.aes_decrypt(m, k, iv, d, aad) | |
| ); | |
| #[cfg(feature = "crypto-graviola-rust")] | |
| fn graviola_aes_supported() -> bool { | |
| #[cfg(target_arch = "aarch64")] | |
| { | |
| std::arch::is_aarch64_feature_detected!("aes") | |
| } | |
| #[cfg(target_arch = "x86_64")] | |
| { | |
| std::arch::is_x86_feature_detected!("aes") | |
| } | |
| #[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))] | |
| { | |
| false | |
| } | |
| } | |
| #[cfg(feature = "crypto-graviola-rust")] | |
| impl_hybrid_provider!( | |
| GraviolaRustProvider, | |
| graviola::GraviolaRustDigest, | |
| graviola::GraviolaRustHmac, | |
| graviola::GraviolaRustDigest::new, | |
| graviola::GraviolaRustHmac::new, | |
| |m: AesMode, k: &[u8], iv: &[u8], d: &[u8], aad: Option<&[u8]>| { | |
| if graviola_aes_supported() | |
| && matches!(m, AesMode::Gcm { .. }) | |
| && matches!(k.len(), 16 | 32) | |
| { | |
| graviola::GraviolaProvider.aes_encrypt(m, k, iv, d, aad) | |
| } else { | |
| rust::RustCryptoProvider.aes_encrypt(m, k, iv, d, aad) | |
| } | |
| }, | |
| |m: AesMode, k: &[u8], iv: &[u8], d: &[u8], aad: Option<&[u8]>| { | |
| if graviola_aes_supported() | |
| && matches!(m, AesMode::Gcm { .. }) | |
| && matches!(k.len(), 16 | 32) | |
| { | |
| graviola::GraviolaProvider.aes_decrypt(m, k, iv, d, aad) | |
| } else { | |
| rust::RustCryptoProvider.aes_decrypt(m, k, iv, d, aad) | |
| } | |
| } | |
| ); | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| fn provider() -> impl CryptoProvider { | |
| #[cfg(feature = "crypto-rust")] | |
| return rust::RustCryptoProvider; | |
| #[cfg(feature = "crypto-ring-rust")] | |
| return RingRustProvider; | |
| #[cfg(feature = "crypto-graviola-rust")] | |
| return GraviolaRustProvider; | |
| #[cfg(feature = "crypto-openssl")] | |
| return openssl::OpenSslProvider; | |
| #[cfg(feature = "crypto-ring")] | |
| return ring::RingProvider; | |
| #[cfg(all(feature = "crypto-graviola", not(feature = "crypto-graviola-rust")))] | |
| return graviola::GraviolaProvider; | |
| } | |
| fn to_hex(bytes: &[u8]) -> String { | |
| bytes.iter().map(|b| format!("{:02x}", b)).collect() | |
| } | |
| // SHA digest tests | |
| #[test] | |
| fn test_sha256_digest() { | |
| let p = provider(); | |
| let mut digest = p.digest(HashAlgorithm::Sha256); | |
| digest.update(b"hello world"); | |
| let result = digest.finalize(); | |
| assert_eq!(result.len(), 32); | |
| assert_eq!( | |
| to_hex(&result), | |
| "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" | |
| ); | |
| } | |
| #[test] | |
| fn test_sha384_digest() { | |
| let p = provider(); | |
| let mut digest = p.digest(HashAlgorithm::Sha384); | |
| digest.update(b"hello world"); | |
| let result = digest.finalize(); | |
| assert_eq!(result.len(), 48); | |
| } | |
| #[test] | |
| fn test_sha512_digest() { | |
| let p = provider(); | |
| let mut digest = p.digest(HashAlgorithm::Sha512); | |
| digest.update(b"hello world"); | |
| let result = digest.finalize(); | |
| assert_eq!(result.len(), 64); | |
| } | |
| // HMAC tests | |
| #[test] | |
| fn test_hmac_sha256() { | |
| let p = provider(); | |
| let key = b"secret key"; | |
| let mut hmac = p.hmac(HashAlgorithm::Sha256, key); | |
| hmac.update(b"hello world"); | |
| let result = hmac.finalize(); | |
| assert_eq!(result.len(), 32); | |
| } | |
| // AES-GCM tests - only for providers that support AES | |
| #[cfg(any( | |
| feature = "crypto-rust", | |
| feature = "crypto-openssl", | |
| feature = "crypto-ring-rust", | |
| feature = "crypto-graviola-rust" | |
| ))] | |
| #[test] | |
| fn test_aes_gcm_128_roundtrip() { | |
| let p = provider(); | |
| let key = [0u8; 16]; | |
| let iv = [0u8; 12]; | |
| let plaintext = b"hello world"; | |
| let aad = b"additional data"; | |
| let ciphertext = p | |
| .aes_encrypt( | |
| AesMode::Gcm { tag_length: 128 }, | |
| &key, | |
| &iv, | |
| plaintext, | |
| Some(aad), | |
| ) | |
| .unwrap(); | |
| assert_eq!(ciphertext.len(), plaintext.len() + 16); // plaintext + tag | |
| let decrypted = p | |
| .aes_decrypt( | |
| AesMode::Gcm { tag_length: 128 }, | |
| &key, | |
| &iv, | |
| &ciphertext, | |
| Some(aad), | |
| ) | |
| .unwrap(); | |
| assert_eq!(decrypted, plaintext); | |
| } | |
| #[cfg(any( | |
| feature = "crypto-rust", | |
| feature = "crypto-openssl", | |
| feature = "crypto-ring-rust", | |
| feature = "crypto-graviola-rust" | |
| ))] | |
| #[test] | |
| fn test_aes_gcm_256_roundtrip() { | |
| let p = provider(); | |
| let key = [0u8; 32]; | |
| let iv = [0u8; 12]; | |
| let plaintext = b"hello world"; | |
| let ciphertext = p | |
| .aes_encrypt(AesMode::Gcm { tag_length: 128 }, &key, &iv, plaintext, None) | |
| .unwrap(); | |
| let decrypted = p | |
| .aes_decrypt( | |
| AesMode::Gcm { tag_length: 128 }, | |
| &key, | |
| &iv, | |
| &ciphertext, | |
| None, | |
| ) | |
| .unwrap(); | |
| assert_eq!(decrypted, plaintext); | |
| } | |
| #[cfg(any( | |
| feature = "crypto-rust", | |
| feature = "crypto-openssl", | |
| feature = "crypto-ring-rust", | |
| feature = "crypto-graviola-rust" | |
| ))] | |
| #[test] | |
| fn test_aes_gcm_wrong_key_fails() { | |
| let p = provider(); | |
| let key = [0u8; 16]; | |
| let wrong_key = [1u8; 16]; | |
| let iv = [0u8; 12]; | |
| let plaintext = b"hello world"; | |
| let ciphertext = p | |
| .aes_encrypt(AesMode::Gcm { tag_length: 128 }, &key, &iv, plaintext, None) | |
| .unwrap(); | |
| let result = p.aes_decrypt( | |
| AesMode::Gcm { tag_length: 128 }, | |
| &wrong_key, | |
| &iv, | |
| &ciphertext, | |
| None, | |
| ); | |
| assert!(result.is_err()); | |
| } | |
| // Key generation tests - only for providers that support key generation | |
| #[cfg(any( | |
| feature = "crypto-rust", | |
| feature = "crypto-openssl", | |
| feature = "crypto-ring-rust", | |
| feature = "crypto-graviola-rust" | |
| ))] | |
| #[test] | |
| fn test_generate_aes_key_128() { | |
| let p = provider(); | |
| let key = p.generate_aes_key(128).unwrap(); | |
| assert_eq!(key.len(), 16); | |
| } | |
| #[cfg(any( | |
| feature = "crypto-rust", | |
| feature = "crypto-openssl", | |
| feature = "crypto-ring-rust", | |
| feature = "crypto-graviola-rust" | |
| ))] | |
| #[test] | |
| fn test_generate_aes_key_256() { | |
| let p = provider(); | |
| let key = p.generate_aes_key(256).unwrap(); | |
| assert_eq!(key.len(), 32); | |
| } | |
| #[cfg(any( | |
| feature = "crypto-rust", | |
| feature = "crypto-openssl", | |
| feature = "crypto-ring-rust", | |
| feature = "crypto-graviola-rust" | |
| ))] | |
| #[test] | |
| fn test_generate_hmac_key() { | |
| let p = provider(); | |
| let key = p.generate_hmac_key(HashAlgorithm::Sha256, 256).unwrap(); | |
| assert_eq!(key.len(), 32); | |
| } | |
| // Tests that require full crypto support | |
| #[cfg(any( | |
| feature = "crypto-rust", | |
| feature = "crypto-openssl", | |
| feature = "crypto-ring-rust", | |
| feature = "crypto-graviola-rust" | |
| ))] | |
| mod full_provider_tests { | |
| use super::*; | |
| #[test] | |
| fn test_aes_cbc_roundtrip() { | |
| let p = provider(); | |
| let key = [0u8; 16]; | |
| let iv = [0u8; 16]; | |
| let plaintext = b"hello world12345"; // 16 bytes for block alignment | |
| let ciphertext = p | |
| .aes_encrypt(AesMode::Cbc, &key, &iv, plaintext, None) | |
| .unwrap(); | |
| let decrypted = p | |
| .aes_decrypt(AesMode::Cbc, &key, &iv, &ciphertext, None) | |
| .unwrap(); | |
| assert_eq!(decrypted, plaintext); | |
| } | |
| #[test] | |
| fn test_aes_ctr_roundtrip() { | |
| let p = provider(); | |
| let key = [0u8; 16]; | |
| let iv = [0u8; 16]; | |
| let plaintext = b"hello world"; | |
| let ciphertext = p | |
| .aes_encrypt( | |
| AesMode::Ctr { counter_length: 64 }, | |
| &key, | |
| &iv, | |
| plaintext, | |
| None, | |
| ) | |
| .unwrap(); | |
| let decrypted = p | |
| .aes_decrypt( | |
| AesMode::Ctr { counter_length: 64 }, | |
| &key, | |
| &iv, | |
| &ciphertext, | |
| None, | |
| ) | |
| .unwrap(); | |
| assert_eq!(decrypted, plaintext); | |
| } | |
| #[test] | |
| fn test_aes_kw_roundtrip() { | |
| let p = provider(); | |
| let kek = [0u8; 16]; | |
| let key_to_wrap = [1u8; 16]; | |
| let wrapped = p.aes_kw_wrap(&kek, &key_to_wrap).unwrap(); | |
| let unwrapped = p.aes_kw_unwrap(&kek, &wrapped).unwrap(); | |
| assert_eq!(unwrapped, key_to_wrap); | |
| } | |
| #[test] | |
| fn test_hkdf_derive() { | |
| let p = provider(); | |
| let ikm = b"input key material"; | |
| let salt = b"salt"; | |
| let info = b"info"; | |
| let derived = p | |
| .hkdf_derive_key(ikm, salt, info, 32, HashAlgorithm::Sha256) | |
| .unwrap(); | |
| assert_eq!(derived.len(), 32); | |
| } | |
| #[test] | |
| fn test_pbkdf2_derive() { | |
| let p = provider(); | |
| let password = b"password"; | |
| let salt = b"salt"; | |
| let derived = p | |
| .pbkdf2_derive_key(password, salt, 1000, 32, HashAlgorithm::Sha256) | |
| .unwrap(); | |
| assert_eq!(derived.len(), 32); | |
| } | |
| #[test] | |
| fn test_ec_p256_sign_verify() { | |
| let p = provider(); | |
| let (private_key, public_key) = p.generate_ec_key(EllipticCurve::P256).unwrap(); | |
| // Create a digest to sign | |
| let mut digest = p.digest(HashAlgorithm::Sha256); | |
| digest.update(b"message to sign"); | |
| let hash = digest.finalize(); | |
| let signature = p | |
| .ecdsa_sign(EllipticCurve::P256, &private_key, &hash) | |
| .unwrap(); | |
| let valid = p | |
| .ecdsa_verify(EllipticCurve::P256, &public_key, &signature, &hash) | |
| .unwrap(); | |
| assert!(valid); | |
| } | |
| #[test] | |
| fn test_ec_p384_sign_verify() { | |
| let p = provider(); | |
| let (private_key, public_key) = p.generate_ec_key(EllipticCurve::P384).unwrap(); | |
| let mut digest = p.digest(HashAlgorithm::Sha384); | |
| digest.update(b"message to sign"); | |
| let hash = digest.finalize(); | |
| let signature = p | |
| .ecdsa_sign(EllipticCurve::P384, &private_key, &hash) | |
| .unwrap(); | |
| let valid = p | |
| .ecdsa_verify(EllipticCurve::P384, &public_key, &signature, &hash) | |
| .unwrap(); | |
| assert!(valid); | |
| } | |
| #[test] | |
| fn test_ed25519_sign_verify() { | |
| let p = provider(); | |
| let (private_key, public_key) = p.generate_ed25519_key().unwrap(); | |
| let message = b"message to sign"; | |
| let signature = p.ed25519_sign(&private_key, message).unwrap(); | |
| let valid = p.ed25519_verify(&public_key, &signature, message).unwrap(); | |
| assert!(valid); | |
| } | |
| #[test] | |
| fn test_x25519_key_exchange() { | |
| let p = provider(); | |
| let (alice_private, alice_public) = p.generate_x25519_key().unwrap(); | |
| let (bob_private, bob_public) = p.generate_x25519_key().unwrap(); | |
| let alice_shared = p.x25519_derive_bits(&alice_private, &bob_public).unwrap(); | |
| let bob_shared = p.x25519_derive_bits(&bob_private, &alice_public).unwrap(); | |
| assert_eq!(alice_shared, bob_shared); | |
| assert_eq!(alice_shared.len(), 32); | |
| } | |
| #[test] | |
| fn test_ecdh_p256_key_exchange() { | |
| let p = provider(); | |
| let (alice_private, alice_public) = p.generate_ec_key(EllipticCurve::P256).unwrap(); | |
| let (bob_private, bob_public) = p.generate_ec_key(EllipticCurve::P256).unwrap(); | |
| let alice_shared = p | |
| .ecdh_derive_bits(EllipticCurve::P256, &alice_private, &bob_public) | |
| .unwrap(); | |
| let bob_shared = p | |
| .ecdh_derive_bits(EllipticCurve::P256, &bob_private, &alice_public) | |
| .unwrap(); | |
| assert_eq!(alice_shared, bob_shared); | |
| } | |
| #[test] | |
| fn test_rsa_pss_sign_verify() { | |
| let p = provider(); | |
| let (private_key, public_key) = p.generate_rsa_key(2048, &[1, 0, 1]).unwrap(); | |
| let mut digest = p.digest(HashAlgorithm::Sha256); | |
| digest.update(b"message to sign"); | |
| let hash = digest.finalize(); | |
| let signature = p | |
| .rsa_pss_sign(&private_key, &hash, 32, HashAlgorithm::Sha256) | |
| .unwrap(); | |
| let valid = p | |
| .rsa_pss_verify(&public_key, &signature, &hash, 32, HashAlgorithm::Sha256) | |
| .unwrap(); | |
| assert!(valid); | |
| } | |
| #[test] | |
| fn test_rsa_pkcs1v15_sign_verify() { | |
| let p = provider(); | |
| let (private_key, public_key) = p.generate_rsa_key(2048, &[1, 0, 1]).unwrap(); | |
| let mut digest = p.digest(HashAlgorithm::Sha256); | |
| digest.update(b"message to sign"); | |
| let hash = digest.finalize(); | |
| let signature = p | |
| .rsa_pkcs1v15_sign(&private_key, &hash, HashAlgorithm::Sha256) | |
| .unwrap(); | |
| let valid = p | |
| .rsa_pkcs1v15_verify(&public_key, &signature, &hash, HashAlgorithm::Sha256) | |
| .unwrap(); | |
| assert!(valid); | |
| } | |
| #[test] | |
| fn test_rsa_oaep_encrypt_decrypt() { | |
| let p = provider(); | |
| let (private_key, public_key) = p.generate_rsa_key(2048, &[1, 0, 1]).unwrap(); | |
| let plaintext = b"secret message"; | |
| let ciphertext = p | |
| .rsa_oaep_encrypt(&public_key, plaintext, HashAlgorithm::Sha256, None) | |
| .unwrap(); | |
| let decrypted = p | |
| .rsa_oaep_decrypt(&private_key, &ciphertext, HashAlgorithm::Sha256, None) | |
| .unwrap(); | |
| assert_eq!(decrypted, plaintext); | |
| } | |
| } | |
| } |