Fix FMTS per-title resolve, extract multi-CPS keying, trailing-partial guard
- resolve_fmts_key_map: filter segments to those addressable within THIS title's extents; a title with no forensic content (menu/extras playlist, or a different clip) returns Ok(None) and takes the base Unit-Key/CPS path instead of hard-failing FmtsKeyMissing. Previously the first non-forensic title aborted the entire whole-disc sweep (resolve_content_key_map iterates every title) and blocked muxing any non-main title. - FMTS phase probe: an even/odd is_clean tie now only fails loud when BOTH halves are 0 (no clean decrypt). A both-clean tie is source-zero padding (is_clean is true for any key on all-zero content) — the key is valid, default Even, never abort the rip on a padding-heavy sample. - extract_tree: multi-CPS discs now build the exact per-CPS content map (resolve_content_key_map) instead of a blanket key-0 map that silently mis-decrypted every secondary-CPS file into garbage. Single-CPS keeps the blanket key-0 map (one key opens every unit, incl. orphan clips). - decrypt_sectors_mapped: a trailing partial unit that is inside a mapped range AND flagged encrypted in its clear seed now fails loud (a CBC fragment split across a boundary can't be decrypted) instead of being emitted as clear. New aacs_unit_seed_encrypted reads the flag on a partial. - Correct the stale decrypt_sectors doc (AACS arm now always errors; AACS decrypts only via decrypt_sectors_mapped).
This commit is contained in:
@@ -106,6 +106,23 @@ pub fn aacs_unit_encrypted(unit: &[u8], format: crate::disc::ContentFormat) -> b
|
||||
}
|
||||
}
|
||||
|
||||
/// The AACS encrypted flag from an aligned unit's CLEAR seed, readable even on a
|
||||
/// trailing PARTIAL unit (unlike [`aacs_unit_encrypted`], which requires a whole
|
||||
/// 6144-byte unit). The flag lives at a fixed low offset in the clear header, so a
|
||||
/// fragment that still contains that byte can be classified. Used to catch an
|
||||
/// encrypted unit truncated across a buffer/extent boundary — a fragment we cannot
|
||||
/// CBC-decrypt and must not emit as clear. `false` for a slice too short to hold
|
||||
/// the flag byte. Same clip-anchored-read caveat as [`aacs_unit_encrypted`].
|
||||
pub fn aacs_unit_seed_encrypted(unit: &[u8], format: crate::disc::ContentFormat) -> bool {
|
||||
use crate::disc::ContentFormat;
|
||||
match format {
|
||||
ContentFormat::BdTs => unit.first().is_some_and(|b| b & 0xC0 != 0),
|
||||
ContentFormat::MpegPs => unit
|
||||
.get(PS_SCRAMBLE_OFF)
|
||||
.is_some_and(|b| b & PS_SCRAMBLE_MASK != 0),
|
||||
}
|
||||
}
|
||||
|
||||
/// True when an aligned unit is flagged encrypted AND still looks scrambled
|
||||
/// (structure not yet restored) — i.e. genuine encrypted content NOT yet decrypted.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user