diff --git a/DeDRM_calibre_plugin/DeDRM_plugin.zip b/DeDRM_calibre_plugin/DeDRM_plugin.zip index a2ea798..2cce483 100644 Binary files a/DeDRM_calibre_plugin/DeDRM_plugin.zip and b/DeDRM_calibre_plugin/DeDRM_plugin.zip differ diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py b/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py index 4592aab..19eee96 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py @@ -2,6 +2,10 @@ # -*- coding: utf-8 -*- from __future__ import with_statement + +# __init__.py for DeDRM_plugin +# Copyright © 2008-2017 Apprentice Harper et al. + __license__ = 'GPL v3' __docformat__ = 'restructuredtext en' @@ -58,6 +62,7 @@ __docformat__ = 'restructuredtext en' # 6.5.2 - Another Topaz fix # 6.5.3 - Warn about KFX files explicitly # 6.5.4 - Mac App Fix, improve PDF decryption, handle latest tcl changes in ActivePython +# 6.5.5 - Finally a fix for the Windows non-ASCII user names. """ @@ -65,7 +70,7 @@ Decrypt DRMed ebooks. """ PLUGIN_NAME = u"DeDRM" -PLUGIN_VERSION_TUPLE = (6, 5, 4) +PLUGIN_VERSION_TUPLE = (6, 5, 5) PLUGIN_VERSION = u".".join([unicode(str(x)) for x in PLUGIN_VERSION_TUPLE]) # Include an html helpfile in the plugin's zipfile with the following name. RESOURCE_NAME = PLUGIN_NAME + '_Help.htm' @@ -289,8 +294,8 @@ class DeDRM(FileTypePlugin): except Exception, e: pass - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead 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(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) + print u"{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(u"{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)) # import the Adobe Adept ePub handler import calibre_plugins.dedrm.ineptepub as ineptepub @@ -380,17 +385,19 @@ class DeDRM(FileTypePlugin): except: print u"{0} v{1}: Exception when saving a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) traceback.print_exc() - print u"{0} v{1}: Decrypted with new default key after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + print u"{0} v{1}: Decrypted with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) # Return the modified PersistentTemporary file to calibre. return of.name print u"{0} v{1}: Failed to decrypt with new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) except Exception, e: + print u"{0} v{1}: Unexpected Exception trying a new default key after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime) + traceback.print_exc() pass # Something went wrong with decryption. - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead 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(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) + print u"{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(u"{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)) # Not a Barnes & Noble nor an Adobe Adept # Import the fixed epub. @@ -489,8 +496,8 @@ class DeDRM(FileTypePlugin): pass # Something went wrong with decryption. - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead 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(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) + print u"{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(u"{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)) def KindleMobiDecrypt(self,path_to_ebook): @@ -557,8 +564,8 @@ class DeDRM(FileTypePlugin): pass if not decoded: #if you reached here then no luck raise and exception - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead 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(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime)) + print u"{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(u"{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)) of = self.temporary_file(book.getBookExtension()) book.getFile(of.name) @@ -592,8 +599,8 @@ class DeDRM(FileTypePlugin): print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,keyname_masked,time.time()-self.starttime) - print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead 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(u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION, time.time()-self.starttime)) + print u"{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(u"{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)) def run(self, path_to_ebook): diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/k4mobidedrm.py b/DeDRM_calibre_plugin/DeDRM_plugin/k4mobidedrm.py index c3e475c..941a134 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/k4mobidedrm.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/k4mobidedrm.py @@ -3,10 +3,13 @@ from __future__ import with_statement -# k4mobidedrm.py, version 5.3 -# Copyright © 2009-2015 by ApprenticeHarper et al. +# k4mobidedrm.py +# Copyright © 2008-2017 by Apprentice Harper et al. -# engine to remove drm from Kindle and Mobipocket ebooks +__license__ = 'GPL v3' +__version__ = '5.5' + +# Engine to remove drm from Kindle and Mobipocket ebooks # for personal use for archiving and converting your ebooks # PLEASE DO NOT PIRATE EBOOKS! @@ -17,12 +20,11 @@ from __future__ import with_statement # readable for a long, long time # This borrows very heavily from works by CMBDTC, IHeartCabbages, skindle, -# unswindle, DarkReverser, ApprenticeAlf, DiapDealer, some_updates -# and many many others +# unswindle, DarkReverser, ApprenticeAlf, and many many others + # Special thanks to The Dark Reverser for MobiDeDrm and CMBDTC for cmbdtc_dump # from which this script borrows most unashamedly. - # Changelog # 1.0 - Name change to k4mobidedrm. Adds Mac support, Adds plugin code # 1.1 - Adds support for additional kindle.info files @@ -57,9 +59,7 @@ from __future__ import with_statement # 5.2 - Fixed error in command line processing of unicode arguments # 5.3 - Changed Android support to allow passing of backup .ab files # 5.4 - Recognise KFX files masquerading as azw, even if we can't decrypt them yet. - -__version__ = '5.4' - +# 5.5 - Added GPL v3 licence explicitly. import sys, os, re import csv @@ -295,7 +295,7 @@ def usage(progname): def cli_main(): argv=unicode_argv() progname = os.path.basename(argv[0]) - print u"K4MobiDeDrm v{0}.\nCopyright © 2008-2013 The Dark Reverser et al.".format(__version__) + print u"K4MobiDeDrm v{0}.\nCopyright © 2008-2017 Apprentice Harper et al.".format(__version__) try: opts, args = getopt.getopt(argv[1:], "k:p:s:a:") diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py b/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py index e99857a..d899193 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py @@ -4,10 +4,14 @@ from __future__ import with_statement # kgenpids.py -# Copyright © 2010-2015 by some_updates, Apprentice Alf and Apprentice Harper +# Copyright © 2008-2017 Apprentice Harper et al. + +__license__ = 'GPL v3' +__version__ = '2.1' # Revision history: # 2.0 - Fix for non-ascii Windows user names +# 2.1 - Actual fix for non-ascii WIndows user names. import sys import os, csv @@ -194,21 +198,7 @@ keynames = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted',' def getK4Pids(rec209, token, kindleDatabase): global charMap1 pids = [] - - try: - # Get the Mazama Random number - MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex') - - # Get the IDString used to decode the Kindle Info file - IDString = (kindleDatabase[1])['IDString'].decode('hex') - - # Get the UserName stored when the Kindle Info file was decoded - UserName = (kindleDatabase[1])['UserName'].decode('hex') - - except KeyError: - print u"Keys not found in the database {0}.".format(kindleDatabase[0]) - return pids - + try: # Get the kindle account token, if present kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex') @@ -217,14 +207,47 @@ def getK4Pids(rec209, token, kindleDatabase): kindleAccountToken="" pass - # Get the ID string used - encodedIDString = encodeHash(IDString,charMap1) + try: + # Get the DSN token, if present + DSN = (kindleDatabase[1])['DSN'].decode('hex') + print u"Got DSN key from database {0}".format(kindleDatabase[0]) + except KeyError: + # See if we have the info to generate the DSN + try: + # Get the Mazama Random number + MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex') + #print u"Got MazamaRandomNumber from database {0}".format(kindleDatabase[0]) + + try: + # Get the SerialNumber token, if present + IDString = (kindleDatabase[1])['SerialNumber'].decode('hex') + print u"Got SerialNumber from database {0}".format(kindleDatabase[0]) + except KeyError: + # Get the IDString we added + IDString = (kindleDatabase[1])['IDString'].decode('hex') - # Get the current user name - encodedUsername = encodeHash(UserName,charMap1) + try: + # Get the UsernameHash token, if present + encodedUsername = (kindleDatabase[1])['UsernameHash'].decode('hex') + print u"Got UsernameHash from database {0}".format(kindleDatabase[0]) + except KeyError: + # Get the UserName we added + UserName = (kindleDatabase[1])['UserName'].decode('hex') + # encode it + encodedUsername = encodeHash(UserName,charMap1) + #print u"encodedUsername",encodedUsername.encode('hex') + except KeyError: + print u"Keys not found in the database {0}.".format(kindleDatabase[0]) + return pids - # concat, hash and encode to calculate the DSN - DSN = encode(SHA1(MazamaRandomNumber+encodedIDString+encodedUsername),charMap1) + # Get the ID string used + encodedIDString = encodeHash(IDString,charMap1) + #print u"encodedIDString",encodedIDString.encode('hex') + + # concat, hash and encode to calculate the DSN + DSN = encode(SHA1(MazamaRandomNumber+encodedIDString+encodedUsername),charMap1) + #print u"DSN",DSN.encode('hex') + pass # Compute the device PID (for which I can tell, is used for nothing). table = generatePidEncryptionTable() diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py b/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py index 20979c8..e20b7c9 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py @@ -4,7 +4,10 @@ from __future__ import with_statement # kindlekey.py -# Copyright © 2010-2017 by some_updates, Apprentice Alf and Apprentice Harper +# Copyright © 2008-2017 Apprentice Harper et al. + +__license__ = 'GPL v3' +__version__ = '2.5' # Revision history: # 1.0 - Kindle info file decryption, extracted from k4mobidedrm, etc. @@ -24,15 +27,13 @@ from __future__ import with_statement # Also removed old .kinfo file support (pre-2011) # 2.3 - Added more field names thanks to concavegit's KFX code. # 2.4 - Fix for complex Mac disk setups, thanks to Tibs +# 2.5 - Final Fix for Windows user names with non-ascii characters, thanks to oneofusoneofus """ Retrieve Kindle for PC/Mac user key. """ -__license__ = 'GPL v3' -__version__ = '2.4' - import sys, os, re from struct import pack, unpack, unpack_from import json @@ -887,10 +888,18 @@ if iswindows: if errcd == 234: # bad wine implementation up through wine 1.3.21 return "AlternateUserName" + # double the buffer size buffer = create_unicode_buffer(len(buffer) * 2) size.value = len(buffer) - # return low byte of the unicode value of each character of the username - return buffer.value.encode('utf-16-le')[::2] + + # replace any non-ASCII values with 0xfffd + for i in xrange(0,len(buffer)): + if buffer[i]>u"\u007f": + #print u"swapping char "+str(i)+" ("+buffer[i]+")" + buffer[i] = u"\ufffd" + # return utf-8 encoding of modified username + #print u"modified username:"+buffer.value + return buffer.value.encode('utf-8') return GetUserName GetUserName = GetUserName() @@ -1015,7 +1024,12 @@ if iswindows: 'SerialNumber',\ 'UsernameHash',\ 'kindle.directedid.info',\ - 'DSN' + 'DSN',\ + 'kindle.accounttype.info',\ + 'krx.flashcardsplugin.data.encryption_key',\ + 'krx.notebookexportplugin.data.encryption_key',\ + 'proxy.http.password',\ + 'proxy.http.username' ] DB = {} with open(kInfoFile, 'rb') as infoReader: diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/mobidedrm.py b/DeDRM_calibre_plugin/DeDRM_plugin/mobidedrm.py index 67e9355..501aa2d 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/mobidedrm.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/mobidedrm.py @@ -1,10 +1,12 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# mobidedrm.py, version 0.38 +# mobidedrm.py # Copyright © 2008 The Dark Reverser -# -# Modified 2008–2012 by some_updates, DiapDealer and Apprentice Alf +# Portions © 2008–2017 Apprentice Harper et al. + +__license__ = 'GPL v3' +__version__ = u"0.42" # This is a python script. You need a Python interpreter to run it. # For example, ActiveState Python, which exists for windows. @@ -69,9 +71,7 @@ # 0.39 - Fixed problem with TEXtREAd and getBookType interface # 0.40 - moved unicode_argv call inside main for Windows DeDRM compatibility # 0.41 - Fixed potential unicode problem in command line calls - - -__version__ = u"0.41" +# 0.42 - Added GPL v3 licence. updated/removed some print statements import sys import os @@ -244,7 +244,7 @@ class MobiBook: pass def __init__(self, infile): - print u"MobiDeDrm v{0:s}.\nCopyright © 2008-2012 The Dark Reverser et al.".format(__version__) + print u"MobiDeDrm v{0:s}.\nCopyright © 2008-2017 The Dark Reverser, Apprentice Harper et al.".format(__version__) try: from alfcrypto import Pukall_Cipher @@ -288,10 +288,10 @@ class MobiBook: self.mobi_length, = struct.unpack('>L',self.sect[0x14:0x18]) self.mobi_codepage, = struct.unpack('>L',self.sect[0x1c:0x20]) self.mobi_version, = struct.unpack('>L',self.sect[0x68:0x6C]) - print u"MOBI header version {0:d}, header length {1:d}".format(self.mobi_version, self.mobi_length) + #print u"MOBI header version {0:d}, header length {1:d}".format(self.mobi_version, self.mobi_length) if (self.mobi_length >= 0xE4) and (self.mobi_version >= 5): self.extra_data_flags, = struct.unpack('>H', self.sect[0xF2:0xF4]) - print u"Extra Data Flags: {0:d}".format(self.extra_data_flags) + #print u"Extra Data Flags: {0:d}".format(self.extra_data_flags) if (self.compression != 17480): # multibyte utf8 data is included in the encryption for PalmDoc compression # so clear that byte so that we leave it to be decrypted. @@ -516,7 +516,7 @@ def cli_main(): argv=unicode_argv() progname = os.path.basename(argv[0]) if len(argv)<3 or len(argv)>4: - print u"MobiDeDrm v{0}.\nCopyright © 2008-2012 The Dark Reverser et al.".format(__version__) + print u"MobiDeDrm v{0:s}.\nCopyright © 2008-2017 The Dark Reverser, Apprentice Harper et al.".format(__version__) print u"Removes protection from Kindle/Mobipocket, Kindle/KF8 and Kindle/Print Replica ebooks" print u"Usage:" print u" {0} []".format(progname)