mirror of
https://github.com/noDRM/DeDRM_tools.git
synced 2026-03-20 21:08:57 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7974f0f14 | ||
|
|
ed412bee35 | ||
|
|
6cee615f26 |
@@ -5,7 +5,7 @@
|
|||||||
# Copyright © 2008-2020 Apprentice Harper et al.
|
# Copyright © 2008-2020 Apprentice Harper et al.
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__version__ = '7.0.0'
|
__version__ = '7.0.3'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
@@ -72,6 +72,8 @@ __docformat__ = 'restructuredtext en'
|
|||||||
# 6.8.1 - Kindle key fix for Mac OS X Big Sur
|
# 6.8.1 - Kindle key fix for Mac OS X Big Sur
|
||||||
# 7.0.0 - Switched to Python 3 for calibre 5.0. Thanks to all who contributed
|
# 7.0.0 - Switched to Python 3 for calibre 5.0. Thanks to all who contributed
|
||||||
# 7.0.1 - More Python 3 changes. Adobe PDF decryption should now work in some cases
|
# 7.0.1 - More Python 3 changes. Adobe PDF decryption should now work in some cases
|
||||||
|
# 7.0.2 - More Python 3 changes. Adobe PDF decryption should now work on PC too.
|
||||||
|
# 7.0.3 - More Python 3 changes. Integer division in ineptpdf.py
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Decrypt DRMed ebooks.
|
Decrypt DRMed ebooks.
|
||||||
|
|||||||
@@ -260,6 +260,7 @@ def _load_crypto_pycrypto():
|
|||||||
from Crypto.PublicKey import RSA as _RSA
|
from Crypto.PublicKey import RSA as _RSA
|
||||||
from Crypto.Cipher import ARC4 as _ARC4
|
from Crypto.Cipher import ARC4 as _ARC4
|
||||||
from Crypto.Cipher import AES as _AES
|
from Crypto.Cipher import AES as _AES
|
||||||
|
from Crypto.Cipher import PKCS1_v1_5 as _PKCS1_v1_5
|
||||||
|
|
||||||
# ASN.1 parsing code from tlslite
|
# ASN.1 parsing code from tlslite
|
||||||
class ASN1Error(Exception):
|
class ASN1Error(Exception):
|
||||||
@@ -374,7 +375,7 @@ def _load_crypto_pycrypto():
|
|||||||
|
|
||||||
class RSA(object):
|
class RSA(object):
|
||||||
def __init__(self, der):
|
def __init__(self, der):
|
||||||
key = ASN1Parser([ord(x) for x in der])
|
key = ASN1Parser([x for x in der])
|
||||||
key = [key.getChild(x).value for x in range(1, 4)]
|
key = [key.getChild(x).value for x in range(1, 4)]
|
||||||
key = [self.bytesToNumber(v) for v in key]
|
key = [self.bytesToNumber(v) for v in key]
|
||||||
self._rsa = _RSA.construct(key)
|
self._rsa = _RSA.construct(key)
|
||||||
@@ -386,7 +387,7 @@ def _load_crypto_pycrypto():
|
|||||||
return total
|
return total
|
||||||
|
|
||||||
def decrypt(self, data):
|
def decrypt(self, data):
|
||||||
return self._rsa.decrypt(data)
|
return _PKCS1_v1_5.new(self._rsa).decrypt(data, 172)
|
||||||
|
|
||||||
return (ARC4, RSA, AES)
|
return (ARC4, RSA, AES)
|
||||||
|
|
||||||
@@ -592,7 +593,6 @@ class PSBaseParser(object):
|
|||||||
if not pos:
|
if not pos:
|
||||||
pos = self.bufpos+self.charpos
|
pos = self.bufpos+self.charpos
|
||||||
self.fp.seek(pos)
|
self.fp.seek(pos)
|
||||||
##print >>sys.stderr, 'poll(%d): %r' % (pos, self.fp.read(n))
|
|
||||||
self.fp.seek(pos0)
|
self.fp.seek(pos0)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -918,7 +918,6 @@ class PSStackParser(PSBaseParser):
|
|||||||
'''
|
'''
|
||||||
while not self.results:
|
while not self.results:
|
||||||
(pos, token) = self.nexttoken()
|
(pos, token) = self.nexttoken()
|
||||||
##print (pos,token), (self.curtype, self.curstack)
|
|
||||||
if (isinstance(token, int) or
|
if (isinstance(token, int) or
|
||||||
isinstance(token, Decimal) or
|
isinstance(token, Decimal) or
|
||||||
isinstance(token, bool) or
|
isinstance(token, bool) or
|
||||||
@@ -1031,7 +1030,7 @@ def decipher_all(decipher, objid, genno, x):
|
|||||||
'''
|
'''
|
||||||
Recursively decipher X.
|
Recursively decipher X.
|
||||||
'''
|
'''
|
||||||
if isinstance(x, str):
|
if isinstance(x, bytearray) or isinstance(x,bytes):
|
||||||
return decipher(objid, genno, x)
|
return decipher(objid, genno, x)
|
||||||
decf = lambda v: decipher_all(decipher, objid, genno, v)
|
decf = lambda v: decipher_all(decipher, objid, genno, v)
|
||||||
if isinstance(x, list):
|
if isinstance(x, list):
|
||||||
@@ -1169,7 +1168,6 @@ class PDFStream(PDFObject):
|
|||||||
if 'Filter' not in self.dic:
|
if 'Filter' not in self.dic:
|
||||||
self.data = data
|
self.data = data
|
||||||
self.rawdata = None
|
self.rawdata = None
|
||||||
##print self.dict
|
|
||||||
return
|
return
|
||||||
filters = self.dic['Filter']
|
filters = self.dic['Filter']
|
||||||
if not isinstance(filters, list):
|
if not isinstance(filters, list):
|
||||||
@@ -1484,7 +1482,7 @@ class PDFDocument(object):
|
|||||||
# global static principal key for German Onleihe / Bibliothek Digital
|
# global static principal key for German Onleihe / Bibliothek Digital
|
||||||
principalkeys = { b'bibliothek-digital.de': codecs.decode(b'rRwGv2tbpKov1krvv7PO0ws9S436/lArPlfipz5Pqhw=','base64')}
|
principalkeys = { b'bibliothek-digital.de': codecs.decode(b'rRwGv2tbpKov1krvv7PO0ws9S436/lArPlfipz5Pqhw=','base64')}
|
||||||
self.is_printable = self.is_modifiable = self.is_extractable = True
|
self.is_printable = self.is_modifiable = self.is_extractable = True
|
||||||
length = int_value(param.get('Length', 0)) / 8
|
length = int_value(param.get('Length', 0)) // 8
|
||||||
edcdata = str_value(param.get('EDCData')).decode('base64')
|
edcdata = str_value(param.get('EDCData')).decode('base64')
|
||||||
pdrllic = str_value(param.get('PDRLLic')).decode('base64')
|
pdrllic = str_value(param.get('PDRLLic')).decode('base64')
|
||||||
pdrlpol = str_value(param.get('PDRLPol')).decode('base64')
|
pdrlpol = str_value(param.get('PDRLPol')).decode('base64')
|
||||||
@@ -1549,8 +1547,8 @@ class PDFDocument(object):
|
|||||||
if 5 <= R:
|
if 5 <= R:
|
||||||
# 8
|
# 8
|
||||||
for _ in range(50):
|
for _ in range(50):
|
||||||
hash = hashlib.md5(hash.digest()[:length/8])
|
hash = hashlib.md5(hash.digest()[:length//8])
|
||||||
key = hash.digest()[:length/8]
|
key = hash.digest()[:length//8]
|
||||||
if R == 2:
|
if R == 2:
|
||||||
# Algorithm 3.4
|
# Algorithm 3.4
|
||||||
u1 = ARC4.new(key).decrypt(password)
|
u1 = ARC4.new(key).decrypt(password)
|
||||||
@@ -1592,17 +1590,20 @@ class PDFDocument(object):
|
|||||||
def initialize_ebx(self, password, docid, param):
|
def initialize_ebx(self, password, docid, param):
|
||||||
self.is_printable = self.is_modifiable = self.is_extractable = True
|
self.is_printable = self.is_modifiable = self.is_extractable = True
|
||||||
rsa = RSA(password)
|
rsa = RSA(password)
|
||||||
length = int_value(param.get('Length', 0)) / 8
|
length = int_value(param.get('Length', 0)) // 8
|
||||||
rights = codecs.decode(param.get('ADEPT_LICENSE'), 'base64')
|
rights = codecs.decode(param.get('ADEPT_LICENSE'), 'base64')
|
||||||
rights = zlib.decompress(rights, -15)
|
rights = zlib.decompress(rights, -15)
|
||||||
rights = etree.fromstring(rights)
|
rights = etree.fromstring(rights)
|
||||||
expr = './/{http://ns.adobe.com/adept}encryptedKey'
|
expr = './/{http://ns.adobe.com/adept}encryptedKey'
|
||||||
bookkey = codecs.decode(''.join(rights.findtext(expr)).encode('utf-8'),'base64')
|
bookkey = codecs.decode(''.join(rights.findtext(expr)).encode('utf-8'),'base64')
|
||||||
bookkey = rsa.decrypt(bookkey)
|
bookkey = rsa.decrypt(bookkey)
|
||||||
if bookkey[0] != 2:
|
#if bookkey[0] != 2:
|
||||||
raise ADEPTError('error decrypting book session key')
|
# raise ADEPTError('error decrypting book session key')
|
||||||
|
try:
|
||||||
index = bookkey.index(b'\0') + 1
|
index = bookkey.index(b'\0') + 1
|
||||||
bookkey = bookkey[index:]
|
bookkey = bookkey[index:]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
ebx_V = int_value(param.get('V', 4))
|
ebx_V = int_value(param.get('V', 4))
|
||||||
ebx_type = int_value(param.get('EBX_ENCRYPTIONTYPE', 6))
|
ebx_type = int_value(param.get('EBX_ENCRYPTIONTYPE', 6))
|
||||||
# added because of improper booktype / decryption book session key errors
|
# added because of improper booktype / decryption book session key errors
|
||||||
@@ -1669,7 +1670,6 @@ class PDFDocument(object):
|
|||||||
plaintext = AES.new(key,AES.MODE_CBC,ivector).decrypt(data)
|
plaintext = AES.new(key,AES.MODE_CBC,ivector).decrypt(data)
|
||||||
# remove pkcs#5 aes padding
|
# remove pkcs#5 aes padding
|
||||||
cutter = -1 * plaintext[-1]
|
cutter = -1 * plaintext[-1]
|
||||||
#print cutter
|
|
||||||
plaintext = plaintext[:cutter]
|
plaintext = plaintext[:cutter]
|
||||||
return plaintext
|
return plaintext
|
||||||
|
|
||||||
@@ -1680,7 +1680,6 @@ class PDFDocument(object):
|
|||||||
plaintext = AES.new(key,AES.MODE_CBC,ivector).decrypt(data)
|
plaintext = AES.new(key,AES.MODE_CBC,ivector).decrypt(data)
|
||||||
# remove pkcs#5 aes padding
|
# remove pkcs#5 aes padding
|
||||||
cutter = -1 * plaintext[-1]
|
cutter = -1 * plaintext[-1]
|
||||||
#print cutter
|
|
||||||
plaintext = plaintext[:cutter]
|
plaintext = plaintext[:cutter]
|
||||||
return plaintext
|
return plaintext
|
||||||
|
|
||||||
@@ -2115,7 +2114,7 @@ class PDFSerializer(object):
|
|||||||
# end - hope this doesn't have bad effects
|
# end - hope this doesn't have bad effects
|
||||||
self.write(b'<<')
|
self.write(b'<<')
|
||||||
for key, val in obj.items():
|
for key, val in obj.items():
|
||||||
self.write(b'/%s' % key.encode('utf-8'))
|
self.write(str(LIT(key.encode('utf-8'))).encode('utf-8'))
|
||||||
self.serialize_object(val)
|
self.serialize_object(val)
|
||||||
self.write(b'>>')
|
self.write(b'>>')
|
||||||
elif isinstance(obj, list):
|
elif isinstance(obj, list):
|
||||||
@@ -2175,14 +2174,9 @@ class PDFSerializer(object):
|
|||||||
|
|
||||||
def decryptBook(userkey, inpath, outpath):
|
def decryptBook(userkey, inpath, outpath):
|
||||||
if RSA is None:
|
if RSA is None:
|
||||||
raise ADEPTError("PyCrypto or OpenSSL must be installed.")
|
raise ADEPTError("PyCryptodome or OpenSSL must be installed.")
|
||||||
with open(inpath, 'rb') as inf:
|
with open(inpath, 'rb') as inf:
|
||||||
#try:
|
|
||||||
serializer = PDFSerializer(inf, userkey)
|
serializer = PDFSerializer(inf, userkey)
|
||||||
#except:
|
|
||||||
# print "Error serializing pdf {0}. Probably wrong key.".format(os.path.basename(inpath))
|
|
||||||
# return 2
|
|
||||||
# hope this will fix the 'bad file descriptor' problem
|
|
||||||
with open(outpath, 'wb') as outf:
|
with open(outpath, 'wb') as outf:
|
||||||
# help construct to make sure the method runs to the end
|
# help construct to make sure the method runs to the end
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user