mirror of
https://github.com/freemkv/freemkv-keysources.git
synced 2026-10-07 18:13:11 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00dd77d49b | ||
|
|
fe78d7445f | ||
|
|
36fb6f0c61 | ||
|
|
1a9a3befe3 | ||
|
|
d7152e0f73 | ||
|
|
6ceb92ade9 | ||
|
|
32b24c0ba7 | ||
|
|
974c1dc664 |
@@ -1,5 +1,28 @@
|
||||
# Changelog
|
||||
|
||||
## [1.4.2] — 2026-07-15
|
||||
|
||||
Version sync with the workspace; inherits libfreemkv 1.4.2. The keydb test that
|
||||
feeds real key material into the AACS crypto was adapted to the segregated
|
||||
`decrypt_unit` + `is_clean` primitives (behaviour unchanged).
|
||||
|
||||
## [1.4.1] — 2026-07-14
|
||||
|
||||
Version sync with the workspace; inherits libfreemkv 1.4.1.
|
||||
|
||||
## [1.4.0] — 2026-07-13
|
||||
|
||||
Version sync with the workspace; inherits libfreemkv 1.4.0.
|
||||
|
||||
## [1.3.2] — 2026-07-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Unit keys carry libfreemkv's new `UnitKey.variant_number`; every source
|
||||
(keydb, online, VUK-derived) emits `0` — ordinary, non-forensic content —
|
||||
via the `UnitKey::new` constructor. No behaviour change. Inherits
|
||||
**libfreemkv 1.3.2**.
|
||||
|
||||
## [1.3.1] — 2026-07-10
|
||||
|
||||
### Licensing
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "freemkv-keysources"
|
||||
version = "1.3.1"
|
||||
version = "1.4.2"
|
||||
edition = "2024"
|
||||
rust-version = "1.86"
|
||||
license = "MIT"
|
||||
@@ -17,7 +17,7 @@ publish = false
|
||||
# The crate provides the `KeySource` trait + `Key`/`DiscInputs` types these impls fill.
|
||||
# libfreemkv is git-only now; the committed [patch.crates-io] below redirects this
|
||||
# bare version req to the libfreemkv git tag (local dev overrides it to a path).
|
||||
libfreemkv = "1.3"
|
||||
libfreemkv = "1.4"
|
||||
# OnlineSource: POST disc inputs + samples to a key service over HTTP.
|
||||
ureq = { version = "2", features = ["json"] }
|
||||
serde_json = "1"
|
||||
@@ -40,4 +40,4 @@ codegen-units = 1
|
||||
# overrides it with a path patch via the gitignored .cargo/config.toml (a
|
||||
# config-level [patch.crates-io] wins over this manifest one for the same crate).
|
||||
[patch.crates-io]
|
||||
libfreemkv = { git = "https://github.com/freemkv/libfreemkv", tag = "v1.3.1" }
|
||||
libfreemkv = { git = "https://github.com/freemkv/libfreemkv", tag = "v1.4.2" }
|
||||
|
||||
+1
-4
@@ -184,10 +184,7 @@ impl KeydbSource {
|
||||
// 1. Terminal Unit Keys stored in the entry — directly usable, no
|
||||
// derivation. Preserve the keydb's CPS numbering (idx = num - 1).
|
||||
for (num, key) in &entry.unit_keys {
|
||||
keys.push(UnitKey {
|
||||
idx: num.saturating_sub(1),
|
||||
key: *key,
|
||||
});
|
||||
keys.push(UnitKey::new(num.saturating_sub(1), *key));
|
||||
}
|
||||
|
||||
// The disc's encrypted title keys (from Unit_Key_RO.inf) — what every
|
||||
|
||||
+14
-14
@@ -1412,7 +1412,7 @@ mod tests {
|
||||
//
|
||||
// These exercise the parser (KeyDb::load) end-to-end against a real
|
||||
// keydb.cfg and feed its material into libfreemkv's AACS crypto
|
||||
// (derive_vuk / decrypt_unit_try_keys). They live here now that the
|
||||
// (derive_vuk, then decrypt_unit + is_clean_ts). They live here now that the
|
||||
// parser lives here. All are KEYDB_PATH-env-gated and no-op in CI when
|
||||
// the env is unset; they must still COMPILE.
|
||||
// ════════════════════════════════════════════════════════════════════
|
||||
@@ -1485,20 +1485,20 @@ mod tests {
|
||||
|
||||
eprintln!("Found {} entries with unit keys", candidate_entries.len());
|
||||
|
||||
// Try each entry's unit keys
|
||||
// Try each entry's unit keys: apply the key, then ask whether it opened
|
||||
// the unit (the segregated primitives — decrypt, then structural check).
|
||||
for entry in &candidate_entries {
|
||||
let keys: Vec<[u8; 16]> = entry.unit_keys.iter().map(|(_, k)| *k).collect();
|
||||
let mut unit = original.clone();
|
||||
|
||||
if let Some(res) = libfreemkv::aacs::content::decrypt_unit_try_keys(&mut unit, &keys) {
|
||||
eprintln!(
|
||||
"SUCCESS: Decrypted with entry {} ({res:?})",
|
||||
entry.disc_hash
|
||||
);
|
||||
// Count TS sync bytes
|
||||
let ts = (0..32).filter(|&i| unit[4 + i * 192] == 0x47).count();
|
||||
eprintln!(" TS sync bytes: {}/32", ts);
|
||||
return;
|
||||
for (_, key) in &entry.unit_keys {
|
||||
let mut unit = original.clone();
|
||||
libfreemkv::aacs::content::decrypt_unit(&mut unit, key);
|
||||
if libfreemkv::aacs::content::is_clean(&unit, libfreemkv::disc::ContentFormat::BdTs)
|
||||
{
|
||||
eprintln!("SUCCESS: Decrypted with entry {}", entry.disc_hash);
|
||||
// Count TS sync bytes
|
||||
let ts = (0..32).filter(|&i| unit[4 + i * 192] == 0x47).count();
|
||||
eprintln!(" TS sync bytes: {}/32", ts);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -47,10 +47,7 @@ pub(crate) fn uks_from_vuk(vuk: &[u8; 16], enc_title_keys: &[[u8; 16]]) -> Vec<U
|
||||
enc_title_keys
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, e)| UnitKey {
|
||||
idx: i as u32,
|
||||
key: libfreemkv::aacs::derive::decrypt_unit_key(vuk, e),
|
||||
})
|
||||
.map(|(i, e)| UnitKey::new(i as u32, libfreemkv::aacs::derive::decrypt_unit_key(vuk, e)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -306,7 +306,7 @@ impl OnlineSource {
|
||||
// A terminal UK is used directly (CPS unit 0 → committed cps 1, matching
|
||||
// the old `Key::Unit(vec![(1, uk)])`).
|
||||
if let Some(uk) = json.get("UK").and_then(|u| u.as_str()).and_then(parse_uk) {
|
||||
return vec![UnitKey { idx: 0, key: uk }];
|
||||
return vec![UnitKey::new(0, uk)];
|
||||
}
|
||||
// A VUK is derived to the terminal keys locally, via the disc's
|
||||
// encrypted title keys from the context — the library owns the crypto.
|
||||
|
||||
@@ -267,10 +267,7 @@ impl KeySource for ScriptedSource {
|
||||
}
|
||||
|
||||
fn uk(b: u8) -> UnitKey {
|
||||
UnitKey {
|
||||
idx: 0,
|
||||
key: [b; 16],
|
||||
}
|
||||
UnitKey::new(0, [b; 16])
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user