Map each KID to its fragments from the ciphertext moov/moof (tenc, seig, ISM duration clock) and decode up to three windows per KID that never cross into another KID, so a clear lead cannot hide a wrong key and only the failing KID is flagged. Decode every frame (wrong-key HEVC keyframes decode clean), re-judge mid-GOP starts on keyframes, time out every FFmpeg run, and refuse to store a flagged pair again in SQLite.
2.8 KiB
Key vaults
The full guide is at Vaults. Two keys configure them.
key_vaults
- Type:
list[dict]· Default:[]
An ordered list of key-vault backends. unshackle queries them in order and reuses the
content keys instead of licensing them again. Each entry needs a type (the backend module
name) and a name, plus backend-specific keys.
type |
Purpose | Required keys | Notes |
|---|---|---|---|
SQLite |
Local SQLite database | name, path |
Loaded critically; a failure aborts the run. |
MySQL |
Remote MySQL database | name, host, database, username |
Extra keys (e.g. password, port) forwarded to pymysql. connect_timeout defaults to vault_timeout. |
API |
RESTful JSON API | name, uri, token |
Optional headers map is sent with every request. Honours vault_timeout. |
HTTP |
HTTP API with modes | name, host, one of password/api_key, and username in query mode |
api_mode: query (default), json, decrypt_labs. Honours vault_timeout. |
key_vaults:
- type: SQLite
name: Local
path: ~/.unshackle/keys.db
- type: MySQL
name: Team
host: db.example.com
database: keys
username: unshackle
password: hunter2
no_push: false
!!! note "Per-entry options"
- no_push: true makes a vault read-only (unshackle fetches content keys from it but never writes to it).
- A vault of type: API whose name contains decrypt_labs auto-fills its token from
decrypt_labs_api_key when not set inline. Vault type values are
case-sensitive module names.
- unshackle treats an all-zero content key (32 zeros) as "no key" everywhere and never
stores it.
!!! note "Bad content keys"
A content key from a vault is proven by short FFmpeg decodes of the decrypted output,
with windows inside the fragments of each KID in a fragmented MP4. A content key that
fails the decode is written to the bad_keys table of every SQLite vault with the name
of the vault that supplied it, and every vault lookup skips a flagged pair from then on. A SQLite vault also refuses to
store a flagged pair again. Only the SQLite backend stores flags; an API vault that
supplied the pair gets a report. A serve instance with
server_cdm flags a pair the same way when a remote client reports it, so a server whose
key_vaults hold no SQLite entry cannot remember a bad content key.
vault_timeout
- Type:
float· Default:10.0
Timeout in seconds for vault operations. Injected automatically into any backend whose
constructor accepts a timeout parameter (a per-vault timeout still wins). The MySQL backend
uses it as the default connect_timeout.