aacs: parse HD DVD VTKF title keys at the spec's 36-byte stride
The HD DVD Title Key File (VTKF*.AACS) stores 64 title-key entries of 36 bytes each — 1-byte BIFO + 3 reserved + 16-byte encrypted key + 16-byte binding MAC — per AACS "HD DVD and DVD Pre-recorded Book" Table 3-8, confirmed byte-exact against real discs (Freedom VTKF090, Dukes VTKF000: every 36-byte slot has BIFO=0x80, a clean key, and a 0xFF binding MAC). The parser used a 32-byte stride (a 12-byte pad in place of the 16-byte binding MAC) with flag-based termination. That aligns entry #1 (key at offset 132, where both strides agree) but drifts +4 bytes per entry after it and never terminates (the previous entry's 0xFF MAC reads as a set present-flag), so it recovered a correct key only for single-CPS-unit discs and garbage for CPS unit >=2. Every multi-title HD DVD (Freedom, Harry Potter) was affected. Fix: 36-byte stride, iterate the fixed 64 slots, take slots whose BIFO AV_FLG (bit 7) is set, key at offset 4, slot index = CPS unit (skip empty slots rather than terminate so a gap can't renumber later keys), and never read the trailing 16-byte TKF MAC as a key. Tests rebuilt on the real layout, including a full 64-entry file. Also correct the VTKF-selection TODO in mod.rs: the AACS HD DVD Book gives the selector explicitly (match the TKF's PLAYLIST_NAME field to the active playlist), not the "validate against an encrypted unit" placeholder. Reconciled against the new HD DVD reference (freemkv.org/docs/hddvd/); the spec source is archived in freemkv-private/spec/.
This commit is contained in:
+10
-6
@@ -126,12 +126,16 @@ pub(crate) fn role_paths(udf: &crate::udf::UdfFs, role: AacsRole) -> Vec<String>
|
||||
// VTKF000 (Freedom ships VTKF090 + VTKF100). Sorted for a
|
||||
// deterministic try order.
|
||||
//
|
||||
// TODO(hddvd-encrypted): when a disc carries MULTIPLE VTKF
|
||||
// variants, the CORRECT one is chosen by validating its
|
||||
// VUK-derived key against a real encrypted unit — not by
|
||||
// first-that-reads (all read). Wire that selection here once a
|
||||
// genuinely encrypted HD DVD image exists to validate against
|
||||
// (see `content::aacs_unit_encrypted` UNVERIFIED-HDDVD-DECRYPT).
|
||||
// TODO(hddvd-playlist): each VTKF%%%.AACS is bound to ONE
|
||||
// playlist (VPLST%%%.XPL) — the AACS HD DVD Book gives the
|
||||
// selector explicitly: match the TKF's 12-byte PLAYLIST_NAME
|
||||
// field (bytes 0x10..0x1C) to the playlist of the title being
|
||||
// decrypted; "unless the names are identical, the Title Keys in
|
||||
// this TKF must not be used." Today read_first just takes the
|
||||
// first that reads, which is correct only for a single-playlist
|
||||
// disc. Thread the active playlist name here (owned by the HD
|
||||
// DVD enumerator) and pick the name-matched VTKF once a
|
||||
// multi-playlist encrypted disc is available to validate against.
|
||||
let mut names: Vec<&str> = dir
|
||||
.entries
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user