Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28bc965fa1 | ||
|
|
c81cc5ccaa | ||
|
|
03765184c8 | ||
|
|
827d757a7a | ||
|
|
e123455861 | ||
|
|
cf7e01f90c | ||
|
|
b67d290f3e | ||
|
|
4f6029e4d4 | ||
|
|
46fecaeef1 | ||
|
|
5f973293c0 |
@@ -1,5 +1,37 @@
|
|||||||
# Changelog
|
# 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
|
||||||
|
|
||||||
|
- **Relicensed to the MIT License, from 1.3.1 onwards** (releases up to and
|
||||||
|
including 1.3.0 remain under AGPL-3.0).
|
||||||
|
|
||||||
|
Version sync with the workspace; inherits libfreemkv 1.3.1.
|
||||||
|
|
||||||
## [1.3.0] — 2026-07-08
|
## [1.3.0] — 2026-07-08
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "freemkv-keysources"
|
name = "freemkv-keysources"
|
||||||
version = "1.3.0"
|
version = "1.4.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.86"
|
rust-version = "1.86"
|
||||||
license = "AGPL-3.0-only"
|
license = "MIT"
|
||||||
description = "Pluggable AACS key sources (keydb, online key service) for libfreemkv. Each source looks a disc up and hands libfreemkv its terminal Unit Keys via get_uk; the library does all derivation."
|
description = "Pluggable AACS key sources (keydb, online key service) for libfreemkv. Each source looks a disc up and hands libfreemkv its terminal Unit Keys via get_uk; the library does all derivation."
|
||||||
repository = "https://github.com/freemkv/freemkv-keysources"
|
repository = "https://github.com/freemkv/freemkv-keysources"
|
||||||
keywords = ["aacs", "blu-ray", "uhd", "decryption", "keydb"]
|
keywords = ["aacs", "blu-ray", "uhd", "decryption", "keydb"]
|
||||||
@@ -17,7 +17,7 @@ publish = false
|
|||||||
# The crate provides the `KeySource` trait + `Key`/`DiscInputs` types these impls fill.
|
# 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
|
# 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).
|
# 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.
|
# OnlineSource: POST disc inputs + samples to a key service over HTTP.
|
||||||
ureq = { version = "2", features = ["json"] }
|
ureq = { version = "2", features = ["json"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
@@ -40,4 +40,4 @@ codegen-units = 1
|
|||||||
# overrides it with a path patch via the gitignored .cargo/config.toml (a
|
# 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).
|
# config-level [patch.crates-io] wins over this manifest one for the same crate).
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
libfreemkv = { git = "https://github.com/freemkv/libfreemkv", tag = "v1.3.0" }
|
libfreemkv = { git = "https://github.com/freemkv/libfreemkv", tag = "v1.4.2" }
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Matthew Jackson & Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
+1
-4
@@ -184,10 +184,7 @@ impl KeydbSource {
|
|||||||
// 1. Terminal Unit Keys stored in the entry — directly usable, no
|
// 1. Terminal Unit Keys stored in the entry — directly usable, no
|
||||||
// derivation. Preserve the keydb's CPS numbering (idx = num - 1).
|
// derivation. Preserve the keydb's CPS numbering (idx = num - 1).
|
||||||
for (num, key) in &entry.unit_keys {
|
for (num, key) in &entry.unit_keys {
|
||||||
keys.push(UnitKey {
|
keys.push(UnitKey::new(num.saturating_sub(1), *key));
|
||||||
idx: num.saturating_sub(1),
|
|
||||||
key: *key,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The disc's encrypted title keys (from Unit_Key_RO.inf) — what every
|
// 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
|
// These exercise the parser (KeyDb::load) end-to-end against a real
|
||||||
// keydb.cfg and feed its material into libfreemkv's AACS crypto
|
// 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
|
// parser lives here. All are KEYDB_PATH-env-gated and no-op in CI when
|
||||||
// the env is unset; they must still COMPILE.
|
// the env is unset; they must still COMPILE.
|
||||||
// ════════════════════════════════════════════════════════════════════
|
// ════════════════════════════════════════════════════════════════════
|
||||||
@@ -1485,20 +1485,20 @@ mod tests {
|
|||||||
|
|
||||||
eprintln!("Found {} entries with unit keys", candidate_entries.len());
|
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 {
|
for entry in &candidate_entries {
|
||||||
let keys: Vec<[u8; 16]> = entry.unit_keys.iter().map(|(_, k)| *k).collect();
|
for (_, key) in &entry.unit_keys {
|
||||||
let mut unit = original.clone();
|
let mut unit = original.clone();
|
||||||
|
libfreemkv::aacs::content::decrypt_unit(&mut unit, key);
|
||||||
if let Some(res) = libfreemkv::aacs::content::decrypt_unit_try_keys(&mut unit, &keys) {
|
if libfreemkv::aacs::content::is_clean(&unit, libfreemkv::disc::ContentFormat::BdTs)
|
||||||
eprintln!(
|
{
|
||||||
"SUCCESS: Decrypted with entry {} ({res:?})",
|
eprintln!("SUCCESS: Decrypted with entry {}", entry.disc_hash);
|
||||||
entry.disc_hash
|
// Count TS sync bytes
|
||||||
);
|
let ts = (0..32).filter(|&i| unit[4 + i * 192] == 0x47).count();
|
||||||
// Count TS sync bytes
|
eprintln!(" TS sync bytes: {}/32", ts);
|
||||||
let ts = (0..32).filter(|&i| unit[4 + i * 192] == 0x47).count();
|
return;
|
||||||
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
|
enc_title_keys
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, e)| UnitKey {
|
.map(|(i, e)| UnitKey::new(i as u32, libfreemkv::aacs::derive::decrypt_unit_key(vuk, e)))
|
||||||
idx: i as u32,
|
|
||||||
key: libfreemkv::aacs::derive::decrypt_unit_key(vuk, e),
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -306,7 +306,7 @@ impl OnlineSource {
|
|||||||
// A terminal UK is used directly (CPS unit 0 → committed cps 1, matching
|
// A terminal UK is used directly (CPS unit 0 → committed cps 1, matching
|
||||||
// the old `Key::Unit(vec![(1, uk)])`).
|
// the old `Key::Unit(vec![(1, uk)])`).
|
||||||
if let Some(uk) = json.get("UK").and_then(|u| u.as_str()).and_then(parse_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
|
// A VUK is derived to the terminal keys locally, via the disc's
|
||||||
// encrypted title keys from the context — the library owns the crypto.
|
// encrypted title keys from the context — the library owns the crypto.
|
||||||
|
|||||||
@@ -267,10 +267,7 @@ impl KeySource for ScriptedSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn uk(b: u8) -> UnitKey {
|
fn uk(b: u8) -> UnitKey {
|
||||||
UnitKey {
|
UnitKey::new(0, [b; 16])
|
||||||
idx: 0,
|
|
||||||
key: [b; 16],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user