freemkv-keysources: new crate — KeydbSource + ordered-resolve helper
The published key-source layer for libfreemkv. libfreemkv does no lookup; it is handed a Key and derives down. This crate provides the KeySource impls that do the lookup and hand a Key in. Applications choose and order the sources. This first cut ships: - KeydbSource: parses a local keydb.cfg and enumerates its material as ordered candidate keys (per-disc VUK/unit/media first, then the universal device-key, processing-key, and media-key pools). It does no derivation — the library walks the MKB and verifies media keys. Candidate ordering lets the library try each path a keydb can satisfy. - resolve_first: tries each source's candidates in order and returns the first the caller's validator accepts (validate-before-return), so a stale entry falls through to the next source. OnlineSource (remote key service) and MapfileSource (cached unit key) land with the application wiring, where the sample-read and mapfile paths already live.
This commit is contained in:
+56
@@ -0,0 +1,56 @@
|
||||
//! Pluggable AACS key sources for libfreemkv.
|
||||
//!
|
||||
//! libfreemkv performs no key lookup — it is handed a [`Key`] and derives down
|
||||
//! the AACS chain to decrypt. This crate provides the published [`KeySource`]
|
||||
//! implementations that do the lookup:
|
||||
//!
|
||||
//! - [`KeydbSource`] — a local `keydb.cfg` (source #1).
|
||||
//! - `OnlineSource` — a remote key service (source #2). *(added with the app wiring)*
|
||||
//! - `MapfileSource` — the persisted unit key from a rip mapfile (source #3).
|
||||
//!
|
||||
//! Applications (autorip, the `freemkv` CLI) choose and order the sources from
|
||||
//! their own config — the local-vs-online policy is just which impls they plug
|
||||
//! in — then resolve and hand the resulting key to `Disc::decrypt_with`.
|
||||
//!
|
||||
//! Sources are dumb: they enumerate the raw material they hold as candidate
|
||||
//! keys and do NO derivation or validation. The caller tries the candidates in
|
||||
//! order and keeps the first that decrypts a sample ([`resolve_first`]).
|
||||
|
||||
mod keydb;
|
||||
|
||||
pub use keydb::KeydbSource;
|
||||
|
||||
// Re-exported for downstream convenience so apps need only depend on this crate
|
||||
// for the source-side types.
|
||||
pub use libfreemkv::{DiscInputs, Key, KeySource};
|
||||
|
||||
use libfreemkv::Result;
|
||||
|
||||
/// Try each source's candidate keys in order and return the first that the
|
||||
/// `accept` predicate approves — the *validate-before-return* policy.
|
||||
///
|
||||
/// `accept` is the caller's validation (typically: clone the disc, apply the
|
||||
/// key with `Disc::decrypt_with`, decrypt a sample sector, and check it looks
|
||||
/// like cleartext). It lives with the caller because only the caller can read
|
||||
/// disc content. A stale or wrong candidate is rejected and the next is tried,
|
||||
/// so a wrong keydb entry transparently falls through to the next source.
|
||||
///
|
||||
/// `Ok(None)` means no source offered a candidate the validator accepted; an
|
||||
/// `Err` from any source's `resolve` is propagated.
|
||||
pub fn resolve_first<F>(
|
||||
sources: &[&dyn KeySource],
|
||||
inputs: &DiscInputs,
|
||||
mut accept: F,
|
||||
) -> Result<Option<Key>>
|
||||
where
|
||||
F: FnMut(&Key) -> bool,
|
||||
{
|
||||
for src in sources {
|
||||
for key in src.resolve(inputs)? {
|
||||
if accept(&key) {
|
||||
return Ok(Some(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
Reference in New Issue
Block a user