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:
NikitolProject
2026-02-25 00:37:10 +03:00
parent c67a170919
commit 329bed6f2b

96
tests/golden.rs Normal file
View 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")
);
}