# If we end up here, we didn't find a key with a matching UUID, so lets just try all of them.
- # Attempt to decrypt epub with each encryption key (generated or provided).
+ # Attempt to decrypt PDF with each encryption key (generated or provided).
for keyname, userkeyhex in dedrmprefs['adeptkeys'].items():
userkey = codecs.decode(userkeyhex,'hex')
print("{0} v{1}: Trying encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname))
except Exception as e:
pass
+
+ # Unable to decrypt the PDF with any of the existing keys. Is it a B&N PDF?
+ # Attempt to decrypt PDF with each encryption key (generated or provided).
+ for keyname, userkey in dedrmprefs['bandnkeys'].items():
+ keyname_masked = "".join(("X" if (x.isdigit()) else x) for x in keyname)
+ print("{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked))
+ of = self.temporary_file(".pdf")
+
+ # Give the user key, ebook and TemporaryPersistent file to the decryption function.
+ try:
+ result = ineptpdf.decryptBook(userkey, path_to_ebook, of.name, False)
+ except ineptpdf.ADEPTNewVersionError:
+ print("{0} v{1}: Book uses unsupported (too new) Adobe DRM.".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime))
+ return path_to_ebook
+ except:
+ print("{0} v{1}: Exception when decrypting after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime))
+ traceback.print_exc()
+ result = 1
+
+ of.close()
+
+ if result == 0:
+ # Decryption was successful.
+ # Return the modified PersistentTemporary file to calibre.
+ print("{0} v{1}: Decrypted with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime))
+ return of.name
+
+ print("{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime))
+
+
# Something went wrong with decryption.
print("{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime))
raise DeDRMError("{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds. Read the FAQs at Harper's repository: https://github.com/apprenticeharper/DeDRM_tools/blob/master/FAQs.md".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime))
# Perform the initialization with a given password.
# This step is mandatory even if there's no password associated
# with the document.
- def initialize(self, password=b''):
+ def initialize(self, password=b'', inept=True):
if not self.encryption:
self.is_printable = self.is_modifiable = self.is_extractable = True
self.ready = True
return self.initialize_adobe_ps(password, docid, param)
if type == 'Standard':
return self.initialize_standard(password, docid, param)
- if type == 'EBX_HANDLER':
- return self.initialize_ebx(password, docid, param)
+ if type == 'EBX_HANDLER' and inept is True:
+ return self.initialize_ebx_inept(password, docid, param)
+ if type == 'EBX_HANDLER' and inept is False:
+ return self.initialize_ebx_ignoble(password, docid, param)
+
raise PDFEncryptionError('Unknown filter: param=%r' % param)
def initialize_adobe_ps(self, password, docid, param):
return True
- def initialize_ebx(self, password, docid, param):
+ def initialize_ebx_ignoble(self, keyb64, docid, param):
+ self.is_printable = self.is_modifiable = self.is_extractable = True
+ key = keyb64.decode('base64')[:16]
+ aes = AES.new(key,AES.MODE_CBC,"\x00" * len(key))
+ length = int_value(param.get('Length', 0)) / 8
+ rights = str_value(param.get('ADEPT_LICENSE')).decode('base64')
+ rights = zlib.decompress(rights, -15)
+ rights = etree.fromstring(rights)
+ expr = './/{http://ns.adobe.com/adept}encryptedKey'
+ bookkey = ''.join(rights.findtext(expr)).decode('base64')
+ bookkey = aes.decrypt(bookkey)
+ bookkey = bookkey[:-ord(bookkey[-1])]
+ bookkey = bookkey[-16:]
+ ebx_V = int_value(param.get('V', 4))
+ ebx_type = int_value(param.get('EBX_ENCRYPTIONTYPE', 6))
+ # added because of improper booktype / decryption book session key errors
+ if length > 0:
+ if len(bookkey) == length:
+ if ebx_V == 3:
+ V = 3
+ else:
+ V = 2
+ elif len(bookkey) == length + 1:
+ V = bookkey[0]
+ bookkey = bookkey[1:]
+ else:
+ print("ebx_V is %d and ebx_type is %d" % (ebx_V, ebx_type))
+ print("length is %d and len(bookkey) is %d" % (length, len(bookkey)))
+ print("bookkey[0] is %d" % bookkey[0])
+ raise ADEPTError('error decrypting book session key - mismatched length')
+ else:
+ # proper length unknown try with whatever you have
+ print("ebx_V is %d and ebx_type is %d" % (ebx_V, ebx_type))
+ print("length is %d and len(bookkey) is %d" % (length, len(bookkey)))
+ print("bookkey[0] is %d" % ord(bookkey[0]))
+ if ebx_V == 3:
+ V = 3
+ else:
+ V = 2
+ self.decrypt_key = bookkey
+ self.genkey = self.genkey_v3 if V == 3 else self.genkey_v2
+ self.decipher = self.decrypt_rc4
+ self.ready = True
+ return
+
+ def initialize_ebx_inept(self, password, docid, param):
self.is_printable = self.is_modifiable = self.is_extractable = True
rsa = RSA(password)
length = int_value(param.get('Length', 0)) // 8
def adeptGetUserUUID(inf):
try:
doc = PDFDocument()
+ inf = open(inf, 'rb')
pars = PDFParser(doc, inf)
(docid, param) = doc.encryption
type = literal_name(param['Filter'])
if type != 'EBX_HANDLER':
# No EBX_HANDLER, no idea which user key can decrypt this.
+ inf.close()
return None
rights = codecs.decode(param.get('ADEPT_LICENSE'), 'base64')
+ inf.close()
+
rights = zlib.decompress(rights, -15)
rights = etree.fromstring(rights)
expr = './/{http://ns.adobe.com/adept}user'
### My own code, for which there is none else to blame
class PDFSerializer(object):
- def __init__(self, inf, userkey):
+ def __init__(self, inf, userkey, inept=True):
global GEN_XREF_STM, gen_xref_stm
gen_xref_stm = GEN_XREF_STM > 1
self.version = inf.read(8)
inf.seek(0)
self.doc = doc = PDFDocument()
parser = PDFParser(doc, inf)
- doc.initialize(userkey)
+ doc.initialize(userkey, inept)
self.objids = objids = set()
for xref in reversed(doc.xrefs):
trailer = xref.trailer
-def decryptBook(userkey, inpath, outpath):
+def decryptBook(userkey, inpath, outpath, inept=True):
if RSA is None:
raise ADEPTError("PyCryptodome or OpenSSL must be installed.")
with open(inpath, 'rb') as inf:
- serializer = PDFSerializer(inf, userkey)
+ serializer = PDFSerializer(inf, userkey, inept)
with open(outpath, 'wb') as outf:
# help construct to make sure the method runs to the end
try: