Files
DeDRM_tools/DeDRM_plugin/ignoblekeyAndroid.py
T
JMR-devandClaude Opus 4.8 838700fbec Remove Python 2 compatibility shims
The plugins target calibre 5/6 (Python 3) and the Poetry environment
pins Python >=3.8, so the Python 2 fallbacks are dead code. This removes
them throughout both plugins (behaviour on Python 3 is unchanged):

  - Drop all `from __future__` imports.
  - Collapse `if sys.version_info[0] == 2: ... else: ...` blocks to their
    Python 3 branch (ineptpdf, mobidedrm, kindlekey, kgenpids, alfcrypto,
    erdr2pml, ineptepub, obok, and the various unpad() helpers, etc.).
  - Replace `_winreg` import fallbacks with plain `import winreg`, and
    delete the py2-only adobekey_winreg_unicode module (now unreferenced).
  - Drop py2 name shims: `unicode`/`unichr`, `.iteritems()`,
    `from StringIO import StringIO`, `htmlentitydefs` fallback, and the
    Windows CommandLineToArgvW dance in unicode_argv (py3 sys.argv is
    already Unicode on every platform).
  - Remove the "Calibre < 5" (py2) bugfix block from the compat header.

Verified: every .py file in both plugins still byte-compiles.

Scope: the maintained DeDRM_plugin and Obok_plugin only. The archival
standalone scripts under Other_Tools/ are left as historical snapshots.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 18:42:33 -05:00

66 lines
1.9 KiB
Python

'''
Extracts the user's ccHash from an .adobe-digital-editions folder
typically included in the Nook Android app's data folder.
Based on ignoblekeyWindowsStore.py, updated for Android by noDRM.
'''
import sys
import os
import base64
try:
from Cryptodome.Cipher import AES
except ImportError:
from Crypto.Cipher import AES
import hashlib
from lxml import etree
def unpad(data, padding=16):
pad_len = data[-1]
return data[:-pad_len]
PASS_HASH_SECRET = "9ca588496a1bc4394553d9e018d70b9e"
def dump_keys(path_to_adobe_folder):
activation_path = os.path.join(path_to_adobe_folder, "activation.xml")
device_path = os.path.join(path_to_adobe_folder, "device.xml")
if not os.path.isfile(activation_path):
print("Nook activation file is missing: %s\n" % activation_path)
return []
if not os.path.isfile(device_path):
print("Nook device file is missing: %s\n" % device_path)
return []
# Load files:
activation_xml = etree.parse(activation_path)
device_xml = etree.parse(device_path)
# Get fingerprint:
device_fingerprint = device_xml.findall(".//{http://ns.adobe.com/adept}fingerprint")[0].text
device_fingerprint = base64.b64decode(device_fingerprint).hex()
hash_key = hashlib.sha1(bytearray.fromhex(device_fingerprint + PASS_HASH_SECRET)).digest()[:16]
hashes = []
for pass_hash in activation_xml.findall(".//{http://ns.adobe.com/adept}passHash"):
try:
encrypted_cc_hash = base64.b64decode(pass_hash.text)
cc_hash = unpad(AES.new(hash_key, AES.MODE_CBC, encrypted_cc_hash[:16]).decrypt(encrypted_cc_hash[16:]))
hashes.append(base64.b64encode(cc_hash).decode("ascii"))
#print("Nook ccHash is %s" % (base64.b64encode(cc_hash).decode("ascii")))
except:
pass
return hashes
if __name__ == "__main__":
print("No standalone version available.")