Skip to content

Commit

Permalink
Added partial support for new Kindle for PC
Browse files Browse the repository at this point in the history
  • Loading branch information
Satsuoni committed May 21, 2023
1 parent fb8b003 commit da6b6a0
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 9 deletions.
127 changes: 118 additions & 9 deletions DeDRM_plugin/ion.py
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,101 @@ def pkcs7unpad(msg, blocklen):
"V5683": (0x05, b'z3\n\x039\x12\x13`\x06=v,\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
}

def scramble3(st,magic):
ret=bytearray(len(st))
padlen=len(st)
divs = padlen // magic
cntr = 0
iVar6 = 0
offset = 0
if (0 < ((magic - 1) + divs)):
while True:
if (offset & 1) == 0 :
uVar4 = divs - 1
if offset < divs:
iVar3 = 0
uVar4 = offset
else:
iVar3 = (offset - divs) + 1
if uVar4>=0:
iVar5 = uVar4 * magic
index = ((padlen - 1) - cntr)
while True:
if (magic <= iVar3): break
ret[index] = st[iVar3 + iVar5]
iVar3 = iVar3 + 1
cntr = cntr + 1
uVar4 = uVar4 - 1
iVar5 = iVar5 - magic
index -= 1
if uVar4<=-1: break
else:
if (offset < magic):
iVar3 = 0
else :
iVar3 = (offset - magic) + 1
if (iVar3 < divs):
uVar4 = offset
if (magic <= offset):
uVar4 = magic - 1

index = ((padlen - 1) - cntr)
iVar5 = iVar3 * magic
while True:
if (uVar4 < 0) : break
iVar3 += 1
ret[index] = st[uVar4 + iVar5]
uVar4 -= 1
index=index-1
iVar5 = iVar5 + magic;
cntr += 1;
if iVar3>=divs: break
offset = offset + 1
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
def obfuscate3(secret, version):
if version == 1: # v1 does not use obfuscation
return secret
magic, word = OBFUSCATION_TABLE["V%d" % version]
# extend secret so that its length is divisible by the magic number
if len(secret) % magic != 0:
secret = secret + b'\x00' * (magic - len(secret) % magic)
#secret = bytearray(secret)
obfuscated = bytearray(len(secret))
wordhash = bytearray(hashlib.sha256(word).digest())
print(wordhash.hex())
shuffled=bytearray(scramble3(secret,magic))
print(shuffled)
# shuffle secret and xor it with the first half of the word hash
for i in range(0, len(secret)):
obfuscated[i] = shuffled[i] ^ wordhash[i % 16]
return obfuscated

def scramble(st,magic):
ret=bytearray(len(st))
padlen=len(st)
for counter in range(len(st)):
ivar2=(padlen//2)-2*(counter%magic)+magic+counter-1
ret[ivar2%padlen]=st[counter]
return ret

def obfuscate2(secret, version):
if version == 1: # v1 does not use obfuscation
return secret
magic, word = OBFUSCATION_TABLE["V%d" % version]
# extend secret so that its length is divisible by the magic number
if len(secret) % magic != 0:
secret = secret + b'\x00' * (magic - len(secret) % magic)
obfuscated = bytearray(len(secret))
wordhash = bytearray(hashlib.sha256(word).digest()[16:])
print(wordhash.hex())
shuffled=bytearray(scramble(secret,magic))
# shuffle secret and xor it with the first half of the word hash
for i in range(0, len(secret)):
obfuscated[i] = shuffled[i] ^ wordhash[i % 16]
return obfuscated

# obfuscate shared secret according to the VoucherEnvelope version
def obfuscate(secret, version):
Expand Down Expand Up @@ -868,7 +963,6 @@ def __init__(self, voucherenv, dsn, secret):

def decryptvoucher(self):
shared = ("PIDv3" + self.encalgorithm + self.enctransformation + self.hashalgorithm).encode('ASCII')

self.lockparams.sort()
for param in self.lockparams:
if param == "ACCOUNT_SECRET":
Expand All @@ -877,14 +971,24 @@ def decryptvoucher(self):
shared += param.encode('ASCII') + self.dsn
else:
_assert(False, "Unknown lock parameter: %s" % param)

sharedsecret = obfuscate(shared, self.version)

key = hmac.new(sharedsecret, b"PIDv3", digestmod=hashlib.sha256).digest()
aes = AES.new(key[:32], AES.MODE_CBC, self.cipheriv[:16])
b = aes.decrypt(self.ciphertext)
b = pkcs7unpad(b, 16)



sharedsecrets = [obfuscate(shared, self.version),obfuscate2(shared, self.version),obfuscate3(shared, self.version)]
decrypted=False
ex=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])
try:
b = aes.decrypt(self.ciphertext)
b = pkcs7unpad(b, 16)
decrypted=True
print("Decryption succeeded")
break
except Exception as ex:
print("Decryption failed, trying next fallback ")
if not decrypted:
raise ex
self.drmkey = BinaryIonParser(BytesIO(b))
addprottable(self.drmkey)

Expand Down Expand Up @@ -923,6 +1027,7 @@ def parse(self):
while self.envelope.hasnext():
self.envelope.next()
field = self.envelope.getfieldname()
print(field)
if field == "voucher":
self.voucher = BinaryIonParser(BytesIO(self.envelope.lobvalue()))
addprottable(self.voucher)
Expand All @@ -936,6 +1041,10 @@ def parse(self):
while self.envelope.hasnext():
self.envelope.next()
field = self.envelope.getfieldname()
try:
print(self.envelope.stringvalue())
except:
pass
if field == "encryption_algorithm":
self.encalgorithm = self.envelope.stringvalue()
elif field == "encryption_transformation":
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# Note

Forked this for my own convenience. Release includes bugfixes from [noDRM](https://github.com/noDRM) that were not in latest release and partial support of Kindle for PC 1.40 .
I will probably not maintain this, unless I need some functionality.

# DeDRM_tools
DeDRM tools for ebooks

Expand Down

0 comments on commit da6b6a0

Please sign in to comment.