diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist index d8c82fa..e2d4077 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist @@ -24,7 +24,7 @@ CFBundleExecutable droplet CFBundleGetInfoString - DeDRM AppleScript 6.0.4. Written 2010–2013 by Apprentice Alf and others. + DeDRM AppleScript 6.0.5. Written 2010–2013 by Apprentice Alf and others. CFBundleIconFile DeDRM CFBundleIdentifier @@ -36,7 +36,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 6.0.4 + 6.0.5 CFBundleSignature dplt LSRequiresCarbon diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py index ce72c8d..35c37d7 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py @@ -34,7 +34,7 @@ Decrypt DRMed ebooks. """ PLUGIN_NAME = u"DeDRM" -PLUGIN_VERSION_TUPLE = (6, 0, 2) +PLUGIN_VERSION_TUPLE = (6, 0, 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' diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py index f2cd005..1e58476 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py @@ -6,7 +6,7 @@ from __future__ import with_statement __license__ = 'GPL v3' # Standard Python modules. -import os, traceback +import os, traceback, json # PyQT4 modules (part of calibre). from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, @@ -178,8 +178,8 @@ class ManageKeysDialog(QDialog): self.create_key = create_key self.keyfile_ext = keyfile_ext self.import_key = (keyfile_ext != u"") - self.binary_file = (keyfile_ext == u".der") - self.json_file = (keyfile_ext == u".k4i") + self.binary_file = (keyfile_ext == u"der") + self.json_file = (keyfile_ext == u"k4i") self.wineprefix = wineprefix self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) @@ -676,7 +676,7 @@ class AddAdeptDialog(QDialog): from calibre_plugins.dedrm.adobekey import adeptkeys defaultkeys = adeptkeys() - else: # linux + else: # linux from wineutils import WineGetKeys scriptpath = os.path.join(parent.parent.alfdir,u"adobekey.py") diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py index 97f6583..72f8797 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py @@ -71,7 +71,7 @@ def unicode_argv(): argvencoding = sys.stdin.encoding if argvencoding == None: argvencoding = 'utf-8' - return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv] + return [arg if (type(arg) == unicode) else unicode(arg, argvencoding) for arg in sys.argv] #global switch debug = False @@ -92,12 +92,12 @@ class DrmException(Exception): def zipUpDir(myzip, tdir, localname): currentdir = tdir if localname != u"": - currentdir = os.path.join(currentdir,localname) + currentdir = os.path.join(currentdir, localname) list = os.listdir(currentdir) for file in list: afilename = file localfilePath = os.path.join(localname, afilename) - realfilePath = os.path.join(currentdir,file) + realfilePath = os.path.join(currentdir, file) if os.path.isfile(realfilePath): myzip.write(realfilePath, localfilePath) elif os.path.isdir(realfilePath): @@ -116,7 +116,7 @@ def bookReadEncodedNumber(fo): data = ord(fo.read(1)) if data >= 0x80: datax = (data & 0x7F) - while data >= 0x80 : + while data >= 0x80: data = ord(fo.read(1)) datax = (datax <<7) + (data & 0x7F) data = datax diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw index f00b934..26eb06e 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw @@ -10,8 +10,9 @@ # 6.0.2 - Fixed problem with spaces in paths and the bat file # 6.0.3 - Fix for Windows non-ascii user names # 6.0.4 - Fix for other potential unicode problems +# 6.0.5 - Fix typo -__version__ = '6.0.4' +__version__ = '6.0.5' import sys import os, os.path diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py index ce72c8d..830b66d 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py @@ -27,14 +27,17 @@ __docformat__ = 'restructuredtext en' # Revision history: # 6.0.0 - Initial release # 6.0.1 - Bug Fixes for Windows App, Kindle for Mac and Windows Adobe Digital Editions -# 6.0.2 - Restored call to Wine to get Kindle for PC keys +# 6.0.2 - Restored call to Wine to get Kindle for PC keys, added for ADE +# 6.0.3 - Fixes for Kindle for Mac and Windows non-ascii user names +# 6.0.4 - Fixes for stand-alone scripts and applications +# and pdb files in plugin and initial conversion of prefs. """ Decrypt DRMed ebooks. """ PLUGIN_NAME = u"DeDRM" -PLUGIN_VERSION_TUPLE = (6, 0, 2) +PLUGIN_VERSION_TUPLE = (6, 0, 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' @@ -426,7 +429,7 @@ class DeDRM(FileTypePlugin): import calibre_plugins.dedrm.prefs as prefs import calibre_plugins.dedrm.erdr2pml - dedrmrefs = prefs.DeDRM_Prefs() + dedrmprefs = prefs.DeDRM_Prefs() # Attempt to decrypt epub with each encryption key (generated or provided). for keyname, userkey in dedrmprefs['ereaderkeys'].items(): keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname) diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py index f2cd005..1e58476 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py @@ -6,7 +6,7 @@ from __future__ import with_statement __license__ = 'GPL v3' # Standard Python modules. -import os, traceback +import os, traceback, json # PyQT4 modules (part of calibre). from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, @@ -178,8 +178,8 @@ class ManageKeysDialog(QDialog): self.create_key = create_key self.keyfile_ext = keyfile_ext self.import_key = (keyfile_ext != u"") - self.binary_file = (keyfile_ext == u".der") - self.json_file = (keyfile_ext == u".k4i") + self.binary_file = (keyfile_ext == u"der") + self.json_file = (keyfile_ext == u"k4i") self.wineprefix = wineprefix self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) @@ -676,7 +676,7 @@ class AddAdeptDialog(QDialog): from calibre_plugins.dedrm.adobekey import adeptkeys defaultkeys = adeptkeys() - else: # linux + else: # linux from wineutils import WineGetKeys scriptpath = os.path.join(parent.parent.alfdir,u"adobekey.py") diff --git a/DeDRM_calibre_plugin/DeDRM_plugin.zip b/DeDRM_calibre_plugin/DeDRM_plugin.zip index 0420378..d3b1b91 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 fe7e223..830b66d 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py @@ -37,7 +37,7 @@ Decrypt DRMed ebooks. """ PLUGIN_NAME = u"DeDRM" -PLUGIN_VERSION_TUPLE = (6, 0, 4) +PLUGIN_VERSION_TUPLE = (6, 0, 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' diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/config.py b/DeDRM_calibre_plugin/DeDRM_plugin/config.py index f2cd005..1e58476 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/config.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/config.py @@ -6,7 +6,7 @@ from __future__ import with_statement __license__ = 'GPL v3' # Standard Python modules. -import os, traceback +import os, traceback, json # PyQT4 modules (part of calibre). from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, @@ -178,8 +178,8 @@ class ManageKeysDialog(QDialog): self.create_key = create_key self.keyfile_ext = keyfile_ext self.import_key = (keyfile_ext != u"") - self.binary_file = (keyfile_ext == u".der") - self.json_file = (keyfile_ext == u".k4i") + self.binary_file = (keyfile_ext == u"der") + self.json_file = (keyfile_ext == u"k4i") self.wineprefix = wineprefix self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) @@ -676,7 +676,7 @@ class AddAdeptDialog(QDialog): from calibre_plugins.dedrm.adobekey import adeptkeys defaultkeys = adeptkeys() - else: # linux + else: # linux from wineutils import WineGetKeys scriptpath = os.path.join(parent.parent.alfdir,u"adobekey.py") diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/plugin-import-name-dedrm.txt b/DeDRM_calibre_plugin/DeDRM_plugin/plugin-import-name-dedrm.txt index 478372e..05065ac 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/plugin-import-name-dedrm.txt +++ b/DeDRM_calibre_plugin/DeDRM_plugin/plugin-import-name-dedrm.txt @@ -114,7 +114,7 @@ def convertprefs(always = False): # Generate eReader user key from name and credit card number. keyname = u"{0}_{1}".format(name.strip(),cc.strip()[-4:]) keyvalue = getuser_key(name,cc).encode('hex') - userkeysappend([keyname,keyvalue]) + userkeys.append([keyname,keyvalue]) except Exception, e: traceback.print_exc() print e.args[0] diff --git a/Other_Tools/DRM_Key_Scripts/Kindle_for_iOS/kindleiospidgen.py b/Other_Tools/DRM_Key_Scripts/Kindle_for_iOS/kindleiospidgen.py new file mode 100644 index 0000000..0c0b11b --- /dev/null +++ b/Other_Tools/DRM_Key_Scripts/Kindle_for_iOS/kindleiospidgen.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +# kindleforios4key.py +# Copyright © 2013 by Apprentice Alf +# Portions Copyright © 2007, 2009 Igor Skochinsky + +# Revision history: +# 1.0 - Generates fixed PID for Kindle for iOS 3.1.1 running on iOS 4.x + + +""" +Generate fixed PID for Kindle for iOS 3.1.1 +""" + +__license__ = 'GPL v3' +__version__ = '1.0' + +import sys, os +import getopt +import binascii + +# Wrap a stream so that output gets flushed immediately +# and also make sure that any unicode strings get +# encoded using "replace" before writing them. +class SafeUnbuffered: + def __init__(self, stream): + self.stream = stream + self.encoding = stream.encoding + if self.encoding == None: + self.encoding = "utf-8" + def write(self, data): + if isinstance(data,unicode): + data = data.encode(self.encoding,"replace") + self.stream.write(data) + self.stream.flush() + def __getattr__(self, attr): + return getattr(self.stream, attr) + +iswindows = sys.platform.startswith('win') +isosx = sys.platform.startswith('darwin') + +def unicode_argv(): + if iswindows: + # Uses shell32.GetCommandLineArgvW to get sys.argv as a list of Unicode + # strings. + + # Versions 2.x of Python don't support Unicode in sys.argv on + # Windows, with the underlying Windows API instead replacing multi-byte + # characters with '?'. + + + from ctypes import POINTER, byref, cdll, c_int, windll + from ctypes.wintypes import LPCWSTR, LPWSTR + + GetCommandLineW = cdll.kernel32.GetCommandLineW + GetCommandLineW.argtypes = [] + GetCommandLineW.restype = LPCWSTR + + CommandLineToArgvW = windll.shell32.CommandLineToArgvW + CommandLineToArgvW.argtypes = [LPCWSTR, POINTER(c_int)] + CommandLineToArgvW.restype = POINTER(LPWSTR) + + cmd = GetCommandLineW() + argc = c_int(0) + argv = CommandLineToArgvW(cmd, byref(argc)) + if argc.value > 0: + # Remove Python executable and commands if present + start = argc.value - len(sys.argv) + return [argv[i] for i in + xrange(start, argc.value)] + # if we don't have any arguments at all, just pass back script name + # this should never happen + return [u"mobidedrm.py"] + else: + argvencoding = sys.stdin.encoding + if argvencoding == None: + argvencoding = "utf-8" + return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv] + +import hashlib + +def SHA256(message): + ctx = hashlib.sha256() + ctx.update(message) + return ctx.digest() + +def crc32(s): + return (~binascii.crc32(s,-1))&0xFFFFFFFF + +letters = 'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789' + +def checksumPid(s): + crc = crc32(s) + crc = crc ^ (crc >> 16) + res = s + l = len(letters) + for i in (0,1): + b = crc & 0xff + pos = (b // l) ^ (b % l) + res += letters[pos%l] + crc >>= 8 + + return res + +def pidFromSerial(s, l): + crc = crc32(s) + + arr1 = [0]*l + for i in xrange(len(s)): + arr1[i%l] ^= ord(s[i]) + + crc_bytes = [crc >> 24 & 0xff, crc >> 16 & 0xff, crc >> 8 & 0xff, crc & 0xff] + for i in xrange(l): + arr1[i] ^= crc_bytes[i&3] + + pid = '' + for i in xrange(l): + b = arr1[i] & 0xff + pid+=letters[(b >> 7) + ((b >> 5 & 3) ^ (b & 0x1f))] + + return pid + +def generatekeys(email, mac): + keys = [] + email = email.encode('utf-8').lower() + mac = mac.encode('utf-8').lower() + cleanmac = "".join(c if (c in "0123456789abcdef") else "" for c in mac) + lowermac = cleanmac.lower() + #print lowermac + keyseed = lowermac + email.encode('utf-8') + #print keyseed + keysha256 = SHA256(keyseed) + keybase64 = keysha256.encode('base64') + #print keybase64 + cleankeybase64 = "".join(c if (c in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") else "0" for c in keybase64) + #print cleankeybase64 + pseudoudid = cleankeybase64[:40] + #print pseudoudid + keys.append(pidFromSerial(pseudoudid.encode("utf-8"),8)) + return keys + +# interface for Python DeDRM +# returns single key or multiple keys, depending on path or file passed in +def getkey(email, mac, outpath): + keys = generatekeys(email,mac) + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'w') as keyfileout: + keyfileout.write(keys[0]) + print u"Saved a key to {0}".format(outfile) + else: + keycount = 0 + for key in keys: + while True: + keycount += 1 + outfile = os.path.join(outpath,u"kindleios{0:d}.pid".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'w') as keyfileout: + keyfileout.write(key) + print u"Saved a key to {0}".format(outfile) + return True + return False + +def usage(progname): + print u"Generates the key for Kindle for iOS 3.1.1" + print u"Requires email address of Amazon acccount" + print u"And MAC address for iOS device’s wifi" + print u"Outputs to a file or to stdout" + print u"Usage:" + print u" {0:s} [-h] []".format(progname) + + +def cli_main(): + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + argv=unicode_argv() + progname = os.path.basename(argv[0]) + print u"{0} v{1}\nCopyright © 2013 Apprentice Alf".format(progname,__version__) + + try: + opts, args = getopt.getopt(argv[1:], "h") + except getopt.GetoptError, err: + print u"Error in options or arguments: {0}".format(err.args[0]) + usage(progname) + sys.exit(2) + + for o, a in opts: + if o == "-h": + usage(progname) + sys.exit(0) + + + if len(args) < 2 or len(args) > 3: + usage(progname) + sys.exit(2) + + if len(args) == 3: + # save to the specified file or folder + getkey(args[0],args[1],args[2]) + else: + keys = generatekeys(args[0],args[1]) + for key in keys: + print key + + return 0 + + +def gui_main(): + try: + import Tkinter + import Tkconstants + import tkMessageBox + except: + print "Tkinter not installed" + return cli_main() + + class DecryptionDialog(Tkinter.Frame): + def __init__(self, root): + Tkinter.Frame.__init__(self, root, border=5) + self.status = Tkinter.Label(self, text=u"Enter parameters") + self.status.pack(fill=Tkconstants.X, expand=1) + body = Tkinter.Frame(self) + body.pack(fill=Tkconstants.X, expand=1) + sticky = Tkconstants.E + Tkconstants.W + body.grid_columnconfigure(1, weight=2) + Tkinter.Label(body, text=u"Amazon email address").grid(row=0) + self.email = Tkinter.Entry(body, width=40) + self.email.grid(row=0, column=1, sticky=sticky) + Tkinter.Label(body, text=u"iOS MAC address").grid(row=1) + self.mac = Tkinter.Entry(body, width=40) + self.mac.grid(row=1, column=1, sticky=sticky) + buttons = Tkinter.Frame(self) + buttons.pack() + button = Tkinter.Button( + buttons, text=u"Generate", width=10, command=self.generate) + button.pack(side=Tkconstants.LEFT) + Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT) + button = Tkinter.Button( + buttons, text=u"Quit", width=10, command=self.quit) + button.pack(side=Tkconstants.RIGHT) + + def generate(self): + email = self.email.get() + mac = self.mac.get() + if not email: + self.status['text'] = u"Email not specified" + return + if not mac: + self.status['text'] = u"MAC not specified" + return + self.status['text'] = u"Generating..." + try: + keys = generatekeys(email, mac) + except Exception, e: + self.status['text'] = u"Error: (0}".format(e.args[0]) + return + self.status['text'] = ", ".join(key for key in keys) + + root = Tkinter.Tk() + root.title(u"Kindle for iOS PID Generator v.{0}".format(__version__)) + root.resizable(True, False) + root.minsize(300, 0) + DecryptionDialog(root).pack(fill=Tkconstants.X, expand=1) + root.mainloop() + return 0 + +if __name__ == '__main__': + if len(sys.argv) > 1: + sys.exit(cli_main()) + sys.exit(gui_main()) diff --git a/ReadMe_First.txt b/ReadMe_First.txt index 5143509..b08fd6c 100644 --- a/ReadMe_First.txt +++ b/ReadMe_First.txt @@ -1,7 +1,7 @@ Welcome to the tools! ===================== -This ReadMe_First.txt is meant to give users a quick overview of what is available and how to get started. This document is part of the Tools v6.0.4 archive from Apprentice Alf's Blog: http://apprenticealf.wordpress.com/ +This ReadMe_First.txt is meant to give users a quick overview of what is available and how to get started. This document is part of the Tools v6.0.5 archive from Apprentice Alf's Blog: http://apprenticealf.wordpress.com/ The is archive includes tools to remove DRM from: