Harden the decryptors against corrupt/edge-case input so a single bad file
errors cleanly instead of panicking (and, in a batch, aborting the whole run):
* ADEPT EPUB: the content-decrypt guard was `len < 16` but then sliced off the
16-byte pad block before reading the trailing pad length; a one-block (16-byte)
ciphertext left an empty slice and panicked on `.last().unwrap()`. Guard is
now `len <= 16`.
* MOBI: validate the section table before indexing it — require >= 2 sections
and reject a record count that exceeds the section count, preventing
out-of-bounds panics on `section_offsets[1]` / `section_bounds(i)`.
* MOBI: `trailing_size` now uses saturating/checked subtraction, and the caller
clamps the trailing size to the record length, so a corrupt trailing-size
encoding can't underflow.
* MOBI: `normalize_pids` slices PIDs by characters, not bytes, so a non-ASCII
`--pid` can't panic on a non-char-boundary.
* CLI: wrap the per-file decrypt in `catch_unwind` so any future panic is
contained to that file rather than aborting a multi-file run.
Adds 5 regression tests (one per fix). 46 lib tests pass; clippy + fmt clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace specific ASINs, the book title, and the license voucher GUID with
generic placeholders ahead of making the repo public. No technical content
changes (the format census, vault structure, and analysis are unaffected).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Investigated decrypting the My Kindle Content library and automating Kindle
key extraction. Census: 14 KFX, 1 Topaz, 1 MOBI (crypto_type 2) — all 16
account-locked, none decryptable without the Kindle account key.
That key is only in the modern Store/UWP vault: .kinf2024 (char-encoded, no
"/" records) plus main_shared.blob/.salt/.sha256. The blob is NOT a DPAPI blob
and there is no registry entry, no .kinf2018, and no plaintext token file, so
the key cannot be recovered by static file inspection — it would need dynamic
analysis of the UWP app. The realistic workaround (use Kindle for PC <=1.39,
which writes .kinf2018) and the achievable port work it would unlock are
recorded in docs/kfx2024-decryption-effort.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Investigated decrypting a real Microsoft Store Kindle book (KFX). Found the
content is a loose DRMION container with a sibling .voucher, and the account
key material lives in .kinf2024 — a key store newer than and structurally
different from the .kinf2018 that DeDRM supports (zero "/" record separators;
not a version bump). No DeDRM/community support exists for .kinf2024.
The blocker is the key, not KFX itself: without the account DSN/secret the
voucher (and thus the book) cannot be decrypted or tested. Reverse-engineering
.kinf2024 is novel work outside the "port DeDRM" premise, so per decision the
findings, evidence, and a two-part follow-up plan (KFX engine port + .kinf2024
RE) are captured in docs/kfx2024-decryption-effort.md rather than implemented.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On Windows, recover the Adobe ADEPT user key from an installed/activated
Adobe Digital Editions and use it automatically, so ADEPT EPUBs decrypt
with no --key argument. Ported from adobekey.py:
* Build the DPAPI entropy byte-for-byte: system-volume serial number,
CPUID leaf-0 vendor (EBX|EDX|ECX) and leaf-1 signature, and the ADE
username, packed as ">I12s3s13s".
* CryptUnprotectData (DPAPI) recovers the key-encryption-key from the
HKCU\Software\Adobe\Adept\Device "key" value, then each per-credential
privateLicenseKey under ...\Activation is AES-128-CBC decrypted and the
DER RSA key taken from byte 26 onward.
Decryption now lazily auto-extracts and retries when no supplied key fits,
and newly found keys are written back to the TOML config so later runs are
offline. Uses the `windows` (DPAPI/volume info) and `winreg` crates behind
cfg(windows); pure-Rust crypto unchanged.
Verified end-to-end on a real ADEPT EPUB: the key was extracted from the
local ADE and the book decrypted to a valid, DRM-free EPUB (rights.xml and
encryption.xml removed, content readable).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DRMLibre is a standalone, single-binary Rust CLI that removes DRM from
Amazon Kindle and Adobe Digital Editions ebooks. The decryption logic is
ported from DeDRM_tools (GPLv3); this project is GPL-3.0-or-later.
This commit covers the first three milestones of the plan:
* Phase 0 - workspace scaffold (drmlibre-core engine + drmlibre-cli),
native TOML config, magic-byte/zip-content format detection, and the
remove/passhash/config CLI surface with atomic output handling.
* Phase 1 - Adobe ADEPT EPUB: RSA (PKCS#1 v1.5) and PassHash book-key
unwrap, RMSDK>=10 hardening, AES-128-CBC content decryption, and IETF/
Adobe font de-obfuscation. Verified end-to-end with a real RSA key.
* Phase 2 - Kindle MOBI/AZW/AZW3: PC1 cipher, type-1 and type-2 DRM,
serial->PID derivation, EXTH header patches, and trailing-data handling.
Verified end-to-end and against the upstream golden vectors.
All crypto is pure Rust (RustCrypto), so the release binary has no
third-party runtime dependencies. 42 tests pass; clippy and rustfmt clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>