Skip to content

Commit da6b6a0

Browse files
committed
Added partial support for new Kindle for PC
1 parent fb8b003 commit da6b6a0

File tree

2 files changed

+123
-9
lines changed

2 files changed

+123
-9
lines changed

DeDRM_plugin/ion.py

Lines changed: 118 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,101 @@ def pkcs7unpad(msg, blocklen):
810810
"V5683": (0x05, b'z3\n\x039\x12\x13`\x06=v,\x02MTK\x1e%}L\x1c\x1f\x15\x0c\x11\x02\x0c\n8\x17p'),
811811
}
812812

813+
def scramble3(st,magic):
814+
ret=bytearray(len(st))
815+
padlen=len(st)
816+
divs = padlen // magic
817+
cntr = 0
818+
iVar6 = 0
819+
offset = 0
820+
if (0 < ((magic - 1) + divs)):
821+
while True:
822+
if (offset & 1) == 0 :
823+
uVar4 = divs - 1
824+
if offset < divs:
825+
iVar3 = 0
826+
uVar4 = offset
827+
else:
828+
iVar3 = (offset - divs) + 1
829+
if uVar4>=0:
830+
iVar5 = uVar4 * magic
831+
index = ((padlen - 1) - cntr)
832+
while True:
833+
if (magic <= iVar3): break
834+
ret[index] = st[iVar3 + iVar5]
835+
iVar3 = iVar3 + 1
836+
cntr = cntr + 1
837+
uVar4 = uVar4 - 1
838+
iVar5 = iVar5 - magic
839+
index -= 1
840+
if uVar4<=-1: break
841+
else:
842+
if (offset < magic):
843+
iVar3 = 0
844+
else :
845+
iVar3 = (offset - magic) + 1
846+
if (iVar3 < divs):
847+
uVar4 = offset
848+
if (magic <= offset):
849+
uVar4 = magic - 1
850+
851+
index = ((padlen - 1) - cntr)
852+
iVar5 = iVar3 * magic
853+
while True:
854+
if (uVar4 < 0) : break
855+
iVar3 += 1
856+
ret[index] = st[uVar4 + iVar5]
857+
uVar4 -= 1
858+
index=index-1
859+
iVar5 = iVar5 + magic;
860+
cntr += 1;
861+
if iVar3>=divs: break
862+
offset = offset + 1
863+
if offset >= ((magic - 1) + divs) :break
864+
return ret
865+
866+
#not sure if the third variant is used anywhere, but it is in Kindle, so I tried to add it
867+
def obfuscate3(secret, version):
868+
if version == 1: # v1 does not use obfuscation
869+
return secret
870+
magic, word = OBFUSCATION_TABLE["V%d" % version]
871+
# extend secret so that its length is divisible by the magic number
872+
if len(secret) % magic != 0:
873+
secret = secret + b'\x00' * (magic - len(secret) % magic)
874+
#secret = bytearray(secret)
875+
obfuscated = bytearray(len(secret))
876+
wordhash = bytearray(hashlib.sha256(word).digest())
877+
print(wordhash.hex())
878+
shuffled=bytearray(scramble3(secret,magic))
879+
print(shuffled)
880+
# shuffle secret and xor it with the first half of the word hash
881+
for i in range(0, len(secret)):
882+
obfuscated[i] = shuffled[i] ^ wordhash[i % 16]
883+
return obfuscated
884+
885+
def scramble(st,magic):
886+
ret=bytearray(len(st))
887+
padlen=len(st)
888+
for counter in range(len(st)):
889+
ivar2=(padlen//2)-2*(counter%magic)+magic+counter-1
890+
ret[ivar2%padlen]=st[counter]
891+
return ret
892+
893+
def obfuscate2(secret, version):
894+
if version == 1: # v1 does not use obfuscation
895+
return secret
896+
magic, word = OBFUSCATION_TABLE["V%d" % version]
897+
# extend secret so that its length is divisible by the magic number
898+
if len(secret) % magic != 0:
899+
secret = secret + b'\x00' * (magic - len(secret) % magic)
900+
obfuscated = bytearray(len(secret))
901+
wordhash = bytearray(hashlib.sha256(word).digest()[16:])
902+
print(wordhash.hex())
903+
shuffled=bytearray(scramble(secret,magic))
904+
# shuffle secret and xor it with the first half of the word hash
905+
for i in range(0, len(secret)):
906+
obfuscated[i] = shuffled[i] ^ wordhash[i % 16]
907+
return obfuscated
813908

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

869964
def decryptvoucher(self):
870965
shared = ("PIDv3" + self.encalgorithm + self.enctransformation + self.hashalgorithm).encode('ASCII')
871-
872966
self.lockparams.sort()
873967
for param in self.lockparams:
874968
if param == "ACCOUNT_SECRET":
@@ -877,14 +971,24 @@ def decryptvoucher(self):
877971
shared += param.encode('ASCII') + self.dsn
878972
else:
879973
_assert(False, "Unknown lock parameter: %s" % param)
880-
881-
sharedsecret = obfuscate(shared, self.version)
882-
883-
key = hmac.new(sharedsecret, b"PIDv3", digestmod=hashlib.sha256).digest()
884-
aes = AES.new(key[:32], AES.MODE_CBC, self.cipheriv[:16])
885-
b = aes.decrypt(self.ciphertext)
886-
b = pkcs7unpad(b, 16)
887-
974+
975+
976+
sharedsecrets = [obfuscate(shared, self.version),obfuscate2(shared, self.version),obfuscate3(shared, self.version)]
977+
decrypted=False
978+
ex=None
979+
for sharedsecret in sharedsecrets:
980+
key = hmac.new(sharedsecret, b"PIDv3", digestmod=hashlib.sha256).digest()
981+
aes = AES.new(key[:32], AES.MODE_CBC, self.cipheriv[:16])
982+
try:
983+
b = aes.decrypt(self.ciphertext)
984+
b = pkcs7unpad(b, 16)
985+
decrypted=True
986+
print("Decryption succeeded")
987+
break
988+
except Exception as ex:
989+
print("Decryption failed, trying next fallback ")
990+
if not decrypted:
991+
raise ex
888992
self.drmkey = BinaryIonParser(BytesIO(b))
889993
addprottable(self.drmkey)
890994

@@ -923,6 +1027,7 @@ def parse(self):
9231027
while self.envelope.hasnext():
9241028
self.envelope.next()
9251029
field = self.envelope.getfieldname()
1030+
print(field)
9261031
if field == "voucher":
9271032
self.voucher = BinaryIonParser(BytesIO(self.envelope.lobvalue()))
9281033
addprottable(self.voucher)
@@ -936,6 +1041,10 @@ def parse(self):
9361041
while self.envelope.hasnext():
9371042
self.envelope.next()
9381043
field = self.envelope.getfieldname()
1044+
try:
1045+
print(self.envelope.stringvalue())
1046+
except:
1047+
pass
9391048
if field == "encryption_algorithm":
9401049
self.encalgorithm = self.envelope.stringvalue()
9411050
elif field == "encryption_transformation":

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# Note
2+
3+
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 .
4+
I will probably not maintain this, unless I need some functionality.
5+
16
# DeDRM_tools
27
DeDRM tools for ebooks
38

0 commit comments

Comments
 (0)