test(03-02): add golden test vectors for crypto primitives
- 7 deterministic tests: AES-256-CBC encrypt/decrypt, empty, HMAC-SHA256, HMAC verify, SHA-256 x2 - Fixed IV vectors for reproducible results (no randomness) - HMAC golden value cross-verified with openssl (file input) and Python hmac module - SHA-256 values match FORMAT.md Section 12.3 known vectors Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
96
tests/golden.rs
Normal file
96
tests/golden.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
//! Golden test vectors for cryptographic primitives.
|
||||
//!
|
||||
//! All expected values were cross-verified with `openssl enc` / `openssl dgst` / `sha256sum`
|
||||
//! during 03-RESEARCH. These tests use fixed IVs for deterministic output.
|
||||
|
||||
use encrypted_archive::crypto;
|
||||
use encrypted_archive::key::KEY;
|
||||
use hex_literal::hex;
|
||||
|
||||
/// AES-256-CBC encryption of "Hello" with project KEY and fixed IV.
|
||||
///
|
||||
/// Cross-verified:
|
||||
/// echo -n "Hello" | openssl enc -aes-256-cbc -K <hex_key> -iv 00..01 -nosalt | xxd
|
||||
#[test]
|
||||
fn test_golden_aes256cbc_hello() {
|
||||
let iv = hex!("00000000000000000000000000000001");
|
||||
let ciphertext = crypto::encrypt_data(b"Hello", &KEY, &iv);
|
||||
assert_eq!(
|
||||
ciphertext,
|
||||
hex!("6e66ae8bc740efeefe83b5713fcb716f").to_vec()
|
||||
);
|
||||
}
|
||||
|
||||
/// Decrypt the golden ciphertext back to "Hello". Round-trip with exact golden vector.
|
||||
#[test]
|
||||
fn test_golden_aes256cbc_decrypt_hello() {
|
||||
let iv = hex!("00000000000000000000000000000001");
|
||||
let ciphertext = hex!("6e66ae8bc740efeefe83b5713fcb716f");
|
||||
let plaintext = crypto::decrypt_data(&ciphertext, &KEY, &iv).unwrap();
|
||||
assert_eq!(plaintext, b"Hello");
|
||||
}
|
||||
|
||||
/// AES-256-CBC encryption of empty data with PKCS7 produces exactly one 16-byte block.
|
||||
/// Encrypt then decrypt round-trip for empty input.
|
||||
#[test]
|
||||
fn test_golden_aes256cbc_empty() {
|
||||
let iv = [0u8; 16];
|
||||
let ciphertext = crypto::encrypt_data(b"", &KEY, &iv);
|
||||
// PKCS7 on empty input: 16 bytes of 0x10 padding -> encrypts to exactly 16 bytes
|
||||
assert_eq!(ciphertext.len(), 16);
|
||||
// Round-trip: decrypt must produce empty
|
||||
let plaintext = crypto::decrypt_data(&ciphertext, &KEY, &iv).unwrap();
|
||||
assert!(plaintext.is_empty());
|
||||
}
|
||||
|
||||
/// HMAC-SHA256 over IV || ciphertext from the "Hello" golden vector.
|
||||
///
|
||||
/// Cross-verified:
|
||||
/// openssl dgst -sha256 -mac HMAC -macopt hexkey:<key> /tmp/iv_ct.bin
|
||||
/// (where iv_ct.bin = IV || ciphertext as raw binary file)
|
||||
/// Python: hmac.new(key, iv + ct, hashlib.sha256).hexdigest()
|
||||
#[test]
|
||||
fn test_golden_hmac_sha256() {
|
||||
let iv = hex!("00000000000000000000000000000001");
|
||||
let ciphertext = hex!("6e66ae8bc740efeefe83b5713fcb716f");
|
||||
let hmac = crypto::compute_hmac(&KEY, &iv, &ciphertext);
|
||||
assert_eq!(
|
||||
hmac,
|
||||
hex!("efa09db07cb1af629d7fe9eb36f31269d80d8f5ff6b2dc565b62bc4c5719ca13")
|
||||
);
|
||||
}
|
||||
|
||||
/// Verify HMAC returns true for correct value and false for wrong value.
|
||||
#[test]
|
||||
fn test_golden_hmac_verify() {
|
||||
let iv = hex!("00000000000000000000000000000001");
|
||||
let ciphertext = hex!("6e66ae8bc740efeefe83b5713fcb716f");
|
||||
let expected_hmac =
|
||||
hex!("efa09db07cb1af629d7fe9eb36f31269d80d8f5ff6b2dc565b62bc4c5719ca13");
|
||||
// Correct HMAC must verify
|
||||
assert!(crypto::verify_hmac(&KEY, &iv, &ciphertext, &expected_hmac));
|
||||
// Wrong HMAC must fail
|
||||
let wrong_hmac = [0xFFu8; 32];
|
||||
assert!(!crypto::verify_hmac(&KEY, &iv, &ciphertext, &wrong_hmac));
|
||||
}
|
||||
|
||||
/// SHA-256("Hello") matches FORMAT.md Section 12.3 known value.
|
||||
#[test]
|
||||
fn test_golden_sha256_hello() {
|
||||
let hash = crypto::sha256_hash(b"Hello");
|
||||
assert_eq!(
|
||||
hash,
|
||||
hex!("185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969")
|
||||
);
|
||||
}
|
||||
|
||||
/// SHA-256 of 32 bytes of 0x01 matches FORMAT.md Section 12.3 known value.
|
||||
#[test]
|
||||
fn test_golden_sha256_32x01() {
|
||||
let data = [0x01u8; 32];
|
||||
let hash = crypto::sha256_hash(&data);
|
||||
assert_eq!(
|
||||
hash,
|
||||
hex!("72cd6e8422c407fb6d098690f1130b7ded7ec2f7f5e1d30bd9d521f015363793")
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user