A single-command CLI that turns Adobe Digital Editions (ADE)
.acsmfulfillment tickets and Adept-DRM-protected EPUB / PDF files into clean, readable copies.
한국어: README.ko.md
- DRM removal core is a trimmed port of
ineptepubandineptpdffrom noDRM/DeDRM_tools. - ACSM fulfillment is a trimmed port of libgourou from acsm-calibre-plugin (DeACSM).
- No Calibre plugin required. Runs anywhere Python 3.12 runs — scripts, cron jobs, headless servers, CI.
| Task | Subcommand | Output |
|---|---|---|
| Bootstrap state + user key from a local ADE install (macOS) | init |
state files + adobekey.der under ~/.config/dedrm/ |
| ACSM fulfillment and/or Adept DRM removal (EPUB/PDF/ACSM auto-detected) | decrypt |
DRM-free EPUB or PDF |
| Upload a decrypted EPUB/PDF to a Calibre Web library | upload |
new book in your Calibre Web instance |
| Persist Calibre Web connection details | config setup / config set-calibre / config show |
~/.config/dedrm/.env (mode 0600) |
brew install yun-sangho/tap/dedrm dedrm --help
Assuming Adobe Digital Editions is already installed and authorized with your Adobe ID:
# 1. Bootstrap state + user key from your local ADE install (run once) dedrm init # 2. Turn a purchased .acsm into a clean EPUB or PDF in one shot dedrm decrypt ~/Downloads/book.acsm # → ~/Downloads/book.epub (or book.pdf)
Combines ~/Library/Application Support/Adobe/Digital Editions/activation.dat
with the DeviceKey / DeviceFingerprint entries stored in the macOS
keychain, producing ~/.config/dedrm/{devicesalt, device.xml, activation.xml, adobekey.der}
in one shot.
dedrm init [--force] [-o PATH]
- Precondition: ADE is installed and you have already completed Help → Authorize Computer with your Adobe ID.
- macOS may prompt for keychain access when reading the device secrets.
--force: overwrite an existing~/.config/dedrm/directory (and any-otarget).-o / --key-output PATH: also write an extra copy ofadobekey.derto the given path. The canonical copy always lives under the state directory, sodecryptcan find it without-k.- State directory location can be overridden with
$DEDRM_HOME(default:$XDG_CONFIG_HOME/dedrm, falling back to~/.config/dedrm).
dedrm decrypt INPUT [-k KEY.der] [-o OUTPUT] [--force]
Auto-detects the input by extension / magic bytes and does the right thing:
.acsmfulfillment ticket: parses the ticket to extractoperatorURL, builds an Adobe-style tree-hash + textbook-RSA-signed fulfillment request, POSTs it to the ACS4 server, downloads the encrypted book, then immediately decrypts it in memory. No intermediate DRM file is left on disk. Default output is<input_stem>.<epub|pdf>based on what the server returned. Precondition:initmust have populated the state directory.- Encrypted EPUB (
PK...): per-entry AES-CBC decrypt → strip PKCS#7 padding → zlib inflate → re-pack the ZIP without the Adept bits inencryption.xml. Default output:<input>.nodrm.epub. - Encrypted PDF (
%PDF-): unwrap the RSA-encrypted book key from/ADEPT_LICENSE, decrypt every stream/string object, re-serialize the PDF with/Encryptremoved. Default output:<input>.nodrm.pdf.
-k / --key is optional. Resolution order: explicit -k → <state_dir>/adobekey.der
(written by init) → on-the-fly extraction from a local ADE install.
# .acsm → DRM-free file, key auto-resolved from state dir dedrm decrypt ~/Downloads/book.acsm # already-downloaded DRM file, explicit key dedrm decrypt -k ~/adobekey.der encrypted_book.epub # decrypt and push straight to Calibre Web in one shot dedrm decrypt ~/Downloads/book.acsm --upload
dedrm upload FILE [--calibre-url URL] [--calibre-username USER] [--calibre-password PASS] [--calibre-no-verify-tls] [--env-file PATH] [--delete-after-upload]
--delete-after-upload removes the local file only after a
successful upload. If the upload fails the file is left untouched.
Logs into your Calibre Web
instance (scraping the session-bound CSRF token the server requires) and
POSTs FILE as multipart/form-data to /upload. On success prints
Uploaded <name> -> <base-url>/book/<id>.
The decrypt --upload flag runs the exact same upload step right after
a successful decrypt. If the upload fails, the decrypted file is kept
on disk so you can retry with a plain upload.
dedrm config setup # interactive prompt dedrm config set-calibre --url ... --username ... # scripted dedrm config show # inspect all sources
All three commands operate on a single file — ~/.config/dedrm/.env
(mode 0o600). There is no separate JSON config.
config setupprompts for URL, username, and password one by one. Existing values show as[defaults]; press Enter to keep them. The password prompt usesgetpass, so nothing is echoed to the terminal.config set-calibreis the non-interactive form, meant for scripts. Only the fields you pass are rewritten; unrelated lines and comments in the file are preserved.config showprints every place the loader is currently seeing credentials — persistent.env, process environment, and the resolved effective settings — with passwords masked as***.
When upload (or decrypt --upload) needs Calibre Web credentials, it
walks this list in order and takes the first value it finds for each
field:
- CLI flags (
--calibre-url,--calibre-username,--calibre-password,--calibre-verify-tls/--calibre-no-verify-tls) - Process environment variables:
DEDRM_CALIBRE_URLDEDRM_CALIBRE_USERNAMEDEDRM_CALIBRE_PASSWORDDEDRM_CALIBRE_VERIFY_TLS(false/0/no/off→ off)
- A
.envfile. The first of these that exists is loaded:--env-file PATH(explicit)./.envin the current directory~/.config/dedrm/.env(the "persistent" one written byconfig)
Everything missing after that raises a clear error listing the
unresolved fields. See .env.example for the
exact variable names.
# One-time setup dedrm init dedrm config setup # optional: save Calibre Web creds once # Every future purchase is a single command dedrm decrypt ~/Downloads/new_book.acsm -o ~/Books/new_book.epub
# Decrypt and upload, then delete the local copy dedrm decrypt ~/Downloads/new_book.acsm --upload --delete-after-upload # Upload a file you already decrypted earlier dedrm upload ~/Books/old_book.nodrm.epub
If you only have the encrypted file (no .acsm):
# Explicit key dedrm decrypt -k ~/adobekey.der encrypted_book.epub # Or let it pick up the key from the state dir written by `init` dedrm decrypt encrypted_book.pdf
Useful for sandboxed tests or multiple activations:
export DEDRM_HOME=$(mktemp -d) dedrm init dedrm decrypt book.acsm
dedrm config show # → shows the .env file in use, any process env vars, and the effective # resolved settings (password masked).
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Input file is not Adept-DRM protected |
| 2 | Wrong key / decryption failure |
| 3 | I/O problem (file missing, refuse-to-overwrite, TTY missing, etc.) |
| 4 | ACSM fulfillment failed (network, server error, unsupported response) |
| 5 | Calibre Web upload failed (network, auth, CSRF, role, etc.) |
Your Google Play Books account has hit its per-account ACS4 device slot limit. This is a server-side rejection — the CLI itself is working correctly. Resolve it on the Google side:
play.google.com/books→ Settings → Devices, deauthorize devices you no longer use.- If the UI won't let you free a slot, contact Google Play support and ask them to "reset the ACS4 device activation count for my Google Play Books account".
After freeing a slot, download a fresh .acsm from Play Books and retry.
The tool already retries this automatically. If it persists, re-run
init to refresh the state directory, or check the Adobe account
device limit at account.adobe.com.
The adobekey.der in your state directory is from a different ADE
activation than the one that fulfilled the book. Re-run init --force
against the activation.dat that belongs to the same Adobe ID.
That PDF isn't Adept-protected — it's using a different scheme (Apple FairPlay, Amazon, a password handler, etc.). Out of scope for this tool.
Local checkout uses uv for the dev virtualenv. End users do not need uv — only contributors do.
git clone https://github.com/yun-sangho/dedrm.git
cd dedrm
uv syncPython 3.12 is required; uv installs and pins it automatically. Inside
the dev checkout, prefix any command above with uv run (e.g.
uv run dedrm decrypt ...) to use the worktree's editable install instead
of a system one.
uv run pytest tests/ -q
26 cases covering:
- Adobe tree hash + signing (byte-for-byte matching the DeACSM reference).
- pkcs12 unwrap, state directory resolution.
- PDF patch helpers (backward reader, trailer parsing,
/ADEPT_LICENSEinjection). - PDF parser primitives and the "not DRM" branch on a synthetic PDF.
- Synthetic EPUB roundtrip: RSA unwrap → AES-CBC → zlib inflate → ZIP rebuild.
Actual ACSM fulfillment and actual DRM removal require Adobe / Google
servers, so they can't run in CI — verify them manually with a real
purchased .acsm (see the quick start above).
GPL v3. This project ports code from DeDRM_tools and DeACSM, both of
which are GPL v3, so the copyleft is inherited. See NOTICE
for the full attribution chain.
This tool is intended for personal backups and accessibility of EPUB / PDF files you have legitimately purchased. Using it on books you did not buy, library loans, borrowed copies, or anyone else's content may violate copyright law and anti-circumvention statutes in your jurisdiction (for example, the Korean Copyright Act §104-2, the US DMCA §1201, the EU Copyright Directive Article 6). You are solely responsible for how you use this software.
The authors provide this software as-is, without any warranty, and accept no liability for any consequences of its use.