aacs: point integration tests at real module paths

The facade removal (5ff0464) left tests/ calling aacs::disc_hash,
aacs::decrypt_unit, aacs::AacsVersion, etc. at the old flat paths,
so the branch did not compile its integration tests. Repoint each
to its real module (inf/derive/content/mkb). No logic change.
This commit is contained in:
Matthew Jackson
2026-07-04 18:25:59 -07:00
parent 5ff04649ba
commit f4fe651cb9
2 changed files with 50 additions and 50 deletions
+41 -41
View File
@@ -84,9 +84,9 @@ fn aacs_decrypt_unit_roundtrip() {
]; ];
// Build plaintext unit with TS sync bytes every 192 bytes starting at offset 4 // Build plaintext unit with TS sync bytes every 192 bytes starting at offset 4
let mut plain = vec![0u8; aacs::ALIGNED_UNIT_LEN]; let mut plain = vec![0u8; aacs::content::ALIGNED_UNIT_LEN];
let mut offset = 4; let mut offset = 4;
while offset < aacs::ALIGNED_UNIT_LEN { while offset < aacs::content::ALIGNED_UNIT_LEN {
plain[offset] = 0x47; // TS sync byte plain[offset] = 0x47; // TS sync byte
offset += 192; offset += 192;
} }
@@ -118,7 +118,7 @@ fn aacs_decrypt_unit_roundtrip() {
// Step 3: AES-CBC encrypt bytes 16..6144 // Step 3: AES-CBC encrypt bytes 16..6144
let cipher = Aes128::new(GenericArray::from_slice(&encrypt_key)); let cipher = Aes128::new(GenericArray::from_slice(&encrypt_key));
let mut prev = aacs_iv; let mut prev = aacs_iv;
let num_blocks = (aacs::ALIGNED_UNIT_LEN - 16) / 16; let num_blocks = (aacs::content::ALIGNED_UNIT_LEN - 16) / 16;
for i in 0..num_blocks { for i in 0..num_blocks {
let off = 16 + i * 16; let off = 16 + i * 16;
for j in 0..16 { for j in 0..16 {
@@ -131,29 +131,29 @@ fn aacs_decrypt_unit_roundtrip() {
} }
// Verify it looks encrypted (body TS syncs scrambled) // Verify it looks encrypted (body TS syncs scrambled)
assert!(aacs::ts_sync_destroyed(&plain)); assert!(aacs::content::ts_sync_destroyed(&plain));
// Now decrypt // Now decrypt
let result = aacs::decrypt_unit(&mut plain, &unit_key); let result = aacs::content::decrypt_unit(&mut plain, &unit_key);
assert!( assert!(
result, result,
"decrypt_unit should return true on valid encrypted unit" "decrypt_unit should return true on valid encrypted unit"
); );
assert!( assert!(
!aacs::ts_sync_destroyed(&plain), !aacs::content::ts_sync_destroyed(&plain),
"decrypted unit should read as clear (TS syncs restored)" "decrypted unit should read as clear (TS syncs restored)"
); );
// Verify TS sync bytes at expected positions (flag byte is cleared by decrypt) // Verify TS sync bytes at expected positions (flag byte is cleared by decrypt)
let mut sync_count = 0; let mut sync_count = 0;
let mut off = 4; let mut off = 4;
while off < aacs::ALIGNED_UNIT_LEN { while off < aacs::content::ALIGNED_UNIT_LEN {
if plain[off] == 0x47 { if plain[off] == 0x47 {
sync_count += 1; sync_count += 1;
} }
off += 192; off += 192;
} }
let expected_syncs = (aacs::ALIGNED_UNIT_LEN - 4) / 192 + 1; let expected_syncs = (aacs::content::ALIGNED_UNIT_LEN - 4) / 192 + 1;
assert_eq!( assert_eq!(
sync_count, expected_syncs, sync_count, expected_syncs,
"TS sync bytes not recovered: got {}, expected {}", "TS sync bytes not recovered: got {}, expected {}",
@@ -176,11 +176,11 @@ fn aacs_disc_hash_deterministic() {
let data1 = b"Unit_Key_RO.inf test data for deterministic hashing"; let data1 = b"Unit_Key_RO.inf test data for deterministic hashing";
let data2 = b"Different data should produce different hash"; let data2 = b"Different data should produce different hash";
let hash1a = aacs::disc_hash(data1); let hash1a = aacs::inf::disc_hash(data1);
let hash1b = aacs::disc_hash(data1); let hash1b = aacs::inf::disc_hash(data1);
assert_eq!(hash1a, hash1b, "disc_hash not deterministic on same input"); assert_eq!(hash1a, hash1b, "disc_hash not deterministic on same input");
let hash2 = aacs::disc_hash(data2); let hash2 = aacs::inf::disc_hash(data2);
assert_ne!( assert_ne!(
hash1a, hash2, hash1a, hash2,
"different inputs should produce different hashes" "different inputs should produce different hashes"
@@ -190,7 +190,7 @@ fn aacs_disc_hash_deterministic() {
assert_eq!(hash1a.len(), 20); assert_eq!(hash1a.len(), 20);
// Verify disc_hash_hex formatting // Verify disc_hash_hex formatting
let hex = aacs::disc_hash_hex(&hash1a); let hex = aacs::inf::disc_hash_hex(&hash1a);
assert!(hex.starts_with("0x"), "hex should start with 0x prefix"); assert!(hex.starts_with("0x"), "hex should start with 0x prefix");
assert_eq!( assert_eq!(
hex.len(), hex.len(),
@@ -225,7 +225,7 @@ fn aacs_decrypt_unit_key_roundtrip() {
encrypted_uk.copy_from_slice(&block); encrypted_uk.copy_from_slice(&block);
// Decrypt with the public API // Decrypt with the public API
let decrypted = aacs::decrypt_unit_key(&vuk, &encrypted_uk); let decrypted = aacs::derive::decrypt_unit_key(&vuk, &encrypted_uk);
assert_eq!( assert_eq!(
decrypted, original_unit_key, decrypted, original_unit_key,
"decrypt_unit_key did not recover original unit key" "decrypt_unit_key did not recover original unit key"
@@ -246,7 +246,7 @@ fn aacs_vuk_derivation_roundtrip() {
0x30, 0x30,
]; ];
let vuk = aacs::derive_vuk(&media_key, &volume_id); let vuk = aacs::derive::derive_vuk(&media_key, &volume_id);
// VUK should be non-zero and different from both inputs // VUK should be non-zero and different from both inputs
assert_ne!(vuk, [0u8; 16], "VUK should not be all zeros"); assert_ne!(vuk, [0u8; 16], "VUK should not be all zeros");
@@ -254,7 +254,7 @@ fn aacs_vuk_derivation_roundtrip() {
assert_ne!(vuk, volume_id, "VUK should differ from volume_id"); assert_ne!(vuk, volume_id, "VUK should differ from volume_id");
// Verify determinism // Verify determinism
let vuk2 = aacs::derive_vuk(&media_key, &volume_id); let vuk2 = aacs::derive::derive_vuk(&media_key, &volume_id);
assert_eq!(vuk, vuk2, "derive_vuk not deterministic"); assert_eq!(vuk, vuk2, "derive_vuk not deterministic");
} }
@@ -263,14 +263,14 @@ fn aacs_vuk_derivation_roundtrip() {
fn aacs_ts_sync_destroyed_detection() { fn aacs_ts_sync_destroyed_detection() {
// A clear unit: TS sync (0x47) intact at every 192-byte packet → not // A clear unit: TS sync (0x47) intact at every 192-byte packet → not
// scrambled. (Flag bits play no role.) // scrambled. (Flag bits play no role.)
let mut clear = vec![0u8; aacs::ALIGNED_UNIT_LEN]; let mut clear = vec![0u8; aacs::content::ALIGNED_UNIT_LEN];
let mut off = 4; let mut off = 4;
while off < aacs::ALIGNED_UNIT_LEN { while off < aacs::content::ALIGNED_UNIT_LEN {
clear[off] = 0x47; clear[off] = 0x47;
off += 192; off += 192;
} }
assert!( assert!(
!aacs::ts_sync_destroyed(&clear), !aacs::content::ts_sync_destroyed(&clear),
"clear unit (syncs intact) must not be scrambled" "clear unit (syncs intact) must not be scrambled"
); );
@@ -279,21 +279,21 @@ fn aacs_ts_sync_destroyed_detection() {
flagged[0] = 0xC0; // copy-control bits flagged[0] = 0xC0; // copy-control bits
flagged[7] = 0xC0; // TSC bits flagged[7] = 0xC0; // TSC bits
assert!( assert!(
!aacs::ts_sync_destroyed(&flagged), !aacs::content::ts_sync_destroyed(&flagged),
"flag bits must not be read as encryption" "flag bits must not be read as encryption"
); );
// A scrambled body (syncs destroyed) → scrambled. // A scrambled body (syncs destroyed) → scrambled.
let scrambled = vec![0x99u8; aacs::ALIGNED_UNIT_LEN]; let scrambled = vec![0x99u8; aacs::content::ALIGNED_UNIT_LEN];
assert!( assert!(
aacs::ts_sync_destroyed(&scrambled), aacs::content::ts_sync_destroyed(&scrambled),
"unit with no intact TS syncs must read as scrambled" "unit with no intact TS syncs must read as scrambled"
); );
// Too short // Too short
let short = vec![0xFFu8; 100]; let short = vec![0xFFu8; 100];
assert!( assert!(
!aacs::ts_sync_destroyed(&short), !aacs::content::ts_sync_destroyed(&short),
"short buffer should not be detected" "short buffer should not be detected"
); );
} }
@@ -303,10 +303,10 @@ fn aacs_ts_sync_destroyed_detection() {
/// A clear unit (TS syncs intact) should pass through decrypt_unit unchanged. /// A clear unit (TS syncs intact) should pass through decrypt_unit unchanged.
#[test] #[test]
fn aacs_decrypt_unit_unencrypted_passthrough() { fn aacs_decrypt_unit_unencrypted_passthrough() {
let mut unit = vec![0x42u8; aacs::ALIGNED_UNIT_LEN]; let mut unit = vec![0x42u8; aacs::content::ALIGNED_UNIT_LEN];
// Intact TS syncs every 192 bytes → not scrambled → passthrough. // Intact TS syncs every 192 bytes → not scrambled → passthrough.
let mut off = 4; let mut off = 4;
while off < aacs::ALIGNED_UNIT_LEN { while off < aacs::content::ALIGNED_UNIT_LEN {
unit[off] = 0x47; unit[off] = 0x47;
off += 192; off += 192;
} }
@@ -315,8 +315,8 @@ fn aacs_decrypt_unit_unencrypted_passthrough() {
let original = unit.clone(); let original = unit.clone();
let key = [0xAA; 16]; let key = [0xAA; 16];
assert!(!aacs::ts_sync_destroyed(&unit)); assert!(!aacs::content::ts_sync_destroyed(&unit));
let result = aacs::decrypt_unit(&mut unit, &key); let result = aacs::content::decrypt_unit(&mut unit, &key);
assert!(result, "clear unit should return true"); assert!(result, "clear unit should return true");
assert_eq!(unit, original, "clear unit should be unchanged"); assert_eq!(unit, original, "clear unit should be unchanged");
} }
@@ -370,17 +370,17 @@ fn aacs_cross_validation_encrypt_then_decrypt() {
0x10, 0x10,
]; ];
let mut plaintext = vec![0u8; aacs::ALIGNED_UNIT_LEN]; let mut plaintext = vec![0u8; aacs::content::ALIGNED_UNIT_LEN];
// TS sync bytes every 192 bytes starting at offset 4 // TS sync bytes every 192 bytes starting at offset 4
let mut off = 4; let mut off = 4;
while off < aacs::ALIGNED_UNIT_LEN { while off < aacs::content::ALIGNED_UNIT_LEN {
plaintext[off] = 0x47; plaintext[off] = 0x47;
off += 192; off += 192;
} }
// Fill the rest with a recognisable pattern (prime modulus avoids artefacts). // Fill the rest with a recognisable pattern (prime modulus avoids artefacts).
// Index-arithmetic — clearer with a counted loop than an enumerate chain. // Index-arithmetic — clearer with a counted loop than an enumerate chain.
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
for i in 16..aacs::ALIGNED_UNIT_LEN { for i in 16..aacs::content::ALIGNED_UNIT_LEN {
if plaintext[i] == 0 { if plaintext[i] == 0 {
plaintext[i] = (i % 251) as u8; plaintext[i] = (i % 251) as u8;
} }
@@ -402,7 +402,7 @@ fn aacs_cross_validation_encrypt_then_decrypt() {
ref_aes_cbc_encrypt( ref_aes_cbc_encrypt(
&dk, &dk,
&CROSS_AACS_IV, &CROSS_AACS_IV,
&mut plaintext[16..aacs::ALIGNED_UNIT_LEN], &mut plaintext[16..aacs::content::ALIGNED_UNIT_LEN],
); );
// Sanity: ciphertext should differ // Sanity: ciphertext should differ
@@ -413,7 +413,7 @@ fn aacs_cross_validation_encrypt_then_decrypt() {
); );
// -- Decrypt with the library -- // -- Decrypt with the library --
let ok = aacs::decrypt_unit(&mut plaintext, &unit_key); let ok = aacs::content::decrypt_unit(&mut plaintext, &unit_key);
assert!( assert!(
ok, ok,
"decrypt_unit returned false (TS sync verification failed)" "decrypt_unit returned false (TS sync verification failed)"
@@ -436,9 +436,9 @@ fn aacs_cross_validation_alternate_key() {
0x08, 0x08,
]; ];
let mut plaintext = vec![0xFFu8; aacs::ALIGNED_UNIT_LEN]; let mut plaintext = vec![0xFFu8; aacs::content::ALIGNED_UNIT_LEN];
let mut off = 4; let mut off = 4;
while off < aacs::ALIGNED_UNIT_LEN { while off < aacs::content::ALIGNED_UNIT_LEN {
plaintext[off] = 0x47; plaintext[off] = 0x47;
off += 192; off += 192;
} }
@@ -455,10 +455,10 @@ fn aacs_cross_validation_alternate_key() {
ref_aes_cbc_encrypt( ref_aes_cbc_encrypt(
&dk, &dk,
&CROSS_AACS_IV, &CROSS_AACS_IV,
&mut plaintext[16..aacs::ALIGNED_UNIT_LEN], &mut plaintext[16..aacs::content::ALIGNED_UNIT_LEN],
); );
assert!(aacs::decrypt_unit(&mut plaintext, &unit_key)); assert!(aacs::content::decrypt_unit(&mut plaintext, &unit_key));
// Decryption clears no flag, so the unit round-trips byte-for-byte. // Decryption clears no flag, so the unit round-trips byte-for-byte.
assert_eq!(&plaintext[..], &expected[..]); assert_eq!(&plaintext[..], &expected[..]);
@@ -473,15 +473,15 @@ fn aacs_bus_decrypt_cross_validation() {
0x00, 0x00,
]; ];
let mut plaintext = vec![0u8; aacs::ALIGNED_UNIT_LEN]; let mut plaintext = vec![0u8; aacs::content::ALIGNED_UNIT_LEN];
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
for i in 0..aacs::ALIGNED_UNIT_LEN { for i in 0..aacs::content::ALIGNED_UNIT_LEN {
plaintext[i] = ((i * 3 + 17) & 0xFF) as u8; plaintext[i] = ((i * 3 + 17) & 0xFF) as u8;
} }
let expected = plaintext.clone(); let expected = plaintext.clone();
// Encrypt per-sector: AES-CBC encrypt bytes 16..2048 of each 2048-byte sector // Encrypt per-sector: AES-CBC encrypt bytes 16..2048 of each 2048-byte sector
for sector_start in (0..aacs::ALIGNED_UNIT_LEN).step_by(2048) { for sector_start in (0..aacs::content::ALIGNED_UNIT_LEN).step_by(2048) {
ref_aes_cbc_encrypt( ref_aes_cbc_encrypt(
&read_data_key, &read_data_key,
&CROSS_AACS_IV, &CROSS_AACS_IV,
@@ -490,7 +490,7 @@ fn aacs_bus_decrypt_cross_validation() {
} }
assert_ne!(&plaintext[16..32], &expected[16..32]); assert_ne!(&plaintext[16..32], &expected[16..32]);
aacs::decrypt_bus(&mut plaintext, &read_data_key); aacs::content::decrypt_bus(&mut plaintext, &read_data_key);
assert_eq!( assert_eq!(
plaintext, expected, plaintext, expected,
"bus decrypt did not recover original plaintext" "bus decrypt did not recover original plaintext"
@@ -738,7 +738,7 @@ fn aacs_parse_unit_key_ro_minimal() {
data[key_pos + i] = (0xA0 + i) as u8; data[key_pos + i] = (0xA0 + i) as u8;
} }
let result = aacs::parse_unit_key_ro(&data, aacs::AacsVersion::V10); let result = aacs::inf::parse_unit_key_ro(&data, aacs::mkb::AacsVersion::V10);
assert!( assert!(
result.is_some(), result.is_some(),
"parse_unit_key_ro should succeed on valid data" "parse_unit_key_ro should succeed on valid data"
@@ -751,6 +751,6 @@ fn aacs_parse_unit_key_ro_minimal() {
assert_eq!(ukf.disc_hash.len(), 20); assert_eq!(ukf.disc_hash.len(), 20);
// disc_hash should be deterministic // disc_hash should be deterministic
let hash = aacs::disc_hash(&data); let hash = aacs::inf::disc_hash(&data);
assert_eq!(ukf.disc_hash, hash); assert_eq!(ukf.disc_hash, hash);
} }
+9 -9
View File
@@ -10,7 +10,7 @@ use libfreemkv::{aacs, decrypt::DecryptKeys};
#[test] #[test]
fn decrypt_sectors_with_aacs_keys_works() { fn decrypt_sectors_with_aacs_keys_works() {
// Build an encrypted aligned unit // Build an encrypted aligned unit
let mut unit = vec![0xFFu8; aacs::ALIGNED_UNIT_LEN]; let mut unit = vec![0xFFu8; aacs::content::ALIGNED_UNIT_LEN];
// Set encryption flag (bits 6-7 of byte 0) // Set encryption flag (bits 6-7 of byte 0)
unit[0] |= 0xC0; unit[0] |= 0xC0;
@@ -19,7 +19,7 @@ fn decrypt_sectors_with_aacs_keys_works() {
for (i, byte) in unit for (i, byte) in unit
.iter_mut() .iter_mut()
.enumerate() .enumerate()
.take(aacs::ALIGNED_UNIT_LEN) .take(aacs::content::ALIGNED_UNIT_LEN)
.skip(1) .skip(1)
{ {
*byte = ((i * 3 + 7) & 0xFF) as u8; *byte = ((i * 3 + 7) & 0xFF) as u8;
@@ -28,7 +28,7 @@ fn decrypt_sectors_with_aacs_keys_works() {
let unit_key: [u8; 16] = [0xAAu8; 16]; let unit_key: [u8; 16] = [0xAAu8; 16];
// Encrypt the unit using AACS algorithm // Encrypt the unit using AACS algorithm
aacs::decrypt_unit(&mut unit, &unit_key); // decrypt_unit is idempotent on already-encrypted data aacs::content::decrypt_unit(&mut unit, &unit_key); // decrypt_unit is idempotent on already-encrypted data
// Now we have encrypted data - create DecryptKeys with actual keys // Now we have encrypted data - create DecryptKeys with actual keys
let mut keys = DecryptKeys::Aacs { let mut keys = DecryptKeys::Aacs {
@@ -83,23 +83,23 @@ fn decrypt_sectors_with_css_keys_works() {
#[test] #[test]
fn aacs_encryption_flag_detection() { fn aacs_encryption_flag_detection() {
// A clear unit: TS syncs (0x47) intact at every 192-byte packet. // A clear unit: TS syncs (0x47) intact at every 192-byte packet.
let mut unit = vec![0u8; aacs::ALIGNED_UNIT_LEN]; let mut unit = vec![0u8; aacs::content::ALIGNED_UNIT_LEN];
let mut off = 4; let mut off = 4;
while off < aacs::ALIGNED_UNIT_LEN { while off < aacs::content::ALIGNED_UNIT_LEN {
unit[off] = 0x47; unit[off] = 0x47;
off += 192; off += 192;
} }
// Encryption is the scrambled body (TS syncs destroyed), NOT a flag bit. // Encryption is the scrambled body (TS syncs destroyed), NOT a flag bit.
assert!(!aacs::ts_sync_destroyed(&unit)); assert!(!aacs::content::ts_sync_destroyed(&unit));
// Flag bits on a synced unit do not make it look encrypted. // Flag bits on a synced unit do not make it look encrypted.
unit[0] = 0xC0; unit[0] = 0xC0;
unit[7] = 0xC0; unit[7] = 0xC0;
assert!(!aacs::ts_sync_destroyed(&unit)); assert!(!aacs::content::ts_sync_destroyed(&unit));
// Scrambled body (syncs gone) → encrypted. // Scrambled body (syncs gone) → encrypted.
let scrambled = vec![0x99u8; aacs::ALIGNED_UNIT_LEN]; let scrambled = vec![0x99u8; aacs::content::ALIGNED_UNIT_LEN];
assert!(aacs::ts_sync_destroyed(&scrambled)); assert!(aacs::content::ts_sync_destroyed(&scrambled));
} }
/// Test: DecryptKeys::is_encrypted() correctly identifies encrypted state. /// Test: DecryptKeys::is_encrypted() correctly identifies encrypted state.