Document KFX / .kinf2024 decryption blocker and follow-up plan

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>
This commit is contained in:
2026-06-24 19:05:54 -05:00
co-authored by Claude Opus 4.8
parent 2dcfcf5631
commit 8dd81a5aed
+190
View File
@@ -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).