mirror of
https://github.com/freemkv/freemkv-keysources.git
synced 2026-10-07 18:13:11 +00:00
test: assert full key bytes; correct keydb-format docs
Several tests asserted only key[0] (the first byte), which a byte-transposition bug could pass — assert the full 16-byte key everywhere, including a KAT that recomputes the expected VUK-derived keys directly. test_parse_disc_entry used identical all-zero placeholders for M/I/V/U, which couldn't catch a field mix-up; give each field a distinct byte pattern and assert every field. Docs: keydb-format.md claimed DiscEntry::title was genuinely unused dead code, but it's read by to_keydb_cfg and the redacting Debug impl — correct the comment to only list empty/find_vuk as truly unused. Also cross-reference the two independent MAX_KEYDB_BYTES constants (keydb.rs's decompression cap and keydb_format.rs's on-disk load cap) so they're kept in sync, and bump Cargo.lock's version metadata.
This commit is contained in:
Generated
+5
-5
@@ -306,7 +306,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "freemkv-keysources"
|
||||
version = "1.6.14"
|
||||
version = "1.7.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"flate2",
|
||||
@@ -319,7 +319,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "freemkv-unlock"
|
||||
version = "1.6.14"
|
||||
version = "1.7.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"base64",
|
||||
@@ -534,7 +534,7 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "libfreemkv"
|
||||
version = "1.6.14"
|
||||
version = "1.7.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"base64",
|
||||
@@ -1271,8 +1271,8 @@ dependencies = [
|
||||
|
||||
[[patch.unused]]
|
||||
name = "freemkv-engine"
|
||||
version = "1.6.14"
|
||||
version = "1.7.0"
|
||||
|
||||
[[patch.unused]]
|
||||
name = "freemkv-i18n"
|
||||
version = "1.6.14"
|
||||
version = "1.7.0"
|
||||
|
||||
@@ -10,10 +10,12 @@ revision of this comment cited a `candidates_from` function — no such
|
||||
function has ever existed in this crate; the real consumer is
|
||||
`KeydbSource::unit_keys_from` (keydb.rs), which reads `unit_keys`, `vuk`,
|
||||
`media_key` AND `vid` (`vid` is load-bearing for the MK+VID derivation the
|
||||
kat_c / kat_d KATs pin — it is NOT unused). The genuinely unused items —
|
||||
`empty`, `find_vuk`, `DiscEntry::title` — are part of the faithful copy and
|
||||
are retained rather than pruned; allow dead_code so the byte-for-byte copy
|
||||
compiles clean without diverging from the libfreemkv original.
|
||||
kat_c / kat_d KATs pin — it is NOT unused). `DiscEntry::title` is likewise
|
||||
read — by `to_keydb_cfg` and the redacting `Debug` impl — so it is not
|
||||
unused either. The genuinely unused items — `empty` and `find_vuk` — are
|
||||
part of the faithful copy and are retained rather than pruned; allow
|
||||
dead_code so the byte-for-byte copy compiles clean without diverging from
|
||||
the libfreemkv original.
|
||||
|
||||
## ParseStats — what `KeyDb::parse` threw away
|
||||
|
||||
|
||||
+3
-3
@@ -21,9 +21,9 @@ use libfreemkv::{Error, KeySource};
|
||||
|
||||
use crate::keydb_format::KeyDb;
|
||||
|
||||
// Upper bound on decompressed keydb size: caps a decompression bomb (a tiny
|
||||
// zip/gz could otherwise inflate to GiB and OOM the daily refresh thread).
|
||||
// The public UHD keydb is ~62 MiB and growing; 128 MiB leaves headroom.
|
||||
// Upper bound on decompressed keydb size (decompression-bomb cap): a tiny
|
||||
// zip/gz could otherwise inflate to GiB and OOM the refresh thread. Mirrors
|
||||
// keydb_format::MAX_KEYDB_BYTES (the on-disk load cap); keep the two equal.
|
||||
const MAX_KEYDB_BYTES: u64 = 128 * 1024 * 1024;
|
||||
|
||||
/// Result of a KEYDB save/update -- path written, entry count, and byte size.
|
||||
|
||||
+15
-10
@@ -17,9 +17,9 @@ use libfreemkv::aacs::types::{DeviceKey, HostCert};
|
||||
/// A keydb per-disc unit key: the CPS-unit number paired with its 16-byte key.
|
||||
pub type NumberedUnitKey = (u32, [u8; 16]);
|
||||
|
||||
// Upper bound on the on-disk keydb.cfg size accepted by `KeyDb::load`. The
|
||||
// public UHD keydb is ~62 MiB and growing; 128 MiB bounds worst-case
|
||||
// allocation from a hostile or corrupt file.
|
||||
// Upper bound on the on-disk keydb.cfg size accepted by `KeyDb::load` (the
|
||||
// public UHD keydb is ~62 MiB; 128 MiB bounds a hostile/corrupt file).
|
||||
// Mirror of keydb.rs's MAX_KEYDB_BYTES decompression cap; keep them equal.
|
||||
const MAX_KEYDB_BYTES: u64 = 128 * 1024 * 1024;
|
||||
|
||||
/// Upper bound on parsed disc entries. The real public keydb carries
|
||||
@@ -1017,18 +1017,23 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_parse_disc_entry() {
|
||||
// All-zero placeholders — synthetic; no real key material in code.
|
||||
// Synthetic placeholders, DISTINCT per field so a field mix-up (M read
|
||||
// as V, I as U, …) is caught — no real key material in code.
|
||||
let z40 = "00".repeat(20);
|
||||
let z32 = "00".repeat(16);
|
||||
let mk = "11".repeat(16);
|
||||
let id = "22".repeat(16);
|
||||
let vuk = "33".repeat(16);
|
||||
let uk = "44".repeat(16);
|
||||
let line = format!(
|
||||
"0x{z40} = SAMPLE_FILM (Sample Film) | D | 2024-01-01 | M | 0x{z32} | I | 0x{z32} | V | 0x{z32} | U | 1-0x{z32} ; MKBv77"
|
||||
"0x{z40} = SAMPLE_FILM (Sample Film) | D | 2024-01-01 | M | 0x{mk} | I | 0x{id} | V | 0x{vuk} | U | 1-0x{uk} ; MKBv77"
|
||||
);
|
||||
let entry = KeyDb::parse_disc_entry(&line).unwrap();
|
||||
assert_eq!(entry.title, "SAMPLE_FILM (Sample Film)"); // faithful, verbatim
|
||||
assert!(entry.media_key.is_some());
|
||||
assert!(entry.vuk.is_some());
|
||||
assert_eq!(entry.unit_keys.len(), 1);
|
||||
assert_eq!(entry.unit_keys[0].0, 1);
|
||||
assert_eq!(entry.media_key, Some([0x11u8; 16]), "M field");
|
||||
assert_eq!(entry.vid, Some([0x22u8; 16]), "I field");
|
||||
assert_eq!(entry.vuk, Some([0x33u8; 16]), "V field");
|
||||
assert_eq!(entry.unit_keys, vec![(1u32, [0x44u8; 16])], "U field");
|
||||
assert_eq!(entry.mkb_version, Some(77));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+27
-3
@@ -1049,8 +1049,16 @@ mod tests {
|
||||
assert_eq!(keys.len(), 2);
|
||||
assert_eq!(keys[0].idx, 0);
|
||||
assert_eq!(keys[1].idx, 1);
|
||||
assert_eq!(keys[0].key[0], 0x00);
|
||||
assert_eq!(keys[1].key[0], 0x0f);
|
||||
// Full 16 bytes of each key, not just byte 0 — a byte-transposition bug
|
||||
// would pass a first-byte-only check.
|
||||
assert_eq!(
|
||||
keys[0].key,
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
||||
);
|
||||
assert_eq!(
|
||||
keys[1].key,
|
||||
[15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
|
||||
);
|
||||
}
|
||||
|
||||
/// Backward-compatible form: `"UK"` as a bare hex STRING (not an array)
|
||||
@@ -1065,7 +1073,11 @@ mod tests {
|
||||
.expect("a string UK must still resolve");
|
||||
assert_eq!(keys.len(), 1);
|
||||
assert_eq!(keys[0].idx, 0);
|
||||
assert_eq!(keys[0].key[0], 0x00);
|
||||
// Full 16-byte key, not just byte 0.
|
||||
assert_eq!(
|
||||
keys[0].key,
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
||||
);
|
||||
}
|
||||
|
||||
// A malformed `"UK"` STRING falls through to the genuine-miss path,
|
||||
@@ -1117,6 +1129,12 @@ mod tests {
|
||||
);
|
||||
assert_eq!(keys[0].idx, 0);
|
||||
assert_eq!(keys[1].idx, 1);
|
||||
// Full-byte KAT: the derived keys must equal the local VUK boil over
|
||||
// the disc's encrypted title keys (the same primitive the code calls).
|
||||
let vuk = parse_uk(vuk_hex).unwrap();
|
||||
let expected = crate::uks_from_vuk(&vuk, &[[0x11u8; 16], [0x22u8; 16]]);
|
||||
assert_eq!(keys[0].key, expected[0].key);
|
||||
assert_eq!(keys[1].key, expected[1].key);
|
||||
}
|
||||
|
||||
/// The service answered correctly with a VUK, but the DISC's encrypted
|
||||
@@ -1289,6 +1307,12 @@ mod tests {
|
||||
let keys = interpret_reply(Ok(reply(200, &at_cap)), &BareCtx, 1)
|
||||
.expect("a reply exactly at the cap is legal and must be read");
|
||||
assert_eq!(keys.len(), 1, "the key in an at-cap reply must survive");
|
||||
// The surviving key must be the planted UK bytes, not merely present.
|
||||
assert_eq!(
|
||||
keys[0].key,
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
"the at-cap key must be the exact planted UK"
|
||||
);
|
||||
}
|
||||
|
||||
// ── A bad port is CONFIG, not an outage ────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user