#[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 = "_modern-webcrypto")]
pub(crate) mod modern;
#[cfg(feature = "_rustcrypto")]
mod rust;
use crate::crypto::hash::HashAlgorithm;
use crate::crypto::subtle::EllipticCurve;
use crate::str_enum;
#[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,
}
#[derive(Debug)]
#[allow(dead_code)]
pub struct RsaJwkImport<'a> {
pub n: &'a [u8], pub e: &'a [u8], pub d: Option<&'a [u8]>, pub p: Option<&'a [u8]>, pub q: Option<&'a [u8]>, pub dp: Option<&'a [u8]>, pub dq: Option<&'a [u8]>, pub qi: Option<&'a [u8]>, }
#[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>>,
}
#[derive(Debug)]
#[allow(dead_code)]
pub struct EcJwkImport<'a> {
pub x: &'a [u8],
pub y: &'a [u8],
pub d: Option<&'a [u8]>,
}
#[derive(Debug)]
#[allow(dead_code)]
pub struct EcJwkExport {
pub x: Vec<u8>,
pub y: Vec<u8>,
pub d: Option<Vec<u8>>,
}
#[derive(Debug)]
#[allow(dead_code)]
pub struct OkpJwkImport<'a> {
pub x: &'a [u8], pub d: Option<&'a [u8]>, }
#[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;
}
pub const MAX_HMAC_KEY_LENGTH_BITS: u32 = 1024;
pub(crate) fn hmac_length_is_byte_aligned(length_bits: u32) -> bool {
length_bits.is_multiple_of(8)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MlDsaVariant {
MlDsa44,
MlDsa65,
MlDsa87,
}
str_enum!(
MlDsaVariant,
MlDsa44 => "ML-DSA-44",
MlDsa65 => "ML-DSA-65",
MlDsa87 => "ML-DSA-87"
);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MlKemVariant {
MlKem512,
MlKem768,
MlKem1024,
}
str_enum!(
MlKemVariant,
MlKem512 => "ML-KEM-512",
MlKem768 => "ML-KEM-768",
MlKem1024 => "ML-KEM-1024"
);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HybridKemVariant {
MlKem768P256,
MlKem768X25519,
MlKem1024P384,
}
str_enum!(
HybridKemVariant,
MlKem768P256 => "MLKEM768-P256",
MlKem768X25519 => "MLKEM768-X25519",
MlKem1024P384 => "MLKEM1024-P384"
);
impl HybridKemVariant {
pub const fn ml_kem_variant(self) -> MlKemVariant {
match self {
Self::MlKem768P256 | Self::MlKem768X25519 => MlKemVariant::MlKem768,
Self::MlKem1024P384 => MlKemVariant::MlKem1024,
}
}
pub const fn public_key_length(self) -> usize {
match self {
Self::MlKem768P256 => 1249,
Self::MlKem768X25519 => 1216,
Self::MlKem1024P384 => 1665,
}
}
pub const fn ciphertext_length(self) -> usize {
match self {
Self::MlKem768P256 => 1153,
Self::MlKem768X25519 => 1120,
Self::MlKem1024P384 => 1665,
}
}
pub const fn pq_public_key_length(self) -> usize {
match self.ml_kem_variant() {
MlKemVariant::MlKem768 => 1184,
MlKemVariant::MlKem1024 => 1568,
MlKemVariant::MlKem512 => unreachable!(),
}
}
pub const fn pq_ciphertext_length(self) -> usize {
match self.ml_kem_variant() {
MlKemVariant::MlKem768 => 1088,
MlKemVariant::MlKem1024 => 1568,
MlKemVariant::MlKem512 => unreachable!(),
}
}
}
#[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;
fn digest(&self, algorithm: HashAlgorithm) -> Self::Digest;
fn hmac(&self, algorithm: HashAlgorithm, key: &[u8]) -> Self::Hmac;
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>;
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>;
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>;
fn ecdh_derive_bits(
&self,
curve: EllipticCurve,
private_key_der: &[u8],
public_key_sec1: &[u8],
) -> Result<Vec<u8>, CryptoError>;
fn x25519_derive_bits(
&self,
private_key: &[u8],
public_key: &[u8],
) -> Result<Vec<u8>, CryptoError>;
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>;
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>;
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>; 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>;
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>;
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>;
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>;
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>;
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>;
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>;
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>;
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;
#[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 { tag_length: 128 })
&& 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 { tag_length: 128 })
&& 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()
}
#[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);
}
#[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);
}
#[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);
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());
}
#[cfg(all(feature = "crypto-graviola", not(feature = "crypto-graviola-rust")))]
#[test]
fn test_graviola_rejects_unsupported_aes_gcm_tag_length() {
let p = provider();
let result = p.aes_encrypt(
AesMode::Gcm { tag_length: 64 },
&[0; 16],
&[0; 12],
b"hello world",
None,
);
assert!(matches!(result, Err(CryptoError::UnsupportedAlgorithm)));
}
#[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);
}
#[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";
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();
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);
}
}
}