Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 32 additions & 34 deletions DeDRM_plugin/ion.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# ion.py
# Copyright © 2013-2020 Apprentice Harper et al.

__license__ = 'GPL v3'
__version__ = '3.0'

# Revision history:
# Pascal implementation by lulzkabulz.
# BinaryIon.pas + DrmIon.pas + IonSymbols.pas
# 1.0 - Python translation by apprenticenaomi.
# 1.1 - DeDRM integration by anon.
# 1.2 - Added pylzma import fallback
# 1.3 - Fixed lzma support for calibre 4.6+
# 2.0 - VoucherEnvelope v2/v3 support by apprenticesakuya.
# 3.0 - Added Python 3 compatibility for calibre 5.0

"""
Decrypt Kindle KFX files.
"""ion.py: Decrypt Kindle KFX files.

Revision history:
Pascal implementation by lulzkabulz.
BinaryIon.pas + DrmIon.pas + IonSymbols.pas
1.0 - Python translation by apprenticenaomi.
1.1 - DeDRM integration by anon.
1.2 - Added pylzma import fallback
1.3 - Fixed lzma support for calibre 4.6+
2.0 - VoucherEnvelope v2/v3 support by apprenticesakuya.
3.0 - Added Python 3 compatibility for calibre 5.0

Copyright © 2013-2020 Apprentice Harper et al.
"""
from __future__ import annotations

import collections
import hashlib
Expand All @@ -30,6 +24,9 @@

from io import BytesIO

__license__ = 'GPL v3'
__version__ = '3.0'

#@@CALIBRE_COMPAT_CODE@@


Expand Down Expand Up @@ -1096,11 +1093,11 @@ def process_V9888(st):
ws.sbox(d0x6a0bf4d0,d0x6a0dab50,[1,2])
ws.sbox(d0x6a0ba4d0,d0x6a0dab50,[1,2])
ws.shuffle(repl)
ws.shuffle(repl)
ws.shuffle(repl)
ws.shuffle(repl)
ws.sbox(d0x6a0bf4d0,d0x6a0dab50,[1,2])
ws.sbox(d0x6a0ba4d0,d0x6a0dab50,[1,2])
ws.exlookup(d0x6a0be4d0)
ws.exlookup(d0x6a0be4d0)
dat=ws.mask(st[sto:sto+16])
out+=dat
sto+=16
Expand All @@ -1124,7 +1121,7 @@ def process_V4648(st):
ws.sbox(d0x6a0c51a8,d0x6a0dab50,[1,3])
ws.shuffle(repl)
ws.shuffle(repl)
ws.exlookup(d0x6a0c91a8)
ws.exlookup(d0x6a0c91a8)
dat=ws.mask(st[sto:sto+16])
out+=dat
sto+=16
Expand All @@ -1148,7 +1145,7 @@ def process_V5683(st):
ws.shuffle(repl)
ws.sbox(d0x6a0cfe80,d0x6a0dab50,[])
ws.shuffle(repl)
ws.exlookup(d0x6a0d3e80)
ws.exlookup(d0x6a0d3e80)
dat=ws.mask(st[sto:sto+16])
out+=dat
sto+=16
Expand All @@ -1163,12 +1160,12 @@ def process_V5683(st):
# if a<0: a=256+a
# ax.append(ha[(a>>4)]+ha[a%16])
# return "".join(ax)
#
#
# def memhex(adr,sz):
# emu=EmulatorHelper(currentProgram)
# arr=emu.readMemory(getAddress(adr),sz)
# return a2hex(arr)
#
#



Expand Down Expand Up @@ -1254,7 +1251,7 @@ def scramble3(st,magic):
iVar5 = iVar5 - magic
index -= 1
if uVar4<=-1: break
else:
else:
if (offset < magic):
iVar3 = 0
else :
Expand All @@ -1274,9 +1271,9 @@ def scramble3(st,magic):
index=index-1
iVar5 = iVar5 + magic;
cntr += 1;
if iVar3>=divs: break
if iVar3>=divs: break
offset = offset + 1
if offset >= ((magic - 1) + divs) :break
if offset >= ((magic - 1) + divs) :break
return ret

#not sure if the third variant is used anywhere, but it is in Kindle, so I tried to add it
Expand Down Expand Up @@ -1342,14 +1339,14 @@ def decryptvoucher(self):
_assert(False, "Unknown lock parameter: %s" % param)


# i know that version maps to scramble pretty much 1 to 1, but there was precendent where they changed it, so...
# i know that version maps to scramble pretty much 1 to 1, but there was precendent where they changed it, so...
sharedsecrets = [obfuscate(shared, self.version),obfuscate2(shared, self.version),obfuscate3(shared, self.version),
process_V9708(shared), process_V1031(shared), process_V2069(shared), process_V9041(shared),
process_V3646(shared), process_V6052(shared), process_V9479(shared), process_V9888(shared),
process_V4648(shared), process_V5683(shared)]

decrypted=False
ex=None
lastexception: Exception | None = None
for sharedsecret in sharedsecrets:
key = hmac.new(sharedsecret, b"PIDv3", digestmod=hashlib.sha256).digest()
aes = AES.new(key[:32], AES.MODE_CBC, self.cipheriv[:16])
Expand All @@ -1361,14 +1358,15 @@ def decryptvoucher(self):

_assert(self.drmkey.hasnext() and self.drmkey.next() == TID_LIST and self.drmkey.gettypename() == "com.amazon.drm.KeySet@1.0",
"Expected KeySet, got %s" % self.drmkey.gettypename())
decrypted=True
decrypted=True

print("Decryption succeeded")
break
except Exception as ex:
lastexception = ex
print("Decryption failed, trying next fallback ")
if not decrypted:
raise ex
raise lastexception

self.drmkey.stepin()
while self.drmkey.hasnext():
Expand Down