From e729ae890406c5bd13e3c8f9e36a5edc6c289640 Mon Sep 17 00:00:00 2001 From: Apprentice Harper Date: Wed, 25 Mar 2015 07:26:33 +0000 Subject: [PATCH] Fix for Kindle problem in Mac app and non-ascii username problem in Windows (plugin and app). --- .../DeDRM.app/Contents/Info.plist | 4 +- .../Contents/Resources/DeDRM_Help.htm | 2 +- .../DeDRM.app/Contents/Resources/__init__.py | 5 +- .../DeDRM.app/Contents/Resources/android.py | 10 +- .../DeDRM.app/Contents/Resources/kgenpids.py | 17 +- .../DeDRM.app/Contents/Resources/kindlekey.py | 8 +- .../DeDRM_App/DeDRM_lib/DeDRM_App.pyw.bak | 635 ------------------ .../DeDRM_App/DeDRM_lib/DeDRM_app.pyw | 7 +- .../DeDRM_App/DeDRM_lib/lib/DeDRM_Help.htm | 2 +- .../DeDRM_App/DeDRM_lib/lib/__init__.py | 5 +- .../DeDRM_App/DeDRM_lib/lib/android.py | 10 +- .../DeDRM_App/DeDRM_lib/lib/kgenpids.py | 17 +- .../DeDRM_App/DeDRM_lib/lib/kindlekey.py | 8 +- DeDRM_calibre_plugin/DeDRM_plugin.zip | Bin 341636 -> 341881 bytes .../DeDRM_plugin/DeDRM_Help.htm | 2 +- DeDRM_calibre_plugin/DeDRM_plugin/__init__.py | 5 +- DeDRM_calibre_plugin/DeDRM_plugin/android.py | 10 +- DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py | 17 +- .../DeDRM_plugin/kindlekey.py | 8 +- .../Kindle_for_Mac_and_PC/kindlekey.pyw | 8 +- 20 files changed, 97 insertions(+), 683 deletions(-) delete mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_App.pyw.bak diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist index e251216..acdebbb 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.2.0. Written 2010–2015 by Apprentice Alf et al. + DeDRM AppleScript 6.2.1 Written 2010–2015 by Apprentice Alf et al. CFBundleIconFile DeDRM CFBundleIdentifier @@ -36,7 +36,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 6.2.0 + 6.2.1 CFBundleSignature dplt LSRequiresCarbon diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Help.htm index 019ba36..6d703dd 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Help.htm +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Help.htm @@ -17,7 +17,7 @@ p {margin-top: 0} -

DeDRM Plugin (v6.1.0)

+

DeDRM Plugin (v6.2.1)

This plugin removes DRM from ebooks when they are imported into calibre. If you already have DRMed ebooks in your calibre library, you will need to remove them and import them again.

diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py index 37c454c..f0bf535 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py @@ -39,13 +39,14 @@ __docformat__ = 'restructuredtext en' # 6.1.0 - Fixed multiple books import problem and PDF import with no key problem # 6.2.0 - Support for getting B&N key from nook Study log. Fix for UTF-8 filenames in Adobe ePubs. # Fix for not copying needed files. Fix for getting default Adobe key for PDFs +# 6.2.1 - Fix for non-ascii Windows user names """ Decrypt DRMed ebooks. """ PLUGIN_NAME = u"DeDRM" -PLUGIN_VERSION_TUPLE = (6, 2, 0) +PLUGIN_VERSION_TUPLE = (6, 2, 1) 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' @@ -89,7 +90,7 @@ class DeDRM(FileTypePlugin): author = u"DiapDealer, Apprentice Alf, The Dark Reverser and i♥cabbages" version = PLUGIN_VERSION_TUPLE minimum_calibre_version = (0, 7, 55) # Compiled python libraries cannot be imported in earlier versions. - file_types = set(['epub','pdf','pdb','prc','mobi','azw','azw1','azw3','azw4','tpz']) + file_types = set(['epub','pdf','pdb','prc','mobi','pobi','azw','azw1','azw3','azw4','tpz']) on_import = True priority = 600 diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android.py index d8be194..bc76d4b 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/android.py @@ -1,6 +1,14 @@ #!/usr/bin/env python #fileencoding: utf-8 +# android.py +# Copyright © 2013-2015 by Thom and Apprentice Harper + +# Revision history: +# 1.0 - AmazonSecureStorage.xml decryption to serial number +# 1.1 - map_data_storage.db decryption to serial number +# 1.2 - BugFix + import os import sys import zlib @@ -80,7 +88,7 @@ def get_serials(path=None): if path is None and os.path.isfile("backup.ab"): return get_storage() - if not os.path.isfile(path): + if path is None or not os.path.isfile(path): return [] storage = parse_preference(path) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kgenpids.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kgenpids.py index dd88797..faa51d1 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kgenpids.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kgenpids.py @@ -2,6 +2,13 @@ # -*- coding: utf-8 -*- from __future__ import with_statement + +# kgenpids.py +# Copyright © 2010-2015 by some_updates, Apprentice Alf and Apprentice Harper + +# Revision history: +# 2.0 - Fix for non-ascii Windows user names + import sys import os, csv import binascii @@ -164,7 +171,7 @@ def getKindlePids(rec209, token, serialnum): pids=[] if isinstance(serialnum,unicode): - serialnum = serialnum.encode('ascii') + serialnum = serialnum.encode('utf-8') # Compute book PID pidHash = SHA1(serialnum+rec209+token) @@ -190,16 +197,16 @@ def getK4Pids(rec209, token, kindleDatabase): try: # Get the Mazama Random number - MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex').encode('ascii') + MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex') # Get the kindle account token - kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex').encode('ascii') + kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex') # Get the IDString used to decode the Kindle Info file - IDString = (kindleDatabase[1])['IDString'].decode('hex').encode('ascii') + IDString = (kindleDatabase[1])['IDString'].decode('hex') # Get the UserName stored when the Kindle Info file was decoded - UserName = (kindleDatabase[1])['UserName'].decode('hex').encode('ascii') + UserName = (kindleDatabase[1])['UserName'].decode('hex') except KeyError: print u"Keys not found in the database {0}.".format(kindleDatabase[0]) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py index 8852769..a597a26 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py @@ -4,9 +4,7 @@ from __future__ import with_statement # kindlekey.py -# Copyright © 2010-2013 by some_updates and Apprentice Alf -# -# Currently requires alfcrypto.py which requires the alfcrypto library +# Copyright © 2010-2015 by some_updates, Apprentice Alf and Apprentice Harper # Revision history: # 1.0 - Kindle info file decryption, extracted from k4mobidedrm, etc. @@ -20,6 +18,7 @@ from __future__ import with_statement # 1.7 - Work if TkInter is missing # 1.8 - Fixes for Kindle for Mac, and non-ascii in Windows user names # 1.9 - Fixes for Unicode in Windows user names +# 2.0 - Added comments and extra fix for non-ascii Windows user names """ @@ -885,6 +884,7 @@ if iswindows: return "AlternateUserName" 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] return GetUserName GetUserName = GetUserName() @@ -1161,10 +1161,10 @@ if iswindows: DB[keyname] = cleartext if 'kindle.account.tokens' in DB: - print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().decode("latin-1")) # store values used in decryption DB['IDString'] = GetIDString() DB['UserName'] = GetUserName() + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().encode('hex')) else: DB = {} return DB diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_App.pyw.bak b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_App.pyw.bak deleted file mode 100644 index aee98fc..0000000 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_App.pyw.bak +++ /dev/null @@ -1,635 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# DeDRM.pyw, version 6.0.1 -# Copyright 2010-2013 some_updates and Apprentice Alf - -# Revision history: -# 6.0.0 - Release along with unified plugin -# 6.0.1 - Bug Fixes for Windows App -# 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 -# 6.2.0 - Update to match plugin and AppleScript - -__version__ = '6.2.0' - -import sys -import os, os.path -sys.path.append(os.path.join(sys.path[0],"lib")) -import sys, os -import codecs - -from argv_utils import add_cp65001_codec, set_utf8_default_encoding, unicode_argv -add_cp65001_codec() -set_utf8_default_encoding() - - -import shutil -import Tkinter -from Tkinter import * -import Tkconstants -import tkFileDialog -from scrolltextwidget import ScrolledText -from activitybar import ActivityBar -if sys.platform.startswith("win"): - from askfolder_ed import AskFolder -import re -import simpleprefs -import traceback - -from Queue import Full -from Queue import Empty -from multiprocessing import Process, Queue - -from scriptinterface import decryptepub, decryptpdb, decryptpdf, decryptk4mobi - - -# Wrap a stream so that output gets flushed immediately -# and appended to shared queue -class QueuedUTF8Stream: - def __init__(self, stream, q): - self.stream = stream - self.encoding = 'utf-8' - self.q = q - def write(self, data): - if isinstance(data,unicode): - data = data.encode('utf-8',"replace") - self.q.put(data) - def __getattr__(self, attr): - return getattr(self.stream, attr) - -class DrmException(Exception): - pass - -class MainApp(Tk): - def __init__(self, apphome, dnd=False, filenames=[]): - Tk.__init__(self) - self.withdraw() - self.dnd = dnd - self.apphome = apphome - - # preference settings - # [dictionary key, file in preferences directory where info is stored] - description = [ ['pids' , 'pidlist.txt' ], - ['serials', 'seriallist.txt'], - ['sdrms' , 'sdrmlist.txt' ], - ['outdir' , 'outdir.txt' ]] - self.po = simpleprefs.SimplePrefs("DeDRM",description) - if self.dnd: - self.cd = ConvDialog(self) - prefs = self.getPreferences() - self.cd.doit(prefs, filenames) - else: - prefs = self.getPreferences() - self.pd = PrefsDialog(self, prefs) - self.cd = ConvDialog(self) - self.pd.show() - - def getPreferences(self): - prefs = self.po.getPreferences() - prefdir = prefs['dir'] - adeptkeyfile = os.path.join(prefdir,'adeptkey.der') - if not os.path.exists(adeptkeyfile): - import adobekey - try: - adobekey.getkey(adeptkeyfile) - except: - pass - kindlekeyfile = os.path.join(prefdir,'kindlekey.k4i') - if not os.path.exists(kindlekeyfile): - import kindlekey - try: - kindlekey.getkey(kindlekeyfile) - except: - traceback.print_exc() - pass - bnepubkeyfile = os.path.join(prefdir,'bnepubkey.b64') - if not os.path.exists(bnepubkeyfile): - import ignoblekey - try: - ignoblekey.getkey(bnepubkeyfile) - except: - traceback.print_exc() - pass - return prefs - - def setPreferences(self, newprefs): - prefdir = self.po.prefdir - if 'adkfile' in newprefs: - dfile = newprefs['adkfile'] - fname = os.path.basename(dfile) - nfile = os.path.join(prefdir,fname) - if os.path.isfile(dfile): - shutil.copyfile(dfile,nfile) - if 'bnkfile' in newprefs: - dfile = newprefs['bnkfile'] - fname = os.path.basename(dfile) - nfile = os.path.join(prefdir,fname) - if os.path.isfile(dfile): - shutil.copyfile(dfile,nfile) - if 'kinfofile' in newprefs: - dfile = newprefs['kinfofile'] - fname = os.path.basename(dfile) - nfile = os.path.join(prefdir,fname) - if os.path.isfile(dfile): - shutil.copyfile(dfile,nfile) - self.po.setPreferences(newprefs) - return - - def alldone(self): - if not self.dnd: - self.pd.enablebuttons() - else: - self.destroy() - -class PrefsDialog(Toplevel): - def __init__(self, mainapp, prefs_array): - Toplevel.__init__(self, mainapp) - self.withdraw() - self.protocol("WM_DELETE_WINDOW", self.withdraw) - self.title("DeDRM " + __version__) - self.prefs_array = prefs_array - self.status = Tkinter.Label(self, text='Setting Preferences') - self.status.pack(fill=Tkconstants.X, expand=1) - body = Tkinter.Frame(self) - self.body = body - body.pack(fill=Tkconstants.X, expand=1) - sticky = Tkconstants.E + Tkconstants.W - body.grid_columnconfigure(1, weight=2) - - Tkinter.Label(body, text='Adobe Key file (adeptkey.der)').grid(row=0, sticky=Tkconstants.E) - self.adkpath = Tkinter.Entry(body, width=50) - self.adkpath.grid(row=0, column=1, sticky=sticky) - prefdir = self.prefs_array['dir'] - keyfile = os.path.join(prefdir,'adeptkey.der') - if os.path.isfile(keyfile): - path = keyfile - self.adkpath.insert(0, path) - button = Tkinter.Button(body, text="...", command=self.get_adkpath) - button.grid(row=0, column=2) - - Tkinter.Label(body, text='Kindle Key file (kindlekey.k4i)').grid(row=1, sticky=Tkconstants.E) - self.kkpath = Tkinter.Entry(body, width=50) - self.kkpath.grid(row=1, column=1, sticky=sticky) - prefdir = self.prefs_array['dir'] - keyfile = os.path.join(prefdir,'kindlekey.k4i') - if os.path.isfile(keyfile): - path = keyfile - self.kkpath.insert(1, path) - button = Tkinter.Button(body, text="...", command=self.get_kkpath) - button.grid(row=1, column=2) - - Tkinter.Label(body, text='Barnes and Noble Key file (bnepubkey.b64)').grid(row=2, sticky=Tkconstants.E) - self.bnkpath = Tkinter.Entry(body, width=50) - self.bnkpath.grid(row=2, column=1, sticky=sticky) - prefdir = self.prefs_array['dir'] - keyfile = os.path.join(prefdir,'bnepubkey.b64') - if os.path.isfile(keyfile): - path = keyfile - self.bnkpath.insert(2, path) - button = Tkinter.Button(body, text="...", command=self.get_bnkpath) - button.grid(row=2, column=2) - - Tkinter.Label(body, text='Mobipocket PID list\n(8 or 10 characters, comma separated)').grid(row=3, sticky=Tkconstants.E) - self.pidnums = Tkinter.StringVar() - self.pidinfo = Tkinter.Entry(body, width=50, textvariable=self.pidnums) - if 'pids' in self.prefs_array: - self.pidnums.set(self.prefs_array['pids']) - self.pidinfo.grid(row=3, column=1, sticky=sticky) - - Tkinter.Label(body, text='eInk Kindle Serial Number list\n(16 characters, comma separated)').grid(row=4, sticky=Tkconstants.E) - self.sernums = Tkinter.StringVar() - self.serinfo = Tkinter.Entry(body, width=50, textvariable=self.sernums) - if 'serials' in self.prefs_array: - self.sernums.set(self.prefs_array['serials']) - self.serinfo.grid(row=4, column=1, sticky=sticky) - - Tkinter.Label(body, text='eReader data list\n(name:last 8 digits on credit card, comma separated)').grid(row=5, sticky=Tkconstants.E) - self.sdrmnums = Tkinter.StringVar() - self.sdrminfo = Tkinter.Entry(body, width=50, textvariable=self.sdrmnums) - if 'sdrms' in self.prefs_array: - self.sdrmnums.set(self.prefs_array['sdrms']) - self.sdrminfo.grid(row=5, column=1, sticky=sticky) - - Tkinter.Label(body, text="Output Folder (if blank, use input ebook's folder)").grid(row=6, sticky=Tkconstants.E) - self.outpath = Tkinter.Entry(body, width=50) - self.outpath.grid(row=6, column=1, sticky=sticky) - if 'outdir' in self.prefs_array: - dpath = self.prefs_array['outdir'] - self.outpath.insert(0, dpath) - button = Tkinter.Button(body, text="...", command=self.get_outpath) - button.grid(row=6, column=2) - - Tkinter.Label(body, text='').grid(row=7, column=0, columnspan=2, sticky=Tkconstants.N) - - Tkinter.Label(body, text='Alternatively Process an eBook').grid(row=8, column=0, columnspan=2, sticky=Tkconstants.N) - - Tkinter.Label(body, text='Select an eBook to Process*').grid(row=9, sticky=Tkconstants.E) - self.bookpath = Tkinter.Entry(body, width=50) - self.bookpath.grid(row=9, column=1, sticky=sticky) - button = Tkinter.Button(body, text="...", command=self.get_bookpath) - button.grid(row=9, column=2) - - Tkinter.Label(body, font=("Helvetica", "10", "italic"), text='*To DeDRM multiple ebooks simultaneously, set your preferences and quit.\nThen drag and drop ebooks or folders onto the DeDRM_Drop_Target').grid(row=10, column=1, sticky=Tkconstants.E) - - Tkinter.Label(body, text='').grid(row=11, column=0, columnspan=2, sticky=Tkconstants.E) - - buttons = Tkinter.Frame(self) - buttons.pack() - self.sbotton = Tkinter.Button(buttons, text="Set Prefs", width=14, command=self.setprefs) - self.sbotton.pack(side=Tkconstants.LEFT) - - buttons.pack() - self.pbotton = Tkinter.Button(buttons, text="Process eBook", width=14, command=self.doit) - self.pbotton.pack(side=Tkconstants.LEFT) - buttons.pack() - self.qbotton = Tkinter.Button(buttons, text="Quit", width=14, command=self.quitting) - self.qbotton.pack(side=Tkconstants.RIGHT) - buttons.pack() - - def disablebuttons(self): - self.sbotton.configure(state='disabled') - self.pbotton.configure(state='disabled') - self.qbotton.configure(state='disabled') - - def enablebuttons(self): - self.sbotton.configure(state='normal') - self.pbotton.configure(state='normal') - self.qbotton.configure(state='normal') - - def show(self): - self.deiconify() - self.tkraise() - - def hide(self): - self.withdraw() - - def get_outpath(self): - cpath = self.outpath.get() - if sys.platform.startswith("win"): - # tk_chooseDirectory is horribly broken for unicode paths - # on windows - bug has been reported but not fixed for years - # workaround by using our own unicode aware version - outpath = AskFolder(message="Choose the folder for DRM-free ebooks", - defaultLocation=cpath) - else: - outpath = tkFileDialog.askdirectory( - parent=None, title='Choose the folder for DRM-free ebooks', - initialdir=cpath, initialfile=None) - if outpath: - outpath = os.path.normpath(outpath) - self.outpath.delete(0, Tkconstants.END) - self.outpath.insert(0, outpath) - return - - def get_adkpath(self): - cpath = self.adkpath.get() - adkpath = tkFileDialog.askopenfilename(initialdir = cpath, parent=None, title='Select Adept Key file', - defaultextension='.der', filetypes=[('Adept Key file', '.der'), ('All Files', '.*')]) - if adkpath: - adkpath = os.path.normpath(adkpath) - self.adkpath.delete(0, Tkconstants.END) - self.adkpath.insert(0, adkpath) - return - - def get_kkpath(self): - cpath = self.kkpath.get() - kkpath = tkFileDialog.askopenfilename(initialdir = cpath, parent=None, title='Select Kindle Key file', - defaultextension='.k4i', filetypes=[('Kindle Key file', '.k4i'), ('All Files', '.*')]) - if kkpath: - kkpath = os.path.normpath(kkpath) - self.kkpath.delete(0, Tkconstants.END) - self.kkpath.insert(0, kkpath) - return - - def get_bnkpath(self): - cpath = self.bnkpath.get() - bnkpath = tkFileDialog.askopenfilename(initialdir = cpath, parent=None, title='Select Barnes and Noble Key file', - defaultextension='.b64', filetypes=[('Barnes and Noble Key file', '.b64'), ('All Files', '.*')]) - if bnkpath: - bnkpath = os.path.normpath(bnkpath) - self.bnkpath.delete(0, Tkconstants.END) - self.bnkpath.insert(0, bnkpath) - return - - def get_bookpath(self): - cpath = self.bookpath.get() - bookpath = tkFileDialog.askopenfilename(parent=None, title='Select eBook for DRM Removal', - filetypes=[('All Files', '.*'), - ('ePub Files','.epub'), - ('Kindle','.azw'), - ('Kindle','.azw1'), - ('Kindle','.azw3'), - ('Kindle','.azw4'), - ('Kindle','.tpz'), - ('Kindle','.mobi'), - ('Kindle','.prc'), - ('eReader','.pdb'), - ('PDF','.pdf')], - initialdir=cpath) - if bookpath: - bookpath = os.path.normpath(bookpath) - self.bookpath.delete(0, Tkconstants.END) - self.bookpath.insert(0, bookpath) - return - - def quitting(self): - self.master.destroy() - - def setprefs(self): - # setting new prefereces - new_prefs = {} - prefdir = self.prefs_array['dir'] - new_prefs['dir'] = prefdir - new_prefs['pids'] = self.pidinfo.get().replace(" ","") - new_prefs['serials'] = self.serinfo.get().replace(" ","") - new_prefs['sdrms'] = self.sdrminfo.get().strip().replace(", ",",") - new_prefs['outdir'] = self.outpath.get().strip() - adkpath = self.adkpath.get() - if os.path.dirname(adkpath) != prefdir: - new_prefs['adkfile'] = adkpath - bnkpath = self.bnkpath.get() - if os.path.dirname(bnkpath) != prefdir: - new_prefs['bnkfile'] = bnkpath - kkpath = self.kkpath.get() - if os.path.dirname(kkpath) != prefdir: - new_prefs['kindlefile'] = kkpath - self.master.setPreferences(new_prefs) - # and update internal copies - self.prefs_array['pids'] = new_prefs['pids'] - self.prefs_array['serials'] = new_prefs['serials'] - self.prefs_array['sdrms'] = new_prefs['sdrms'] - self.prefs_array['outdir'] = new_prefs['outdir'] - - def doit(self): - self.disablebuttons() - filenames=[] - bookpath = self.bookpath.get() - bookpath = os.path.abspath(bookpath) - filenames.append(bookpath) - self.master.cd.doit(self.prefs_array,filenames) - - - -class ConvDialog(Toplevel): - def __init__(self, master, prefs_array={}, filenames=[]): - Toplevel.__init__(self, master) - self.withdraw() - self.protocol("WM_DELETE_WINDOW", self.withdraw) - self.title("DeDRM Processing") - self.master = master - self.apphome = self.master.apphome - self.prefs_array = prefs_array - self.filenames = filenames - self.interval = 50 - self.p2 = None - self.q = Queue() - self.running = 'inactive' - self.numgood = 0 - self.numbad = 0 - self.status = Tkinter.Label(self, text='DeDRM processing...') - 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='Activity Bar').grid(row=0, sticky=Tkconstants.E) - self.bar = ActivityBar(body, length=80, height=15, barwidth=5) - self.bar.grid(row=0, column=1, sticky=sticky) - - msg1 = '' - self.stext = ScrolledText(body, bd=5, relief=Tkconstants.RIDGE, height=4, width=80, wrap=Tkconstants.WORD) - self.stext.grid(row=2, column=0, columnspan=2,sticky=sticky) - self.stext.insert(Tkconstants.END,msg1) - - buttons = Tkinter.Frame(self) - buttons.pack() - self.qbutton = Tkinter.Button(buttons, text="Quit", width=14, command=self.quitting) - self.qbutton.pack(side=Tkconstants.BOTTOM) - self.status['text'] = '' - - self.logfile = open(os.path.join(os.path.expanduser('~'),'DeDRM.log'),'w') - - def show(self): - self.deiconify() - self.tkraise() - - def hide(self): - self.withdraw() - - def doit(self, prefs, filenames): - self.running = 'inactive' - self.prefs_array = prefs - self.filenames = filenames - self.show() - self.processBooks() - - def conversion_done(self): - self.hide() - self.master.alldone() - - def processBooks(self): - while self.running == 'inactive': - rscpath = self.prefs_array['dir'] - filename = None - if len(self.filenames) > 0: - filename = self.filenames.pop(0) - if filename == None: - msg = 'Complete: ' - msg += 'Successes: %d, ' % self.numgood - msg += 'Failures: %d\n' % self.numbad - self.showCmdOutput(msg) - if self.numbad == 0: - self.after(2000,self.conversion_done()) - self.logfile.write("DeDRM v{0}: {1}".format(__version__,msg)) - self.logfile.close() - return - infile = filename - bname = os.path.basename(infile) - msg = 'Processing: ' + bname + '...' - self.logfile.write("DeDRM v{0}: {1}\n".format(__version__,msg)) - self.showCmdOutput(msg) - outdir = os.path.dirname(filename) - if 'outdir' in self.prefs_array: - dpath = self.prefs_array['outdir'] - if dpath.strip() != '': - outdir = dpath - rv = self.decrypt_ebook(infile, outdir, rscpath) - if rv == 0: - self.bar.start() - self.running = 'active' - self.processQueue() - else: - msg = 'Unknown File: ' + bname + '\n' - self.logfile.write("DeDRM v{0}: {1}".format(__version__,msg)) - self.showCmdOutput(msg) - self.numbad += 1 - - def quitting(self): - # kill any still running subprocess - self.running = 'stopped' - if self.p2 != None: - if (self.p2.exitcode == None): - self.p2.terminate() - self.conversion_done() - - # post output from subprocess in scrolled text widget - def showCmdOutput(self, msg): - if msg and msg !='': - if sys.platform.startswith('win'): - msg = msg.replace('\r\n','\n') - self.stext.insert(Tkconstants.END,msg) - self.stext.yview_pickplace(Tkconstants.END) - return - - # read from subprocess pipe without blocking - # invoked every interval via the widget "after" - # option being used, so need to reset it for the next time - def processQueue(self): - if self.p2 == None: - # nothing to wait for so just return - return - poll = self.p2.exitcode - #print "processing", poll - done = False - text = '' - while not done: - try: - data = self.q.get_nowait() - text += data - except Empty: - done = True - if text != '': - self.logfile.write(text) - if poll != None: - self.bar.stop() - if poll == 0: - msg = 'Success\n' - self.numgood += 1 - else: - msg = 'Failed\n' - self.numbad += 1 - self.p2.join() - self.logfile.write("DeDRM v{0}: {1}\n".format(__version__,msg)) - self.showCmdOutput(msg) - self.p2 = None - self.running = 'inactive' - self.after(50,self.processBooks) - return - # make sure we get invoked again by event loop after interval - self.stext.after(self.interval,self.processQueue) - return - - def decrypt_ebook(self, infile, outdir, rscpath): - q = self.q - rv = 1 - name, ext = os.path.splitext(os.path.basename(infile)) - ext = ext.lower() - if ext == '.epub': - self.p2 = Process(target=processEPUB, args=(q, infile, outdir, rscpath)) - self.p2.start() - return 0 - if ext == '.pdb': - self.p2 = Process(target=processPDB, args=(q, infile, outdir, rscpath)) - self.p2.start() - return 0 - if ext in ['.azw', '.azw1', '.azw3', '.azw4', '.prc', '.mobi', '.tpz']: - self.p2 = Process(target=processK4MOBI,args=(q, infile, outdir, rscpath)) - self.p2.start() - return 0 - if ext == '.pdf': - self.p2 = Process(target=processPDF, args=(q, infile, outdir, rscpath)) - self.p2.start() - return 0 - return rv - - -# child process starts here -def processK4MOBI(q, infile, outdir, rscpath): - add_cp65001_codec() - set_utf8_default_encoding() - sys.stdout = QueuedUTF8Stream(sys.stdout, q) - sys.stderr = QueuedUTF8Stream(sys.stderr, q) - rv = decryptk4mobi(infile, outdir, rscpath) - sys.exit(rv) - -# child process starts here -def processPDF(q, infile, outdir, rscpath): - add_cp65001_codec() - set_utf8_default_encoding() - sys.stdout = QueuedUTF8Stream(sys.stdout, q) - sys.stderr = QueuedUTF8Stream(sys.stderr, q) - rv = decryptpdf(infile, outdir, rscpath) - sys.exit(rv) - -# child process starts here -def processEPUB(q, infile, outdir, rscpath): - add_cp65001_codec() - set_utf8_default_encoding() - sys.stdout = QueuedUTF8Stream(sys.stdout, q) - sys.stderr = QueuedUTF8Stream(sys.stderr, q) - rv = decryptepub(infile, outdir, rscpath) - sys.exit(rv) - -# child process starts here -def processPDB(q, infile, outdir, rscpath): - add_cp65001_codec() - set_utf8_default_encoding() - sys.stdout = QueuedUTF8Stream(sys.stdout, q) - sys.stderr = QueuedUTF8Stream(sys.stderr, q) - rv = decryptpdb(infile, outdir, rscpath) - sys.exit(rv) - - -def main(): - argv=unicode_argv() - apphome = os.path.dirname(argv[0]) - apphome = os.path.abspath(apphome) - - # windows may pass a spurious quoted null string as argv[1] from bat file - # simply work around this until we can figure out a better way to handle things - if sys.platform.startswith('win') and len(argv) == 2: - temp = argv[1] - temp = temp.strip('"') - temp = temp.strip() - if temp == '': - argv.pop() - - if len(argv) == 1: - filenames = [] - dnd = False - - else : # processing books via drag and drop - dnd = True - # build a list of the files to be processed - # note all filenames and paths have been utf-8 encoded - infilelst = argv[1:] - filenames = [] - for infile in infilelst: - infile = infile.replace('"','') - infile = os.path.abspath(infile) - if os.path.isdir(infile): - bpath = infile - filelst = os.listdir(infile) - for afile in filelst: - if not afile.startswith('.'): - filepath = os.path.join(bpath,afile) - if os.path.isfile(filepath): - filenames.append(filepath) - else : - afile = os.path.basename(infile) - if not afile.startswith('.'): - if os.path.isfile(infile): - filenames.append(infile) - - # start up gui app - app = MainApp(apphome, dnd, filenames) - app.mainloop() - return 0 - - -if __name__ == "__main__": - sys.exit(main()) 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 7381664..b56dc8d 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw @@ -12,8 +12,9 @@ # 6.0.4 - Fix for other potential unicode problems # 6.0.5 - Fix typo # 6.2.0 - Update to match plugin and AppleScript +# 6.2.1 - Fix for non-ascii user names -__version__ = '6.2.0' +__version__ = '6.2.1' import sys import os, os.path @@ -536,7 +537,7 @@ class ConvDialog(Toplevel): self.p2 = Process(target=processPDB, args=(q, infile, outdir, rscpath)) self.p2.start() return 0 - if ext in ['.azw', '.azw1', '.azw3', '.azw4', '.prc', '.mobi', '.tpz']: + if ext in ['.azw', '.azw1', '.azw3', '.azw4', '.prc', '.mobi', '.pobi', '.tpz']: self.p2 = Process(target=processK4MOBI,args=(q, infile, outdir, rscpath)) self.p2.start() return 0 @@ -588,7 +589,7 @@ def main(): argv=unicode_argv() apphome = os.path.dirname(argv[0]) apphome = os.path.abspath(apphome) - + # windows may pass a spurious quoted null string as argv[1] from bat file # simply work around this until we can figure out a better way to handle things if sys.platform.startswith('win') and len(argv) == 2: diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Help.htm b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Help.htm index 019ba36..6d703dd 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Help.htm +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Help.htm @@ -17,7 +17,7 @@ p {margin-top: 0} -

DeDRM Plugin (v6.1.0)

+

DeDRM Plugin (v6.2.1)

This plugin removes DRM from ebooks when they are imported into calibre. If you already have DRMed ebooks in your calibre library, you will need to remove them and import them again.

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 37c454c..f0bf535 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py @@ -39,13 +39,14 @@ __docformat__ = 'restructuredtext en' # 6.1.0 - Fixed multiple books import problem and PDF import with no key problem # 6.2.0 - Support for getting B&N key from nook Study log. Fix for UTF-8 filenames in Adobe ePubs. # Fix for not copying needed files. Fix for getting default Adobe key for PDFs +# 6.2.1 - Fix for non-ascii Windows user names """ Decrypt DRMed ebooks. """ PLUGIN_NAME = u"DeDRM" -PLUGIN_VERSION_TUPLE = (6, 2, 0) +PLUGIN_VERSION_TUPLE = (6, 2, 1) 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' @@ -89,7 +90,7 @@ class DeDRM(FileTypePlugin): author = u"DiapDealer, Apprentice Alf, The Dark Reverser and i♥cabbages" version = PLUGIN_VERSION_TUPLE minimum_calibre_version = (0, 7, 55) # Compiled python libraries cannot be imported in earlier versions. - file_types = set(['epub','pdf','pdb','prc','mobi','azw','azw1','azw3','azw4','tpz']) + file_types = set(['epub','pdf','pdb','prc','mobi','pobi','azw','azw1','azw3','azw4','tpz']) on_import = True priority = 600 diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/android.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/android.py index d8be194..bc76d4b 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/android.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/android.py @@ -1,6 +1,14 @@ #!/usr/bin/env python #fileencoding: utf-8 +# android.py +# Copyright © 2013-2015 by Thom and Apprentice Harper + +# Revision history: +# 1.0 - AmazonSecureStorage.xml decryption to serial number +# 1.1 - map_data_storage.db decryption to serial number +# 1.2 - BugFix + import os import sys import zlib @@ -80,7 +88,7 @@ def get_serials(path=None): if path is None and os.path.isfile("backup.ab"): return get_storage() - if not os.path.isfile(path): + if path is None or not os.path.isfile(path): return [] storage = parse_preference(path) diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kgenpids.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kgenpids.py index dd88797..faa51d1 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kgenpids.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kgenpids.py @@ -2,6 +2,13 @@ # -*- coding: utf-8 -*- from __future__ import with_statement + +# kgenpids.py +# Copyright © 2010-2015 by some_updates, Apprentice Alf and Apprentice Harper + +# Revision history: +# 2.0 - Fix for non-ascii Windows user names + import sys import os, csv import binascii @@ -164,7 +171,7 @@ def getKindlePids(rec209, token, serialnum): pids=[] if isinstance(serialnum,unicode): - serialnum = serialnum.encode('ascii') + serialnum = serialnum.encode('utf-8') # Compute book PID pidHash = SHA1(serialnum+rec209+token) @@ -190,16 +197,16 @@ def getK4Pids(rec209, token, kindleDatabase): try: # Get the Mazama Random number - MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex').encode('ascii') + MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex') # Get the kindle account token - kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex').encode('ascii') + kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex') # Get the IDString used to decode the Kindle Info file - IDString = (kindleDatabase[1])['IDString'].decode('hex').encode('ascii') + IDString = (kindleDatabase[1])['IDString'].decode('hex') # Get the UserName stored when the Kindle Info file was decoded - UserName = (kindleDatabase[1])['UserName'].decode('hex').encode('ascii') + UserName = (kindleDatabase[1])['UserName'].decode('hex') except KeyError: print u"Keys not found in the database {0}.".format(kindleDatabase[0]) diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py index 8852769..a597a26 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py @@ -4,9 +4,7 @@ from __future__ import with_statement # kindlekey.py -# Copyright © 2010-2013 by some_updates and Apprentice Alf -# -# Currently requires alfcrypto.py which requires the alfcrypto library +# Copyright © 2010-2015 by some_updates, Apprentice Alf and Apprentice Harper # Revision history: # 1.0 - Kindle info file decryption, extracted from k4mobidedrm, etc. @@ -20,6 +18,7 @@ from __future__ import with_statement # 1.7 - Work if TkInter is missing # 1.8 - Fixes for Kindle for Mac, and non-ascii in Windows user names # 1.9 - Fixes for Unicode in Windows user names +# 2.0 - Added comments and extra fix for non-ascii Windows user names """ @@ -885,6 +884,7 @@ if iswindows: return "AlternateUserName" 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] return GetUserName GetUserName = GetUserName() @@ -1161,10 +1161,10 @@ if iswindows: DB[keyname] = cleartext if 'kindle.account.tokens' in DB: - print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().decode("latin-1")) # store values used in decryption DB['IDString'] = GetIDString() DB['UserName'] = GetUserName() + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().encode('hex')) else: DB = {} return DB diff --git a/DeDRM_calibre_plugin/DeDRM_plugin.zip b/DeDRM_calibre_plugin/DeDRM_plugin.zip index 54af1ae2db87e408b7bad6b288762503a76c90c1..358877c023d6af66d5b262acc63e89300062e0d4 100644 GIT binary patch delta 33740 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 z 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%0Dfo+l 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šAi5In!$=>NR{j}4E`2}e(Y6G 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 EKY#|@ga7~l diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Help.htm index 019ba36..6d703dd 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Help.htm +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Help.htm @@ -17,7 +17,7 @@ p {margin-top: 0} -

DeDRM Plugin (v6.1.0)

+

DeDRM Plugin (v6.2.1)

This plugin removes DRM from ebooks when they are imported into calibre. If you already have DRMed ebooks in your calibre library, you will need to remove them and import them again.

diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py b/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py index 37c454c..f0bf535 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py @@ -39,13 +39,14 @@ __docformat__ = 'restructuredtext en' # 6.1.0 - Fixed multiple books import problem and PDF import with no key problem # 6.2.0 - Support for getting B&N key from nook Study log. Fix for UTF-8 filenames in Adobe ePubs. # Fix for not copying needed files. Fix for getting default Adobe key for PDFs +# 6.2.1 - Fix for non-ascii Windows user names """ Decrypt DRMed ebooks. """ PLUGIN_NAME = u"DeDRM" -PLUGIN_VERSION_TUPLE = (6, 2, 0) +PLUGIN_VERSION_TUPLE = (6, 2, 1) 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' @@ -89,7 +90,7 @@ class DeDRM(FileTypePlugin): author = u"DiapDealer, Apprentice Alf, The Dark Reverser and i♥cabbages" version = PLUGIN_VERSION_TUPLE minimum_calibre_version = (0, 7, 55) # Compiled python libraries cannot be imported in earlier versions. - file_types = set(['epub','pdf','pdb','prc','mobi','azw','azw1','azw3','azw4','tpz']) + file_types = set(['epub','pdf','pdb','prc','mobi','pobi','azw','azw1','azw3','azw4','tpz']) on_import = True priority = 600 diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/android.py b/DeDRM_calibre_plugin/DeDRM_plugin/android.py index d8be194..bc76d4b 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/android.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/android.py @@ -1,6 +1,14 @@ #!/usr/bin/env python #fileencoding: utf-8 +# android.py +# Copyright © 2013-2015 by Thom and Apprentice Harper + +# Revision history: +# 1.0 - AmazonSecureStorage.xml decryption to serial number +# 1.1 - map_data_storage.db decryption to serial number +# 1.2 - BugFix + import os import sys import zlib @@ -80,7 +88,7 @@ def get_serials(path=None): if path is None and os.path.isfile("backup.ab"): return get_storage() - if not os.path.isfile(path): + if path is None or not os.path.isfile(path): return [] storage = parse_preference(path) diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py b/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py index dd88797..faa51d1 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py @@ -2,6 +2,13 @@ # -*- coding: utf-8 -*- from __future__ import with_statement + +# kgenpids.py +# Copyright © 2010-2015 by some_updates, Apprentice Alf and Apprentice Harper + +# Revision history: +# 2.0 - Fix for non-ascii Windows user names + import sys import os, csv import binascii @@ -164,7 +171,7 @@ def getKindlePids(rec209, token, serialnum): pids=[] if isinstance(serialnum,unicode): - serialnum = serialnum.encode('ascii') + serialnum = serialnum.encode('utf-8') # Compute book PID pidHash = SHA1(serialnum+rec209+token) @@ -190,16 +197,16 @@ def getK4Pids(rec209, token, kindleDatabase): try: # Get the Mazama Random number - MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex').encode('ascii') + MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex') # Get the kindle account token - kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex').encode('ascii') + kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex') # Get the IDString used to decode the Kindle Info file - IDString = (kindleDatabase[1])['IDString'].decode('hex').encode('ascii') + IDString = (kindleDatabase[1])['IDString'].decode('hex') # Get the UserName stored when the Kindle Info file was decoded - UserName = (kindleDatabase[1])['UserName'].decode('hex').encode('ascii') + UserName = (kindleDatabase[1])['UserName'].decode('hex') except KeyError: print u"Keys not found in the database {0}.".format(kindleDatabase[0]) diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py b/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py index 8852769..a597a26 100644 --- a/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py @@ -4,9 +4,7 @@ from __future__ import with_statement # kindlekey.py -# Copyright © 2010-2013 by some_updates and Apprentice Alf -# -# Currently requires alfcrypto.py which requires the alfcrypto library +# Copyright © 2010-2015 by some_updates, Apprentice Alf and Apprentice Harper # Revision history: # 1.0 - Kindle info file decryption, extracted from k4mobidedrm, etc. @@ -20,6 +18,7 @@ from __future__ import with_statement # 1.7 - Work if TkInter is missing # 1.8 - Fixes for Kindle for Mac, and non-ascii in Windows user names # 1.9 - Fixes for Unicode in Windows user names +# 2.0 - Added comments and extra fix for non-ascii Windows user names """ @@ -885,6 +884,7 @@ if iswindows: return "AlternateUserName" 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] return GetUserName GetUserName = GetUserName() @@ -1161,10 +1161,10 @@ if iswindows: DB[keyname] = cleartext if 'kindle.account.tokens' in DB: - print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().decode("latin-1")) # store values used in decryption DB['IDString'] = GetIDString() DB['UserName'] = GetUserName() + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().encode('hex')) else: DB = {} return DB diff --git a/Other_Tools/DRM_Key_Scripts/Kindle_for_Mac_and_PC/kindlekey.pyw b/Other_Tools/DRM_Key_Scripts/Kindle_for_Mac_and_PC/kindlekey.pyw index 8852769..a597a26 100644 --- a/Other_Tools/DRM_Key_Scripts/Kindle_for_Mac_and_PC/kindlekey.pyw +++ b/Other_Tools/DRM_Key_Scripts/Kindle_for_Mac_and_PC/kindlekey.pyw @@ -4,9 +4,7 @@ from __future__ import with_statement # kindlekey.py -# Copyright © 2010-2013 by some_updates and Apprentice Alf -# -# Currently requires alfcrypto.py which requires the alfcrypto library +# Copyright © 2010-2015 by some_updates, Apprentice Alf and Apprentice Harper # Revision history: # 1.0 - Kindle info file decryption, extracted from k4mobidedrm, etc. @@ -20,6 +18,7 @@ from __future__ import with_statement # 1.7 - Work if TkInter is missing # 1.8 - Fixes for Kindle for Mac, and non-ascii in Windows user names # 1.9 - Fixes for Unicode in Windows user names +# 2.0 - Added comments and extra fix for non-ascii Windows user names """ @@ -885,6 +884,7 @@ if iswindows: return "AlternateUserName" 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] return GetUserName GetUserName = GetUserName() @@ -1161,10 +1161,10 @@ if iswindows: DB[keyname] = cleartext if 'kindle.account.tokens' in DB: - print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().decode("latin-1")) # store values used in decryption DB['IDString'] = GetIDString() DB['UserName'] = GetUserName() + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName().encode('hex')) else: DB = {} return DB