Fix cargo fmt formatting
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
max_width = 100
|
||||||
@@ -326,13 +326,11 @@ fn read_disc_key(drive: &mut Drive, agid: u8, bus_key: &[u8; 5]) -> Result<[u8;
|
|||||||
// Disc key block starts at offset 4 (skip 4-byte header)
|
// Disc key block starts at offset 4 (skip 4-byte header)
|
||||||
let disc_key_block = &mut buf[4..4 + 2048];
|
let disc_key_block = &mut buf[4..4 + 2048];
|
||||||
|
|
||||||
|
|
||||||
// XOR with reversed bus key (per libdvdcss)
|
// XOR with reversed bus key (per libdvdcss)
|
||||||
for (i, byte) in disc_key_block.iter_mut().enumerate() {
|
for (i, byte) in disc_key_block.iter_mut().enumerate() {
|
||||||
*byte ^= bus_key[4 - (i % 5)];
|
*byte ^= bus_key[4 - (i % 5)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Try each player key against each of 408 disc key entries.
|
// Try each player key against each of 408 disc key entries.
|
||||||
// Each entry in the block is the disc key encrypted with a specific player key.
|
// Each entry in the block is the disc key encrypted with a specific player key.
|
||||||
// We try all known player keys and verify by checking that two different
|
// We try all known player keys and verify by checking that two different
|
||||||
@@ -421,7 +419,6 @@ fn read_title_key(
|
|||||||
);
|
);
|
||||||
tk_result.map_err(|_| Error::CssAuthFailed)?;
|
tk_result.map_err(|_| Error::CssAuthFailed)?;
|
||||||
|
|
||||||
|
|
||||||
// Title key at bytes 5..10, byte-reversed
|
// Title key at bytes 5..10, byte-reversed
|
||||||
let mut title_key = [0u8; 5];
|
let mut title_key = [0u8; 5];
|
||||||
for i in 0..5 {
|
for i in 0..5 {
|
||||||
|
|||||||
+6
-2
@@ -204,7 +204,9 @@ pub fn crack_title_key(sector: &[u8]) -> Option<[u8; 5]> {
|
|||||||
// Padding stream (0xBE): payload is 0xFF bytes, various lengths
|
// Padding stream (0xBE): payload is 0xFF bytes, various lengths
|
||||||
for len_hi in 0u8..8 {
|
for len_hi in 0u8..8 {
|
||||||
for len_lo_top in [0x00u8, 0x80, 0xFF] {
|
for len_lo_top in [0x00u8, 0x80, 0xFF] {
|
||||||
patterns.push([0x00, 0x00, 0x01, 0xBE, len_hi, len_lo_top, 0xFF, 0xFF, 0xFF, 0xFF]);
|
patterns.push([
|
||||||
|
0x00, 0x00, 0x01, 0xBE, len_hi, len_lo_top, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +218,9 @@ pub fn crack_title_key(sector: &[u8]) -> Option<[u8; 5]> {
|
|||||||
let pts0 = if flags2 & 0x80 != 0 { 0x21u8 } else { 0x00 };
|
let pts0 = if flags2 & 0x80 != 0 { 0x21u8 } else { 0x00 };
|
||||||
// Try with several PES lengths
|
// Try with several PES lengths
|
||||||
for &len_hi in &[0x00u8, 0x07] {
|
for &len_hi in &[0x00u8, 0x07] {
|
||||||
patterns.push([0x00, 0x00, 0x01, sid, len_hi, 0x00, flags1, flags2, hdr_len, pts0]);
|
patterns.push([
|
||||||
|
0x00, 0x00, 0x01, sid, len_hi, 0x00, flags1, flags2, hdr_len, pts0,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-11
@@ -958,18 +958,15 @@ impl Disc {
|
|||||||
&& disc.content_format == ContentFormat::MpegPs
|
&& disc.content_format == ContentFormat::MpegPs
|
||||||
&& !disc.titles.is_empty()
|
&& !disc.titles.is_empty()
|
||||||
{
|
{
|
||||||
let lba = disc.titles[0]
|
let lba = disc.titles[0].extents.iter().find_map(|ext| {
|
||||||
.extents
|
let mut buf = vec![0u8; 2048];
|
||||||
.iter()
|
if session.read_sectors(ext.start_lba, 1, &mut buf).is_ok() {
|
||||||
.find_map(|ext| {
|
if crate::css::is_scrambled(&buf) {
|
||||||
let mut buf = vec![0u8; 2048];
|
return Some(ext.start_lba);
|
||||||
if session.read_sectors(ext.start_lba, 1, &mut buf).is_ok() {
|
|
||||||
if crate::css::is_scrambled(&buf) {
|
|
||||||
return Some(ext.start_lba);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None
|
}
|
||||||
});
|
None
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(lba) = lba {
|
if let Some(lba) = lba {
|
||||||
if let Ok(title_key) =
|
if let Ok(title_key) =
|
||||||
|
|||||||
+10
-3
@@ -62,7 +62,10 @@ impl Default for Mpeg2Parser {
|
|||||||
|
|
||||||
impl Mpeg2Parser {
|
impl Mpeg2Parser {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { seq_header: None, has_extension: false }
|
Self {
|
||||||
|
seq_header: None,
|
||||||
|
has_extension: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract resolution from a captured sequence header.
|
/// Extract resolution from a captured sequence header.
|
||||||
@@ -137,14 +140,18 @@ impl CodecParser for Mpeg2Parser {
|
|||||||
} else {
|
} else {
|
||||||
let mut bits = 63u32; // bits consumed so far
|
let mut bits = 63u32; // bits consumed so far
|
||||||
let intra = (data[sc + 11] & 0x02) != 0;
|
let intra = (data[sc + 11] & 0x02) != 0;
|
||||||
if intra { bits += 64 * 8; }
|
if intra {
|
||||||
|
bits += 64 * 8;
|
||||||
|
}
|
||||||
// Non-intra flag is at current bit position
|
// Non-intra flag is at current bit position
|
||||||
let byte_pos = (bits / 8) as usize;
|
let byte_pos = (bits / 8) as usize;
|
||||||
let bit_pos = 7 - (bits % 8) as u8;
|
let bit_pos = 7 - (bits % 8) as u8;
|
||||||
if sc + 4 + byte_pos < data.len() {
|
if sc + 4 + byte_pos < data.len() {
|
||||||
let non_intra = (data[sc + 4 + byte_pos] >> bit_pos) & 1 != 0;
|
let non_intra = (data[sc + 4 + byte_pos] >> bit_pos) & 1 != 0;
|
||||||
bits += 1;
|
bits += 1;
|
||||||
if non_intra { bits += 64 * 8; }
|
if non_intra {
|
||||||
|
bits += 64 * 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let total_bytes = 4 + ((bits + 7) / 8) as usize;
|
let total_bytes = 4 + ((bits + 7) / 8) as usize;
|
||||||
(sc + total_bytes).min(data.len())
|
(sc + total_bytes).min(data.len())
|
||||||
|
|||||||
+4
-8
@@ -285,8 +285,7 @@ impl crate::pes::Stream for DiscStream {
|
|||||||
dts: ps.dts.map(|d| d as i64),
|
dts: ps.dts.map(|d| d as i64),
|
||||||
data: ps.data.clone(),
|
data: ps.data.clone(),
|
||||||
};
|
};
|
||||||
if let Some((_, parser)) =
|
if let Some((_, parser)) = self.parsers.iter_mut().find(|(p, _)| *p == pid)
|
||||||
self.parsers.iter_mut().find(|(p, _)| *p == pid)
|
|
||||||
{
|
{
|
||||||
for frame in parser.parse(&pes) {
|
for frame in parser.parse(&pes) {
|
||||||
self.pending_frames.push_back(
|
self.pending_frames.push_back(
|
||||||
@@ -354,13 +353,10 @@ impl crate::pes::Stream for DiscStream {
|
|||||||
data: ps.data.clone(),
|
data: ps.data.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((_, parser)) =
|
if let Some((_, parser)) = self.parsers.iter_mut().find(|(p, _)| *p == pid) {
|
||||||
self.parsers.iter_mut().find(|(p, _)| *p == pid)
|
|
||||||
{
|
|
||||||
for frame in parser.parse(&pes) {
|
for frame in parser.parse(&pes) {
|
||||||
self.pending_frames.push_back(
|
self.pending_frames
|
||||||
crate::pes::PesFrame::from_codec_frame(track, frame),
|
.push_back(crate::pes::PesFrame::from_codec_frame(track, frame));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -100,7 +100,7 @@ impl PesAssembler {
|
|||||||
pub struct TsDemuxer {
|
pub struct TsDemuxer {
|
||||||
assemblers: Vec<PesAssembler>,
|
assemblers: Vec<PesAssembler>,
|
||||||
pid_index: Vec<i16>, // PID → index into assemblers, -1 = not tracked
|
pid_index: Vec<i16>, // PID → index into assemblers, -1 = not tracked
|
||||||
remainder: Vec<u8>, // leftover bytes from previous feed() call
|
remainder: Vec<u8>, // leftover bytes from previous feed() call
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TsDemuxer {
|
impl TsDemuxer {
|
||||||
|
|||||||
+30
-8
@@ -27,7 +27,9 @@ fn css_descramble_sector_roundtrip_via_public_api() {
|
|||||||
assert_eq!(sector[0x14] & 0x30, 0x00, "flag not cleared");
|
assert_eq!(sector[0x14] & 0x30, 0x00, "flag not cleared");
|
||||||
// Header preserved (except flag byte)
|
// Header preserved (except flag byte)
|
||||||
for i in 0..128 {
|
for i in 0..128 {
|
||||||
if i == 0x14 { continue; }
|
if i == 0x14 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
assert_eq!(sector[i], original[i], "header byte {} changed", i);
|
assert_eq!(sector[i], original[i], "header byte {} changed", i);
|
||||||
}
|
}
|
||||||
// Encrypted region modified
|
// Encrypted region modified
|
||||||
@@ -504,17 +506,33 @@ fn css_roundtrip_with_snapshot() {
|
|||||||
// Determinism: same input → same output
|
// Determinism: same input → same output
|
||||||
let mut sector2 = original.clone();
|
let mut sector2 = original.clone();
|
||||||
css::lfsr::descramble_sector(&title_key, &mut sector2);
|
css::lfsr::descramble_sector(&title_key, &mut sector2);
|
||||||
assert_eq!(§or[0x80..2048], §or2[0x80..2048], "not deterministic");
|
assert_eq!(
|
||||||
|
§or[0x80..2048],
|
||||||
|
§or2[0x80..2048],
|
||||||
|
"not deterministic"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiple key/seed combinations produce different outputs.
|
/// Multiple key/seed combinations produce different outputs.
|
||||||
#[test]
|
#[test]
|
||||||
fn css_roundtrip_multiple_keys() {
|
fn css_roundtrip_multiple_keys() {
|
||||||
let cases: &[([u8; 5], [u8; 5])] = &[
|
let cases: &[([u8; 5], [u8; 5])] = &[
|
||||||
([0x00, 0x00, 0x00, 0x00, 0x00], [0x00, 0x00, 0x00, 0x00, 0x00]),
|
(
|
||||||
([0xFF, 0xFF, 0xFF, 0xFF, 0xFF], [0xFF, 0xFF, 0xFF, 0xFF, 0xFF]),
|
[0x00, 0x00, 0x00, 0x00, 0x00],
|
||||||
([0x01, 0x02, 0x03, 0x04, 0x05], [0xAA, 0xBB, 0xCC, 0xDD, 0xEE]),
|
[0x00, 0x00, 0x00, 0x00, 0x00],
|
||||||
([0xAB, 0xCD, 0xEF, 0x01, 0x23], [0x12, 0x34, 0x56, 0x78, 0x9A]),
|
),
|
||||||
|
(
|
||||||
|
[0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
|
||||||
|
[0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[0x01, 0x02, 0x03, 0x04, 0x05],
|
||||||
|
[0xAA, 0xBB, 0xCC, 0xDD, 0xEE],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
[0xAB, 0xCD, 0xEF, 0x01, 0x23],
|
||||||
|
[0x12, 0x34, 0x56, 0x78, 0x9A],
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
@@ -529,8 +547,12 @@ fn css_roundtrip_multiple_keys() {
|
|||||||
}
|
}
|
||||||
// Different keys/seeds should produce different outputs
|
// Different keys/seeds should produce different outputs
|
||||||
for i in 0..results.len() {
|
for i in 0..results.len() {
|
||||||
for j in (i+1)..results.len() {
|
for j in (i + 1)..results.len() {
|
||||||
assert_ne!(results[i], results[j], "cases {} and {} produced same output", i, j);
|
assert_ne!(
|
||||||
|
results[i], results[j],
|
||||||
|
"cases {} and {} produced same output",
|
||||||
|
i, j
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user