From f55d8f7acda6945baf560f79a226df7a1df472d3 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com> Date: Sat, 4 Jul 2026 13:37:53 -0700 Subject: [PATCH] aacs: extract crypto.rs (shared AES primitives + constants) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relocate the shared low-level primitives into a single crypto module: aes_ecb_encrypt/decrypt, aes_cbc_decrypt, aes_g (from content/variant) and aesg3 + AESG3_SEED (from keys), plus AACS_IV. Fixes the scatter where AES-G lived in the 2.1 file and AES-G3 in keys. Relocation only — no rename, no logic change (logic-hash identical to baseline; 277 items; 2210 tests green). --- src/aacs/boil.rs | 2 +- src/aacs/content.rs | 70 +++++---------------------- src/aacs/crypto.rs | 102 +++++++++++++++++++++++++++++++++++++++ src/aacs/keys.rs | 39 ++++----------- src/aacs/mod.rs | 1 + src/aacs/variant.rs | 24 ++------- src/decrypt.rs | 4 +- src/disc/extract.rs | 4 +- src/disc/mod.rs | 3 +- src/disc/verify.rs | 4 +- src/sector/decrypting.rs | 4 +- 11 files changed, 138 insertions(+), 119 deletions(-) create mode 100644 src/aacs/crypto.rs diff --git a/src/aacs/boil.rs b/src/aacs/boil.rs index 3511def..f1d2372 100644 --- a/src/aacs/boil.rs +++ b/src/aacs/boil.rs @@ -275,7 +275,7 @@ pub fn resolve_candidate( #[cfg(test)] mod tests { use super::*; - use crate::aacs::content::aes_ecb_encrypt; + use crate::aacs::crypto::aes_ecb_encrypt; use crate::aacs::keys::{decrypt_unit_key, derive_vuk}; /// `vuk_from_mk` must equal the inline `derive_vuk` path bit-for-bit, for diff --git a/src/aacs/content.rs b/src/aacs/content.rs index 8694d9f..164c6f2 100644 --- a/src/aacs/content.rs +++ b/src/aacs/content.rs @@ -1,15 +1,17 @@ -//! AACS content decryption — AES primitives, unit decryption, bus encryption. +//! AACS content decryption — aligned-unit / bus decryption and TS verification. +//! The low-level AES primitives it uses live in [`super::crypto`]. use aes::Aes128; -use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit, generic_array::GenericArray}; +use aes::cipher::{BlockDecrypt, KeyInit, generic_array::GenericArray}; + +use super::crypto::{aes_cbc_decrypt, aes_ecb_encrypt}; +// Available at module scope for this module's test fixtures (they reference +// `super::AACS_IV` when building CBC ciphertext directly); test-only. +#[cfg(test)] +use super::crypto::AACS_IV; // ── AACS constants ────────────────────────────────────────────────────────── -/// Fixed IV used by AACS for all AES-CBC operations. [C] §2.1.2 (default CBC IV, `iv0`). -pub(crate) const AACS_IV: [u8; 16] = [ - 0x0B, 0xA0, 0xF8, 0xDD, 0xFE, 0xA6, 0x1F, 0xB3, 0xD8, 0xDF, 0x9F, 0x56, 0x6A, 0x05, 0x0F, 0x78, -]; - /// Size of an AACS aligned unit (3 × 2048-byte sectors). [BD] §3.10.1. pub const ALIGNED_UNIT_LEN: usize = 6144; @@ -47,58 +49,6 @@ use crate::consts::BD_SOURCE_PACKET_BYTES; /// TS sync byte. const TS_SYNC: u8 = 0x47; -// ── AES primitives ────────────────────────────────────────────────────────── - -/// AES-128-ECB encrypt a single 16-byte block. [C] §2.1.1 (`AES-128E`). -pub(crate) fn aes_ecb_encrypt(key: &[u8; 16], data: &[u8; 16]) -> [u8; 16] { - let cipher = Aes128::new(GenericArray::from_slice(key)); - let mut block = GenericArray::clone_from_slice(data); - cipher.encrypt_block(&mut block); - let mut out = [0u8; 16]; - out.copy_from_slice(&block); - out -} - -/// AES-128-ECB decrypt a single 16-byte block. [C] §2.1.1 (`AES-128D`). -pub(crate) fn aes_ecb_decrypt(key: &[u8; 16], data: &[u8; 16]) -> [u8; 16] { - let cipher = Aes128::new(GenericArray::from_slice(key)); - let mut block = GenericArray::clone_from_slice(data); - cipher.decrypt_block(&mut block); - let mut out = [0u8; 16]; - out.copy_from_slice(&block); - out -} - -/// AES-128-CBC decrypt in-place with the fixed AACS IV. [C] §2.1.2 (`AES-128CBCD`). -/// -/// Precondition: `data.len()` is a multiple of 16. Any trailing partial -/// block is silently ignored; all callers pass aligned regions (6128 and -/// 2032 bytes), and the assert documents/enforces that contract. -pub(crate) fn aes_cbc_decrypt(key: &[u8; 16], data: &mut [u8]) { - debug_assert!( - data.len() % 16 == 0, - "aes_cbc_decrypt requires a block-aligned slice" - ); - let cipher = Aes128::new(GenericArray::from_slice(key)); - let num_blocks = data.len() / 16; - // Process blocks in reverse to avoid clobbering ciphertext needed for XOR - for i in (0..num_blocks).rev() { - let offset = i * 16; - let prev = if i == 0 { - AACS_IV - } else { - let mut p = [0u8; 16]; - p.copy_from_slice(&data[(i - 1) * 16..i * 16]); - p - }; - let mut block = GenericArray::clone_from_slice(&data[offset..offset + 16]); - cipher.decrypt_block(&mut block); - for j in 0..16 { - data[offset + j] = block[j] ^ prev[j]; - } - } -} - // ── Content decryption ────────────────────────────────────────────────────── /// True if a 6144-byte aligned unit's MPEG-TS sync structure is DESTROYED — it @@ -587,7 +537,9 @@ pub fn decrypt_unit_full( #[cfg(test)] mod tests { + use super::super::crypto::aes_ecb_decrypt; use super::*; + use aes::cipher::BlockEncrypt; // test fixtures build ciphertext directly #[test] fn test_aes_ecb_roundtrip() { diff --git a/src/aacs/crypto.rs b/src/aacs/crypto.rs new file mode 100644 index 0000000..2017bde --- /dev/null +++ b/src/aacs/crypto.rs @@ -0,0 +1,102 @@ +//! AACS common cryptographic primitives — [C] Chapter 2 / §3.2.2. +//! +//! Source: `[C]` = AACS Introduction and Common Cryptographic Elements Book, +//! Rev 0.953. The shared low-level building blocks — AES-128 ECB E/D, AES-G, +//! the AES-G3 Triple Generator, AES-CBC decrypt — and their fixed constants +//! (`iv0`, `s0`). Used by every AACS generation; relocated here so the +//! primitives live in one place instead of being scattered across the +//! content / keys / variant modules. + +use aes::Aes128; +use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit, generic_array::GenericArray}; + +/// Fixed IV used by AACS for all AES-CBC operations. [C] §2.1.2 (default CBC IV, `iv0`). +pub(crate) const AACS_IV: [u8; 16] = [ + 0x0B, 0xA0, 0xF8, 0xDD, 0xFE, 0xA6, 0x1F, 0xB3, 0xD8, 0xDF, 0x9F, 0x56, 0x6A, 0x05, 0x0F, 0x78, +]; + +/// AES-128-ECB encrypt a single 16-byte block. [C] §2.1.1 (`AES-128E`). +pub(crate) fn aes_ecb_encrypt(key: &[u8; 16], data: &[u8; 16]) -> [u8; 16] { + let cipher = Aes128::new(GenericArray::from_slice(key)); + let mut block = GenericArray::clone_from_slice(data); + cipher.encrypt_block(&mut block); + let mut out = [0u8; 16]; + out.copy_from_slice(&block); + out +} + +/// AES-128-ECB decrypt a single 16-byte block. [C] §2.1.1 (`AES-128D`). +pub(crate) fn aes_ecb_decrypt(key: &[u8; 16], data: &[u8; 16]) -> [u8; 16] { + let cipher = Aes128::new(GenericArray::from_slice(key)); + let mut block = GenericArray::clone_from_slice(data); + cipher.decrypt_block(&mut block); + let mut out = [0u8; 16]; + out.copy_from_slice(&block); + out +} + +/// AES-128-CBC decrypt in-place with the fixed AACS IV. [C] §2.1.2 (`AES-128CBCD`). +/// +/// Precondition: `data.len()` is a multiple of 16. Any trailing partial +/// block is silently ignored; all callers pass aligned regions (6128 and +/// 2032 bytes), and the assert documents/enforces that contract. +pub(crate) fn aes_cbc_decrypt(key: &[u8; 16], data: &mut [u8]) { + debug_assert!( + data.len() % 16 == 0, + "aes_cbc_decrypt requires a block-aligned slice" + ); + let cipher = Aes128::new(GenericArray::from_slice(key)); + let num_blocks = data.len() / 16; + // Process blocks in reverse to avoid clobbering ciphertext needed for XOR + for i in (0..num_blocks).rev() { + let offset = i * 16; + let prev = if i == 0 { + AACS_IV + } else { + let mut p = [0u8; 16]; + p.copy_from_slice(&data[(i - 1) * 16..i * 16]); + p + }; + let mut block = GenericArray::clone_from_slice(&data[offset..offset + 16]); + cipher.decrypt_block(&mut block); + for j in 0..16 { + data[offset + j] = block[j] ^ prev[j]; + } + } +} + +/// AES-G(x1, x2) = AES-128D(x1, x2) XOR x2. [C] §2.1.3 (note: uses AES-128**D**). +/// +/// The Media Key Variant chain uses AES-G to derive both the variant +/// number (`Kvn = AES-G(Kp, Nonce)`) and the Volume Unique Key +/// (`Kvu = AES-G(Km, VID)`). See [`super::keys::derive_vuk`] for the +/// classical VUK form — the math is identical, this exposes it as a +/// neutral primitive for the variant chain. +pub(crate) fn aes_g(x1: &[u8; 16], x2: &[u8; 16]) -> [u8; 16] { + let mut out = aes_ecb_decrypt(x1, x2); + for i in 0..16 { + out[i] ^= x2[i]; + } + out +} + +/// AACS-G3 seed constant (`s0`). [C] §3.2.2. +pub(crate) const AESG3_SEED: [u8; 16] = [ + 0x7B, 0x10, 0x3C, 0x5D, 0xCB, 0x08, 0xC4, 0xE5, 0x1A, 0x27, 0xB0, 0x17, 0x99, 0x05, 0x3B, 0xD9, +]; + +/// AACS-G3: derive a subkey from a parent key. [C] §3.2.2 (Triple AES Generator: +/// left=`D(k,s0)⊕s0` inc 0, pk=`D(k,s0+1)⊕(s0+1)` inc 1, right=`D(k,s0+2)⊕(s0+2)` inc 2). +/// seed[15] += inc, then AES-DEC(key, seed) XOR seed. +/// +/// Shared with [`super::variants`] (its variant chain runs the same SD +/// tree); a single definition keeps the two walks byte-identical. +pub(crate) fn aesg3(key: &[u8; 16], inc: u8) -> [u8; 16] { + let mut seed = AESG3_SEED; + seed[15] = seed[15].wrapping_add(inc); + let mut out = aes_ecb_decrypt(key, &seed); + for i in 0..16 { + out[i] ^= seed[i]; + } + out +} diff --git a/src/aacs/keys.rs b/src/aacs/keys.rs index 43067f0..9e02eb8 100644 --- a/src/aacs/keys.rs +++ b/src/aacs/keys.rs @@ -1,6 +1,6 @@ //! AACS key resolution — VUK derivation, MKB processing, disc hash, unit key parsing. -use super::content::aes_ecb_decrypt; +use super::crypto::{aes_ecb_decrypt, aesg3}; use super::types::DeviceKey; // ── AACS version ──────────────────────────────────────────────────────────── @@ -600,27 +600,6 @@ pub fn mkb_is_uhd(mkb: &[u8]) -> Option { // ── AACS-G3 key derivation (subset-difference tree) ───────────────────────── -/// AACS-G3 seed constant (`s0`). [C] §3.2.2. -const AESG3_SEED: [u8; 16] = [ - 0x7B, 0x10, 0x3C, 0x5D, 0xCB, 0x08, 0xC4, 0xE5, 0x1A, 0x27, 0xB0, 0x17, 0x99, 0x05, 0x3B, 0xD9, -]; - -/// AACS-G3: derive a subkey from a parent key. [C] §3.2.2 (Triple AES Generator: -/// left=`D(k,s0)⊕s0` inc 0, pk=`D(k,s0+1)⊕(s0+1)` inc 1, right=`D(k,s0+2)⊕(s0+2)` inc 2). -/// seed[15] += inc, then AES-DEC(key, seed) XOR seed. -/// -/// Shared with [`super::variants`] (its variant chain runs the same SD -/// tree); a single definition keeps the two walks byte-identical. -pub(super) fn aesg3(key: &[u8; 16], inc: u8) -> [u8; 16] { - let mut seed = AESG3_SEED; - seed[15] = seed[15].wrapping_add(inc); - let mut out = aes_ecb_decrypt(key, &seed); - for i in 0..16 { - out[i] ^= seed[i]; - } - out -} - /// Compute v_mask from a UV value. [C] §3.2.3. Shared with [`super::variants`]. pub(super) fn calc_v_mask(uv: u32) -> u32 { let mut v_mask: u32 = 0xFFFF_FFFF; @@ -1536,7 +1515,7 @@ mod tests { // keeps the crypto covered in libfreemkv. `aes_ecb_encrypt` is // pub(crate), reachable here but not from keysources — the reason this // half stays. - use super::super::content::aes_ecb_encrypt; + use super::super::crypto::aes_ecb_encrypt; let vuk = [0x5Au8; 16]; // A few representative "decrypted" unit keys. for expected_uk in [[0x11u8; 16], [0x22u8; 16], [0xCDu8; 16]] { @@ -1726,7 +1705,7 @@ mod tests { // whose derived Media Key satisfies a synthetic verify record; confirm // the scan ACCEPTS it against caller-supplied SD/cvalue tables and // REJECTS a 1-byte corruption. - use super::super::content::aes_ecb_encrypt as enc; + use super::super::crypto::aes_ecb_encrypt as enc; let pk: [u8; 16] = [ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, @@ -1772,7 +1751,7 @@ mod tests { // recovers mk. Catches the bugs that landed pre-fix: // * uv XOR step was missing → mk wrong whenever uv != 0 // * AES-128E + 12-zero check instead of AES-128D + magic - use super::super::content::{aes_ecb_decrypt as dec, aes_ecb_encrypt as enc}; + use super::super::crypto::{aes_ecb_decrypt as dec, aes_ecb_encrypt as enc}; let pk: [u8; 16] = [ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, @@ -2191,7 +2170,7 @@ mod tests { // The keyless-disc case: this disc's own hash/VID are NOT in keydb, but its // Media Key IS — filed under a sibling disc that shares its MKB. Path // 2.5 must km_verifies that MK against the MKB and resolve. - use super::super::content::aes_ecb_encrypt as enc; + use super::super::crypto::aes_ecb_encrypt as enc; let km = [0x11u8; 16]; let vid = [0x22u8; 16]; // MKB: 0x10 type/version + 0x86 verify record whose mk_dv decrypts under @@ -2272,7 +2251,7 @@ mod tests { // Independently compute AES-ECB-D(mk, vid) XOR vid and confirm // derive_vuk produces the same 16 bytes. A mutation that dropped the // XOR-VID step, or used encrypt instead of decrypt, fails this. - use super::super::content::aes_ecb_decrypt as dec; + use super::super::crypto::aes_ecb_decrypt as dec; let mk = [ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, @@ -2292,7 +2271,7 @@ mod tests { // The encrypted unit key in Unit_Key_RO.inf is AES-ECB-E(VUK, uk); // decrypt_unit_key must be the matching ECB-decrypt. Round-trip via // encrypt to pin the relation. - use super::super::content::aes_ecb_encrypt as enc; + use super::super::crypto::aes_ecb_encrypt as enc; let vuk = [0x9Eu8; 16]; let uk = [0x3Cu8; 16]; let enc_uk = enc(&vuk, &uk); @@ -2692,7 +2671,7 @@ mod tests { fn resolve_keys_v21_path4_resolves_by_hash() { // resolve_keys_v21 must hit path 4 (hash→VUK) and stamp version V21, // deriving unit keys from the VUK. - use super::super::content::aes_ecb_encrypt as enc; + use super::super::crypto::aes_ecb_encrypt as enc; let data = build_unit_key_ro(1, 64); // The single encrypted key in build_unit_key_ro is [0x10;16]. let hash = disc_hash(&data); @@ -2842,7 +2821,7 @@ mod tests { // - 0x86 Verify Media Key: mk_dv = AES-E(mk, magic || pad) // and a DK with node=4, uv=2, u_mask_shift=3 so dev_key_v_mask == // v_mask: the calc_pk_from_dk loop is a no-op and Kp == aesg3(dk, 1). - use super::super::content::aes_ecb_encrypt as enc; + use super::super::crypto::aes_ecb_encrypt as enc; let dk_bytes: [u8; 16] = [ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, diff --git a/src/aacs/mod.rs b/src/aacs/mod.rs index 4fe56d0..4422e4f 100644 --- a/src/aacs/mod.rs +++ b/src/aacs/mod.rs @@ -27,6 +27,7 @@ pub mod boil; pub mod content; +pub mod crypto; pub mod host_certs; pub mod keys; pub mod provider; diff --git a/src/aacs/variant.rs b/src/aacs/variant.rs index a10b429..cbabbd9 100644 --- a/src/aacs/variant.rs +++ b/src/aacs/variant.rs @@ -72,7 +72,7 @@ //! that final gate — the per-match magic check no longer protects the //! variant path. -use super::content::aes_ecb_decrypt; +use super::crypto::{aes_ecb_decrypt, aes_g}; use super::types::DeviceKey; // ── Public constants ────────────────────────────────────────────────────── @@ -203,23 +203,6 @@ pub(crate) fn variant_key_data(records: &[MkbRecord]) -> Option<&[u8]> { .map(|r| r.body.as_slice()) } -// ── AES-G ──────────────────────────────────────────────────────────────── - -/// AES-G(x1, x2) = AES-128D(x1, x2) XOR x2. [C] §2.1.3 (note: uses AES-128**D**). -/// -/// The Media Key Variant chain uses AES-G to derive both the variant -/// number (`Kvn = AES-G(Kp, Nonce)`) and the Volume Unique Key -/// (`Kvu = AES-G(Km, VID)`). See [`super::keys::derive_vuk`] for the -/// classical VUK form — the math is identical, this exposes it as a -/// neutral primitive for the variant chain. -fn aes_g(x1: &[u8; 16], x2: &[u8; 16]) -> [u8; 16] { - let mut out = aes_ecb_decrypt(x1, x2); - for i in 0..16 { - out[i] ^= x2[i]; - } - out -} - // ── Subset-difference walk that exposes (Kp, uv) ────────────────────────── // `calc_v_mask` and `calc_pk_from_dk` (and the AES-G3 seed step they ride @@ -564,7 +547,8 @@ mod tests { // These three live in `super::keys` now (consolidated SD-walk helpers); // `use super::*` does not re-export the parent module's private `use` // imports, so pull them in directly for the tests below. - use super::super::keys::{aesg3, calc_pk_from_dk}; + use super::super::crypto::aesg3; + use super::super::keys::calc_pk_from_dk; #[test] fn calc_pk_from_dk_terminates_on_nonconvergent_mask() { @@ -743,7 +727,7 @@ mod tests { /// /// Returns (records, dk, planted_kp, planted_kmp). fn synthetic_variant_setup(kmp15: u8) -> (Vec, DeviceKey, [u8; 16], [u8; 16]) { - use crate::aacs::content::aes_ecb_encrypt; + use crate::aacs::crypto::aes_ecb_encrypt; // Build header. let mut mkb = vec![ diff --git a/src/decrypt.rs b/src/decrypt.rs index 1b88450..490272f 100644 --- a/src/decrypt.rs +++ b/src/decrypt.rs @@ -1129,13 +1129,13 @@ mod tests { // the per-unit key so the recovered plaintext header matches. unit[0] |= 0xC0; let header: [u8; 16] = unit[..16].try_into().unwrap(); - let derived = crate::aacs::content::aes_ecb_encrypt(unit_key, &header); + let derived = crate::aacs::crypto::aes_ecb_encrypt(unit_key, &header); let mut k = [0u8; 16]; for i in 0..16 { k[i] = derived[i] ^ header[i]; } let cipher = Aes128::new(GenericArray::from_slice(&k)); - let mut prev = crate::aacs::content::AACS_IV; + let mut prev = crate::aacs::crypto::AACS_IV; let num_blocks = (aacs::ALIGNED_UNIT_LEN - 16) / 16; for i in 0..num_blocks { let off = 16 + i * 16; diff --git a/src/disc/extract.rs b/src/disc/extract.rs index 4b718a5..dd30a0e 100644 --- a/src/disc/extract.rs +++ b/src/disc/extract.rs @@ -1101,13 +1101,13 @@ mod tests { // Flag encrypted via CPI bits (byte 0) before key derivation. unit[0] |= 0xC0; let header: [u8; 16] = unit[..16].try_into().unwrap(); - let derived = crate::aacs::content::aes_ecb_encrypt(unit_key, &header); + let derived = crate::aacs::crypto::aes_ecb_encrypt(unit_key, &header); let mut k = [0u8; 16]; for i in 0..16 { k[i] = derived[i] ^ header[i]; } let cipher = Aes128::new(GenericArray::from_slice(&k)); - let mut prev = crate::aacs::content::AACS_IV; + let mut prev = crate::aacs::crypto::AACS_IV; let blocks = (crate::aacs::ALIGNED_UNIT_LEN - 16) / 16; for i in 0..blocks { let o = 16 + i * 16; diff --git a/src/disc/mod.rs b/src/disc/mod.rs index 6423256..e765377 100644 --- a/src/disc/mod.rs +++ b/src/disc/mod.rs @@ -5220,7 +5220,8 @@ mod tests { /// unit algorithm — ECB-derive the per-unit key, then AES-CBC encrypt the /// body with the fixed AACS IV. fn encrypt_unit_for_test(clear: &[u8], uk: &[u8; 16]) -> Vec { - use crate::aacs::content::{AACS_IV, ALIGNED_UNIT_LEN}; + use crate::aacs::content::ALIGNED_UNIT_LEN; + use crate::aacs::crypto::AACS_IV; use aes::Aes128; use aes::cipher::{BlockEncrypt, KeyInit, generic_array::GenericArray}; let mut unit = clear[..ALIGNED_UNIT_LEN].to_vec(); diff --git a/src/disc/verify.rs b/src/disc/verify.rs index 3c8c33c..009d8f7 100644 --- a/src/disc/verify.rs +++ b/src/disc/verify.rs @@ -523,13 +523,13 @@ mod tests { use aes::cipher::{BlockEncrypt, KeyInit, generic_array::GenericArray}; unit[0] |= 0xC0; // CPI flag => reads as encrypted let header: [u8; 16] = unit[..16].try_into().unwrap(); - let derived = crate::aacs::content::aes_ecb_encrypt(unit_key, &header); + let derived = crate::aacs::crypto::aes_ecb_encrypt(unit_key, &header); let mut k = [0u8; 16]; for i in 0..16 { k[i] = derived[i] ^ header[i]; } let cipher = Aes128::new(GenericArray::from_slice(&k)); - let mut prev = crate::aacs::content::AACS_IV; + let mut prev = crate::aacs::crypto::AACS_IV; for i in 0..(ALIGNED_UNIT_LEN - 16) / 16 { let off = 16 + i * 16; for j in 0..16 { diff --git a/src/sector/decrypting.rs b/src/sector/decrypting.rs index d394abc..283926f 100644 --- a/src/sector/decrypting.rs +++ b/src/sector/decrypting.rs @@ -1267,13 +1267,13 @@ mod tests { // CPI bits on byte 0 so it reads as encrypted; set before key derivation. unit[0] |= 0xC0; let header: [u8; 16] = unit[..16].try_into().unwrap(); - let derived = crate::aacs::content::aes_ecb_encrypt(unit_key, &header); + let derived = crate::aacs::crypto::aes_ecb_encrypt(unit_key, &header); let mut k = [0u8; 16]; for i in 0..16 { k[i] = derived[i] ^ header[i]; } let cipher = Aes128::new(GenericArray::from_slice(&k)); - let mut prev = crate::aacs::content::AACS_IV; + let mut prev = crate::aacs::crypto::AACS_IV; let blocks = (crate::aacs::ALIGNED_UNIT_LEN - 16) / 16; for i in 0..blocks { let o = 16 + i * 16;