From 68836cfff4234e49a82efb3204776ed256a82304 Mon Sep 17 00:00:00 2001 From: JohnE Date: Wed, 11 Mar 2026 16:12:12 -0700 Subject: [PATCH] MOD: formatting --- crates/ccc-crypto-core/src/algorithms.rs | 56 ++-- crates/ccc-crypto-core/src/provider.rs | 15 +- crates/ccc-crypto-core/src/registry.rs | 72 +++-- crates/ccc-crypto-wolfssl/build.rs | 57 ++-- crates/ccc-crypto-wolfssl/src/aead.rs | 145 +++++---- crates/ccc-crypto-wolfssl/src/capabilities.rs | 132 +++++--- crates/ccc-crypto-wolfssl/src/hash.rs | 96 ++++-- crates/ccc-crypto-wolfssl/src/kdf.rs | 45 +-- crates/ccc-crypto-wolfssl/src/kem.rs | 220 ++++++++------ crates/ccc-crypto-wolfssl/src/lib.rs | 282 +++++++++++++----- crates/ccc-crypto-wolfssl/src/mac.rs | 91 +++--- crates/ccc-crypto-wolfssl/src/provider.rs | 113 ++++--- tests/conformance/src/main.rs | 176 ++++++++--- 13 files changed, 963 insertions(+), 537 deletions(-) diff --git a/crates/ccc-crypto-core/src/algorithms.rs b/crates/ccc-crypto-core/src/algorithms.rs index b75f5b5..bc3b580 100644 --- a/crates/ccc-crypto-core/src/algorithms.rs +++ b/crates/ccc-crypto-core/src/algorithms.rs @@ -42,30 +42,30 @@ impl AeadAlgorithm { /// Human-readable name, suitable for logs and diagnostics. pub fn name(self) -> &'static str { match self { - Self::AesGcm256 => "AES-256-GCM", - Self::ChaCha20Poly1305 => "ChaCha20-Poly1305", + Self::AesGcm256 => "AES-256-GCM", + Self::ChaCha20Poly1305 => "ChaCha20-Poly1305", Self::XChaCha20Poly1305 => "XChaCha20-Poly1305", - Self::Ascon128a => "Ascon-AEAD-128a", + Self::Ascon128a => "Ascon-AEAD-128a", } } /// Expected nonce length in bytes for this algorithm. pub fn nonce_len(self) -> usize { match self { - Self::AesGcm256 => 12, - Self::ChaCha20Poly1305 => 12, + Self::AesGcm256 => 12, + Self::ChaCha20Poly1305 => 12, Self::XChaCha20Poly1305 => 24, - Self::Ascon128a => 16, + Self::Ascon128a => 16, } } /// Expected key length in bytes for this algorithm. pub fn key_len(self) -> usize { match self { - Self::AesGcm256 => 32, - Self::ChaCha20Poly1305 => 32, + Self::AesGcm256 => 32, + Self::ChaCha20Poly1305 => 32, Self::XChaCha20Poly1305 => 32, - Self::Ascon128a => 16, + Self::Ascon128a => 16, } } } @@ -112,12 +112,12 @@ impl KdfAlgorithm { /// Human-readable name. pub fn name(self) -> &'static str { match self { - Self::Sha256 => "HKDF-SHA-256", - Self::Sha384 => "HKDF-SHA-384", - Self::Sha512 => "HKDF-SHA-512", + Self::Sha256 => "HKDF-SHA-256", + Self::Sha384 => "HKDF-SHA-384", + Self::Sha512 => "HKDF-SHA-512", Self::Blake2b512 => "HKDF-BLAKE2b-512", - Self::Argon2id => "Argon2id", - Self::Kmac256 => "KMAC256", + Self::Argon2id => "Argon2id", + Self::Kmac256 => "KMAC256", } } } @@ -223,24 +223,24 @@ impl HashAlgorithm { /// Human-readable name. pub fn name(self) -> &'static str { match self { - Self::Sha256 => "SHA-256", - Self::Sha384 => "SHA-384", - Self::Sha512 => "SHA-512", + Self::Sha256 => "SHA-256", + Self::Sha384 => "SHA-384", + Self::Sha512 => "SHA-512", Self::Blake2b512 => "BLAKE2b-512", - Self::Sha3_256 => "SHA3-256", - Self::Sha3_512 => "SHA3-512", + Self::Sha3_256 => "SHA3-256", + Self::Sha3_512 => "SHA3-512", } } /// Digest output length in bytes. pub fn digest_len(self) -> usize { match self { - Self::Sha256 => 32, - Self::Sha384 => 48, - Self::Sha512 => 64, + Self::Sha256 => 32, + Self::Sha384 => 48, + Self::Sha512 => 64, Self::Blake2b512 => 64, - Self::Sha3_256 => 32, - Self::Sha3_512 => 64, + Self::Sha3_256 => 32, + Self::Sha3_512 => 64, } } } @@ -285,10 +285,10 @@ impl KemAlgorithm { /// Human-readable name. pub fn name(self) -> &'static str { match self { - Self::X25519 => "X25519", - Self::X448 => "X448", - Self::MlKem768 => "ML-KEM-768", - Self::MlKem1024 => "ML-KEM-1024", + Self::X25519 => "X25519", + Self::X448 => "X448", + Self::MlKem768 => "ML-KEM-768", + Self::MlKem1024 => "ML-KEM-1024", Self::ClassicMcEliece460896 => "Classic-McEliece-460896", } } diff --git a/crates/ccc-crypto-core/src/provider.rs b/crates/ccc-crypto-core/src/provider.rs index e89dcf3..f475d42 100644 --- a/crates/ccc-crypto-core/src/provider.rs +++ b/crates/ccc-crypto-core/src/provider.rs @@ -110,11 +110,7 @@ pub trait MacProvider { /// Cryptographic hash operations. pub trait HashProvider { /// Compute a digest of `data` using the specified algorithm. - fn hash( - &self, - algo: HashAlgorithm, - data: &[u8], - ) -> Result, CryptoError>; + fn hash(&self, algo: HashAlgorithm, data: &[u8]) -> Result, CryptoError>; } /// Key encapsulation mechanism operations. @@ -124,10 +120,7 @@ pub trait HashProvider { /// functions separately and looks up a `KemProvider` from the registry. pub trait KemProvider { /// Generate a new KEM key pair. - fn generate_keypair( - &self, - algo: KemAlgorithm, - ) -> Result; + fn generate_keypair(&self, algo: KemAlgorithm) -> Result; /// Encapsulate a shared secret for the holder of `public_key`. /// @@ -170,7 +163,9 @@ pub trait KemProvider { /// `ProviderRegistry::global().register(name, Box::new(provider))`. /// 5. Call `ccc_crypto_::init()` from `ccc-flutter-bridge/src/lib.rs`. /// 6. Add NIST test vectors for every algorithm you expose. -pub trait CryptoProvider: AeadProvider + KdfProvider + MacProvider + HashProvider + Send + Sync { +pub trait CryptoProvider: + AeadProvider + KdfProvider + MacProvider + HashProvider + Send + Sync +{ /// The provider's canonical name (e.g. `"wolfssl"`). /// /// Must be lowercase, no spaces, match the `CccCryptoProvider` enum value diff --git a/crates/ccc-crypto-core/src/registry.rs b/crates/ccc-crypto-core/src/registry.rs index 325b58d..33ccc46 100644 --- a/crates/ccc-crypto-core/src/registry.rs +++ b/crates/ccc-crypto-core/src/registry.rs @@ -118,12 +118,22 @@ mod tests { impl AeadProvider for StubProvider { fn encrypt_aead( - &self, _a: AeadAlgorithm, _k: &[u8], _n: &[u8], pt: &[u8], _aad: &[u8], + &self, + _a: AeadAlgorithm, + _k: &[u8], + _n: &[u8], + pt: &[u8], + _aad: &[u8], ) -> Result, CryptoError> { Ok(pt.to_vec()) } fn decrypt_aead( - &self, _a: AeadAlgorithm, _k: &[u8], _n: &[u8], ct: &[u8], _aad: &[u8], + &self, + _a: AeadAlgorithm, + _k: &[u8], + _n: &[u8], + ct: &[u8], + _aad: &[u8], ) -> Result, CryptoError> { Ok(ct.to_vec()) } @@ -131,7 +141,12 @@ mod tests { impl KdfProvider for StubProvider { fn derive_key( - &self, _a: KdfAlgorithm, _ikm: &[u8], _salt: &[u8], _info: &[u8], length: usize, + &self, + _a: KdfAlgorithm, + _ikm: &[u8], + _salt: &[u8], + _info: &[u8], + length: usize, ) -> Result>, CryptoError> { Ok(Zeroizing::new(vec![0u8; length])) } @@ -139,41 +154,56 @@ mod tests { impl MacProvider for StubProvider { fn compute_mac( - &self, _a: MacAlgorithm, _k: &[u8], _data: &[u8], + &self, + _a: MacAlgorithm, + _k: &[u8], + _data: &[u8], ) -> Result, CryptoError> { Ok(vec![0u8; 32]) } fn verify_mac( - &self, _a: MacAlgorithm, _k: &[u8], _data: &[u8], _mac: &[u8], + &self, + _a: MacAlgorithm, + _k: &[u8], + _data: &[u8], + _mac: &[u8], ) -> Result { Ok(true) } } impl HashProvider for StubProvider { - fn hash( - &self, _a: HashAlgorithm, data: &[u8], - ) -> Result, CryptoError> { + fn hash(&self, _a: HashAlgorithm, data: &[u8]) -> Result, CryptoError> { Ok(data.to_vec()) } } impl CryptoProvider for StubProvider { - fn provider_name(&self) -> &'static str { "stub" } + fn provider_name(&self) -> &'static str { + "stub" + } fn capabilities(&self) -> ProviderCapabilities { ProviderCapabilities::empty("stub") } fn self_test(&self) -> SelfTestReport { - SelfTestReport::finalise("stub", vec![AlgoTestResult { - algo_id: 12, algo_name: "stub".into(), passed: true, error_message: None, - }]) + SelfTestReport::finalise( + "stub", + vec![AlgoTestResult { + algo_id: 12, + algo_name: "stub".into(), + passed: true, + error_message: None, + }], + ) } fn benchmark(&self) -> BenchmarkReport { BenchmarkReport { provider_name: "stub".into(), results: vec![AlgoBenchResult { - algo_id: 12, algo_name: "stub".into(), - throughput_mbps: 999.0, efficiency_score: 100, + algo_id: 12, + algo_name: "stub".into(), + throughput_mbps: 999.0, + efficiency_score: 100, }], } } @@ -182,7 +212,9 @@ mod tests { // ── Tests ────────────────────────────────────────────────────────────────── fn fresh_registry() -> ProviderRegistry { - ProviderRegistry { inner: Mutex::new(HashMap::new()) } + ProviderRegistry { + inner: Mutex::new(HashMap::new()), + } } #[test] @@ -216,7 +248,7 @@ mod tests { fn register_replaces_existing() { let reg = fresh_registry(); reg.register("stub", Box::new(StubProvider)); - reg.register("stub", Box::new(StubProvider)); // replace + reg.register("stub", Box::new(StubProvider)); // replace assert_eq!(reg.list().len(), 1); } @@ -227,7 +259,13 @@ mod tests { let provider = reg.get("stub").unwrap(); let plaintext = b"hello world"; let ct = provider - .encrypt_aead(AeadAlgorithm::AesGcm256, &[0u8; 32], &[0u8; 12], plaintext, b"") + .encrypt_aead( + AeadAlgorithm::AesGcm256, + &[0u8; 32], + &[0u8; 12], + plaintext, + b"", + ) .unwrap(); let pt = provider .decrypt_aead(AeadAlgorithm::AesGcm256, &[0u8; 32], &[0u8; 12], &ct, b"") diff --git a/crates/ccc-crypto-wolfssl/build.rs b/crates/ccc-crypto-wolfssl/build.rs index 1ceff80..3548153 100644 --- a/crates/ccc-crypto-wolfssl/build.rs +++ b/crates/ccc-crypto-wolfssl/build.rs @@ -14,7 +14,10 @@ //! a pre-installed wolfSSL at this path. The path must contain //! `include/wolfssl/` and `lib/libwolfssl.a`. -use std::{env, path::{Path, PathBuf}}; +use std::{ + env, + path::{Path, PathBuf}, +}; fn main() { // When the `stub_ffi` feature is enabled (e.g. for type-checking without @@ -34,29 +37,31 @@ fn main() { // ── 1. Locate wolfSSL ──────────────────────────────────────────────────── - let (include_dir, lib_dir) = - if let Ok(install_dir) = env::var("WOLFSSL_INSTALL_DIR") { - // Use a pre-installed wolfSSL — skip the CMake build. - let p = PathBuf::from(&install_dir); - println!("cargo:warning=Using pre-installed wolfSSL at {}", install_dir); - (p.join("include"), p.join("lib")) - } else { - // Build from source (default — uses our git submodule). - let source_dir = env::var("WOLFSSL_SOURCE_DIR") - .map(PathBuf::from) - .unwrap_or_else(|_| workspace_root.join("vendors/wolfssl")); + let (include_dir, lib_dir) = if let Ok(install_dir) = env::var("WOLFSSL_INSTALL_DIR") { + // Use a pre-installed wolfSSL — skip the CMake build. + let p = PathBuf::from(&install_dir); + println!( + "cargo:warning=Using pre-installed wolfSSL at {}", + install_dir + ); + (p.join("include"), p.join("lib")) + } else { + // Build from source (default — uses our git submodule). + let source_dir = env::var("WOLFSSL_SOURCE_DIR") + .map(PathBuf::from) + .unwrap_or_else(|_| workspace_root.join("vendors/wolfssl")); - if !source_dir.join("CMakeLists.txt").exists() { - panic!( - "\n\nwolfSSL source not found at {}.\n\ + if !source_dir.join("CMakeLists.txt").exists() { + panic!( + "\n\nwolfSSL source not found at {}.\n\ Run `git submodule update --init --recursive` to fetch it,\n\ or set WOLFSSL_SOURCE_DIR to an alternative path.\n", - source_dir.display() - ); - } + source_dir.display() + ); + } - build_wolfssl_cmake(&source_dir, &out_dir) - }; + build_wolfssl_cmake(&source_dir, &out_dir) + }; // ── 2. Tell Cargo how to link ──────────────────────────────────────────── @@ -153,15 +158,15 @@ fn build_wolfssl_cmake(source_dir: &Path, _out_dir: &Path) -> (PathBuf, PathBuf) .cflag("-DWOLFCRYPT_ONLY") // Key & certificate generation. // Adds X.509 cert/CSR/key generation capability on top of wolfCrypt. - .define("WOLFSSL_KEYGEN", "yes") // -DWOLFSSL_KEY_GEN - .define("WOLFSSL_CERTGEN", "yes") // -DWOLFSSL_CERT_GEN - .define("WOLFSSL_CERTREQ", "yes") // -DWOLFSSL_CERT_REQ - .define("WOLFSSL_CERTEXT", "yes"); // -DWOLFSSL_CERT_EXT + .define("WOLFSSL_KEYGEN", "yes") // -DWOLFSSL_KEY_GEN + .define("WOLFSSL_CERTGEN", "yes") // -DWOLFSSL_CERT_GEN + .define("WOLFSSL_CERTREQ", "yes") // -DWOLFSSL_CERT_REQ + .define("WOLFSSL_CERTEXT", "yes"); // -DWOLFSSL_CERT_EXT let install_path = cfg.build(); let include_dir = install_path.join("include"); - let lib_dir = install_path.join("lib"); + let lib_dir = install_path.join("lib"); (include_dir, lib_dir) } @@ -302,7 +307,7 @@ fn generate_bindings(include_dir: &Path, out_dir: &Path) { .allowlist_type("WC_RNG") .allowlist_type("OS_Seed") .allowlist_type("wc_Sha256") - .allowlist_type("wc_Sha512") // also used as wc_Sha384 (typedef) + .allowlist_type("wc_Sha512") // also used as wc_Sha384 (typedef) .allowlist_type("wc_Sha3") .allowlist_type("Blake2b") .allowlist_type("curve25519_key") diff --git a/crates/ccc-crypto-wolfssl/src/aead.rs b/crates/ccc-crypto-wolfssl/src/aead.rs index 0f853ed..aea4afc 100644 --- a/crates/ccc-crypto-wolfssl/src/aead.rs +++ b/crates/ccc-crypto-wolfssl/src/aead.rs @@ -26,11 +26,10 @@ pub fn encrypt( ) -> Result, CryptoError> { validate_key_nonce(algo, key, nonce)?; match algo { - AeadAlgorithm::AesGcm256 => aes_gcm_256_encrypt(key, nonce, plaintext, aad), - AeadAlgorithm::ChaCha20Poly1305 => chacha20_poly1305_encrypt(key, nonce, plaintext, aad), + AeadAlgorithm::AesGcm256 => aes_gcm_256_encrypt(key, nonce, plaintext, aad), + AeadAlgorithm::ChaCha20Poly1305 => chacha20_poly1305_encrypt(key, nonce, plaintext, aad), AeadAlgorithm::XChaCha20Poly1305 => xchacha20_poly1305_encrypt(key, nonce, plaintext, aad), - AeadAlgorithm::Ascon128a => - Err(CryptoError::FeatureNotCompiled("Ascon-128a".into())), + AeadAlgorithm::Ascon128a => Err(CryptoError::FeatureNotCompiled("Ascon-128a".into())), } } @@ -47,11 +46,14 @@ pub fn decrypt( ) -> Result, CryptoError> { validate_key_nonce(algo, key, nonce)?; match algo { - AeadAlgorithm::AesGcm256 => aes_gcm_256_decrypt(key, nonce, ciphertext_and_tag, aad), - AeadAlgorithm::ChaCha20Poly1305 => chacha20_poly1305_decrypt(key, nonce, ciphertext_and_tag, aad), - AeadAlgorithm::XChaCha20Poly1305 => xchacha20_poly1305_decrypt(key, nonce, ciphertext_and_tag, aad), - AeadAlgorithm::Ascon128a => - Err(CryptoError::FeatureNotCompiled("Ascon-128a".into())), + AeadAlgorithm::AesGcm256 => aes_gcm_256_decrypt(key, nonce, ciphertext_and_tag, aad), + AeadAlgorithm::ChaCha20Poly1305 => { + chacha20_poly1305_decrypt(key, nonce, ciphertext_and_tag, aad) + } + AeadAlgorithm::XChaCha20Poly1305 => { + xchacha20_poly1305_decrypt(key, nonce, ciphertext_and_tag, aad) + } + AeadAlgorithm::Ascon128a => Err(CryptoError::FeatureNotCompiled("Ascon-128a".into())), } } @@ -60,18 +62,22 @@ pub fn decrypt( // ────────────────────────────────────────────────────────────────────────────── fn validate_key_nonce(algo: AeadAlgorithm, key: &[u8], nonce: &[u8]) -> Result<(), CryptoError> { - let expected_key = algo.key_len(); + let expected_key = algo.key_len(); let expected_nonce = algo.nonce_len(); if key.len() != expected_key { return Err(CryptoError::InvalidKey(format!( "{}: expected {}-byte key, got {}", - algo.name(), expected_key, key.len() + algo.name(), + expected_key, + key.len() ))); } if nonce.len() != expected_nonce { return Err(CryptoError::InvalidNonce(format!( "{}: expected {}-byte nonce, got {}", - algo.name(), expected_nonce, nonce.len() + algo.name(), + expected_nonce, + nonce.len() ))); } Ok(()) @@ -85,7 +91,7 @@ const TAG_LEN: usize = 16; fn aes_gcm_256_encrypt( key: &[u8], - nonce: &[u8], // 12 bytes + nonce: &[u8], // 12 bytes plaintext: &[u8], aad: &[u8], ) -> Result, CryptoError> { @@ -98,11 +104,8 @@ fn aes_gcm_256_encrypt( use std::alloc::{alloc_zeroed, dealloc, Layout}; // sizeof(Aes) = 288 bytes; alignment = 16. - let layout = Layout::from_size_align( - std::mem::size_of::().max(288), - 16, - ) - .expect("layout must be valid"); + let layout = Layout::from_size_align(std::mem::size_of::().max(288), 16) + .expect("layout must be valid"); let aes_ptr = alloc_zeroed(layout) as *mut crate::sys::Aes; if aes_ptr.is_null() { @@ -116,18 +119,20 @@ fn aes_gcm_256_encrypt( ); if ret != 0 { dealloc(aes_ptr as *mut u8, layout); - return Err(CryptoError::InternalError(format!("wc_AesInit returned {}", ret))); + return Err(CryptoError::InternalError(format!( + "wc_AesInit returned {}", + ret + ))); } - let ret = crate::sys::wc_AesGcmSetKey( - aes_ptr, - key.as_ptr(), - key.len() as u32, - ); + let ret = crate::sys::wc_AesGcmSetKey(aes_ptr, key.as_ptr(), key.len() as u32); if ret != 0 { crate::sys::wc_AesFree(aes_ptr); dealloc(aes_ptr as *mut u8, layout); - return Err(CryptoError::InvalidKey(format!("wc_AesGcmSetKey returned {}", ret))); + return Err(CryptoError::InvalidKey(format!( + "wc_AesGcmSetKey returned {}", + ret + ))); } let ret = crate::sys::wc_AesGcmEncrypt( @@ -139,13 +144,20 @@ fn aes_gcm_256_encrypt( nonce.len() as u32, tag_buf.as_mut_ptr(), TAG_LEN as u32, - if aad.is_empty() { std::ptr::null() } else { aad.as_ptr() }, + if aad.is_empty() { + std::ptr::null() + } else { + aad.as_ptr() + }, aad.len() as u32, ); crate::sys::wc_AesFree(aes_ptr); dealloc(aes_ptr as *mut u8, layout); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_AesGcmEncrypt returned {}", ret))); + return Err(CryptoError::InternalError(format!( + "wc_AesGcmEncrypt returned {}", + ret + ))); } } @@ -160,7 +172,7 @@ fn aes_gcm_256_decrypt( ) -> Result, CryptoError> { if ciphertext_and_tag.len() < TAG_LEN { return Err(CryptoError::InvalidInput( - "AES-256-GCM: ciphertext too short (no room for tag)".into() + "AES-256-GCM: ciphertext too short (no room for tag)".into(), )); } let ct_len = ciphertext_and_tag.len() - TAG_LEN; @@ -172,11 +184,8 @@ fn aes_gcm_256_decrypt( // alignment so the C code's SIMD operations work correctly on ARM64. use std::alloc::{alloc_zeroed, dealloc, Layout}; - let layout = Layout::from_size_align( - std::mem::size_of::().max(288), - 16, - ) - .expect("layout must be valid"); + let layout = Layout::from_size_align(std::mem::size_of::().max(288), 16) + .expect("layout must be valid"); let aes_ptr = alloc_zeroed(layout) as *mut crate::sys::Aes; if aes_ptr.is_null() { @@ -190,18 +199,20 @@ fn aes_gcm_256_decrypt( ); if ret != 0 { dealloc(aes_ptr as *mut u8, layout); - return Err(CryptoError::InternalError(format!("wc_AesInit returned {}", ret))); + return Err(CryptoError::InternalError(format!( + "wc_AesInit returned {}", + ret + ))); } - let ret = crate::sys::wc_AesGcmSetKey( - aes_ptr, - key.as_ptr(), - key.len() as u32, - ); + let ret = crate::sys::wc_AesGcmSetKey(aes_ptr, key.as_ptr(), key.len() as u32); if ret != 0 { crate::sys::wc_AesFree(aes_ptr); dealloc(aes_ptr as *mut u8, layout); - return Err(CryptoError::InvalidKey(format!("wc_AesGcmSetKey returned {}", ret))); + return Err(CryptoError::InvalidKey(format!( + "wc_AesGcmSetKey returned {}", + ret + ))); } let ret = crate::sys::wc_AesGcmDecrypt( @@ -213,7 +224,11 @@ fn aes_gcm_256_decrypt( nonce.len() as u32, tag.as_ptr(), TAG_LEN as u32, - if aad.is_empty() { std::ptr::null() } else { aad.as_ptr() }, + if aad.is_empty() { + std::ptr::null() + } else { + aad.as_ptr() + }, aad.len() as u32, ); crate::sys::wc_AesFree(aes_ptr); @@ -233,7 +248,7 @@ fn aes_gcm_256_decrypt( fn chacha20_poly1305_encrypt( key: &[u8], - nonce: &[u8], // 12 bytes + nonce: &[u8], // 12 bytes plaintext: &[u8], aad: &[u8], ) -> Result, CryptoError> { @@ -245,7 +260,11 @@ fn chacha20_poly1305_encrypt( let ret = crate::sys::wc_ChaCha20Poly1305_Encrypt( key.as_ptr(), nonce.as_ptr(), - if aad.is_empty() { std::ptr::null() } else { aad.as_ptr() }, + if aad.is_empty() { + std::ptr::null() + } else { + aad.as_ptr() + }, aad.len() as u32, plaintext.as_ptr(), plaintext.len() as u32, @@ -253,9 +272,10 @@ fn chacha20_poly1305_encrypt( tag_buf.as_mut_ptr(), ); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_ChaCha20Poly1305_Encrypt returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_ChaCha20Poly1305_Encrypt returned {}", + ret + ))); } } @@ -270,7 +290,7 @@ fn chacha20_poly1305_decrypt( ) -> Result, CryptoError> { if ciphertext_and_tag.len() < TAG_LEN { return Err(CryptoError::InvalidInput( - "ChaCha20-Poly1305: ciphertext too short".into() + "ChaCha20-Poly1305: ciphertext too short".into(), )); } let ct_len = ciphertext_and_tag.len() - TAG_LEN; @@ -282,7 +302,11 @@ fn chacha20_poly1305_decrypt( let ret = crate::sys::wc_ChaCha20Poly1305_Decrypt( key.as_ptr(), nonce.as_ptr(), - if aad.is_empty() { std::ptr::null() } else { aad.as_ptr() }, + if aad.is_empty() { + std::ptr::null() + } else { + aad.as_ptr() + }, aad.len() as u32, ciphertext.as_ptr(), ct_len as u32, @@ -310,7 +334,7 @@ fn chacha20_poly1305_decrypt( fn xchacha20_poly1305_encrypt( key: &[u8], - nonce: &[u8], // 24 bytes + nonce: &[u8], // 24 bytes plaintext: &[u8], aad: &[u8], ) -> Result, CryptoError> { @@ -325,7 +349,11 @@ fn xchacha20_poly1305_encrypt( dst.len(), plaintext.as_ptr(), plaintext.len(), - if aad.is_empty() { std::ptr::null() } else { aad.as_ptr() }, + if aad.is_empty() { + std::ptr::null() + } else { + aad.as_ptr() + }, aad.len(), nonce.as_ptr(), nonce.len(), @@ -333,9 +361,10 @@ fn xchacha20_poly1305_encrypt( key.len(), ); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_XChaCha20Poly1305_Encrypt returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_XChaCha20Poly1305_Encrypt returned {}", + ret + ))); } } @@ -344,13 +373,13 @@ fn xchacha20_poly1305_encrypt( fn xchacha20_poly1305_decrypt( key: &[u8], - nonce: &[u8], // 24 bytes + nonce: &[u8], // 24 bytes ciphertext_and_tag: &[u8], aad: &[u8], ) -> Result, CryptoError> { if ciphertext_and_tag.len() < TAG_LEN { return Err(CryptoError::InvalidInput( - "XChaCha20-Poly1305: ciphertext too short".into() + "XChaCha20-Poly1305: ciphertext too short".into(), )); } let pt_len = ciphertext_and_tag.len() - TAG_LEN; @@ -364,7 +393,11 @@ fn xchacha20_poly1305_decrypt( dst.len(), ciphertext_and_tag.as_ptr(), ciphertext_and_tag.len(), - if aad.is_empty() { std::ptr::null() } else { aad.as_ptr() }, + if aad.is_empty() { + std::ptr::null() + } else { + aad.as_ptr() + }, aad.len(), nonce.as_ptr(), nonce.len(), diff --git a/crates/ccc-crypto-wolfssl/src/capabilities.rs b/crates/ccc-crypto-wolfssl/src/capabilities.rs index f2b9ed0..1a21bf2 100644 --- a/crates/ccc-crypto-wolfssl/src/capabilities.rs +++ b/crates/ccc-crypto-wolfssl/src/capabilities.rs @@ -43,12 +43,15 @@ pub fn probe_capabilities(benchmarks: Option<&BenchmarkReport>) -> ProviderCapab .map(|r| r.efficiency_score) .unwrap_or(0); - caps = caps.with_aead(algo, AlgorithmCapability { - available, - deterministic_io: true, // wolfSSL output is deterministic for same key/nonce - efficiency_score: efficiency, - reliability_score: if available { 100 } else { 0 }, - }); + caps = caps.with_aead( + algo, + AlgorithmCapability { + available, + deterministic_io: true, // wolfSSL output is deterministic for same key/nonce + efficiency_score: efficiency, + reliability_score: if available { 100 } else { 0 }, + }, + ); } // Ascon-128a is not in this wolfSSL build. @@ -57,72 +60,105 @@ pub fn probe_capabilities(benchmarks: Option<&BenchmarkReport>) -> ProviderCapab // ── KDF ────────────────────────────────────────────────────────────────── for algo in [KdfAlgorithm::Sha256, KdfAlgorithm::Sha384, KdfAlgorithm::Sha512] { let available = crate::kdf::derive_key(algo, b"key", b"salt", b"info", 32).is_ok(); - caps = caps.with_kdf(algo, AlgorithmCapability { - available, - deterministic_io: true, - efficiency_score: 80, // HKDF is fast; benchmark not run for KDF - reliability_score: if available { 100 } else { 0 }, - }); + caps = caps.with_kdf( + algo, + AlgorithmCapability { + available, + deterministic_io: true, + efficiency_score: 80, // HKDF is fast; benchmark not run for KDF + reliability_score: if available { 100 } else { 0 }, + }, + ); } for algo in [KdfAlgorithm::Blake2b512, KdfAlgorithm::Argon2id] { - let salt: &[u8] = if algo == KdfAlgorithm::Argon2id { b"saltsalt" } else { b"" }; + let salt: &[u8] = if algo == KdfAlgorithm::Argon2id { + b"saltsalt" + } else { + b"" + }; let available = crate::kdf::derive_key(algo, b"key", salt, b"", 32).is_ok(); - caps = caps.with_kdf(algo, AlgorithmCapability { - available, - deterministic_io: true, - efficiency_score: if algo == KdfAlgorithm::Argon2id { 10 } else { 70 }, - reliability_score: if available { 100 } else { 0 }, - }); + caps = caps.with_kdf( + algo, + AlgorithmCapability { + available, + deterministic_io: true, + efficiency_score: if algo == KdfAlgorithm::Argon2id { + 10 + } else { + 70 + }, + reliability_score: if available { 100 } else { 0 }, + }, + ); } caps = caps.with_kdf(KdfAlgorithm::Kmac256, AlgorithmCapability::unavailable()); // ── MAC ────────────────────────────────────────────────────────────────── for algo in [MacAlgorithm::HmacSha256, MacAlgorithm::HmacSha384, MacAlgorithm::HmacSha512] { let available = crate::mac::compute_mac(algo, b"key", b"data").is_ok(); - caps = caps.with_mac(algo, AlgorithmCapability { - available, - deterministic_io: true, - efficiency_score: 85, - reliability_score: if available { 100 } else { 0 }, - }); + caps = caps.with_mac( + algo, + AlgorithmCapability { + available, + deterministic_io: true, + efficiency_score: 85, + reliability_score: if available { 100 } else { 0 }, + }, + ); } { - let available = crate::mac::compute_mac(MacAlgorithm::Blake2bMac, b"key-that-is-16-by", b"data").is_ok(); - caps = caps.with_mac(MacAlgorithm::Blake2bMac, AlgorithmCapability { - available, - deterministic_io: true, - efficiency_score: 90, - reliability_score: if available { 100 } else { 0 }, - }); + let available = + crate::mac::compute_mac(MacAlgorithm::Blake2bMac, b"key-that-is-16-by", b"data") + .is_ok(); + caps = caps.with_mac( + MacAlgorithm::Blake2bMac, + AlgorithmCapability { + available, + deterministic_io: true, + efficiency_score: 90, + reliability_score: if available { 100 } else { 0 }, + }, + ); } caps = caps.with_mac(MacAlgorithm::Poly1305, AlgorithmCapability::unavailable()); // ── Hash ───────────────────────────────────────────────────────────────── for algo in [ - HashAlgorithm::Sha256, HashAlgorithm::Sha384, HashAlgorithm::Sha512, - HashAlgorithm::Blake2b512, HashAlgorithm::Sha3_256, HashAlgorithm::Sha3_512, + HashAlgorithm::Sha256, + HashAlgorithm::Sha384, + HashAlgorithm::Sha512, + HashAlgorithm::Blake2b512, + HashAlgorithm::Sha3_256, + HashAlgorithm::Sha3_512, ] { let available = crate::hash::hash(algo, b"probe").is_ok(); - caps = caps.with_hash(algo, AlgorithmCapability { - available, - deterministic_io: true, - efficiency_score: 90, - reliability_score: if available { 100 } else { 0 }, - }); + caps = caps.with_hash( + algo, + AlgorithmCapability { + available, + deterministic_io: true, + efficiency_score: 90, + reliability_score: if available { 100 } else { 0 }, + }, + ); } // ── KEM ────────────────────────────────────────────────────────────────── for algo in [KemAlgorithm::X25519, KemAlgorithm::X448] { let available = crate::kem::generate_keypair(algo).is_ok(); - caps = caps.with_kem(algo, AlgorithmCapability { - available, - deterministic_io: false, // key generation is randomised - efficiency_score: 80, - reliability_score: if available { 100 } else { 0 }, - }); + caps = caps.with_kem( + algo, + AlgorithmCapability { + available, + deterministic_io: false, // key generation is randomised + efficiency_score: 80, + reliability_score: if available { 100 } else { 0 }, + }, + ); } for algo in [ - KemAlgorithm::MlKem768, KemAlgorithm::MlKem1024, + KemAlgorithm::MlKem768, + KemAlgorithm::MlKem1024, KemAlgorithm::ClassicMcEliece460896, ] { caps = caps.with_kem(algo, AlgorithmCapability::unavailable()); @@ -153,7 +189,7 @@ pub fn run_benchmark() -> BenchmarkReport { let mut raw_results: Vec<(AeadAlgorithm, f64)> = Vec::new(); for algo in algos { - let key = vec![0u8; algo.key_len()]; + let key = vec![0u8; algo.key_len()]; let nonce = vec![0u8; algo.nonce_len()]; // Probe first; skip unavailable algorithms. diff --git a/crates/ccc-crypto-wolfssl/src/hash.rs b/crates/ccc-crypto-wolfssl/src/hash.rs index 59b346c..52cf1e6 100644 --- a/crates/ccc-crypto-wolfssl/src/hash.rs +++ b/crates/ccc-crypto-wolfssl/src/hash.rs @@ -14,12 +14,12 @@ use ccc_crypto_core::{algorithms::HashAlgorithm, error::CryptoError}; /// [`HashAlgorithm::digest_len`] for output lengths). pub fn hash(algo: HashAlgorithm, data: &[u8]) -> Result, CryptoError> { match algo { - HashAlgorithm::Sha256 => sha256(data), - HashAlgorithm::Sha384 => sha384(data), - HashAlgorithm::Sha512 => sha512(data), + HashAlgorithm::Sha256 => sha256(data), + HashAlgorithm::Sha384 => sha384(data), + HashAlgorithm::Sha512 => sha512(data), HashAlgorithm::Blake2b512 => blake2b_512(data), - HashAlgorithm::Sha3_256 => sha3_256(data), - HashAlgorithm::Sha3_512 => sha3_512(data), + HashAlgorithm::Sha3_256 => sha3_256(data), + HashAlgorithm::Sha3_512 => sha3_512(data), } } @@ -42,11 +42,9 @@ fn sha256(data: &[u8]) -> Result, CryptoError> { use std::alloc::{alloc_zeroed, dealloc, Layout}; // Size reported by C's sizeof(wc_Sha256) = 120 bytes; alignment = 16. - let layout = Layout::from_size_align( - std::mem::size_of::().max(120), - 16, - ) - .expect("layout must be valid"); + let layout = + Layout::from_size_align(std::mem::size_of::().max(120), 16) + .expect("layout must be valid"); let sha_ptr = alloc_zeroed(layout) as *mut crate::sys::wc_Sha256; if sha_ptr.is_null() { @@ -56,23 +54,33 @@ fn sha256(data: &[u8]) -> Result, CryptoError> { let ret = crate::sys::wc_InitSha256(sha_ptr); if ret != 0 { dealloc(sha_ptr as *mut u8, layout); - return Err(CryptoError::InternalError(format!("wc_InitSha256 returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_InitSha256 returned {ret}" + ))); } let ret = crate::sys::wc_Sha256Update( sha_ptr, - if data.is_empty() { std::ptr::null() } else { data.as_ptr() }, + if data.is_empty() { + std::ptr::null() + } else { + data.as_ptr() + }, data.len() as u32, ); if ret != 0 { crate::sys::wc_Sha256Free(sha_ptr); dealloc(sha_ptr as *mut u8, layout); - return Err(CryptoError::InternalError(format!("wc_Sha256Update returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha256Update returned {ret}" + ))); } let ret = crate::sys::wc_Sha256Final(sha_ptr, out.as_mut_ptr()); crate::sys::wc_Sha256Free(sha_ptr); dealloc(sha_ptr as *mut u8, layout); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_Sha256Final returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha256Final returned {ret}" + ))); } } Ok(out) @@ -85,17 +93,23 @@ fn sha384(data: &[u8]) -> Result, CryptoError> { let mut sha: crate::sys::wc_Sha512 = std::mem::zeroed(); let ret = crate::sys::wc_InitSha384(&mut sha); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_InitSha384 returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_InitSha384 returned {ret}" + ))); } let ret = crate::sys::wc_Sha384Update(&mut sha, data.as_ptr(), data.len() as u32); if ret != 0 { crate::sys::wc_Sha384Free(&mut sha); - return Err(CryptoError::InternalError(format!("wc_Sha384Update returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha384Update returned {ret}" + ))); } let ret = crate::sys::wc_Sha384Final(&mut sha, out.as_mut_ptr()); crate::sys::wc_Sha384Free(&mut sha); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_Sha384Final returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha384Final returned {ret}" + ))); } } Ok(out) @@ -107,17 +121,23 @@ fn sha512(data: &[u8]) -> Result, CryptoError> { let mut sha: crate::sys::wc_Sha512 = std::mem::zeroed(); let ret = crate::sys::wc_InitSha512(&mut sha); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_InitSha512 returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_InitSha512 returned {ret}" + ))); } let ret = crate::sys::wc_Sha512Update(&mut sha, data.as_ptr(), data.len() as u32); if ret != 0 { crate::sys::wc_Sha512Free(&mut sha); - return Err(CryptoError::InternalError(format!("wc_Sha512Update returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha512Update returned {ret}" + ))); } let ret = crate::sys::wc_Sha512Final(&mut sha, out.as_mut_ptr()); crate::sys::wc_Sha512Free(&mut sha); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_Sha512Final returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha512Final returned {ret}" + ))); } } Ok(out) @@ -135,17 +155,23 @@ fn sha3_256(data: &[u8]) -> Result, CryptoError> { let mut sha: crate::sys::wc_Sha3 = std::mem::zeroed(); let ret = crate::sys::wc_InitSha3_256(&mut sha, std::ptr::null_mut(), -2); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_InitSha3_256 returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_InitSha3_256 returned {ret}" + ))); } let ret = crate::sys::wc_Sha3_256_Update(&mut sha, data.as_ptr(), data.len() as u32); if ret != 0 { crate::sys::wc_Sha3_256_Free(&mut sha); - return Err(CryptoError::InternalError(format!("wc_Sha3_256_Update returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha3_256_Update returned {ret}" + ))); } let ret = crate::sys::wc_Sha3_256_Final(&mut sha, out.as_mut_ptr()); crate::sys::wc_Sha3_256_Free(&mut sha); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_Sha3_256_Final returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha3_256_Final returned {ret}" + ))); } } Ok(out) @@ -157,17 +183,23 @@ fn sha3_512(data: &[u8]) -> Result, CryptoError> { let mut sha: crate::sys::wc_Sha3 = std::mem::zeroed(); let ret = crate::sys::wc_InitSha3_512(&mut sha, std::ptr::null_mut(), -2); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_InitSha3_512 returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_InitSha3_512 returned {ret}" + ))); } let ret = crate::sys::wc_Sha3_512_Update(&mut sha, data.as_ptr(), data.len() as u32); if ret != 0 { crate::sys::wc_Sha3_512_Free(&mut sha); - return Err(CryptoError::InternalError(format!("wc_Sha3_512_Update returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha3_512_Update returned {ret}" + ))); } let ret = crate::sys::wc_Sha3_512_Final(&mut sha, out.as_mut_ptr()); crate::sys::wc_Sha3_512_Free(&mut sha); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_Sha3_512_Final returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Sha3_512_Final returned {ret}" + ))); } } Ok(out) @@ -187,16 +219,22 @@ pub fn blake2b_512(data: &[u8]) -> Result, CryptoError> { let mut b2b: crate::sys::Blake2b = std::mem::zeroed(); let ret = crate::sys::wc_InitBlake2b(&mut b2b, OUT_LEN); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_InitBlake2b returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_InitBlake2b returned {ret}" + ))); } let ret = crate::sys::wc_Blake2bUpdate(&mut b2b, data.as_ptr(), data.len() as u32); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_Blake2bUpdate returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Blake2bUpdate returned {ret}" + ))); } // requestSz = OUT_LEN → produce the full 64-byte digest. let ret = crate::sys::wc_Blake2bFinal(&mut b2b, out.as_mut_ptr(), OUT_LEN); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_Blake2bFinal returned {ret}"))); + return Err(CryptoError::InternalError(format!( + "wc_Blake2bFinal returned {ret}" + ))); } } Ok(out) diff --git a/crates/ccc-crypto-wolfssl/src/kdf.rs b/crates/ccc-crypto-wolfssl/src/kdf.rs index 93accc9..d12f29c 100644 --- a/crates/ccc-crypto-wolfssl/src/kdf.rs +++ b/crates/ccc-crypto-wolfssl/src/kdf.rs @@ -54,8 +54,7 @@ pub fn derive_key( KdfAlgorithm::Sha512 => hkdf(WC_HASH_TYPE_SHA512, ikm, salt, info, length), KdfAlgorithm::Blake2b512 => blake2b_kdf(ikm, salt, info, length), KdfAlgorithm::Argon2id => argon2id(ikm, salt, length), - KdfAlgorithm::Kmac256 => - Err(CryptoError::FeatureNotCompiled("KMAC256 (Phase 5+)".into())), + KdfAlgorithm::Kmac256 => Err(CryptoError::FeatureNotCompiled("KMAC256 (Phase 5+)".into())), } } @@ -103,16 +102,20 @@ fn hkdf_extract( unsafe { let ret = crate::sys::wc_Tls13_HKDF_Extract( prk.as_mut_ptr(), - if salt.is_empty() { std::ptr::null() } else { salt.as_ptr() }, + if salt.is_empty() { + std::ptr::null() + } else { + salt.as_ptr() + }, salt.len() as u32, ikm_buf.as_mut_ptr(), ikm_buf.len() as u32, hash_type, ); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_Tls13_HKDF_Extract returned {ret}") - )); + return Err(CryptoError::InternalError(format!( + "wc_Tls13_HKDF_Extract returned {ret}" + ))); } } Ok(prk) @@ -133,14 +136,14 @@ fn hkdf_expand( // Maximum HKDF output is 255 * HashLen (RFC 5869 §2.3). let max_len = 255 * hash_len; if length > max_len { - return Err(CryptoError::InvalidInput( - format!("HKDF: requested length {length} exceeds maximum {max_len}") - )); + return Err(CryptoError::InvalidInput(format!( + "HKDF: requested length {length} exceeds maximum {max_len}" + ))); } - let mut okm = Zeroizing::new(vec![0u8; length]); - let mut t = Vec::new(); // T(i-1); starts empty per spec - let mut pos = 0usize; + let mut okm = Zeroizing::new(vec![0u8; length]); + let mut t = Vec::new(); // T(i-1); starts empty per spec + let mut pos = 0usize; let mut counter = 1u8; while pos < length { @@ -156,9 +159,9 @@ fn hkdf_expand( let copy_len = (length - pos).min(hash_len); okm[pos..pos + copy_len].copy_from_slice(&t[..copy_len]); pos += copy_len; - counter = counter.checked_add(1).ok_or_else(|| { - CryptoError::InternalError("HKDF counter overflow".into()) - })?; + counter = counter + .checked_add(1) + .ok_or_else(|| CryptoError::InternalError("HKDF counter overflow".into()))?; } Ok(okm) @@ -194,7 +197,7 @@ fn blake2b_kdf( // callers should use HKDF-SHA512 instead. if length > digest.len() { return Err(CryptoError::InvalidInput( - "BLAKE2b-512 KDF: requested length exceeds 64 bytes; use HKDF-SHA512".into() + "BLAKE2b-512 KDF: requested length exceeds 64 bytes; use HKDF-SHA512".into(), )); } @@ -221,7 +224,7 @@ fn argon2id( // Argon2 requires at least 8 bytes of salt. if salt.len() < 8 { return Err(CryptoError::InvalidInput( - "Argon2id requires at least 8-byte salt".into() + "Argon2id requires at least 8-byte salt".into(), )); } @@ -232,10 +235,10 @@ fn argon2id( // argon2_iterations: 3 // argon2_parallelism: 4 let params = Params::new( - 65_536, // m_cost: 64 MiB - 3, // t_cost: iterations - 4, // p_cost: parallelism (lanes) - Some(length), // output length + 65_536, // m_cost: 64 MiB + 3, // t_cost: iterations + 4, // p_cost: parallelism (lanes) + Some(length), // output length ) .map_err(|e| CryptoError::InternalError(format!("Argon2 params error: {e}")))?; diff --git a/crates/ccc-crypto-wolfssl/src/kem.rs b/crates/ccc-crypto-wolfssl/src/kem.rs index 2b6e777..c544cef 100644 --- a/crates/ccc-crypto-wolfssl/src/kem.rs +++ b/crates/ccc-crypto-wolfssl/src/kem.rs @@ -20,15 +20,13 @@ use ccc_crypto_core::{ pub fn generate_keypair(algo: KemAlgorithm) -> Result { match algo { KemAlgorithm::X25519 => x25519_generate(), - KemAlgorithm::X448 => x448_generate(), - KemAlgorithm::MlKem768 | KemAlgorithm::MlKem1024 => - Err(CryptoError::FeatureNotCompiled( - "ML-KEM is deferred to Phase 5 (requires wolfSSL PQ build)".into() - )), - KemAlgorithm::ClassicMcEliece460896 => - Err(CryptoError::FeatureNotCompiled( - "Classic-McEliece is deferred to Phase 5".into() - )), + KemAlgorithm::X448 => x448_generate(), + KemAlgorithm::MlKem768 | KemAlgorithm::MlKem1024 => Err(CryptoError::FeatureNotCompiled( + "ML-KEM is deferred to Phase 5 (requires wolfSSL PQ build)".into(), + )), + KemAlgorithm::ClassicMcEliece460896 => Err(CryptoError::FeatureNotCompiled( + "Classic-McEliece is deferred to Phase 5".into(), + )), } } @@ -44,15 +42,13 @@ pub fn encapsulate( ) -> Result { match algo { KemAlgorithm::X25519 => x25519_encapsulate(recipient_public_key), - KemAlgorithm::X448 => x448_encapsulate(recipient_public_key), - KemAlgorithm::MlKem768 | KemAlgorithm::MlKem1024 => - Err(CryptoError::FeatureNotCompiled( - "ML-KEM is deferred to Phase 5".into() - )), - KemAlgorithm::ClassicMcEliece460896 => - Err(CryptoError::FeatureNotCompiled( - "Classic-McEliece is deferred to Phase 5".into() - )), + KemAlgorithm::X448 => x448_encapsulate(recipient_public_key), + KemAlgorithm::MlKem768 | KemAlgorithm::MlKem1024 => Err(CryptoError::FeatureNotCompiled( + "ML-KEM is deferred to Phase 5".into(), + )), + KemAlgorithm::ClassicMcEliece460896 => Err(CryptoError::FeatureNotCompiled( + "Classic-McEliece is deferred to Phase 5".into(), + )), } } @@ -65,15 +61,13 @@ pub fn decapsulate( ) -> Result>, CryptoError> { match algo { KemAlgorithm::X25519 => x25519_decapsulate(private_key, peer_ephemeral_public_key), - KemAlgorithm::X448 => x448_decapsulate(private_key, peer_ephemeral_public_key), - KemAlgorithm::MlKem768 | KemAlgorithm::MlKem1024 => - Err(CryptoError::FeatureNotCompiled( - "ML-KEM is deferred to Phase 5".into() - )), - KemAlgorithm::ClassicMcEliece460896 => - Err(CryptoError::FeatureNotCompiled( - "Classic-McEliece is deferred to Phase 5".into() - )), + KemAlgorithm::X448 => x448_decapsulate(private_key, peer_ephemeral_public_key), + KemAlgorithm::MlKem768 | KemAlgorithm::MlKem1024 => Err(CryptoError::FeatureNotCompiled( + "ML-KEM is deferred to Phase 5".into(), + )), + KemAlgorithm::ClassicMcEliece460896 => Err(CryptoError::FeatureNotCompiled( + "Classic-McEliece is deferred to Phase 5".into(), + )), } } @@ -96,41 +90,51 @@ fn x25519_generate() -> Result { let ret = crate::sys::wc_InitRng(&mut rng); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_InitRng returned {}", ret))); + return Err(CryptoError::InternalError(format!( + "wc_InitRng returned {}", + ret + ))); } let ret = crate::sys::wc_curve25519_make_key(&mut rng, 32, &mut key); if ret != 0 { crate::sys::wc_FreeRng(&mut rng); - return Err(CryptoError::InternalError( - format!("wc_curve25519_make_key returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve25519_make_key returned {}", + ret + ))); } - let mut pub_sz = public_key.len() as u32; + let mut pub_sz = public_key.len() as u32; let mut priv_sz = private_key.len() as u32; - // Export in little-endian (EC25519_LITTLE_ENDIAN=0) so all key + // Export in little-endian (EC25519_LITTLE_ENDIAN=0) so all key // material is in RFC 7748 canonical format. let ret = crate::sys::wc_curve25519_export_key_raw_ex( &mut key, - private_key.as_mut_ptr(), &mut priv_sz, - public_key.as_mut_ptr(), &mut pub_sz, + private_key.as_mut_ptr(), + &mut priv_sz, + public_key.as_mut_ptr(), + &mut pub_sz, X25519_LE, ); if ret != 0 { crate::sys::wc_curve25519_free(&mut key); crate::sys::wc_FreeRng(&mut rng); - return Err(CryptoError::InternalError( - format!("wc_curve25519_export_key_raw_ex returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve25519_export_key_raw_ex returned {}", + ret + ))); } crate::sys::wc_curve25519_free(&mut key); crate::sys::wc_FreeRng(&mut rng); } - Ok(KemKeyPair { public_key, private_key }) + Ok(KemKeyPair { + public_key, + private_key, + }) } fn x25519_encapsulate(recipient_pub: &[u8]) -> Result { @@ -140,7 +144,7 @@ fn x25519_encapsulate(recipient_pub: &[u8]) -> Result Result>, CryptoError> { if private_key.len() != 32 || public_key.len() != 32 { return Err(CryptoError::InvalidKey( - "X25519: keys must be 32 bytes each".into() + "X25519: keys must be 32 bytes each".into(), )); } let mut shared = Zeroizing::new(vec![0u8; 32]); unsafe { - let mut local_key: crate::sys::curve25519_key = std::mem::zeroed(); + let mut local_key: crate::sys::curve25519_key = std::mem::zeroed(); let mut remote_key: crate::sys::curve25519_key = std::mem::zeroed(); // Initialise both key structs before use (sets dp, calls fe_init, etc.). let ret = crate::sys::wc_curve25519_init(&mut local_key); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_curve25519_init (local) returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve25519_init (local) returned {}", + ret + ))); } let ret = crate::sys::wc_curve25519_init(&mut remote_key); if ret != 0 { crate::sys::wc_curve25519_free(&mut local_key); - return Err(CryptoError::InternalError( - format!("wc_curve25519_init (remote) returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve25519_init (remote) returned {}", + ret + ))); } // Import private key in little-endian (EC25519_LITTLE_ENDIAN = 0). let ret = crate::sys::wc_curve25519_import_private_ex( - private_key.as_ptr(), 32, + private_key.as_ptr(), + 32, &mut local_key, X25519_LE, ); if ret != 0 { crate::sys::wc_curve25519_free(&mut local_key); crate::sys::wc_curve25519_free(&mut remote_key); - return Err(CryptoError::InvalidKey( - format!("wc_curve25519_import_private_ex returned {}", ret) - )); + return Err(CryptoError::InvalidKey(format!( + "wc_curve25519_import_private_ex returned {}", + ret + ))); } // Import remote public key in little-endian. let ret = crate::sys::wc_curve25519_import_public_ex( - public_key.as_ptr(), 32, + public_key.as_ptr(), + 32, &mut remote_key, X25519_LE, ); if ret != 0 { crate::sys::wc_curve25519_free(&mut local_key); crate::sys::wc_curve25519_free(&mut remote_key); - return Err(CryptoError::InvalidKey( - format!("wc_curve25519_import_public_ex returned {}", ret) - )); + return Err(CryptoError::InvalidKey(format!( + "wc_curve25519_import_public_ex returned {}", + ret + ))); } let mut shared_sz = 32u32; @@ -231,9 +241,10 @@ fn x25519_dh(private_key: &[u8], public_key: &[u8]) -> Result> crate::sys::wc_curve25519_free(&mut remote_key); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_curve25519_shared_secret_ex returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve25519_shared_secret_ex returned {}", + ret + ))); } } @@ -250,56 +261,66 @@ fn x25519_dh(private_key: &[u8], public_key: &[u8]) -> Result> const X448_LE: i32 = 0; fn x448_generate() -> Result { - let mut public_key = vec![0u8; 56]; + let mut public_key = vec![0u8; 56]; let mut private_key = vec![0u8; 56]; unsafe { let mut key: crate::sys::curve448_key = std::mem::zeroed(); - let mut rng: crate::sys::WC_RNG = std::mem::zeroed(); + let mut rng: crate::sys::WC_RNG = std::mem::zeroed(); let ret = crate::sys::wc_InitRng(&mut rng); if ret != 0 { - return Err(CryptoError::InternalError(format!("wc_InitRng returned {}", ret))); + return Err(CryptoError::InternalError(format!( + "wc_InitRng returned {}", + ret + ))); } let ret = crate::sys::wc_curve448_make_key(&mut rng, 56, &mut key); if ret != 0 { crate::sys::wc_FreeRng(&mut rng); - return Err(CryptoError::InternalError( - format!("wc_curve448_make_key returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve448_make_key returned {}", + ret + ))); } - let mut pub_sz = public_key.len() as u32; + let mut pub_sz = public_key.len() as u32; let mut priv_sz = private_key.len() as u32; // Export in little-endian (EC448_LITTLE_ENDIAN=0), RFC 7748 canonical format. let ret = crate::sys::wc_curve448_export_key_raw_ex( &mut key, - private_key.as_mut_ptr(), &mut priv_sz, - public_key.as_mut_ptr(), &mut pub_sz, + private_key.as_mut_ptr(), + &mut priv_sz, + public_key.as_mut_ptr(), + &mut pub_sz, X448_LE, ); if ret != 0 { crate::sys::wc_curve448_free(&mut key); crate::sys::wc_FreeRng(&mut rng); - return Err(CryptoError::InternalError( - format!("wc_curve448_export_key_raw_ex returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve448_export_key_raw_ex returned {}", + ret + ))); } crate::sys::wc_curve448_free(&mut key); crate::sys::wc_FreeRng(&mut rng); } - Ok(KemKeyPair { public_key, private_key }) + Ok(KemKeyPair { + public_key, + private_key, + }) } fn x448_encapsulate(recipient_pub: &[u8]) -> Result { let ephemeral = x448_generate()?; - let shared = x448_dh(&ephemeral.private_key, recipient_pub)?; + let shared = x448_dh(&ephemeral.private_key, recipient_pub)?; Ok(KemEncapResult { - ciphertext: ephemeral.public_key.clone(), + ciphertext: ephemeral.public_key.clone(), shared_secret: (*shared).clone(), }) } @@ -319,52 +340,64 @@ fn x448_decapsulate( /// pattern) before importing keys. fn x448_dh(private_key: &[u8], public_key: &[u8]) -> Result>, CryptoError> { if private_key.len() != 56 || public_key.len() != 56 { - return Err(CryptoError::InvalidKey("X448: keys must be 56 bytes each".into())); + return Err(CryptoError::InvalidKey( + "X448: keys must be 56 bytes each".into(), + )); } let mut shared = Zeroizing::new(vec![0u8; 56]); unsafe { - let mut local_key: crate::sys::curve448_key = std::mem::zeroed(); + let mut local_key: crate::sys::curve448_key = std::mem::zeroed(); let mut remote_key: crate::sys::curve448_key = std::mem::zeroed(); // Initialise both key structs before use. let ret = crate::sys::wc_curve448_init(&mut local_key); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_curve448_init (local) returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve448_init (local) returned {}", + ret + ))); } let ret = crate::sys::wc_curve448_init(&mut remote_key); if ret != 0 { crate::sys::wc_curve448_free(&mut local_key); - return Err(CryptoError::InternalError( - format!("wc_curve448_init (remote) returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve448_init (remote) returned {}", + ret + ))); } // Import private key in little-endian (EC448_LITTLE_ENDIAN = 0). let ret = crate::sys::wc_curve448_import_private_ex( - private_key.as_ptr(), 56, &mut local_key, X448_LE, + private_key.as_ptr(), + 56, + &mut local_key, + X448_LE, ); if ret != 0 { crate::sys::wc_curve448_free(&mut local_key); crate::sys::wc_curve448_free(&mut remote_key); - return Err(CryptoError::InvalidKey( - format!("wc_curve448_import_private_ex returned {}", ret) - )); + return Err(CryptoError::InvalidKey(format!( + "wc_curve448_import_private_ex returned {}", + ret + ))); } // Import remote public key in little-endian. let ret = crate::sys::wc_curve448_import_public_ex( - public_key.as_ptr(), 56, &mut remote_key, X448_LE, + public_key.as_ptr(), + 56, + &mut remote_key, + X448_LE, ); if ret != 0 { crate::sys::wc_curve448_free(&mut local_key); crate::sys::wc_curve448_free(&mut remote_key); - return Err(CryptoError::InvalidKey( - format!("wc_curve448_import_public_ex returned {}", ret) - )); + return Err(CryptoError::InvalidKey(format!( + "wc_curve448_import_public_ex returned {}", + ret + ))); } let mut shared_sz = 56u32; @@ -381,9 +414,10 @@ fn x448_dh(private_key: &[u8], public_key: &[u8]) -> Result>, crate::sys::wc_curve448_free(&mut remote_key); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_curve448_shared_secret_ex returned {}", ret) - )); + return Err(CryptoError::InternalError(format!( + "wc_curve448_shared_secret_ex returned {}", + ret + ))); } } diff --git a/crates/ccc-crypto-wolfssl/src/lib.rs b/crates/ccc-crypto-wolfssl/src/lib.rs index c268ff3..308b84c 100644 --- a/crates/ccc-crypto-wolfssl/src/lib.rs +++ b/crates/ccc-crypto-wolfssl/src/lib.rs @@ -20,7 +20,13 @@ pub mod provider; // FFI bindings generated by bindgen in build.rs. // When wolfSSL headers are not present (e.g. docs.rs), use a stub. -#[allow(non_camel_case_types, non_snake_case, non_upper_case_globals, dead_code, clippy::all)] +#[allow( + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + dead_code, + clippy::all +)] mod sys { // ── Manual ABI-critical type definitions ──────────────────────────────── // @@ -112,48 +118,98 @@ mod sys { // ── AES-GCM ───────────────────────────────────────────────────────── - pub unsafe fn wc_AesGcmSetKey(aes: *mut Aes, key: *const c_uchar, len: c_uint) -> c_int { unreachable!() } + pub unsafe fn wc_AesGcmSetKey(aes: *mut Aes, key: *const c_uchar, len: c_uint) -> c_int { + unreachable!() + } pub unsafe fn wc_AesGcmEncrypt( - aes: *mut Aes, out: *mut c_uchar, in_: *const c_uchar, sz: c_uint, - iv: *const c_uchar, iv_sz: c_uint, auth_tag: *mut c_uchar, auth_tag_sz: c_uint, - auth_in: *const c_uchar, auth_in_sz: c_uint, - ) -> c_int { unreachable!() } + aes: *mut Aes, + out: *mut c_uchar, + in_: *const c_uchar, + sz: c_uint, + iv: *const c_uchar, + iv_sz: c_uint, + auth_tag: *mut c_uchar, + auth_tag_sz: c_uint, + auth_in: *const c_uchar, + auth_in_sz: c_uint, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_AesGcmDecrypt( - aes: *mut Aes, out: *mut c_uchar, in_: *const c_uchar, sz: c_uint, - iv: *const c_uchar, iv_sz: c_uint, auth_tag: *const c_uchar, auth_tag_sz: c_uint, - auth_in: *const c_uchar, auth_in_sz: c_uint, - ) -> c_int { unreachable!() } - pub unsafe fn wc_AesInit(aes: *mut Aes, heap: *mut c_void, dev_id: c_int) -> c_int { unreachable!() } - pub unsafe fn wc_AesFree(aes: *mut Aes) { unreachable!() } + aes: *mut Aes, + out: *mut c_uchar, + in_: *const c_uchar, + sz: c_uint, + iv: *const c_uchar, + iv_sz: c_uint, + auth_tag: *const c_uchar, + auth_tag_sz: c_uint, + auth_in: *const c_uchar, + auth_in_sz: c_uint, + ) -> c_int { + unreachable!() + } + pub unsafe fn wc_AesInit(aes: *mut Aes, heap: *mut c_void, dev_id: c_int) -> c_int { + unreachable!() + } + pub unsafe fn wc_AesFree(aes: *mut Aes) { + unreachable!() + } // ── ChaCha20-Poly1305 ──────────────────────────────────────────────── pub unsafe fn wc_ChaCha20Poly1305_Encrypt( - key: *const c_uchar, iv: *const c_uchar, - aad: *const c_uchar, aad_sz: c_uint, - in_: *const c_uchar, in_sz: c_uint, - out: *mut c_uchar, auth_tag: *mut c_uchar, - ) -> c_int { unreachable!() } + key: *const c_uchar, + iv: *const c_uchar, + aad: *const c_uchar, + aad_sz: c_uint, + in_: *const c_uchar, + in_sz: c_uint, + out: *mut c_uchar, + auth_tag: *mut c_uchar, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_ChaCha20Poly1305_Decrypt( - key: *const c_uchar, iv: *const c_uchar, - aad: *const c_uchar, aad_sz: c_uint, - in_: *const c_uchar, in_sz: c_uint, - auth_tag: *const c_uchar, out: *mut c_uchar, - ) -> c_int { unreachable!() } + key: *const c_uchar, + iv: *const c_uchar, + aad: *const c_uchar, + aad_sz: c_uint, + in_: *const c_uchar, + in_sz: c_uint, + auth_tag: *const c_uchar, + out: *mut c_uchar, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_XChaCha20Poly1305_Encrypt( - dst: *mut c_uchar, dst_space: usize, - src: *const c_uchar, src_len: usize, - ad: *const c_uchar, ad_len: usize, - nonce: *const c_uchar, nonce_len: usize, - key: *const c_uchar, key_len: usize, - ) -> c_int { unreachable!() } + dst: *mut c_uchar, + dst_space: usize, + src: *const c_uchar, + src_len: usize, + ad: *const c_uchar, + ad_len: usize, + nonce: *const c_uchar, + nonce_len: usize, + key: *const c_uchar, + key_len: usize, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_XChaCha20Poly1305_Decrypt( - dst: *mut c_uchar, dst_space: usize, - src: *const c_uchar, src_len: usize, - ad: *const c_uchar, ad_len: usize, - nonce: *const c_uchar, nonce_len: usize, - key: *const c_uchar, key_len: usize, - ) -> c_int { unreachable!() } + dst: *mut c_uchar, + dst_space: usize, + src: *const c_uchar, + src_len: usize, + ad: *const c_uchar, + ad_len: usize, + nonce: *const c_uchar, + nonce_len: usize, + key: *const c_uchar, + key_len: usize, + ) -> c_int { + unreachable!() + } // ── SHA-256 (init/update/final) ────────────────────────────────────── @@ -195,76 +251,161 @@ mod sys { pub unsafe fn wc_InitBlake2b(b2b: *mut Blake2b, digest_sz: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_InitBlake2b_WithKey( - b2b: *mut Blake2b, digest_sz: c_uint, - key: *const c_uchar, key_sz: c_uint, - ) -> c_int { unreachable!() } - pub unsafe fn wc_Blake2bUpdate(b2b: *mut Blake2b, in_: *const c_uchar, in_sz: c_uint) -> c_int { unreachable!() } - pub unsafe fn wc_Blake2bFinal(b2b: *mut Blake2b, final_: *mut c_uchar, request_sz: c_uint) -> c_int { unreachable!() } + b2b: *mut Blake2b, + digest_sz: c_uint, + key: *const c_uchar, + key_sz: c_uint, + ) -> c_int { + unreachable!() + } + pub unsafe fn wc_Blake2bUpdate( + b2b: *mut Blake2b, + in_: *const c_uchar, + in_sz: c_uint, + ) -> c_int { + unreachable!() + } + pub unsafe fn wc_Blake2bFinal( + b2b: *mut Blake2b, + final_: *mut c_uchar, + request_sz: c_uint, + ) -> c_int { + unreachable!() + } // ── HMAC ──────────────────────────────────────────────────────────── pub unsafe fn wc_HmacInit(hmac: *mut Hmac, heap: *mut c_void, dev_id: c_int) -> c_int { unreachable!() } - pub unsafe fn wc_HmacSetKey(hmac: *mut Hmac, type_: c_int, key: *const c_uchar, key_sz: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_HmacUpdate(hmac: *mut Hmac, in_: *const c_uchar, in_sz: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_HmacFinal(hmac: *mut Hmac, out: *mut c_uchar) -> c_int { unreachable!() } pub unsafe fn wc_HmacFree(hmac: *mut Hmac) { unreachable!() } + pub unsafe fn wc_HmacSetKey( + hmac: *mut Hmac, + type_: c_int, + key: *const c_uchar, + key_sz: c_uint, + ) -> c_int { + unreachable!() + } // ── HKDF (TLS-1.3 Extract — RFC 5869 Extract step) ────────────────── pub unsafe fn wc_Tls13_HKDF_Extract( prk: *mut c_uchar, - salt: *const c_uchar, salt_len: c_uint, - ikm: *mut c_uchar, ikm_len: c_uint, + salt: *const c_uchar, + salt_len: c_uint, + ikm: *mut c_uchar, + ikm_len: c_uint, digest: c_int, - ) -> c_int { unreachable!() } + ) -> c_int { + unreachable!() + } // ── RNG ───────────────────────────────────────────────────────────── pub unsafe fn wc_InitRng(rng: *mut WC_RNG) -> c_int { unreachable!() } - pub unsafe fn wc_RNG_GenerateBlock(rng: *mut WC_RNG, buf: *mut c_uchar, sz: c_uint) -> c_int { unreachable!() } pub unsafe fn wc_FreeRng(rng: *mut WC_RNG) -> c_int { unreachable!() } + pub unsafe fn wc_RNG_GenerateBlock( + rng: *mut WC_RNG, + buf: *mut c_uchar, + sz: c_uint, + ) -> c_int { + unreachable!() + } // ── Curve25519 ─────────────────────────────────────────────────────── - pub unsafe fn wc_curve25519_make_key(rng: *mut WC_RNG, key_sz: c_int, key: *mut curve25519_key) -> c_int { unreachable!() } pub unsafe fn wc_curve25519_init(key: *mut curve25519_key) -> c_int { unreachable!() } + pub unsafe fn wc_curve25519_make_key( + rng: *mut WC_RNG, + key_sz: c_int, + key: *mut curve25519_key, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_curve25519_export_key_raw( key: *mut curve25519_key, - priv_: *mut c_uchar, priv_sz: *mut c_uint, - pub_: *mut c_uchar, pub_sz: *mut c_uint, - ) -> c_int { unreachable!() } + priv_: *mut c_uchar, + priv_sz: *mut c_uint, + pub_: *mut c_uchar, + pub_sz: *mut c_uint, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_curve25519_import_private( - priv_: *const c_uchar, priv_sz: c_uint, key: *mut curve25519_key, - ) -> c_int { unreachable!() } + priv_: *const c_uchar, + priv_sz: c_uint, + key: *mut curve25519_key, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_curve25519_import_public( - pub_: *const c_uchar, pub_sz: c_uint, key: *mut curve25519_key, - ) -> c_int { unreachable!() } + pub_: *const c_uchar, + pub_sz: c_uint, + key: *mut curve25519_key, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_curve25519_shared_secret_ex( - local: *mut curve25519_key, remote: *mut curve25519_key, - out: *mut c_uchar, out_sz: *mut c_uint, endian: c_int, - ) -> c_int { unreachable!() } - pub unsafe fn wc_curve25519_free(key: *mut curve25519_key) { unreachable!() } + local: *mut curve25519_key, + remote: *mut curve25519_key, + out: *mut c_uchar, + out_sz: *mut c_uint, + endian: c_int, + ) -> c_int { + unreachable!() + } + pub unsafe fn wc_curve25519_free(key: *mut curve25519_key) { + unreachable!() + } // ── Curve448 ───────────────────────────────────────────────────────── - pub unsafe fn wc_curve448_make_key(rng: *mut WC_RNG, key_sz: c_int, key: *mut curve448_key) -> c_int { unreachable!() } - pub unsafe fn wc_curve448_init(key: *mut curve448_key) -> c_int { unreachable!() } + pub unsafe fn wc_curve448_make_key( + rng: *mut WC_RNG, + key_sz: c_int, + key: *mut curve448_key, + ) -> c_int { + unreachable!() + } + pub unsafe fn wc_curve448_init(key: *mut curve448_key) -> c_int { + unreachable!() + } pub unsafe fn wc_curve448_export_key_raw( key: *mut curve448_key, - priv_: *mut c_uchar, priv_sz: *mut c_uint, - pub_: *mut c_uchar, pub_sz: *mut c_uint, - ) -> c_int { unreachable!() } + priv_: *mut c_uchar, + priv_sz: *mut c_uint, + pub_: *mut c_uchar, + pub_sz: *mut c_uint, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_curve448_import_private( - priv_: *const c_uchar, priv_sz: c_uint, key: *mut curve448_key, - ) -> c_int { unreachable!() } + priv_: *const c_uchar, + priv_sz: c_uint, + key: *mut curve448_key, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_curve448_import_public( - pub_: *const c_uchar, pub_sz: c_uint, key: *mut curve448_key, - ) -> c_int { unreachable!() } + pub_: *const c_uchar, + pub_sz: c_uint, + key: *mut curve448_key, + ) -> c_int { + unreachable!() + } pub unsafe fn wc_curve448_shared_secret_ex( - local: *mut curve448_key, remote: *mut curve448_key, - out: *mut c_uchar, out_sz: *mut c_uint, endian: c_int, - ) -> c_int { unreachable!() } - pub unsafe fn wc_curve448_free(key: *mut curve448_key) { unreachable!() } + local: *mut curve448_key, + remote: *mut curve448_key, + out: *mut c_uchar, + out_sz: *mut c_uint, + endian: c_int, + ) -> c_int { + unreachable!() + } + pub unsafe fn wc_curve448_free(key: *mut curve448_key) { + unreachable!() + } } } @@ -276,7 +417,6 @@ pub use provider::WolfSslProvider; /// Call this once from `ccc_init()` in the bridge crate. pub fn init() { let provider = WolfSslProvider::new(); - ccc_crypto_core::ProviderRegistry::global() - .register("wolfssl", Box::new(provider)); + ccc_crypto_core::ProviderRegistry::global().register("wolfssl", Box::new(provider)); log::info!("[ccc-crypto-wolfssl] provider registered"); } diff --git a/crates/ccc-crypto-wolfssl/src/mac.rs b/crates/ccc-crypto-wolfssl/src/mac.rs index 9335013..0ec9d59 100644 --- a/crates/ccc-crypto-wolfssl/src/mac.rs +++ b/crates/ccc-crypto-wolfssl/src/mac.rs @@ -17,20 +17,15 @@ const WC_HASH_TYPE_SHA512: i32 = 8; // ────────────────────────────────────────────────────────────────────────────── /// Compute a MAC tag over `data` using the specified algorithm and `key`. -pub fn compute_mac( - algo: MacAlgorithm, - key: &[u8], - data: &[u8], -) -> Result, CryptoError> { +pub fn compute_mac(algo: MacAlgorithm, key: &[u8], data: &[u8]) -> Result, CryptoError> { match algo { MacAlgorithm::HmacSha256 => hmac(WC_HASH_TYPE_SHA256, key, data, 32), MacAlgorithm::HmacSha384 => hmac(WC_HASH_TYPE_SHA384, key, data, 48), MacAlgorithm::HmacSha512 => hmac(WC_HASH_TYPE_SHA512, key, data, 64), MacAlgorithm::Blake2bMac => blake2b_mac(key, data), - MacAlgorithm::Poly1305 => - Err(CryptoError::UnsupportedAlgorithm( - "Poly1305 standalone MAC is not exposed in this Phase".into() - )), + MacAlgorithm::Poly1305 => Err(CryptoError::UnsupportedAlgorithm( + "Poly1305 standalone MAC is not exposed in this Phase".into(), + )), } } @@ -71,11 +66,8 @@ pub(crate) fn hmac( use std::alloc::{alloc_zeroed, dealloc, Layout}; // sizeof(Hmac) = 456 bytes; alignment = 16 (from embedded wc_Sha256). - let layout = Layout::from_size_align( - std::mem::size_of::().max(456), - 16, - ) - .expect("layout must be valid"); + let layout = Layout::from_size_align(std::mem::size_of::().max(456), 16) + .expect("layout must be valid"); let hmac_ptr = alloc_zeroed(layout) as *mut crate::sys::Hmac; if hmac_ptr.is_null() { @@ -90,40 +82,40 @@ pub(crate) fn hmac( ); if ret != 0 { dealloc(hmac_ptr as *mut u8, layout); - return Err(CryptoError::InternalError(format!("wc_HmacInit returned {}", ret))); + return Err(CryptoError::InternalError(format!( + "wc_HmacInit returned {}", + ret + ))); } - let ret = crate::sys::wc_HmacSetKey( - hmac_ptr, - hash_type, - key.as_ptr(), - key.len() as u32, - ); + let ret = crate::sys::wc_HmacSetKey(hmac_ptr, hash_type, key.as_ptr(), key.len() as u32); if ret != 0 { crate::sys::wc_HmacFree(hmac_ptr); dealloc(hmac_ptr as *mut u8, layout); - return Err(CryptoError::InvalidKey(format!("wc_HmacSetKey returned {}", ret))); + return Err(CryptoError::InvalidKey(format!( + "wc_HmacSetKey returned {}", + ret + ))); } - let ret = crate::sys::wc_HmacUpdate( - hmac_ptr, - data.as_ptr(), - data.len() as u32, - ); + let ret = crate::sys::wc_HmacUpdate(hmac_ptr, data.as_ptr(), data.len() as u32); if ret != 0 { crate::sys::wc_HmacFree(hmac_ptr); dealloc(hmac_ptr as *mut u8, layout); - return Err(CryptoError::InternalError(format!("wc_HmacUpdate returned {}", ret))); + return Err(CryptoError::InternalError(format!( + "wc_HmacUpdate returned {}", + ret + ))); } - let ret = crate::sys::wc_HmacFinal( - hmac_ptr, - out.as_mut_ptr(), - ); + let ret = crate::sys::wc_HmacFinal(hmac_ptr, out.as_mut_ptr()); if ret != 0 { crate::sys::wc_HmacFree(hmac_ptr); dealloc(hmac_ptr as *mut u8, layout); - return Err(CryptoError::InternalError(format!("wc_HmacFinal returned {}", ret))); + return Err(CryptoError::InternalError(format!( + "wc_HmacFinal returned {}", + ret + ))); } crate::sys::wc_HmacFree(hmac_ptr); @@ -146,7 +138,7 @@ pub(crate) fn hmac( fn blake2b_mac(key: &[u8], data: &[u8]) -> Result, CryptoError> { if key.is_empty() || key.len() > 64 { return Err(CryptoError::InvalidKey( - "BLAKE2b-MAC: key must be 1–64 bytes".into() + "BLAKE2b-MAC: key must be 1–64 bytes".into(), )); } @@ -157,30 +149,26 @@ fn blake2b_mac(key: &[u8], data: &[u8]) -> Result, CryptoError> { let mut b2b: crate::sys::Blake2b = std::mem::zeroed(); // Initialise with digest size and key for keyed (MAC) mode. - let ret = crate::sys::wc_InitBlake2b_WithKey( - &mut b2b, - OUT_LEN, - key.as_ptr(), - key.len() as u32, - ); + let ret = + crate::sys::wc_InitBlake2b_WithKey(&mut b2b, OUT_LEN, key.as_ptr(), key.len() as u32); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_InitBlake2b_WithKey returned {ret}") - )); + return Err(CryptoError::InternalError(format!( + "wc_InitBlake2b_WithKey returned {ret}" + ))); } let ret = crate::sys::wc_Blake2bUpdate(&mut b2b, data.as_ptr(), data.len() as u32); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_Blake2bUpdate returned {ret}") - )); + return Err(CryptoError::InternalError(format!( + "wc_Blake2bUpdate returned {ret}" + ))); } let ret = crate::sys::wc_Blake2bFinal(&mut b2b, out.as_mut_ptr(), OUT_LEN); if ret != 0 { - return Err(CryptoError::InternalError( - format!("wc_Blake2bFinal returned {ret}") - )); + return Err(CryptoError::InternalError(format!( + "wc_Blake2bFinal returned {ret}" + ))); } } @@ -201,7 +189,10 @@ fn constant_time_eq(a: &[u8], b: &[u8]) -> bool { } // Accumulate XOR differences; the branch is on the final accumulated value // only, not on any individual byte. - let diff: u8 = a.iter().zip(b.iter()).fold(0u8, |acc, (x, y)| acc | (x ^ y)); + let diff: u8 = a + .iter() + .zip(b.iter()) + .fold(0u8, |acc, (x, y)| acc | (x ^ y)); diff == 0 } diff --git a/crates/ccc-crypto-wolfssl/src/provider.rs b/crates/ccc-crypto-wolfssl/src/provider.rs index 293285d..fb634d2 100644 --- a/crates/ccc-crypto-wolfssl/src/provider.rs +++ b/crates/ccc-crypto-wolfssl/src/provider.rs @@ -12,9 +12,7 @@ use ccc_crypto_core::{ algorithms::{AeadAlgorithm, HashAlgorithm, KdfAlgorithm, KemAlgorithm, MacAlgorithm}, capabilities::ProviderCapabilities, error::CryptoError, - provider::{ - AeadProvider, CryptoProvider, HashProvider, KdfProvider, KemProvider, MacProvider, - }, + provider::{AeadProvider, CryptoProvider, HashProvider, KdfProvider, KemProvider, MacProvider}, types::{AlgoTestResult, BenchmarkReport, KemEncapResult, KemKeyPair, SelfTestReport}, }; @@ -27,34 +25,34 @@ use crate::{aead, capabilities, hash, kdf, kem, mac}; // ────────────────────────────────────────────────────────────────────────────── struct AeadVector { - algo: AeadAlgorithm, - key: &'static str, - nonce: &'static str, - aad: &'static str, - pt: &'static str, - ct_tag: &'static str, // ciphertext || tag, hex-encoded + algo: AeadAlgorithm, + key: &'static str, + nonce: &'static str, + aad: &'static str, + pt: &'static str, + ct_tag: &'static str, // ciphertext || tag, hex-encoded } /// NIST SP 800-38D and RFC 8439 test vectors. static AEAD_VECTORS: &[AeadVector] = &[ // ── AES-256-GCM: NIST CAVS test case GCM-256/96/128 (test case 1) ─────── AeadVector { - algo: AeadAlgorithm::AesGcm256, - key: "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308", - nonce: "cafebabefacedbaddecaf888", - aad: "", - pt: "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72\ + algo: AeadAlgorithm::AesGcm256, + key: "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308", + nonce: "cafebabefacedbaddecaf888", + aad: "", + pt: "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72\ 1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255", ct_tag: "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa\ 8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad", }, // ── ChaCha20-Poly1305: RFC 8439 §2.8.2 test vector ────────────────────── AeadVector { - algo: AeadAlgorithm::ChaCha20Poly1305, - key: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", - nonce: "070000004041424344454647", - aad: "50515253c0c1c2c3c4c5c6c7", - pt: "4c616469657320616e642047656e746c656d656e206f662074686520636c617373\ + algo: AeadAlgorithm::ChaCha20Poly1305, + key: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", + nonce: "070000004041424344454647", + aad: "50515253c0c1c2c3c4c5c6c7", + pt: "4c616469657320616e642047656e746c656d656e206f662074686520636c617373\ 206f6620273939", ct_tag: "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63\ dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b369\ @@ -97,14 +95,19 @@ impl WolfSslProvider { self.bench.get_or_init(|| { log::info!("[ccc-crypto-wolfssl] running throughput benchmark…"); let report = capabilities::run_benchmark(); - log::info!("[ccc-crypto-wolfssl] benchmark complete ({} algos)", report.results.len()); + log::info!( + "[ccc-crypto-wolfssl] benchmark complete ({} algos)", + report.results.len() + ); report }) } } impl Default for WolfSslProvider { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } // ────────────────────────────────────────────────────────────────────────────── @@ -113,15 +116,23 @@ impl Default for WolfSslProvider { impl AeadProvider for WolfSslProvider { fn encrypt_aead( - &self, algo: AeadAlgorithm, key: &[u8], nonce: &[u8], - plaintext: &[u8], aad: &[u8], + &self, + algo: AeadAlgorithm, + key: &[u8], + nonce: &[u8], + plaintext: &[u8], + aad: &[u8], ) -> Result, CryptoError> { aead::encrypt(algo, key, nonce, plaintext, aad) } fn decrypt_aead( - &self, algo: AeadAlgorithm, key: &[u8], nonce: &[u8], - ciphertext_and_tag: &[u8], aad: &[u8], + &self, + algo: AeadAlgorithm, + key: &[u8], + nonce: &[u8], + ciphertext_and_tag: &[u8], + aad: &[u8], ) -> Result, CryptoError> { aead::decrypt(algo, key, nonce, ciphertext_and_tag, aad) } @@ -129,7 +140,12 @@ impl AeadProvider for WolfSslProvider { impl KdfProvider for WolfSslProvider { fn derive_key( - &self, algo: KdfAlgorithm, ikm: &[u8], salt: &[u8], info: &[u8], length: usize, + &self, + algo: KdfAlgorithm, + ikm: &[u8], + salt: &[u8], + info: &[u8], + length: usize, ) -> Result>, CryptoError> { kdf::derive_key(algo, ikm, salt, info, length) } @@ -137,13 +153,20 @@ impl KdfProvider for WolfSslProvider { impl MacProvider for WolfSslProvider { fn compute_mac( - &self, algo: MacAlgorithm, key: &[u8], data: &[u8], + &self, + algo: MacAlgorithm, + key: &[u8], + data: &[u8], ) -> Result, CryptoError> { mac::compute_mac(algo, key, data) } fn verify_mac( - &self, algo: MacAlgorithm, key: &[u8], data: &[u8], mac_bytes: &[u8], + &self, + algo: MacAlgorithm, + key: &[u8], + data: &[u8], + mac_bytes: &[u8], ) -> Result { mac::verify_mac(algo, key, data, mac_bytes) } @@ -162,12 +185,17 @@ impl KemProvider for WolfSslProvider { kem::generate_keypair(algo) } fn encapsulate( - &self, algo: KemAlgorithm, public_key: &[u8], + &self, + algo: KemAlgorithm, + public_key: &[u8], ) -> Result { kem::encapsulate(algo, public_key) } fn decapsulate( - &self, algo: KemAlgorithm, private_key: &[u8], ciphertext: &[u8], + &self, + algo: KemAlgorithm, + private_key: &[u8], + ciphertext: &[u8], ) -> Result>, CryptoError> { kem::decapsulate(algo, private_key, ciphertext) } @@ -178,13 +206,17 @@ impl KemProvider for WolfSslProvider { // ────────────────────────────────────────────────────────────────────────────── impl CryptoProvider for WolfSslProvider { - fn provider_name(&self) -> &'static str { "wolfssl" } + fn provider_name(&self) -> &'static str { + "wolfssl" + } fn capabilities(&self) -> ProviderCapabilities { - self.caps.get_or_init(|| { - let bench = self.get_or_run_benchmark(); - capabilities::probe_capabilities(Some(bench)) - }).clone() + self.caps + .get_or_init(|| { + let bench = self.get_or_run_benchmark(); + capabilities::probe_capabilities(Some(bench)) + }) + .clone() } fn self_test(&self) -> SelfTestReport { @@ -218,10 +250,10 @@ fn run_aead_vector(v: &AeadVector) -> AlgoTestResult { .collect() }; - let key = decode(v.key); - let nonce = decode(v.nonce); - let aad = decode(v.aad); - let pt = decode(v.pt); + let key = decode(v.key); + let nonce = decode(v.nonce); + let aad = decode(v.aad); + let pt = decode(v.pt); let expected = decode(v.ct_tag); match aead::encrypt(v.algo, &key, &nonce, &pt, &aad) { @@ -237,7 +269,8 @@ fn run_aead_vector(v: &AeadVector) -> AlgoTestResult { passed: false, error_message: Some(format!( "output mismatch: got {} bytes, expected {} bytes", - ct_tag.len(), expected.len() + ct_tag.len(), + expected.len() )), }, Err(e) => AlgoTestResult { diff --git a/tests/conformance/src/main.rs b/tests/conformance/src/main.rs index ab77d06..c1a1c20 100644 --- a/tests/conformance/src/main.rs +++ b/tests/conformance/src/main.rs @@ -61,17 +61,17 @@ struct HashVec { /// Both sides are symmetric: `decapsulate(algo, bob_private, alice_public)` is /// verified as a second assertion in `run_kem()`. struct KemDhVec { - name: &'static str, - algo: KemAlgorithm, + name: &'static str, + algo: KemAlgorithm, /// Alice's static private key (little-endian). - alice_private: &'static str, + alice_private: &'static str, /// Alice's corresponding public key (little-endian), used for the Bob→Alice /// direction check. - alice_public: &'static str, + alice_public: &'static str, /// Bob's static private key (little-endian). - bob_private: &'static str, + bob_private: &'static str, /// Bob's corresponding public key (little-endian). - bob_public: &'static str, + bob_public: &'static str, /// Expected shared secret (little-endian). expected_shared: &'static str, } @@ -347,12 +347,24 @@ fn run_aead(p: &WolfSslProvider, failures: &mut usize) { // Verify round-trip decrypt as well. match p.decrypt_aead(v.algo, &key, &nonce, &ct_tag, &aad) { Ok(recovered) if recovered == pt => pass(v.name), - Ok(_) => { *failures += 1; println!(" [FAIL] {} (decrypt mismatch)", v.name); } - Err(e) => { *failures += 1; println!(" [FAIL] {} (decrypt error: {e})", v.name); } + Ok(_) => { + *failures += 1; + println!(" [FAIL] {} (decrypt mismatch)", v.name); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} (decrypt error: {e})", v.name); + } } } - Ok(ct_tag) => { *failures += 1; fail(v.name, &ct_tag, &expected); } - Err(e) => { *failures += 1; println!(" [FAIL] {} (encrypt error: {e})", v.name); } + Ok(ct_tag) => { + *failures += 1; + fail(v.name, &ct_tag, &expected); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} (encrypt error: {e})", v.name); + } } } } @@ -367,8 +379,14 @@ fn run_kdf(p: &WolfSslProvider, failures: &mut usize) { match p.derive_key(v.algo, &ikm, &salt, &info, v.length) { Ok(out) if out.as_slice() == expected.as_slice() => pass(v.name), - Ok(out) => { *failures += 1; fail(v.name, &out, &expected); } - Err(e) => { *failures += 1; println!(" [FAIL] {} ({e})", v.name); } + Ok(out) => { + *failures += 1; + fail(v.name, &out, &expected); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} ({e})", v.name); + } } } } @@ -385,12 +403,24 @@ fn run_mac(p: &WolfSslProvider, failures: &mut usize) { // Also verify constant-time path. match p.verify_mac(v.algo, &key, &data, &tag) { Ok(true) => pass(v.name), - Ok(false) => { *failures += 1; println!(" [FAIL] {} (verify false)", v.name); } - Err(e) => { *failures += 1; println!(" [FAIL] {} (verify error: {e})", v.name); } + Ok(false) => { + *failures += 1; + println!(" [FAIL] {} (verify false)", v.name); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} (verify error: {e})", v.name); + } } } - Ok(tag) => { *failures += 1; fail(v.name, &tag, &expected); } - Err(e) => { *failures += 1; println!(" [FAIL] {} ({e})", v.name); } + Ok(tag) => { + *failures += 1; + fail(v.name, &tag, &expected); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} ({e})", v.name); + } } } } @@ -403,8 +433,14 @@ fn run_hash(p: &WolfSslProvider, failures: &mut usize) { match p.hash(v.algo, &data) { Ok(digest) if digest == expected => pass(v.name), - Ok(digest) => { *failures += 1; fail(v.name, &digest, &expected); } - Err(e) => { *failures += 1; println!(" [FAIL] {} ({e})", v.name); } + Ok(digest) => { + *failures += 1; + fail(v.name, &digest, &expected); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} ({e})", v.name); + } } } } @@ -431,16 +467,28 @@ fn run_kem(p: &WolfSslProvider, failures: &mut usize) { let test_a = format!("{} (Alice→Bob)", v.name); match p.decapsulate(v.algo, &alice_priv, &bob_pub) { Ok(shared) if shared.as_slice() == expected.as_slice() => pass(&test_a), - Ok(shared) => { *failures += 1; fail(&test_a, &shared, &expected); } - Err(e) => { *failures += 1; println!(" [FAIL] {} ({e})", test_a); } + Ok(shared) => { + *failures += 1; + fail(&test_a, &shared, &expected); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} ({e})", test_a); + } } // Bob→Alice direction (symmetric). let test_b = format!("{} (Bob→Alice)", v.name); match p.decapsulate(v.algo, &bob_priv, &alice_pub) { Ok(shared) if shared.as_slice() == expected.as_slice() => pass(&test_b), - Ok(shared) => { *failures += 1; fail(&test_b, &shared, &expected); } - Err(e) => { *failures += 1; println!(" [FAIL] {} ({e})", test_b); } + Ok(shared) => { + *failures += 1; + fail(&test_b, &shared, &expected); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} ({e})", test_b); + } } } } @@ -455,27 +503,33 @@ fn run_kem_roundtrip(p: &WolfSslProvider, failures: &mut usize) { for algo in [KemAlgorithm::X25519, KemAlgorithm::X448] { let name = format!("{:?} ephemeral roundtrip", algo); match p.generate_keypair(algo) { - Err(e) => { *failures += 1; println!(" [FAIL] {} (keygen: {e})", name); continue; } - Ok(kp) => { - match p.encapsulate(algo, &kp.public_key) { - Err(e) => { *failures += 1; println!(" [FAIL] {} (encap: {e})", name); } - Ok(encap) => { - match p.decapsulate(algo, &kp.private_key, &encap.ciphertext) { - Err(e) => { *failures += 1; println!(" [FAIL] {} (decap: {e})", name); } - Ok(decap_secret) => { - if decap_secret.as_slice() == encap.shared_secret.as_slice() { - pass(&name); - } else { - *failures += 1; - println!(" [FAIL] {} (shared-secret mismatch)", name); - println!(" encap: {}", hex::encode(&encap.shared_secret)); - println!(" decap: {}", hex::encode(&decap_secret)); - } - } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} (keygen: {e})", name); + continue; + } + Ok(kp) => match p.encapsulate(algo, &kp.public_key) { + Err(e) => { + *failures += 1; + println!(" [FAIL] {} (encap: {e})", name); + } + Ok(encap) => match p.decapsulate(algo, &kp.private_key, &encap.ciphertext) { + Err(e) => { + *failures += 1; + println!(" [FAIL] {} (decap: {e})", name); + } + Ok(decap_secret) => { + if decap_secret.as_slice() == encap.shared_secret.as_slice() { + pass(&name); + } else { + *failures += 1; + println!(" [FAIL] {} (shared-secret mismatch)", name); + println!(" encap: {}", hex::encode(&encap.shared_secret)); + println!(" decap: {}", hex::encode(&decap_secret)); } } - } - } + }, + }, } } } @@ -511,10 +565,22 @@ fn run_xchacha20_kat(p: &WolfSslProvider, failures: &mut usize) { // Print the ct_tag for pinning purposes. println!(" [INFO] {} ct_tag = {}", v.name, hex::encode(&ct_tag)); - match p.decrypt_aead(AeadAlgorithm::XChaCha20Poly1305, &key, &nonce, &ct_tag, &aad) { + match p.decrypt_aead( + AeadAlgorithm::XChaCha20Poly1305, + &key, + &nonce, + &ct_tag, + &aad, + ) { Ok(recovered) if recovered == pt => pass(&rt_name), - Ok(_) => { *failures += 1; println!(" [FAIL] {} (decrypt mismatch)", rt_name); } - Err(e) => { *failures += 1; println!(" [FAIL] {} (decrypt error: {e})", rt_name); } + Ok(_) => { + *failures += 1; + println!(" [FAIL] {} (decrypt mismatch)", rt_name); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} (decrypt error: {e})", rt_name); + } } // ── Auth-failure check ──────────────────────────────────── @@ -522,10 +588,24 @@ fn run_xchacha20_kat(p: &WolfSslProvider, failures: &mut usize) { let auth_name = format!("{} [auth-fail]", v.name); let mut tampered = ct_tag.clone(); *tampered.last_mut().unwrap() ^= 0xff; - match p.decrypt_aead(AeadAlgorithm::XChaCha20Poly1305, &key, &nonce, &tampered, &aad) { - Err(ccc_crypto_core::error::CryptoError::AuthenticationFailed) => pass(&auth_name), - Ok(_) => { *failures += 1; println!(" [FAIL] {} (expected auth failure, got Ok)", auth_name); } - Err(e) => { *failures += 1; println!(" [FAIL] {} (wrong error type: {e})", auth_name); } + match p.decrypt_aead( + AeadAlgorithm::XChaCha20Poly1305, + &key, + &nonce, + &tampered, + &aad, + ) { + Err(ccc_crypto_core::error::CryptoError::AuthenticationFailed) => { + pass(&auth_name) + } + Ok(_) => { + *failures += 1; + println!(" [FAIL] {} (expected auth failure, got Ok)", auth_name); + } + Err(e) => { + *failures += 1; + println!(" [FAIL] {} (wrong error type: {e})", auth_name); + } } } }