Skip to content

Commit

Permalink
Allow user to specify crypto_period_index, algorithm, protection_scheme
Browse files Browse the repository at this point in the history
  • Loading branch information
emarsden committed Feb 25, 2024
1 parent 08dbdfb commit cc717f2
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 23 deletions.
1 change: 1 addition & 0 deletions www-zola/content/decode.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ following <abbr title="Digital Rights Management">DRM</abbr> systems:
- <a href="https://irdeto.com/video-entertainment/multi-drm/">Irdeto</a>
- <a href="https://www.marlin-community.com/">Marlin</a>
- <a href="https://developer.huawei.com/consumer/en/hms/huawei-wiseplay/">WisePlay</a>, owned by Huawei
- The unofficial variant of Apple Fairplay that is used for DASH-like streaming by Netflix
- Common Encryption (CENC)


Expand Down
68 changes: 53 additions & 15 deletions www-zola/content/generate.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,73 @@ title = "PSSH box generator"
description = "Generate a Widevine PSSH box directly in your browser (WASM)."
+++

Note: all fields except for key ID can be left empty.
Given a Key ID and other optional arguments, this tool generates a Widevine PSSH box and encodes it
in Base 64 format.


<form>
<label data-tooltip="Key ID (32 hex characters)">Key ID
<input id="kid" type="text" minlength="32" maxlength="36"
pattern="[0-9ABCDEFabcdef]{8}-?[0-9ABCDEFabcdef]{4}-?[0-9ABCDEFabcdef]{4}-?[0-9ABCDEFabcdef]{4}-?[0-9ABCDEFabcdef]{12}" /></label>
<label>Content provider name <input id="provider" type="text"/></label>
<label>Content ID <input id="contentid" type="text"/></label>
<label>Policy <input id="policy" type="text"/></label>
<label>Crypto period index, for media using key rotation (an uint32)
<article>
<header><h3>Mandatory field</h3></header>
<label data-tooltip="Key ID (32 hex characters)">Key ID or KID (required argument)
<input id="kid" type="text" minlength="32" maxlength="36"
pattern="[0-9ABCDEFabcdef]{8}-?[0-9ABCDEFabcdef]{4}-?[0-9ABCDEFabcdef]{4}-?[0-9ABCDEFabcdef]{4}-?[0-9ABCDEFabcdef]{12}"
/>
</label>
</article>

<article>
<header><h3>Optional fields</h3>

<p>All fields below can be left blank or at their default values.</p>
</header>

<fieldset>
<legend>PSSH box version:</legend>
<input id="v0" type="radio" name="version" value="0" checked />
<label htmlFor="v0">Version 0 (recommended)</label>
<input id="v1" type="radio" name="version" value="1" />
<label htmlFor="v1">Version 1</label>
</fieldset>
<small>v0 PSSH boxes are more widely supported by Widevine license servers</small>


<label>Content provider name (optional) <input id="provider" type="text"/></label>

<label>Content ID (optional) <input id="contentid" type="text" aria-describedby="contentid-help"/>
<small id="contentid-help">An identifier supplied by a content provider, used to identify a piece of content and
derive key IDs and content keys</small>
</label>

<label>Policy (optional) <input id="policy" type="text" aria-describedby="policy-help"/>
<small id="policy-help">A policy name that refers to a stored policy in Widevine service</small></label>

<fieldset>
<legend>Encryption algorithm (optional)</legend>
<label><input type="radio" name="algorithm" value="unspecified" checked />Unspecified (recommended)</label>
<label><input type="radio" name="algorithm" value="0"/>Unencrypted (algorithm = 0)</label>
<label><input type="radio" name="algorithm" value="1"/>AES-CTR (algorithm = 1)</label>
</fieldset>

<label>Crypto period index, for media using key rotation (an uint32, optional)
<input id="crypto_period_index" type="number"/></label>

<fieldset>
<legend>Protection scheme</legend>
<label><input type="radio" name="protection_scheme" value="cenc" checked/>cenc (AES-CTR)</label>
<label><input type="radio" name="protection_scheme" value="cbc1"/>cbc1 (AES-CBC)</label>
<label><input type="radio" name="protection_scheme" value="cens"/>cens (AES-CTR subsample)</label>
<label><input type="radio" name="protection_scheme" value="cbcs"/>cbcs (AES-CBC subsample)</label>
<label><input type="radio" name="protection_scheme" value="unspecified" checked/>Unspecified</label>
<label><input type="radio" name="protection_scheme" value="CENC"/>cenc (AES-CTR)</label>
<label><input type="radio" name="protection_scheme" value="CBC1"/>cbc1 (AES-CBC)</label>
<label><input type="radio" name="protection_scheme" value="CENS"/>cens (AES-CTR subsample)</label>
<label><input type="radio" name="protection_scheme" value="CBCS"/>cbcs (AES-CBC subsample)</label>
</fieldset>
</article>

<button id="go" data-tooltip="Generate PSSH">Generate</button>
</form>

<div style="margin-top:1.5em;margin-bottom:1.5em;padding:1em" id="output"></div>

Given a Key ID, this tool generates a Widevine PSSH box and encodes it in Base 64 format.

**Privacy**: this tool is implemented in [WebAssembly](https://webassembly.org/) (WASM)
and runs fully inside your web browser (there is no server backend).



<script type="module" src="../js/generate-pssh.js"></script>
36 changes: 28 additions & 8 deletions www-zola/static/js/generate-pssh.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,35 @@ init().then(() => {

document.getElementById("go").addEventListener("click", function(e) {
e.preventDefault();
let kid = document.getElementById("kid").value.trim();
let provider = document.getElementById("provider").value.trim();
let contentid = document.getElementById("contentid").value.trim();
let policy = document.getElementById("policy").value.trim();
let crypto_period_index = document.getElementById("crypto_period_index").value.trim();
let protection_scheme = document.querySelector("input[name='protection_scheme']:checked").value;
const kid = document.getElementById("kid").value.trim();
const version_str = document.querySelector("input[name='version']:checked").value;
const provider = document.getElementById("provider").value.trim();
const contentid = document.getElementById("contentid").value.trim();
const policy = document.getElementById("policy").value.trim();
const crypto_period_idx_str = document.getElementById("crypto_period_index").value.trim();
var protection_scheme = document.querySelector("input[name='protection_scheme']:checked").value;
const algorithm_str = document.querySelector("input[name='algorithm']:checked").value;
let out = document.getElementById("output");
try {
let encoded = generate_widevine_pssh_b64([kid], provider, contentid, policy);
let version = 0;
if (version_str === "1") {
version = 1;
}
let cpi = null; // maps to None in Rust
if (crypto_period_idx_str.length > 0) {
cpi = Number(crypto_period_idx_str);
}
if (protection_scheme === "unspecified") {
protection_scheme = "";
}
let algorithm = null;
if (algorithm_str === "0") {
algorithm = 0;
} else if (algorithm_str === "1") {
algorithm = 1;
}
let encoded = generate_widevine_pssh_b64(version, [kid], provider, contentid, policy,
cpi, protection_scheme, algorithm);
out.innerHTML = "<h3>Generated PSSH in Base 64</h3>" + "<p>" + encoded;
out.style.backgroundColor = "#CCC";
} catch (e) {
Expand All @@ -38,7 +58,7 @@ function initValidation(form) {

const fields = Array.from(form.elements);
fields.forEach(field => {
if (!(field.type == "radio")) {
if (field.pattern && !(field.type == "radio")) {
field.setAttribute("aria-invalid", false);
const helpBox = document.createElement("small");
const helpId = field.id + "Helper";
Expand Down

0 comments on commit cc717f2

Please sign in to comment.