Deployed cc4bf19 with MkDocs version: 1.6.1

This commit is contained in:
2026-10-23 21:31:56 +00:00
parent e95917458e
commit bed0a230ce
4 changed files with 10 additions and 8 deletions
+2 -2
View File
@@ -2403,10 +2403,10 @@
</ul>
<p>unshackle pushes keys from every source, not only a local CDM. A run against a remote server that licenses with its own CDM (<code>--remote</code>) writes the keys the server returns, and <code>unshackle import</code> writes the keys it reads from an export file.</p>
<h3 id="wrong-keys-from-a-poisoned-vault">Wrong keys from a poisoned vault<a class="headerlink" href="#wrong-keys-from-a-poisoned-vault" title="Permanent link">&para;</a></h3>
<p>A public vault can return the right KID with a wrong content key. The decrypters accept a wrong content key and write noise. unshackle therefore trusts a content key from a vault only after FFmpeg decodes the decrypted track with strict error detection. For a fragmented MP4, unshackle reads from the encrypted file which fragments each KID encrypts, and FFmpeg decodes up to three windows of each KID: from its first, middle and last fragment on through the next fragments of that KID, for up to 4 seconds. A window never runs into a fragment of another KID or a clear fragment. A clear lead or a lead under another KID therefore cannot hide a wrong content key, and only the KID that fails is flagged. A KID that is not in this map, and every KID of any other file, gets one check of the whole file. FFmpeg decodes the first seconds and the last seconds. A failure there flags each of those KIDs. When a mapped KID fails, the KIDs that are not in the map get no verdict from that pass; the retry with the replaced key judges them. Content keys from a licence skip this check. A file this FFmpeg build cannot judge counts as a pass, never as a wrong content key: a codec it has no decoder for, or a header it cannot read. A pass is not proof. A wrong content key for HEVC video can decode without an error for some seconds, most often at a low resolution, and that content key passes the check. Without FFmpeg there is no check at all.</p>
<p>A public vault can return the right KID with a wrong content key. The decrypters accept a wrong content key and write noise. unshackle therefore trusts a content key from a vault only after FFmpeg decodes the decrypted track with strict error detection. For a fragmented MP4, unshackle reads from the encrypted file which fragments each KID encrypts, and FFmpeg decodes up to three windows of each KID: from its first, middle and last fragment on through the next fragments of that KID, for up to 4 seconds. A window never runs into a fragment of another KID or a clear fragment. A clear lead or a lead under another KID therefore cannot hide a wrong content key, and only the KID that fails is flagged. When every KID in the map has a content key, the map is complete, and a KID that is not in it does not encrypt this file. This file does not judge that KID; the file of its own track judges it. A KID that is not in an incomplete map, for example one with an all-zero KID, and every KID of any other file, gets one check of the whole file. FFmpeg decodes the first seconds and the last seconds. A failure there flags each of those KIDs. When a mapped KID fails, the KIDs that are not in the map get no verdict from that pass; the retry with the replaced key judges them. Content keys from a licence skip this check. A file this FFmpeg build cannot judge counts as a pass, never as a wrong content key: a codec it has no decoder for, or a header it cannot read. A pass is not proof. A wrong content key for HEVC video can decode without an error for some seconds, most often at a low resolution, and that content key passes the check. Without FFmpeg there is no check at all.</p>
<p>When the decode fails, unshackle:</p>
<ol>
<li>Flags the KID:KEY in the <code>bad_keys</code> table of every local SQLite vault, with the service and the name of the vault it came from. The pair also goes out of the service table, except in a vault marked <code>no_push</code>, where only the flag is written. A flagged pair cannot go back into a local vault from another vault, a later run, or <code>kv copy</code>. A licence that returns the pair clears the flag and stores it. An <code>API</code> vault that served the pair also gets a report; <code>HTTP</code> and <code>MySQL</code> vaults have no report route. A pair from a local vault goes to no remote vault, even when a remote vault holds the same pair.</li>
<li>Flags the KID:KEY in the <code>bad_keys</code> table of every local SQLite vault, with the service and the name of the vault it came from. The pair also goes out of the service table, except in a vault marked <code>no_push</code>, where only the flag is written. A flagged pair cannot go back into a local vault from another vault, a later run, or <code>kv copy</code>. A licence that returns the pair clears the flag and stores it. An <code>API</code> vault that served the pair gets a report only when a different content key for that KID is accepted. When the CDM returns the same content key, that vault gets no report. <code>HTTP</code> and <code>MySQL</code> vaults have no report route. A pair from a local vault goes to no remote vault, even when a remote vault holds the same pair.</li>
<li>Restores the ciphertext from a hard link it made before decryption, then asks for the content key again. Every vault lookup skips a flagged pair, so the request reaches the remaining vaults and then the CDM. A remote answer that arrived after the winning one is reused instead of queried again.</li>
<li>Removes the flag when the CDM returns the same content key, because then the decode check was wrong, not the content key. A content key from another vault is checked in its turn, and flagged as well if it also fails.</li>
</ol>