pycenc
Pure-Python CENC (Common Encryption) decryptor for fragmented MP4.
pycenc decrypts cenc-encrypted DASH/fragmented MP4 files (the scheme used by Widevine, PlayReady, and ClearKey) using a content key you already have. It is a pure-Python alternative to Bento4's mp4decrypt — no compiled dependencies, just the cryptography library.
What this is: an implementation of ISO/IEC 23001-7 (CENC) — a published standard for common encryption of fragmented MP4. It performs standard AES-128-CTR decryption given a content key.
What this is not: it does not obtain keys. There is no CDM, no key exchange, no license server, no network access. You supply the key; the library does the crypto. (Obtaining keys from a DRM system is a separate concern this library does not address.)
Install
pip install pycenc
# or, from source:
uv tool install . # or: pip install .
CLI
# file -> file (mp4decrypt-style)
pycenc --key KID:KEY input.m4s output.mp4
# streaming: stdin -> stdout (for live pipelines)
producer | pycenc --stream --key KID:KEY | consumer
# equivalent:
pycenc --key KID:KEY - -
Because decryption is a streaming transform with bounded memory, pycenc
fits directly into a pipeline: yt-dlp | pycenc --stream | ffmpeg | vlc.
The output begins before the input is fully downloaded.
Library
from pycenc import decrypt_bytes, decrypt_file, decrypt_stream
# in-memory (whole file)
with open("encrypted.m4s", "rb") as f:
data = f.read()
clear = decrypt_bytes(key_bytes, data) # -> bytes
# file-based
with open("encrypted.m4s", "rb") as fi, open("decrypted.mp4", "wb") as fo:
decrypt_file(key_bytes, fi, fo)
# streaming (bounded memory; stdin/stdout, pipes, live pipelines)
decrypt_stream(key_bytes, input_stream, output_stream)
key_bytes is a 16-byte AES-128 content key.
How it works
- Walks the ISO BMFF box tree (
moov/trak/moof/traf/mdat) without external parsers. - For each fragment, reads the
sencbox (per-sample IVs + subsample split) and thetrunbox (sample sizes), then decrypts each sample's encrypted bytes with AES-128-CTR. - Auto-detects the IV size (8 or 16 bytes) and whether subsample encryption is used — some files in the wild carry non-compliant
sencflags ortencreportingper_sample_iv_size=0, so detection validates each interpretation against the box length rather than trusting the flags. - Produces a clean, muxable MP4: strips the CENC boxes (
sinf/senc/saiz/saio/pssh), restores sample-entry types (encv→avc1,enca→mp4a), recomputes box sizes, and fixestrun.data_offset. The output opens directly in ffmpeg and standard players.
Supported
| Scheme | Status |
|---|---|
cenc (AES-CTR, full-sample & subsample) |
✅ |
cbcs (pattern, AES-CBC) |
planned |
cens (partial, AES-CTR) |
planned |
| Feature | Status |
|---|---|
| Single content key per file | ✅ |
| Multi-key (per-track KID matching) | planned |
Limitations
- Single content key per file (the common case). Multi-key support is planned.
cencscheme only for now;cbcs/censare on the roadmap.decrypt_bytesloads the whole file into memory; usedecrypt_stream(ordecrypt_file, which streams internally) for pipes and large files.
License
MIT — see LICENSE.
Release files for pycenc 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pycenc-0.2.0.tar.gz | 10.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pycenc-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.1 kB
Release files / pycenc-0.2.0.tar.gz
| Download URL | pycenc-0.2.0.tar.gz |
|---|---|
| Size | 10.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4c8a4212a36a12663a34595f2b3b7f2cdac7e9ba472b885d9e136c2ea90605fa
|
|
BLAKE2b-256 checksum How to use checksums |
ea85c8a332441c6b641a7a0e31dfa808e967c74af85ee0b5a5a22b6fb6926de9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / pycenc-0.2.0-py3-none-any.whl
| Download URL | pycenc-0.2.0-py3-none-any.whl |
|---|---|
| Size | 13.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
22d6ca9cf9d0269188f428dfd093bc90e2b3f628e1bd35a021734635913b7d50
|
|
BLAKE2b-256 checksum How to use checksums |
b22d9f4e7520443b3c079d2b2da9a5b27917aa0d1fe170422130a1f85f513467
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|