feat(crypto,pki): implement Wave 1 — hybrid KEM + PKI
aura-crypto: X25519 + ML-KEM-768 (FIPS 203) hybrid KEM, HKDF-SHA256 session key derivation, ChaCha20-Poly1305 AeadSession with counter nonces; genuine NIST ACVP ML-KEM-768 KAT (decapsulation vector). 16 tests green, clippy clean. aura-pki: self-signed CA, server/client cert issuance (rcgen 0.14), mutual X.509 chain verification via rustls-webpki, CRL revocation. 8 tests green. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
//! ML-KEM-768 (FIPS 203) Known-Answer Test.
|
||||
//!
|
||||
//! This is a **real** KAT, not merely a roundtrip. The vector below is an official NIST ACVP
|
||||
//! ML-KEM ("encapDecap") sample vector:
|
||||
//!
|
||||
//! * Source: <https://github.com/usnistgov/ACVP-Server>,
|
||||
//! `gen-val/json-files/ML-KEM-encapDecap-FIPS203/internalProjection.json`
|
||||
//! * `vsId = 42`, ML-KEM-768 AFT, `tcId = 26` (`isSample: true`).
|
||||
//!
|
||||
//! The decapsulation key (`DK`, 2400-byte FIPS 203 expanded form) and ciphertext (`CT`, 1088
|
||||
//! bytes) are fed into our wrapper; the recovered shared secret must equal the expected `K`.
|
||||
//! ML-KEM decapsulation is deterministic, so this needs no RNG and pins exact bytes.
|
||||
//!
|
||||
//! We also assert the canonical ML-KEM-768 sizes (ek = 1184, dk = 2400, ct = 1088, ss = 32) and
|
||||
//! perform a fresh keygen/encapsulate/decapsulate roundtrip.
|
||||
|
||||
use aura_crypto::kem::kyber;
|
||||
use aura_crypto::kem::sizes::{CT_LEN, DK_LEN, EK_LEN, SS_LEN};
|
||||
|
||||
// NIST ACVP ML-KEM-768 vector (vsId 42, tcId 26).
|
||||
const KAT_EK_HEX: &str = "b649b9ad5a59aa45640b03ace153499bc1244465735dca6e5ed0c7116070287758e7a31ee53ba171e7c8964b3615075286a4af1ea12479ab0218608692a2606a024d12fcae691c8114828f3547c9d0344af9920d952ba6bce6aae6a47360da1588697f91ab5475c5588ad6328389a34ba50e41514343c534ad7947c5aa4220c73d335bb24f6676cc2549fd40759cd4b54549b04d8932921b183ecb634b579a54742dd6734c7225741ba32ac196aa68faaf3d1425d4a44cc563aaf8816a8258bf745842f1ca7d8eda9a7a6ccd72966abab9061ee21ef3d2b1155133f4b8099b653ba8b5224360cf00295f2b3887d1b12d601b18bd407b80d167aefa0d3f6a906fc2cd08a663b7766815a26c6e2bc83318ac99b5a56d338ec347adbd9a57ec53359ce898fb637b32fc4a6fc216bfa30eec501681751bee46c5c02317c3b3b98f24ac67acc53941cd20035fe2a59890e9ab7cf063fe07a62703643e0580d99c152343c5bdd8cb9f9c1fd0c194ee7281913a7d1f0473722c024df76568a731d309cd5fa87fb3a0c771aa42efd160af89752c1c3eeac74a934b163af92d4ee74c709a31e901045fe6202de9622b552acd807829f46ad9c47087e2856f294b97546103568292a4b7462895f161891af4a66d537e79087f87f63e4e5a7d767a5d6a4a52267c8ce41413ef6c3dc4b1c64ee5ad75d9542099361ef81246a64ad997885fe0631d02919ab6b967b8c441d73b67d52b5fa64ac7789d30e659d776334da3a65a3b4081014455bc858637b23a991fe8ec315c687c36d81553c79f159c2b4b285604c0541ab62749cba6c29472b5dc6ab61b2be2e6a57a1942e729c1e95ba95c8100d4554fcedc0d73ac8023f736a94ac757b7b5108807a5eaba507b6f22e627ef325c0ef3b28123be7882840b7a8efcba7e0d82434c330b37b7c7f546b123d460a0d0c58893a7e4664f49acc9150a5dfbb71fbef44374a987e3192be4a50fc1f1160a0488844864532689e9f29d55366969e014b19869251977c34049437bb41b334c2de7a2eb63cc3ff21b042aa0e6839469e4bfa226cdbf8331cd1640e04b4cf2a89bffc20283dc2d90706604c1021153417b26c650b483856463df2c2c064ab4a9f316c5ba02109b1023370dded31ab1da2eb837bd8ccc52106712eb91a019119bd60951b3662f3f6291ecb76561b253dc4a1cb8e41b3a16b2ec87a252c4b747448823902845527b31c15a3ef18e174b644f548faf30b3da5610edccb73e3a8714bbbdd668c14a9472718b34efc545fff2783f033f13fc1665bc324ca244f1e91851d8ce2df2b388ea24b2cb8eab400f5a8ac1d01442f765688393ce21c4c63113ba49480b247c3fb4d49df82b1f493430bfa78f6d948da4e927bdd9bd2d18a7f230046853bd8be51cd59178d0295509213b7e1b0798584dce835b48312f0257a185d9360e0a702ad8bb0a53c119336889974b8e52b636328556ca1a9eec413f5259c66503c90206a7857925c727815c94fd545f0112c6a7e89c2ef54ae897a4b0792f98f5710ca174288658f5c8596c7807008369831135e1d50d5ac77f6ae9641de0622bca6a8e746700818c4a22a9ad30c9bc660117f3462617baf392280de09f5695b3cdda5e931c5b521bdaa455c3d0f0f7375153a754ed9620da68dd";
|
||||
const KAT_DK_HEX: &str = "0af8cf210b1b442c963feb4297f3a1c0513353f6808c8450b3c698a0f75034f9349591201c674fb835c6f9ba484376b15abc27a0443ca7b293602321717ca9ec4411d8a184032289b6398e07c34d46e05d8a10cf51984486fc90c5ebb08d23a740db30e6c88e2cb0ba758590b413a3ea50583d885945053b66631547405f59a053fb6b9e57e2b7d9593d71615eab21b78774b32a6c9fbcc3b845e48130d86aacbc6900295dbfab17e9f532f6635b45216fc71727b9f2c67ee5619691bec4a1b2baa990445978eda08a6ab0279460bd6a7590c66044079c8728a68a11a1469f8139572572e3e2b1a8a4226e9bafe8f871e2c21695b20aa15bcb56a974b582cfc168838e75226717b398cc5b3da780d4c5310f35c37d2376f773a06ac0c2d8e524ec50abc6d72e18f509027c3dc6d47dc7b28e52f779094458c8948623610ff9c045b865885e08a8d946235fe053b9e3042b152fc5a318b6b785d9919bb030467ac775c9eb56fa00135b3c5b7e14bb5522a281598d584425c0234f358a713e581efb5a2ce1560d53a36d48a8330e18c6c99bb7018275445bcf72c3a6a8db27f90455dea48f7858978004b672094f1ceb700c284205864dbbd61c5f68b59df95e8b01258f630e2f302919e10551400602656ccba21fb931c365ea6b79936d7743b59763433e24a337cc2443a067c5733205189c38502399fc2ca7b360050555d4f719ea677d06b134cbf35559784a5727629ad888ebf37d57e012de56b9978b8ccda395b2ac4b56443ad22053f382b409088851c2146aea2d4105d091fb91a5f63fbebcc7bca382b2046f47e20119506157ab9a2104a62ad82e100c8a99093b4f787809491268e19fed6ab4436a513294419dc5322e076b686719cda59b891462ffe246d338767ee52a14e87a3ba99142291c62d42bba2697e72b810d335e4d7987cb208ec2aa466d09bacaf407b62a6a71442edabba9ffe03cefeb8ae84abf0fac3641c79479f67b6d04c98458a2cae7cd817b6acfa4b0c4a3a85104b610b746adb75d817a9c104bb2d29bc9b0a948fe4682f1416bfe44000290ab22319ec0a531a89a9a5fb544ef72ce93b1cd0bc3056ac768e4c50804cb3db4c2372f506d12649776175d127bb5edb7c2d79a01e304a7acb76f164c2143f6056feacf9690700fe15eb2fac559646c765c708248698218404080c0f1a35e7ec44969875a301ca59000289a685a31cc69e5f2285f9a260bdb8a1cb13b4467b98f782051dcb8f5e91889581277a359bd279905abcf9a1a452507b810171865821fc7fbcb7c0ab2fe651706c4478323acf69a1f2fdc539b547b25bc9302d9c6272ab027852c1ff4c8b33357cd77730ad6160aab68eda2b532d8bc7c4061594044478569e1d7238d464f66b141d5cc3d9b67a7cf554dd4460d60265f8c0b5899b68d57073a034b0e0b6cb9391ab9a8ea75a0e19d86125b34ab885885839f726548d54d954061411801f5651f780cb74ddba0471c33319772b8661acaa9c6dab97dd31a684288c84dc56f3193a8e2d7cb29d74044321e77f3a0b1c27cb056c16161a9e2d417e4020e990bc9ea3abef2101d4d89ad5f390b2c81cb221429ce796f7dc890c0807008bcc0b649b9ad5a59aa45640b03ace153499bc1244465735dca6e5ed0c7116070287758e7a31ee53ba171e7c8964b3615075286a4af1ea12479ab0218608692a2606a024d12fcae691c8114828f3547c9d0344af9920d952ba6bce6aae6a47360da1588697f91ab5475c5588ad6328389a34ba50e41514343c534ad7947c5aa4220c73d335bb24f6676cc2549fd40759cd4b54549b04d8932921b183ecb634b579a54742dd6734c7225741ba32ac196aa68faaf3d1425d4a44cc563aaf8816a8258bf745842f1ca7d8eda9a7a6ccd72966abab9061ee21ef3d2b1155133f4b8099b653ba8b5224360cf00295f2b3887d1b12d601b18bd407b80d167aefa0d3f6a906fc2cd08a663b7766815a26c6e2bc83318ac99b5a56d338ec347adbd9a57ec53359ce898fb637b32fc4a6fc216bfa30eec501681751bee46c5c02317c3b3b98f24ac67acc53941cd20035fe2a59890e9ab7cf063fe07a62703643e0580d99c152343c5bdd8cb9f9c1fd0c194ee7281913a7d1f0473722c024df76568a731d309cd5fa87fb3a0c771aa42efd160af89752c1c3eeac74a934b163af92d4ee74c709a31e901045fe6202de9622b552acd807829f46ad9c47087e2856f294b97546103568292a4b7462895f161891af4a66d537e79087f87f63e4e5a7d767a5d6a4a52267c8ce41413ef6c3dc4b1c64ee5ad75d9542099361ef81246a64ad997885fe0631d02919ab6b967b8c441d73b67d52b5fa64ac7789d30e659d776334da3a65a3b4081014455bc858637b23a991fe8ec315c687c36d81553c79f159c2b4b285604c0541ab62749cba6c29472b5dc6ab61b2be2e6a57a1942e729c1e95ba95c8100d4554fcedc0d73ac8023f736a94ac757b7b5108807a5eaba507b6f22e627ef325c0ef3b28123be7882840b7a8efcba7e0d82434c330b37b7c7f546b123d460a0d0c58893a7e4664f49acc9150a5dfbb71fbef44374a987e3192be4a50fc1f1160a0488844864532689e9f29d55366969e014b19869251977c34049437bb41b334c2de7a2eb63cc3ff21b042aa0e6839469e4bfa226cdbf8331cd1640e04b4cf2a89bffc20283dc2d90706604c1021153417b26c650b483856463df2c2c064ab4a9f316c5ba02109b1023370dded31ab1da2eb837bd8ccc52106712eb91a019119bd60951b3662f3f6291ecb76561b253dc4a1cb8e41b3a16b2ec87a252c4b747448823902845527b31c15a3ef18e174b644f548faf30b3da5610edccb73e3a8714bbbdd668c14a9472718b34efc545fff2783f033f13fc1665bc324ca244f1e91851d8ce2df2b388ea24b2cb8eab400f5a8ac1d01442f765688393ce21c4c63113ba49480b247c3fb4d49df82b1f493430bfa78f6d948da4e927bdd9bd2d18a7f230046853bd8be51cd59178d0295509213b7e1b0798584dce835b48312f0257a185d9360e0a702ad8bb0a53c119336889974b8e52b636328556ca1a9eec413f5259c66503c90206a7857925c727815c94fd545f0112c6a7e89c2ef54ae897a4b0792f98f5710ca174288658f5c8596c7807008369831135e1d50d5ac77f6ae9641de0622bca6a8e746700818c4a22a9ad30c9bc660117f3462617baf392280de09f5695b3cdda5e931c5b521bdaa455c3d0f0f7375153a754ed9620da68dd6d0d1469801b55e3aee59aa34b9097e964bf39a8c8ea9526289e5f19d213e6bd6294966bbadd4259c7036c078207214ba15e55120960c4191162722b5e781907";
|
||||
const KAT_CT_HEX: &str = "04f4a18c69708a17f561778b2ac10d94380abea4a20835939c9015d78dac41a5012ced1bed948aed6c79193f8b2fc6deabd3b092ec33ae2f54778f1c54ce762a69521764e20c05bc2ef96992f463ca95d09dd588af622c297bbd8805113e985388fc9e16fda06b5eed42da629d514f86ed84acff0a09418e720201b794b49d072df15e7b7d6ec6d82379a212c71c7603a1c9bbe57fb1cb9a431de1980ecada0a4fbf5cace9ad0ceedbfdc40761839d9cc1c8590eb6335179075892a8015e04ecadad37fdcd4644ec2284cf4cbb4620fbab6055a163e3733e3a7747044b766ebc356436b33e28fa4e67b083592b05811361445c719f6ae8add4ef8ce145e3933cee75d19e98bb964d58044b6de2b46107f80c3d4690114cc84fb0d3b3d4c3af671ea7b833746b54fce5cc761ca4fd20cd163afa849e5797619c31144a74140abe1c7540d1a3c557a9f23af6e6e3523667ffd13b92444cd3be01b1581ca0cf7a536ce4c073dc17de955ba22e469bc1c0ec213b3b7ceddfc47567a7ecfc2a58a6c2a3c2185563277866f8979bbb86af844349c6021eb9926acfe0188fd0f809e056a8e0a8aaa2a4208562e775ef60c56cadd6e26a9e52d60187bf6ed0565616020e0c2bfd79d961b1069ff261b2abf40c9ee2a2c442877f4edb8d9ad717cb434fed67ef2eacd629da1ce78023548853eeaf7d998923db7ceb0174e67875e787f398435da84c26b478ff6bf785c4714bc6f8e91804e10cc699e1be342c952d57d3c84654d603709f4f6bb596e022e2e6149c81025226b9925045ff365d83991f7d4c8693544ca7ba6da60f8e4f6723c9f14ac48882556336ed88c20163544c55ab4238e510aa910b04f445252d507af02ad24e7467920c81f2d31a71a7241be2726bb9f8b20bf2100633f616a1233801eb37597ddbe2def36ef0727515e7da178da7760a41edf9ffe98fbaa3495a35025f2bd100b3d63e940ba7d997104ac67f653d0a24a2ba2c8a355af1ee048cb116b1a492577cc7cf61226fbbbabd9cbb043839585f2e00ae673ee6becaaf5da7919921c90c74d5b8b173b8a1a650f379b3b5e5f1d04538b936fc2cd0d4f8b9df9f5052ecd9e66602815b4f96586d038d5bd5a3e44bde1ef9ff9cfcb6b9aece3129ef1f026befd299a7a8ad324149b156bc5ab868099df52a2056103432879b495b0655fc1fe8073b502f3f40d403548b1629118ce0edd41558e4215e8e241a45637a3434bf070f17dac885ed656f80783a4c47000464fe78b9db0dbb55895e271d3376bf0c50cec9a403a8729982dc5b9172b5e80a0ef03fa2a24873188f8022a6f9da8ca4f2e24aa7e29987b1060ecfe0b08e039ee1f7fb55a0cd35a73b6c25dc26e469bbc2d034265db5f74e644842bb99199f83947c97bf87532b37a8d40a06f8bc5508efb117d11dfb07325d9482cdce60aa34529546d4c8d8f98e3f5b34b5c757075fee9c3443e0a1109253f5f0a905c571e5343b277e0636a5a46ab36becf5672e93b712b9bc8e3cd3656cad1b29c16e";
|
||||
const KAT_K_HEX: &str = "11b62291b1a9d307c8240d70be0b45436db445793173f6e79fcd2b273d7f3b01";
|
||||
|
||||
#[test]
|
||||
fn test_kyber768_kat_decapsulation() {
|
||||
let ek = hex::decode(KAT_EK_HEX).expect("valid ek hex");
|
||||
let dk = hex::decode(KAT_DK_HEX).expect("valid dk hex");
|
||||
let ct = hex::decode(KAT_CT_HEX).expect("valid ct hex");
|
||||
let expected_k = hex::decode(KAT_K_HEX).expect("valid k hex");
|
||||
|
||||
// Exact ML-KEM-768 sizes from FIPS 203.
|
||||
assert_eq!(ek.len(), EK_LEN, "ek must be 1184 bytes");
|
||||
assert_eq!(ek.len(), 1184);
|
||||
assert_eq!(dk.len(), DK_LEN, "dk must be 2400 bytes");
|
||||
assert_eq!(dk.len(), 2400);
|
||||
assert_eq!(ct.len(), CT_LEN, "ct must be 1088 bytes");
|
||||
assert_eq!(ct.len(), 1088);
|
||||
assert_eq!(expected_k.len(), SS_LEN, "shared secret must be 32 bytes");
|
||||
assert_eq!(expected_k.len(), 32);
|
||||
|
||||
// The core KAT: decapsulate the pinned ciphertext under the pinned dk.
|
||||
let recovered = kyber::decapsulate(&dk, &ct).expect("decapsulation succeeds");
|
||||
assert_eq!(
|
||||
recovered.as_slice(),
|
||||
expected_k.as_slice(),
|
||||
"decapsulated shared secret must match the NIST ACVP expected value"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kyber768_sizes_on_fresh_keypair() {
|
||||
let kp = kyber::generate();
|
||||
assert_eq!(kp.ek.len(), EK_LEN);
|
||||
assert_eq!(kp.dk.len(), DK_LEN);
|
||||
|
||||
let (ct, ss) = kyber::encapsulate(&kp.ek).expect("encapsulate");
|
||||
assert_eq!(ct.len(), CT_LEN);
|
||||
assert_eq!(ss.len(), SS_LEN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kyber768_roundtrip() {
|
||||
let kp = kyber::generate();
|
||||
let (ct, ss_server) = kyber::encapsulate(&kp.ek).expect("encapsulate");
|
||||
let ss_client = kyber::decapsulate(&kp.dk, &ct).expect("decapsulate");
|
||||
assert_eq!(
|
||||
ss_server, ss_client,
|
||||
"fresh ML-KEM-768 roundtrip must agree"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user