Fix CSS decryption: full key hierarchy, correct cipher tables

- Implement complete CSS key chain: bus auth → disc key → title key
- Add 31 player keys for disc key decryption
- Read disc key via READ DVD STRUCTURE format 0x02
- Read title key via REPORT KEY format 0x04
- Fix CryptKey round 1: use original scratch for term, not modified tmp1
- Fix decrypt_key: use TAB5 for LFSR1 output, TAB4 for LFSR0^invert
- Fix descramble_sector: use TAB5 for LFSR1, TAB4 for LFSR0 (no invert),
  and apply TAB1 permutation to ciphertext before XOR
- Fix title key bus XOR: forward order (bus_key[i]), not reversed
- Two-session auth: disc key and title key need separate AGID sessions
- Fix crack_key: scan across extents for scrambled sectors
- Fix TsDemuxer: dynamic PID table size for DVD PIDs
- Set max read speed after scan for DVD riplock removal
This commit is contained in:
MattJackson
2026-04-16 04:42:42 +00:00
parent 3422cbcd22
commit 65c6c8cfe0
5 changed files with 358 additions and 136 deletions
+35 -4
View File
@@ -946,11 +946,42 @@ impl Disc {
// AACS handshake (Blu-ray/UHD)
let handshake = Self::do_handshake(session, opts);
// CSS authentication (DVD) — must happen before scan reads VOB sectors.
// Harmless on BD (AGID alloc fails, no effect).
let _ = crate::css::auth::authenticate(session);
// Request max read speed — removes riplock on DVD
// (BD/UHD speed is set by firmware init, but DVD needs explicit SET CD SPEED)
session.set_speed(0xFFFF);
Self::scan_with(session, capacity, handshake, opts)
let mut disc = Self::scan_with(session, capacity, handshake, opts)?;
// CSS key extraction for DVDs (bus auth → disc key → title key).
// Must be a single auth session — can't call authenticate() separately.
if disc.css.is_none()
&& disc.content_format == ContentFormat::MpegPs
&& !disc.titles.is_empty()
{
let lba = disc.titles[0]
.extents
.iter()
.find_map(|ext| {
let mut buf = vec![0u8; 2048];
if session.read_sectors(ext.start_lba, 1, &mut buf).is_ok() {
if crate::css::is_scrambled(&buf) {
return Some(ext.start_lba);
}
}
None
});
if let Some(lba) = lba {
if let Ok(title_key) =
crate::css::auth::authenticate_and_read_title_key(session, lba)
{
disc.css = Some(crate::css::CssState { title_key });
disc.encrypted = true;
}
}
}
Ok(disc)
}
/// Scan a disc image (ISO or any SectorReader). No SCSI, no handshake.