From 8dd81a5aed65627a6cbaa95b9f594baf7417eeef Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 24 Jun 2026 19:05:54 -0500 Subject: [PATCH] Document KFX / .kinf2024 decryption blocker and follow-up plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- docs/kfx2024-decryption-effort.md | 190 ++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 docs/kfx2024-decryption-effort.md diff --git a/docs/kfx2024-decryption-effort.md b/docs/kfx2024-decryption-effort.md new file mode 100644 index 0000000..3c85a5c --- /dev/null +++ b/docs/kfx2024-decryption-effort.md @@ -0,0 +1,190 @@ +# KFX + `.kinf2024` decryption — follow-up research notes + +**Status:** parked (not implemented). This documents what we found while trying +to test Phase 4 (KFX) on a real Microsoft Store Kindle book, why it's blocked, +and what a future effort would need to do. + +**Date investigated:** 2026-06-24. **Machine:** Windows 11, Kindle installed via +Microsoft Store. + +--- + +## TL;DR + +- The target book (*The Chronicles of Narnia*, ASIN `B008LUYSAE`) is in **KFX** + form: a DRMION-wrapped `.azw` plus a separate `.voucher` and `.res` resources. +- Decrypting KFX requires a per-book content key that is itself encrypted in a + **voucher**, unlockable only with the Kindle account's **DSN + account secret**. +- Those credentials live in **`.kinf2024`** — a key store **newer than and + structurally different from** the `.kinf2018` that DeDRM supports. There is + **no published reverse-engineering** of `.kinf2024` (it is not in DeDRM_tools). +- Therefore the blocker is **the key, not the KFX format**. Even a perfect KFX + decryptor cannot be tested on this book until `.kinf2024` is cracked. That is + novel reverse-engineering of a deliberately-obfuscated, rotating format — + outside this project's original "port the DeDRM logic" premise. + +A follow-up has **two independent parts**: (A) a KFX decryption engine (a +tractable *port* of DeDRM) and (B) `.kinf2024` key extraction (a *research* +problem). (A) is useless on Store-Kindle books without (B). + +--- + +## Evidence we gathered + +### The Kindle install (Microsoft Store) + +- Package: `AMZNKindle.AmazonKindleReadingApp_m1sc522ngdk36` +- Content root: + `%LOCALAPPDATA%\Packages\AMZNKindle.AmazonKindleReadingApp_m1sc522ngdk36\LocalState\Classic\Content\` +- Key store: + `…\LocalState\Classic\Data\storage\.kinf2024` + +### The book folder (`…\Content\B008LUYSAE_EBOK\`) + +| File | Size | Notes | +|---|---|---| +| `B008LUYSAE_EBOK.azw` | 1,166,844 | **DRMION container** (see magic below) | +| `amzn1.drm-voucher.v1.77b9b3e1-…-db5a276a8d6c.voucher` | 1,199 | Encrypted DRM voucher (holds the content key) | +| `CR!….azw.res` (many) | 1–6 MB each | KFX resource containers (images/fonts/text) | +| `B008LUYSAE_EBOK.mbpV2` | 554 | annotations/sidecar | +| `B008LUYSAE_EBOK.phl` | 1,129 | popular-highlights sidecar | + +First 16 bytes of `B008LUYSAE_EBOK.azw`: + +``` +ea 44 52 4d 49 4f 4e ee e0 01 00 ea ee 9e 81 83 .DRMION......... +… "ProtectedData" … "amz…" +``` + +`\xeaDRMION\xee` is the KFX DRMION magic. **Note:** this is a *loose* DRMION +file, not a `.kfx-zip`. (Our current `Format::detect` only recognizes DRMION +*inside a ZIP* — see "DRMLibre changes needed" below.) + +### `.kinf2024` facts + +- Size: 86,477 bytes. +- **Zero `/` (0x2F) bytes.** `.kinf2018`/`.kinf2011` are `/`-delimited record + streams; the absence of any `/` means `.kinf2024` uses a **completely + different serialization** — this is not a renamed `.kinf2018`. +- Content is char-map-style encoded (first 64 chars looked like + `bAY8YkY8bkd8AfdYA69v08b799A1AC0YC0009SAAY0d8CM94Ytz992zhb6Yt9J0J`). +- No legacy `.kinf2018`/`.kinf2011` exists anywhere on this machine (no old + desktop "Kindle for PC" install to fall back on). + +There is also a Google-Drive-synced `~\My Drive\Documents\My Kindle Content\` +with many classic `*_EBOK.azw` files from an older install. Those are also +account-locked and would need the same Kindle key material to decrypt. + +--- + +## Background: how KFX decryption works (the tractable part — a port) + +Reference: `DeDRM_tools/DeDRM_plugin/kfxdedrm.py`, `ion.py`, `kfxtables.py`. + +1. **Identify the pieces.** A KFX book is a DRMION content file (`…\xeaDRMION\xee`) + plus a `*.voucher` (the `DrmIonVoucher`). Both are **Amazon Ion** binary. +2. **Parse the voucher** (Ion) to read the encryption algorithm (AES), transform + (CBC), hash (SHA-256) and the **lock parameters**: `CLIENT_ID` = DSN, + `ACCOUNT_SECRET` = account token. +3. **Derive the voucher key.** Build `shared = "PIDv3" + algos + lockparams`, run + it through **13 obfuscation variants** (`ion.py` `obfuscate*` / `process_V*`, + ~lines 1051–1610), then `key = HMAC_SHA256(secret, b"PIDv3")[:32]`. AES-256-CBC + decrypt the voucher with its IV, PKCS#7-unpad → a `KeySet` → the `SecretKey` + (`DrmIonVoucher.decryptvoucher`, ~lines 1643–1699). +4. **Decrypt the DRMION** content with the `SecretKey` (AES-CBC) and repackage a + DRM-free KFX. (Output is decrypted **KFX**, not EPUB — same limitation DeDRM + has; a separate KFX→EPUB converter would be needed for a readable EPUB.) + +What a Rust port needs: +- A **minimal Amazon-Ion binary reader** (enough for the voucher + DRMION). +- The **YJ shared symbol table** (the 2 MB `kfxtables.py`) embedded as a + compressed `include_bytes!` blob, to resolve symbol IDs used in the voucher. +- **LZMA** (`lzma-rs`) for compressed Ion LOBs — verify it handles KFX's framing. +- Crypto we already have: AES-256-CBC (add 256-bit path to `crypto.rs`), + HMAC-SHA256 (`hmac` crate), SHA-256, PKCS#7 unpad. + +Risk: the 13-variant key derivation and the symbol-table embedding are fiddly, +and "Amazon changes KFX DRM frequently" (DeDRM's own warning). + +## Background: `.kinf2018` (closest documented relative of `.kinf2024`) + +Reference: `kindlekey.py::getDBfromFile`, ~lines 419–572, and `getK4Pids` +(`kgenpids.py` ~219–309). For **version 6 / `.kinf2018`**: + +- File = `/`-separated records; first record is a DPAPI-protected header + (`UnprotectHeaderData`) decoded with `testMap1`, containing + `[Version:6][Build:b][Cksum:…][Guid:g]`. +- Per-key derivation: + `salt = str(0x6D8*build) + guid`, + `sp = GetUserName() + "+@#$%+" + GetIDString()`, + `passwd = encode(SHA256(sp), charMap5)`, + `key = PBKDF2(passwd, salt, 10000, 0x400)[:32]`. +- Each value: rearrange (prime-offset) → `decode(testMap8)` → `iv||ciphertext`, + with `iv = iv[:12] + 00 00 00 02`, then **AES-CTR** decrypt → `decode(charMap5)`. +- `GetIDString()` = disk volume serial / MAC-derived machine id. + +The useful outputs are `kindle.account.tokens` (account secret) and `DSN` +(or the inputs to derive it: `MazamaRandomNumber` + `IDString` + `UsernameHash`). +These feed **both** `getK4Pids` (for MOBI/AZW PIDs) **and** the KFX voucher lock +params (`CLIENT_ID`=DSN, `ACCOUNT_SECRET`=token). + +**What's unknown for `.kinf2024`:** the serialization (no `/` records), the +header/version encoding, the per-value cipher and key derivation, and what +machine/account entropy it binds to. All of this must be reverse-engineered. + +--- + +## What a follow-up needs to do + +### Part A — KFX decryption engine (port; ~the original Phase 4) +1. Extend `Format::detect` to recognize a **loose DRMION** file (starts with + `\xeaDRMION\xee`) as KFX, in addition to KFX-ZIP, and to recognize a Kindle + content **folder** (`.azw` DRMION + `*.voucher` + `*.res`). +2. Minimal Ion binary reader (`kindle/kfx/ion.rs`). +3. Embedded YJ symbol table (`kindle/kfx/symbols.rs`, compressed blob). +4. Voucher key derivation + DRMION decrypt (`kindle/kfx/voucher.rs`). +5. Add AES-256-CBC + HMAC-SHA256 helpers to `crypto.rs`; add `lzma-rs`. +6. Repackage decrypted KFX; wire the `KfxZip`/`Kfx` branch in `decrypt.rs`. + +### Part B — `.kinf2024` key extraction (research; the real blocker) +1. **Decode the container.** Figure out `.kinf2024`'s framing (it is *not* + `/`-delimited). Inspect for length-prefixes / a new separator / base-N blocks. +2. **Header + version.** Find how the `[Version:…][Build:…][Guid:…]` (or its + successor) is stored; confirm whether the header is still DPAPI-protected. +3. **Per-value crypto.** Determine the v7+ key derivation and cipher (is it still + PBKDF2 + AES-CTR? new salt/entropy? new char-maps?). +4. **Goal outputs:** `kindle.account.tokens` and `DSN` (or `MazamaRandomNumber` + + `IDString` + `UsernameHash`). +5. Likely needs dynamic analysis of the Store Kindle app (the encoder is in the + app), or watching for any community RE of `.kinf2024`. + +Once Part B yields DSN + account secret, Part A can be validated on the Narnia +book, and `getK4Pids` (already ported in `kindle/pid.rs`: `encode`, +`encode_hash`, `generate_device_pid`) lets the existing **MOBI** path also +decrypt account-locked classic `.azw` files. + +--- + +## DRMLibre changes already implied +- `crates/drmlibre-core/src/format.rs`: add loose-DRMION detection + a `Kfx` + (non-zip) variant; currently such a file returns "can't determine file type". +- `crates/drmlibre-core/src/kindle/pid.rs`: `encode`/`encode_hash`/ + `generate_device_pid` are ported and tested but `#[allow(dead_code)]` until + `getK4Pids` (the Kindle-DB → PID path) is wired — that wiring is the natural + companion to Part B. +- `crates/drmlibre-core/src/extract/`: a `kindle` extractor would live here, + alongside the working Windows Adobe extractor. + +## Open questions / risks +- `.kinf2024` may bind to hardware/account in new ways; extraction might only + work on the same machine where Kindle is activated (acceptable for our use). +- KFX DRM is a moving target; a port valid today may break on future books. +- Output of Part A is decrypted **KFX**, not EPUB — readability needs a separate + KFX→EPUB step (out of scope here). + +## References +- DeDRM_tools: `DeDRM_plugin/kfxdedrm.py`, `ion.py` (`DrmIonVoucher`, + `obfuscate*`/`process_V*`), `kfxtables.py` (symbol table), `kindlekey.py` + (`getDBfromFile`, `.kinf2018` v5/v6), `kgenpids.py` (`getK4Pids`). +- Our notes on the KFX crypto core are in the project plan + (`~/.claude/plans/fizzy-sparking-wadler.md`, Phase 4 section).