#![allow(clippy::disallowed_methods)]
use async_trait::async_trait;
use crate::provider::{CryptoError, CryptoProvider, ED25519_PUBLIC_KEY_LEN, SecureSeed};
pub struct CnsaProvider;
impl CnsaProvider {
pub fn p384_generate() -> Result<(SecureSeed, Vec<u8>), CryptoError> {
use p384::ecdsa::SigningKey;
use p384::elliptic_curve::rand_core::OsRng;
let sk = SigningKey::random(&mut OsRng);
let vk = p384::ecdsa::VerifyingKey::from(&sk);
let compressed = vk.to_encoded_point(true);
let pubkey_bytes = compressed.as_bytes().to_vec();
let scalar_bytes = sk.to_bytes();
let mut seed = [0u8; 32];
let take = scalar_bytes.len().min(32);
seed[..take].copy_from_slice(&scalar_bytes[..take]);
Ok((SecureSeed::new(seed), pubkey_bytes))
}
pub fn p384_sign(scalar_48: &[u8], message: &[u8]) -> Result<Vec<u8>, CryptoError> {
use p384::ecdsa::{SigningKey, signature::Signer};
let sk = SigningKey::from_slice(scalar_48)
.map_err(|e| CryptoError::InvalidPrivateKey(format!("P-384: {e}")))?;
let sig: p384::ecdsa::Signature = sk.sign(message);
Ok(sig.to_bytes().to_vec())
}
pub fn p256_sign(_seed: &[u8; 32], _message: &[u8]) -> Result<Vec<u8>, CryptoError> {
Err(CryptoError::OperationFailed(
"P-256 sign is rejected under --features cnsa; use P-384".into(),
))
}
pub fn p256_public_key_from_seed(_seed: &[u8; 32]) -> Result<Vec<u8>, CryptoError> {
Err(CryptoError::OperationFailed(
"P-256 pubkey derivation is rejected under --features cnsa; use P-384".into(),
))
}
pub fn ed25519_sign(seed: &[u8; 32], message: &[u8]) -> Result<Vec<u8>, CryptoError> {
crate::ring_provider::RingCryptoProvider::ed25519_sign(seed, message)
}
pub fn ed25519_public_key(seed: &[u8; 32]) -> Result<[u8; 32], CryptoError> {
crate::ring_provider::RingCryptoProvider::ed25519_public_key(seed)
}
pub fn p384_verify(pubkey: &[u8], message: &[u8], signature: &[u8]) -> Result<(), CryptoError> {
use p384::ecdsa::{Signature, VerifyingKey, signature::Verifier};
let vk = VerifyingKey::from_sec1_bytes(pubkey)
.map_err(|e| CryptoError::OperationFailed(format!("P-384 key parse: {e}")))?;
let sig = Signature::from_slice(signature)
.map_err(|e| CryptoError::OperationFailed(format!("P-384 sig parse: {e}")))?;
vk.verify(message, &sig)
.map_err(|_| CryptoError::InvalidSignature)
}
}
#[async_trait]
impl CryptoProvider for CnsaProvider {
async fn verify_ed25519(
&self,
pubkey: &[u8],
message: &[u8],
signature: &[u8],
) -> Result<(), CryptoError> {
if pubkey.len() != ED25519_PUBLIC_KEY_LEN {
return Err(CryptoError::InvalidKeyLength {
expected: ED25519_PUBLIC_KEY_LEN,
actual: pubkey.len(),
});
}
crate::ring_provider::RingCryptoProvider::ed25519_verify(pubkey, message, signature)
}
async fn verify_p256(
&self,
_pubkey: &[u8],
_message: &[u8],
_signature: &[u8],
) -> Result<(), CryptoError> {
Err(CryptoError::OperationFailed(
"P-256 verify is rejected under --features cnsa; use P-384".into(),
))
}
async fn sign_ed25519(
&self,
seed: &SecureSeed,
message: &[u8],
) -> Result<Vec<u8>, CryptoError> {
crate::ring_provider::RingCryptoProvider::ed25519_sign(seed.as_bytes(), message)
}
async fn generate_ed25519_keypair(&self) -> Result<(SecureSeed, [u8; 32]), CryptoError> {
crate::ring_provider::RingCryptoProvider
.generate_ed25519_keypair()
.await
}
async fn ed25519_public_key_from_seed(
&self,
seed: &SecureSeed,
) -> Result<[u8; 32], CryptoError> {
crate::ring_provider::RingCryptoProvider::ed25519_public_key(seed.as_bytes())
}
async fn sign_p256(&self, _seed: &SecureSeed, _message: &[u8]) -> Result<Vec<u8>, CryptoError> {
Err(CryptoError::OperationFailed(
"P-256 sign is rejected under --features cnsa; use P-384".into(),
))
}
async fn generate_p256_keypair(&self) -> Result<(SecureSeed, Vec<u8>), CryptoError> {
Err(CryptoError::OperationFailed(
"P-256 keygen is rejected under --features cnsa; use P-384".into(),
))
}
async fn p256_public_key_from_seed(&self, _seed: &SecureSeed) -> Result<Vec<u8>, CryptoError> {
Err(CryptoError::OperationFailed(
"P-256 pubkey derivation is rejected under --features cnsa; use P-384".into(),
))
}
async fn aead_encrypt(
&self,
key: &[u8; 32],
nonce: &[u8; 12],
aad: &[u8],
plaintext: &[u8],
) -> Result<Vec<u8>, CryptoError> {
use aes_gcm::{
Aes256Gcm, Key, Nonce,
aead::{Aead, KeyInit, Payload},
};
let key = Key::<Aes256Gcm>::from_slice(key);
let cipher = Aes256Gcm::new(key);
let nonce = Nonce::from_slice(nonce);
cipher
.encrypt(
nonce,
Payload {
msg: plaintext,
aad,
},
)
.map_err(|e| CryptoError::OperationFailed(format!("AES-256-GCM encrypt: {e}")))
}
async fn aead_decrypt(
&self,
key: &[u8; 32],
nonce: &[u8; 12],
aad: &[u8],
ciphertext: &[u8],
) -> Result<Vec<u8>, CryptoError> {
use aes_gcm::{
Aes256Gcm, Key, Nonce,
aead::{Aead, KeyInit, Payload},
};
let key = Key::<Aes256Gcm>::from_slice(key);
let cipher = Aes256Gcm::new(key);
let nonce = Nonce::from_slice(nonce);
cipher
.decrypt(
nonce,
Payload {
msg: ciphertext,
aad,
},
)
.map_err(|_| CryptoError::InvalidSignature)
}
async fn hkdf_sha256_expand(
&self,
_ikm: &[u8],
_salt: &[u8],
_info: &[u8],
_out_len: usize,
) -> Result<Vec<u8>, CryptoError> {
Err(CryptoError::OperationFailed(
"HKDF-SHA256 is rejected under --features cnsa; use HKDF-SHA384".into(),
))
}
async fn hkdf_sha384_expand(
&self,
ikm: &[u8],
salt: &[u8],
info: &[u8],
out_len: usize,
) -> Result<Vec<u8>, CryptoError> {
use hkdf::Hkdf;
use sha2::Sha384;
if out_len > 255 * 48 {
return Err(CryptoError::OperationFailed(
"HKDF-SHA384 output length exceeds 255 * 48 = 12240 bytes".into(),
));
}
let hk = Hkdf::<Sha384>::new(if salt.is_empty() { None } else { Some(salt) }, ikm);
let mut out = vec![0u8; out_len];
hk.expand(info, &mut out)
.map_err(|e| CryptoError::OperationFailed(format!("HKDF-SHA384 expand: {e}")))?;
Ok(out)
}
async fn hmac_sha256_compute(&self, _key: &[u8], _msg: &[u8]) -> Result<[u8; 32], CryptoError> {
Err(CryptoError::OperationFailed(
"HMAC-SHA256 is rejected under --features cnsa; use HMAC-SHA384".into(),
))
}
async fn hmac_sha256_verify(
&self,
_key: &[u8],
_msg: &[u8],
_tag: &[u8],
) -> Result<(), CryptoError> {
Err(CryptoError::OperationFailed(
"HMAC-SHA256 verify is rejected under --features cnsa; use HMAC-SHA384".into(),
))
}
async fn hmac_sha384_compute(&self, key: &[u8], msg: &[u8]) -> Result<[u8; 48], CryptoError> {
use hmac::{Hmac, Mac};
use sha2::Sha384;
let mut mac = <Hmac<Sha384> as Mac>::new_from_slice(key)
.map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA384 key: {e}")))?;
mac.update(msg);
let tag = mac.finalize().into_bytes();
let out: [u8; 48] = tag.into();
Ok(out)
}
async fn hmac_sha384_verify(
&self,
key: &[u8],
msg: &[u8],
tag: &[u8],
) -> Result<(), CryptoError> {
use hmac::{Hmac, Mac};
use sha2::Sha384;
let mut mac = <Hmac<Sha384> as Mac>::new_from_slice(key)
.map_err(|e| CryptoError::OperationFailed(format!("HMAC-SHA384 key: {e}")))?;
mac.update(msg);
mac.verify_slice(tag)
.map_err(|_| CryptoError::InvalidSignature)
}
}