From 20bc936e99ffefe1f7481bf77e543548412e4e74 Mon Sep 17 00:00:00 2001 From: Apprentice Alf Date: Wed, 20 Mar 2013 10:23:54 +0000 Subject: [PATCH] tools v6.0.0 The first unified calibre plugin --- Calibre_Plugins/Ignobleepub_ReadMe.txt | 70 - Calibre_Plugins/Ineptepub_ReadMe.txt | 114 - Calibre_Plugins/Ineptpdf_ReadMe.txt | 113 - .../K4MobiDeDRM_plugin/__init__.py | 274 --- Calibre_Plugins/K4MobiDeDRM_plugin/config.py | 62 - .../K4MobiDeDRM_plugin/getk4pcpids.py | 84 - .../K4MobiDeDRM_plugin/scrolltextwidget.py | 27 - .../K4MobiDeDRM_plugin/subasyncio.py | 148 -- Calibre_Plugins/eReaderPDB2PML_ReadMe.txt | 42 - Calibre_Plugins/eReaderPDB2PML_plugin.zip | Bin 15437 -> 0 bytes .../eReaderPDB2PML_plugin/__init__.py | 124 -- Calibre_Plugins/ignobleepub_plugin.zip | Bin 42116 -> 0 bytes .../Ignoble Epub DeDRM_Help.htm | Bin 225 -> 0 bytes .../ignobleepub_plugin/__init__.py | 188 -- Calibre_Plugins/ignobleepub_plugin/config.py | 305 --- Calibre_Plugins/ignobleepub_plugin/dialogs.py | 160 -- .../ignobleepub_plugin/ignobleepub.py | 98 - .../ignobleepub_plugin/utilities.py | Bin 225 -> 0 bytes .../ignobleepub_plugin/zipfilerugged.py | Bin 225 -> 0 bytes Calibre_Plugins/ineptepub_plugin.zip | Bin 33009 -> 0 bytes Calibre_Plugins/ineptepub_plugin/__init__.py | 205 -- .../plugin-import-name-ineptepub.txt | 0 Calibre_Plugins/ineptpdf_plugin.zip | Bin 29701 -> 0 bytes Calibre_Plugins/ineptpdf_plugin/__init__.py | 196 -- .../plugin-import-name-ineptpdf.txt | 0 Calibre_Plugins/k4mobidedrm_plugin.zip | Bin 230152 -> 0 bytes .../k4mobidedrm_plugin/k4mutils.py | 747 ------- .../k4mobidedrm_plugin/k4pcutils.py | 457 ---- DeDRM_Macintosh_Application/DeDRM ReadMe.rtf | 46 +- DeDRM_Macintosh_Application/DeDRM.app.txt | Bin 59910 -> 131522 bytes .../DeDRM.app/Contents/Info.plist | 8 +- .../DeDRM_Adobe Digital Editions Key_Help.htm | 55 + .../DeDRM_Barnes and Noble Key_Help.htm | 57 + .../DeDRM_EInk Kindle Serial Number_Help.htm | 43 + .../Contents/Resources/DeDRM_Help.htm | 73 + .../DeDRM_Kindle for Mac and PC Key_Help.htm | 55 + .../Resources/DeDRM_Mobipocket PID_Help.htm | 42 + .../Resources/DeDRM_eReader Key_Help.htm | 56 + .../Contents/Resources/Scripts/main.scpt | Bin 273522 -> 293024 bytes .../DeDRM.app/Contents/Resources/__init__.py | 450 ++++ .../DeDRM.app/Contents/Resources/adobekey.py | 184 +- .../DeDRM.app/Contents/Resources/config.py | 482 ++++- .../Contents/Resources/convert2xml.py | 11 +- .../Resources/description.rtfd/TXT.rtf | 2 +- .../DeDRM.app/Contents/Resources/dialogs.py | 719 +++++++ .../DeDRM.app/Contents/Resources/epubtest.py | 4 +- .../DeDRM.app/Contents/Resources/erdr2pml.py | 15 +- .../DeDRM.app/Contents/Resources/genbook.py | 8 +- .../Contents/Resources/getk4pcpids.py | 84 - .../Contents/Resources/ignobleepub.py | 49 +- .../Contents/Resources/ignoblekeygen.py | 29 +- .../DeDRM.app/Contents/Resources/ineptepub.py | 49 +- .../Contents/Resources/k4mobidedrm.py | 53 +- .../DeDRM.app/Contents/Resources/k4mutils.py | 747 ------- .../DeDRM.app/Contents/Resources/k4pcutils.py | 457 ---- .../DeDRM.app/Contents/Resources/kgenpids.py | 71 +- .../DeDRM.app/Contents/Resources/kindlekey.py | 1893 +++++++++++++++++ .../DeDRM.app/Contents/Resources/mobidedrm.py | 2 +- .../Contents/Resources/openssl_des.py | 2 +- .../Resources/plugin-import-name-dedrm.txt | 0 .../Contents/Resources/scrolltextwidget.py | 27 - .../Contents/Resources/subasyncio.py | 148 -- .../Contents/Resources/topazextract.py | 14 +- .../DeDRM.app/Contents/Resources/utilities.py | 0 .../Contents/Resources/zipfilerugged.py | 2 +- .../DeDRM.app/Contents/Resources/zipfix.py | 51 +- .../DeDRM_App/DeDRM_lib/DeDRM_app.pyw | 137 +- .../DeDRM_Adobe Digital Editions Key_Help.htm | 55 + .../lib/DeDRM_Barnes and Noble Key_Help.htm | 57 + .../DeDRM_EInk Kindle Serial Number_Help.htm | 43 + .../DeDRM_App/DeDRM_lib/lib/DeDRM_Help.htm | 73 + .../DeDRM_Kindle for Mac and PC Key_Help.htm | 55 + .../lib/DeDRM_Mobipocket PID_Help.htm | 42 + .../DeDRM_lib/lib/DeDRM_eReader Key_Help.htm | 56 + .../DeDRM_App/DeDRM_lib/lib/__init__.py | 450 ++++ .../DeDRM_App/DeDRM_lib/lib/adobekey.py | 184 +- .../DeDRM_App/DeDRM_lib/lib/askfolder_ed.py | 211 ++ .../DeDRM_App/DeDRM_lib/lib/config.py | 482 ++++- .../DeDRM_App/DeDRM_lib/lib/convert2xml.py | 11 +- .../DeDRM_App/DeDRM_lib/lib/dialogs.py | 719 +++++++ .../DeDRM_App/DeDRM_lib/lib/epubtest.py | 4 +- .../DeDRM_App/DeDRM_lib/lib/erdr2pml.py | 15 +- .../DeDRM_App/DeDRM_lib/lib/genbook.py | 8 +- .../DeDRM_App/DeDRM_lib/lib/ignobleepub.py | 49 +- .../DeDRM_App/DeDRM_lib/lib/ignoblekeygen.py | 29 +- .../DeDRM_App/DeDRM_lib/lib/ineptepub.py | 49 +- .../DeDRM_App/DeDRM_lib/lib/k4mobidedrm.py | 53 +- .../DeDRM_App/DeDRM_lib/lib/kgenpids.py | 71 +- .../DeDRM_App/DeDRM_lib/lib/kindlekey.py | 1893 +++++++++++++++++ .../DeDRM_App/DeDRM_lib/lib/mobidedrm.py | 2 +- .../DeDRM_App/DeDRM_lib/lib/openssl_des.py | 2 +- .../DeDRM_lib/lib/scriptinterface.py | 102 +- .../DeDRM_App/DeDRM_lib/lib/topazextract.py | 14 +- .../DeDRM_App/DeDRM_lib/lib/utilities.py | 39 + .../DeDRM_App/DeDRM_lib/lib/zipfilerugged.py | 2 +- .../DeDRM_App/DeDRM_lib/lib/zipfix.py | 51 +- .../DeDRM_App_ReadMe.txt | 66 + DeDRM_Windows_Application/DeDRM_ReadMe.txt | 52 - DeDRM_calibre_plugin/DeDRM_plugin.zip | Bin 0 -> 319654 bytes .../DeDRM_Adobe Digital Editions Key_Help.htm | 55 + .../DeDRM_Barnes and Noble Key_Help.htm | 57 + .../DeDRM_EInk Kindle Serial Number_Help.htm | 43 + .../DeDRM_plugin/DeDRM_Help.htm | 73 + .../DeDRM_Kindle for Mac and PC Key_Help.htm | 55 + .../DeDRM_Mobipocket PID_Help.htm | 42 + .../DeDRM_plugin/DeDRM_eReader Key_Help.htm | 56 + DeDRM_calibre_plugin/DeDRM_plugin/__init__.py | 450 ++++ .../DeDRM_plugin/adobekey.py | 184 +- .../DeDRM_plugin}/aescbc.py | 0 .../DeDRM_plugin}/alfcrypto.dll | Bin .../DeDRM_plugin}/alfcrypto.py | 0 .../DeDRM_plugin}/alfcrypto64.dll | Bin .../DeDRM_plugin}/alfcrypto_src.zip | Bin DeDRM_calibre_plugin/DeDRM_plugin/config.py | 464 ++++ .../DeDRM_plugin}/convert2xml.py | 11 +- DeDRM_calibre_plugin/DeDRM_plugin/dialogs.py | 719 +++++++ .../DeDRM_plugin/encodebase64.py | 45 + DeDRM_calibre_plugin/DeDRM_plugin/epubtest.py | 169 ++ .../DeDRM_plugin}/erdr2pml.py | 15 +- .../DeDRM_plugin}/flatxml2html.py | 0 .../DeDRM_plugin}/flatxml2svg.py | 0 .../DeDRM_plugin}/genbook.py | 8 +- .../DeDRM_plugin/ignobleepub.py | 49 +- .../DeDRM_plugin/ignoblekeygen.py | 29 +- .../DeDRM_plugin}/ineptepub.py | 49 +- .../DeDRM_plugin}/ineptpdf.py | 0 .../DeDRM_plugin}/k4mobidedrm.py | 53 +- .../DeDRM_plugin}/kgenpids.py | 71 +- .../DeDRM_plugin/kindlekey.py | 1893 +++++++++++++++++ .../DeDRM_plugin}/kindlepid.py | 0 .../DeDRM_plugin}/libalfcrypto.dylib | Bin .../DeDRM_plugin}/libalfcrypto32.so | Bin .../DeDRM_plugin}/libalfcrypto64.so | Bin .../DeDRM_plugin}/mobidedrm.py | 2 +- .../DeDRM_plugin}/openssl_des.py | 2 +- .../DeDRM_plugin/plugin-import-name-dedrm.txt | 0 .../DeDRM_plugin}/pycrypto_des.py | 0 .../DeDRM_plugin}/python_des.py | 0 .../DeDRM_plugin}/stylexml2css.py | 0 .../DeDRM_plugin}/topazextract.py | 14 +- .../DeDRM_plugin/utilities.py | 39 + .../DeDRM_plugin}/zipfilerugged.py | 2 +- .../DeDRM_plugin}/zipfix.py | 51 +- .../DeDRM_plugin_ReadMe.txt | 79 +- .../Adobe_Digital_Editions/adobekey.pyw | 594 ++++++ .../Barnes_and_Noble_ePubs/ignoblekeygen.pyw | 324 +++ .../Kindle_for_Mac_and_PC/kindlekey.pyw | 1893 +++++++++++++++++ Other_Tools/Rocket_ebooks/rebhack.zip | Bin 0 -> 206771 bytes Other_Tools/Rocket_ebooks/rebhack_ReadMe.txt | 8 + ReadMe_First.txt | 40 +- 150 files changed, 16383 insertions(+), 5733 deletions(-) delete mode 100644 Calibre_Plugins/Ignobleepub_ReadMe.txt delete mode 100644 Calibre_Plugins/Ineptepub_ReadMe.txt delete mode 100644 Calibre_Plugins/Ineptpdf_ReadMe.txt delete mode 100644 Calibre_Plugins/K4MobiDeDRM_plugin/__init__.py delete mode 100644 Calibre_Plugins/K4MobiDeDRM_plugin/config.py delete mode 100644 Calibre_Plugins/K4MobiDeDRM_plugin/getk4pcpids.py delete mode 100644 Calibre_Plugins/K4MobiDeDRM_plugin/scrolltextwidget.py delete mode 100644 Calibre_Plugins/K4MobiDeDRM_plugin/subasyncio.py delete mode 100644 Calibre_Plugins/eReaderPDB2PML_ReadMe.txt delete mode 100644 Calibre_Plugins/eReaderPDB2PML_plugin.zip delete mode 100644 Calibre_Plugins/eReaderPDB2PML_plugin/__init__.py delete mode 100644 Calibre_Plugins/ignobleepub_plugin.zip delete mode 100644 Calibre_Plugins/ignobleepub_plugin/Ignoble Epub DeDRM_Help.htm delete mode 100644 Calibre_Plugins/ignobleepub_plugin/__init__.py delete mode 100644 Calibre_Plugins/ignobleepub_plugin/config.py delete mode 100644 Calibre_Plugins/ignobleepub_plugin/dialogs.py delete mode 100644 Calibre_Plugins/ignobleepub_plugin/ignobleepub.py delete mode 100644 Calibre_Plugins/ignobleepub_plugin/utilities.py delete mode 100644 Calibre_Plugins/ignobleepub_plugin/zipfilerugged.py delete mode 100644 Calibre_Plugins/ineptepub_plugin.zip delete mode 100644 Calibre_Plugins/ineptepub_plugin/__init__.py delete mode 100644 Calibre_Plugins/ineptepub_plugin/plugin-import-name-ineptepub.txt delete mode 100644 Calibre_Plugins/ineptpdf_plugin.zip delete mode 100644 Calibre_Plugins/ineptpdf_plugin/__init__.py delete mode 100644 Calibre_Plugins/ineptpdf_plugin/plugin-import-name-ineptpdf.txt delete mode 100644 Calibre_Plugins/k4mobidedrm_plugin.zip delete mode 100644 Calibre_Plugins/k4mobidedrm_plugin/k4mutils.py delete mode 100644 Calibre_Plugins/k4mobidedrm_plugin/k4pcutils.py create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Adobe Digital Editions Key_Help.htm create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Barnes and Noble Key_Help.htm create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_EInk Kindle Serial Number_Help.htm create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Help.htm create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Mac and PC Key_Help.htm create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Mobipocket PID_Help.htm create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_eReader Key_Help.htm create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py rename Calibre_Plugins/ineptpdf_plugin/ineptkey.py => DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/adobekey.py (76%) create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/dialogs.py delete mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/getk4pcpids.py delete mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mutils.py delete mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4pcutils.py create mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py rename Calibre_Plugins/K4MobiDeDRM_plugin/plugin-import-name-k4mobidedrm.txt => DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/plugin-import-name-dedrm.txt (100%) delete mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/scrolltextwidget.py delete mode 100644 DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/subasyncio.py rename Calibre_Plugins/ignobleepub_plugin/zipfix.py => DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/utilities.py (100%) create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Adobe Digital Editions Key_Help.htm create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Barnes and Noble Key_Help.htm create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_EInk Kindle Serial Number_Help.htm create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Help.htm create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Kindle for Mac and PC Key_Help.htm create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Mobipocket PID_Help.htm create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_eReader Key_Help.htm create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py rename DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.py => DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/adobekey.py (76%) create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/askfolder_ed.py create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/dialogs.py create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py create mode 100644 DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/utilities.py create mode 100644 DeDRM_Windows_Application/DeDRM_App_ReadMe.txt delete mode 100644 DeDRM_Windows_Application/DeDRM_ReadMe.txt create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin.zip create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Adobe Digital Editions Key_Help.htm create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Barnes and Noble Key_Help.htm create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_EInk Kindle Serial Number_Help.htm create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Help.htm create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Kindle for Mac and PC Key_Help.htm create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Mobipocket PID_Help.htm create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_eReader Key_Help.htm create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/__init__.py rename Calibre_Plugins/ineptepub_plugin/ineptkey.py => DeDRM_calibre_plugin/DeDRM_plugin/adobekey.py (76%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/aescbc.py (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/alfcrypto.dll (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/alfcrypto.py (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/alfcrypto64.dll (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/alfcrypto_src.zip (100%) create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/config.py rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/convert2xml.py (98%) create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/dialogs.py create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/encodebase64.py create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/epubtest.py rename {Calibre_Plugins/eReaderPDB2PML_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/erdr2pml.py (98%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/flatxml2html.py (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/flatxml2svg.py (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/genbook.py (99%) rename Calibre_Plugins/ignobleepub_plugin/ignoblekeygen.py => DeDRM_calibre_plugin/DeDRM_plugin/ignobleepub.py (89%) rename Calibre_Plugins/ignobleepub_plugin/plugin-import-name-ignobleepub.txt => DeDRM_calibre_plugin/DeDRM_plugin/ignoblekeygen.py (92%) rename {Calibre_Plugins/ineptepub_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/ineptepub.py (91%) rename {Calibre_Plugins/ineptpdf_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/ineptpdf.py (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/k4mobidedrm.py (86%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/kgenpids.py (79%) create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/kindlepid.py (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/libalfcrypto.dylib (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/libalfcrypto32.so (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/libalfcrypto64.so (100%) rename {Calibre_Plugins/k4mobidedrm_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/mobidedrm.py (99%) rename {Calibre_Plugins/eReaderPDB2PML_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/openssl_des.py (98%) rename Calibre_Plugins/eReaderPDB2PML_plugin/plugin-import-name-erdrpdb2pml.txt => DeDRM_calibre_plugin/DeDRM_plugin/plugin-import-name-dedrm.txt (100%) rename {Calibre_Plugins/eReaderPDB2PML_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/pycrypto_des.py (100%) rename {Calibre_Plugins/eReaderPDB2PML_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/python_des.py (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/stylexml2css.py (100%) rename {Calibre_Plugins/K4MobiDeDRM_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/topazextract.py (97%) create mode 100644 DeDRM_calibre_plugin/DeDRM_plugin/utilities.py rename {Calibre_Plugins/ineptepub_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/zipfilerugged.py (99%) rename {Calibre_Plugins/ineptepub_plugin => DeDRM_calibre_plugin/DeDRM_plugin}/zipfix.py (70%) rename Calibre_Plugins/K4MobiDeDRM_ReadMe.txt => DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt (53%) create mode 100644 Other_Tools/DRM_Key_Scripts/Adobe_Digital_Editions/adobekey.pyw create mode 100644 Other_Tools/DRM_Key_Scripts/Barnes_and_Noble_ePubs/ignoblekeygen.pyw create mode 100644 Other_Tools/DRM_Key_Scripts/Kindle_for_Mac_and_PC/kindlekey.pyw create mode 100644 Other_Tools/Rocket_ebooks/rebhack.zip create mode 100644 Other_Tools/Rocket_ebooks/rebhack_ReadMe.txt diff --git a/Calibre_Plugins/Ignobleepub_ReadMe.txt b/Calibre_Plugins/Ignobleepub_ReadMe.txt deleted file mode 100644 index 5cbe648..0000000 --- a/Calibre_Plugins/Ignobleepub_ReadMe.txt +++ /dev/null @@ -1,70 +0,0 @@ -Ignoble Epub DeDRM - ignobleepub_v02.6_plugin.zip -================================================= - -All credit given to i♥cabbages for the original standalone scripts. I had the much easier job of converting them to a calibre plugin. - -This plugin is meant to decrypt Barnes & Noble Epubs that are protected with Adobe's Adept encryption. It is meant to function without having to install any dependencies... other than having calibre installed, of course. It will still work if you have Python and PyCrypto already installed, but they aren't necessary. - - -Installation ------------- - -Do **NOT** select "Get plugins to enhance calibre" as this is reserved for "official" calibre plugins, instead select "Change calibre behavior" to go to Calibre's Preferences page. Under "Advanced" click on the Plugins button. Use the "Load plugin from file" button to select the plugin's zip file (ignobleepub_v02.6_plugin.zip) and click the 'Add' button. Click 'Yes' in the the "Are you sure?" dialog. Click OK in the "Success" dialog. - - -Customization -------------- - -Upon first installing the plugin (or upgrading from a version earlier than 0.2.0), the plugin will be unconfigured. Until you create at least one B&N key—or migrate your existing key(s)/data from an earlier version of the plugin—the plugin will not function. When unconfigured (no saved keys)... an error message will occur whenever ePubs are imported to calibre. To eliminate the error message, open the plugin's customization dialog and create/import/migrate a key (or disable/uninstall the plugin). You can get to the plugin's customization dialog by opening calibre's Preferences dialog, and clicking Plugins (under the Advanced section). Once in the Plugin Preferences, expand the "File type plugins" section and look for the "Ignoble Epub DeDRM" plugin. Highlight that plugin and click the "Customize plugin" button. - -Upgrading from old keys - -If you are upgrading from an earlier version of this plugin and have provided your name(s) and credit card number(s) as part of the old plugin's customization string, you will be prompted to migrate this data to the plugin's new, more secure, key storage method when you open the customization dialog for the first time. If you choose NOT to migrate that data, you will be prompted to save that data as a text file in a location of your choosing. Either way, this plugin will no longer be storing names and credit card numbers in plain sight (or anywhere for that matter) on your computer or in calibre. If you don't choose to migrate OR save the data, that data will be lost. You have been warned!! - -Upon configuring for the first time, you may also be asked if you wish to import your existing *.b64 keyfiles (if you use them) to the plugin's new key storage method. The new plugin no longer looks for keyfiles in calibre's configuration directory, so it's highly recommended that you import any existing keyfiles when prompted ... but you always have the ability to import existing keyfiles anytime you might need/want to. - -If you have upgraded from an earlier version of the plugin, the above instructions may be all you need to do to get the new plugin up and running. Continue reading for new-key generation and existing-key management instructions. - -Creating New Keys: - -On the right-hand side of the plugin's customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key. - -* Unique Key Name: this is a unique name you choose to help you identify the key after it's created. This name will show in the list of configured keys. Choose something that will help you remember the data (name, cc#) it was created with. -* Your Name: Your name as set in your Barnes & Noble account, My Account page, directly under PERSONAL INFORMATION. It is usually just your first name and last name separated by a space. This name will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that's stored in the preferences. For some B&N accounts, the name to use is the name used in the default shipping address. For some B&N accounts, the name to use is the name used for the default Credit Card. -* Credit Card number: this is the credit card number that was set as default with Barnes & Noble at the time of download. Nothing fancy here; no dashes or spaces ... just the 16 (15?) digits. Again... this number will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that's stored in the preferences. -Click the 'OK" button to create and store the generated key. Or Cancel if you didn't want to create a key. - -Deleting Keys: - -On the right-hand side of the plugin's customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that's what you truly mean to do. Once gone, it's permanently gone. - -Exporting Keys: - -On the right-hand side of the plugin's customization dialog, you will see a button with an icon that looks like a computer's hard-drive. Use this button to export the highlighted key to a file (*.b64). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file. - -Importing Existing Keyfiles: - -At the bottom-left of the plugin's customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing *.b64 keyfiles. Used for migrating keyfiles from older versions of the plugin (or keys generated with the original I <3 Cabbages script), or moving keyfiles from computer to computer, or restoring a backup. Some very basic validation is done to try to avoid overwriting already configured keys with incoming, imported keyfiles with the same base file name, but I'm sure that could be broken if someone tried hard. Just take care when importing. - -Once done creating/importing/exporting/deleting decryption keys; click "OK" to exit the customization dialogue (the cancel button will actually work the same way here ... at this point all data/changes are committed already, so take your pick). - -Troubleshooting ---------------- - -If you find that it's not working for you (imported ebooks still have DRM), you can save a lot of time and trouble by first deleting the DRMed ebook from calibre and then trying to add the ebook to calibre with the command line tools. This will print out a lot of helpful debugging info that can be copied into any online help requests. I'm going to ask you to do it first, anyway, so you might as well get used to it. ;) - -On Macintosh only you must first run calibre, open Preferences, open Miscellaneous, and click on the “Install command line tools” button. (On Windows and Linux the command line tools are installed automatically.) - -On Windows, open a terminal/command window. (Start/Run… and then type 'cmd' (without the 's) as the program to run). -On Macintosh, open the Terminal application (in your Utilities folder). -On Linux open a command window. Hopefully all Linux users know how to do this, as I do not. - -You should now have a text-based command-line window open. Also have open the folder containing the ebook to be imported. Make sure that book isn’t already in calibre, and that calibre isn’t running. - -Now type in "calibredb add " (without the " but don’t miss that final space) and now drag the book to be imported onto the window. The full path to the book should be inserted into the command line. Now press the return/enter key. The import routines will run and produce some logging information. - -Now copy the output from the terminal window. -On Windows, you must use the window menu (little icon at left of window bar) to select all the text and then to copy it. -On Macintosh and Linux, just use the normal text select and copy commands. - -Paste the information into a comment at my blog, http://apprenticealf.wordpress.com/ describing your problem. diff --git a/Calibre_Plugins/Ineptepub_ReadMe.txt b/Calibre_Plugins/Ineptepub_ReadMe.txt deleted file mode 100644 index dabcb28..0000000 --- a/Calibre_Plugins/Ineptepub_ReadMe.txt +++ /dev/null @@ -1,114 +0,0 @@ -Inept Epub DeDRM - ineptepub_v02.1_plugin.zip -============================================= - -All credit given to i♥cabbages for the original standalone scripts. I had the much easier job of converting them to a Calibre plugin. - -This plugin is meant to decrypt Adobe Digital Edition Epubs that are protected with Adobe's Adept encryption. It is meant to function without having to install any dependencies... other than having Calibre installed, of course. It will still work if you have Python and PyCrypto already installed, but they aren't necessary. - - -Installation ------------- - -Do **NOT** select "Get plugins to enhance calibre" as this is reserved for "official" calibre plugins, instead select "Change calibre behavior" to go to Calibre's Preferences page. Under "Advanced" click on the Plugins button. Use the "Load plugin from file" button to select the plugin's zip file (ineptepub_v02.1_plugin.zip) and click the 'Add' button. Click 'Yes' in the the "Are you sure?" dialog. Click OK in the "Success" dialog. - - - -Customization -------------- - -When first run, the plugin will attempt to find your Adobe Digital Editions installation (on Windows and Mac OS). If successful, it will create 'calibre-adeptkey[number].der' file(s) and save them in Calibre's configuration directory. It will use those files and any other '*.der' files in any decryption attempts. If there is already at least one 'calibre-adept*.der' file in the directory, the plugin won't attempt to find the Adobe Digital Editions installation keys again. - -So if you have Adobe Digital Editions installation installed on the same machine as Calibre... you are ready to go. If not... keep reading. - -If you already have keyfiles generated with i♥cabbages' ineptkey.pyw script, you can put those keyfiles in Calibre's configuration directory. The easiest way to find the correct directory is to go to Calibre's Preferences page... click on the 'Miscellaneous' button (looks like a gear), and then click the 'Open Calibre configuration directory' button. Paste your keyfiles in there. Just make sure that they have different names and are saved with the '.der' extension (like the ineptkey script produces). This directory isn't touched when upgrading Calibre, so it's quite safe to leave them there. - -Since there is no Linux version of Adobe Digital Editions, Linux users will have to obtain a keyfile through other methods and put the file in Calibre's configuration directory. - -All keyfiles with a '.der' extension found in Calibre's configuration directory will be used to attempt to decrypt a book. - - -** NOTE ** There is no plugin customization data for the Inept Epub DeDRM plugin. - - -Troubleshooting ---------------- - -If you find that it's not working for you (imported ebooks still have DRM), you can save a lot of time and trouble by first deleting the DRMed ebook from calibre and then trying to add the ebook to calibre with the command line tools. This will print out a lot of helpful debugging info that can be copied into any online help requests. I'm going to ask you to do it first, anyway, so you might as well get used to it. ;) - -On Macintosh only you must first run calibre, open Preferences, open Miscellaneous, and click on the “Install command line tools” button. (On Windows and Linux the command line tools are installed automatically.) - -On Windows, open a terminal/command window. (Start/Run… and then type ‘cmd’ (without the ‘s) as the program to run). -On Macintosh, open the Terminal application (in your Utilities folder). -On Linux open a command window. Hopefully all Linux users know how to do this, as I do not. - -You should now have a text-based command-line window open. Also have open the folder containing the ebook to be imported. Make sure that book isn’t already in calibre, and that calibre isn’t running. - -Now type in "calibredb add " (without the " but don’t miss that final space) and now drag the book to be imported onto the window. The full path to the book should be inserted into the command line. Now press the return/enter key. The import routines will run and produce some logging information. - -Now copy the output from the terminal window. -On Windows, you must use the window menu (little icon at left of window bar) to select all the text and then to copy it. -On Macintosh and Linux, just use the normal text select and copy commands. - -Paste the information into a comment at my blog, http://apprenticealf.wordpress.com/ describing your problem. - - -Linux and Adobe Digital Editions ePubs --------------------------------------- - -Here are the instructions for using the tools with ePub books and Adobe Digital Editions on Linux under Wine. (Thank you mclien and Fadel!) - - -1. download the most recent version of wine from winehq.org (1.3.29 in my case) - -For debian users: - -to get a recent version of wine I decited to use aptosid (2011-02, xfce) -(because I’m used to debian) -install aptosid and upgrade it (see aptosid site for detaild instructions) - - -2. properly install Wine (see the Wine site for details) - -For debian users: - -cd to this dir and install the packages as root: -‘dpkg -i *.deb’ -you will get some error messages, which can be ignored. -again as root use -‘apt-get -f install’ to correct this errors - -3. python 2.7 should already be installed on your system but you may need the following additional python package - -'apt-get install python-tk’ - -4. all programms need to be installed as normal user. The .exe files are installed using ‘wine ’ but .msi files must be installed using ‘wine start ’ -we need: -a) Adobe Digital Edition 1.7.2(from: http://kb2.adobe.com/cps/403/kb403051.html) -(there is a “can’t install ADE” site, where the setup.exe hides) - -b) ActivePython-2.7.2.5-win32-x86.msi (from: http://www.activestate.com/activepython/downloads) - -c) Win32OpenSSL_Light-0_9_8r.exe (from: http://www.slproweb.com/) - -d) pycrypto-2.3.win32-py2.7.msi (from: http://www.voidspace.org.uk/python/modules.shtml) - -5. now get and unpack the very latest tools_vX.X (from Apprentice Alf) in the users drive_c of wine -(~/.wine/drive_c/) - -6. start ADE with: -‘wine digitaleditions.exe’ or from the start menue wine-adobe-digital.. - -7. register this instance of ADE with your adobeID and close it - change to the tools_vX.X dir: -cd ~/.wine/drive_c/tools_vX.X/Other_Tools/ - -8. create the adeptkey.der with: -‘wine python ineptkey.py’ (only need once!) -(key will be here: ~/.wine/drive_c/tools_vX.X/Other_Tools/adeptkey.der) - -9. Use ADE running under Wine to dowload all of your purchased ePub ebooks - -10. install the ineptepub and ineptpdf plugins from the tools as discribed in the readmes. - -11. copy the adeptkey.der into the config dir of calibre (~/.config/calibre in debian). Your ADE books imported to calibre will automatically be freed from DRM. - diff --git a/Calibre_Plugins/Ineptpdf_ReadMe.txt b/Calibre_Plugins/Ineptpdf_ReadMe.txt deleted file mode 100644 index da7d281..0000000 --- a/Calibre_Plugins/Ineptpdf_ReadMe.txt +++ /dev/null @@ -1,113 +0,0 @@ -Inept PDF Plugin - ineptpdf_v02.0_plugin.zip -============================================ - -All credit given to i♥cabbages for the original standalone scripts. I had the much easier job of converting them to a Calibre plugin. - -This plugin is meant to decrypt Adobe Digital Edition PDFs that are protected with Adobe's Adept encryption. It is meant to function without having to install any dependencies... other than having Calibre installed, of course. It will still work if you have Python, PyCrypto and/or OpenSSL already installed, but they aren't necessary. - - -Installation ------------- - -Do **NOT** select "Get plugins to enhance calibre" as this is reserved for "official" calibre plugins, instead select "Change calibre behavior" to go to Calibre's Preferences page. Under "Advanced" click on the Plugins button. Use the "Load plugin from file" button to select the plugin's zip file (ineptpdf_v02.0_plugin.zip) and click the 'Add' button. Click 'Yes' in the the "Are you sure?" dialog. Click OK in the "Success" dialog. - - -Customization -------------- - -When first run, the plugin will attempt to find your Adobe Digital Editions installation (on Windows and Mac OS). If successful, it will create 'calibre-adeptkey[number].der' file(s) and save them in Calibre's configuration directory. It will use those files and any other '*.der' files in any decryption attempts. If there is already at least one 'calibre-adept*.der' file in the directory, the plugin won't attempt to find the Adobe Digital Editions installation keys again. - -So if you have Adobe Digital Editions installation installed on the same machine as Calibre... you are ready to go. If not... keep reading. - -If you already have keyfiles generated with i♥cabbages' ineptkey.pyw script, you can put those keyfiles in Calibre's configuration directory. The easiest way to find the correct directory is to go to Calibre's Preferences page... click on the 'Miscellaneous' button (looks like a gear), and then click the 'Open Calibre configuration directory' button. Paste your keyfiles in there. Just make sure that -they have different names and are saved with the '.der' extension (like the ineptkey script produces). This directory isn't touched when upgrading Calibre, so it's quite safe to leave them there. - -Since there is no Linux version of Adobe Digital Editions, Linux users will have to obtain a keyfile through other methods and put the file in Calibre's configuration directory. - -All keyfiles with a '.der' extension found in Calibre's configuration directory will be used to attempt to decrypt a book. - -** NOTE ** There is no plugin customization data for the Inept PDF plugin. - - -Troubleshooting ---------------- - -If you find that it's not working for you (imported ebooks still have DRM), you can save a lot of time and trouble by first deleting the DRMed ebook from calibre and then trying to add the ebook to calibre with the command line tools. This will print out a lot of helpful debugging info that can be copied into any online help requests. I'm going to ask you to do it first, anyway, so you might as well get used to it. ;) - -On Macintosh only you must first run calibre, open Preferences, open Miscellaneous, and click on the “Install command line tools” button. (On Windows and Linux the command line tools are installed automatically.) - -On Windows, open a terminal/command window. (Start/Run… and then type ‘cmd’ (without the ‘s) as the program to run). -On Macintosh, open the Terminal application (in your Utilities folder). -On Linux open a command window. Hopefully all Linux users know how to do this, as I do not. - -You should now have a text-based command-line window open. Also have open the folder containing the ebook to be imported. Make sure that book isn’t already in calibre, and that calibre isn’t running. - -Now type in "calibredb add " (without the " but don’t miss that final space) and now drag the book to be imported onto the window. The full path to the book should be inserted into the command line. Now press the return/enter key. The import routines will run and produce some logging information. - -Now copy the output from the terminal window. -On Windows, you must use the window menu (little icon at left of window bar) to select all the text and then to copy it. -On Macintosh and Linux, just use the normal text select and copy commands. - -Paste the information into a comment at my blog, http://apprenticealf.wordpress.com/ describing your problem. - - -Linux and Adobe Digital Editions PDFs --------------------------------------- - -Here are the instructions for using the tools with PDF books and Adobe Digital Editions on Linux under Wine. (Thank you mclien and Fadel!) - - -1. download the most recent version of wine from winehq.org (1.3.29 in my case) - -For debian users: - -to get a recent version of wine I decited to use aptosid (2011-02, xfce) -(because I’m used to debian) -install aptosid and upgrade it (see aptosid site for detaild instructions) - - -2. properly install Wine (see the Wine site for details) - -For debian users: - -cd to this dir and install the packages as root: -‘dpkg -i *.deb’ -you will get some error messages, which can be ignored. -again as root use -‘apt-get -f install’ to correct this errors - -3. python 2.7 should already be installed on your system but you may need the following additional python package - -'apt-get install python-tk’ - -4. all programms need to be installed as normal user. The .exe files are installed using ‘wine ’ but .msi files must be installed using ‘wine start ’ -we need: -a) Adobe Digital Editions 1.7.2(from: http://kb2.adobe.com/cps/403/kb403051.html) -(there is a “can’t install ADE” site, where the setup.exe hides) - -b) ActivePython-2.7.2.5-win32-x86.msi (from: http://www.activestate.com/activepython/downloads) - -c) Win32OpenSSL_Light-0_9_8r.exe (from: http://www.slproweb.com/) - -d) pycrypto-2.3.win32-py2.7.msi (from: http://www.voidspace.org.uk/python/modules.shtml) - -5. now get and unpack the very latest tools_vX.X (from Apprentice Alf) in the users drive_c of wine -(~/.wine/drive_c/) - -6. start ADE with: -‘wine digitaleditions.exe’ or from the start menue wine-adobe-digital.. - -7. register this instance of ADE with your adobeID and close it - change to the tools_vX.X dir: -cd ~/.wine/drive_c/tools_vX.X/Other_Tools/ - -8. create the adeptkey.der with: -‘wine python ineptkey.py’ (only need once!) -(key will be here: ~/.wine/drive_c/tools_vX.X/Other_Tools/adeptkey.der) - -9. Use ADE running under Wine to dowload all of your purchased PDF ebooks - -10. install the ineptpdf plugins from the tools as discribed in the readmes. - -11. copy the adeptkey.der into the config dir of calibre (~/.config/calibre in debian). Your ADE books imported to calibre will automatically be freed from DRM. - diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/__init__.py b/Calibre_Plugins/K4MobiDeDRM_plugin/__init__.py deleted file mode 100644 index c1dfa1b..0000000 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/__init__.py +++ /dev/null @@ -1,274 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import with_statement -__license__ = 'GPL v3' -__docformat__ = 'restructuredtext en' - - -# Released under the terms of the GNU General Public Licence, version 3 -# -# -# Requires Calibre version 0.7.55 or higher. -# -# All credit given to The Dark Reverser for the original mobidedrm script. -# Thanks to all those who've worked on the scripts since 2008 to improve -# the support for formats and sources. -# -# Revision history: -# 0.4.8 - Major code change to use unaltered k4mobidedrm.py 4.8 and later -# 0.4.9 - typo fix -# 0.4.10 - Another Topaz Fix (class added to page and group and region) -# 0.4.11 - Fixed Linux support of K4PC -# 0.4.12 - More Linux Wine fixes -# 0.4.13 - Ancient Mobipocket files fix -# 0.4.14 - Error on invalid character in book names fix -# 0.4.15 - Another Topaz fix -# 0.4.16 - Yet another Topaz fix -# 0.4.17 - Manage to include the actual fix. -# 0.4.18 - More Topaz fixes -# 0.4.19 - MobiDeDRM PalmDoc fix - -""" -Decrypt Amazon Kindle and Mobipocket encrypted ebooks. -""" - -PLUGIN_NAME = u"Kindle and Mobipocket DeDRM" -PLUGIN_VERSION_TUPLE = (0, 4, 19) -PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE]) - -import sys, os, re -import time -from zipfile import ZipFile - -from calibre.customize import FileTypePlugin -from calibre.constants import iswindows, isosx -from calibre.gui2 import is_ok_to_use_qt -from calibre.utils.config import config_dir - -# 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) - - -class K4DeDRM(FileTypePlugin): - name = PLUGIN_NAME - description = u"Removes DRM from eInk Kindle, Kindle 4 Mac and Kindle 4 PC ebooks, and from Mobipocket ebooks. Provided by the work of many including The Dark Reverser, DiapDealer, SomeUpdates, i♥cabbages, CMBDTC, Skindle, mdlnx, ApprenticeAlf, and probably others." - supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on - author = u"DiapDealer, SomeUpdates, mdlnx, Apprentice Alf and The Dark Reverser" - version = PLUGIN_VERSION_TUPLE - file_types = set(['prc','mobi','azw','azw1','azw3','azw4','tpz']) # The file types that this plugin will be applied to - on_import = True # Run this plugin during the import - priority = 521 # run this plugin before earlier versions - minimum_calibre_version = (0, 7, 55) - - def initialize(self): - """ - Dynamic modules can't be imported/loaded from a zipfile... so this routine - runs whenever the plugin gets initialized. This will extract the appropriate - library for the target OS and copy it to the 'alfcrypto' subdirectory of - calibre's configuration directory. That 'alfcrypto' directory is then - inserted into the syspath (as the very first entry) in the run function - so the CDLL stuff will work in the alfcrypto.py script. - """ - if iswindows: - names = [u"alfcrypto.dll",u"alfcrypto64.dll"] - elif isosx: - names = [u"libalfcrypto.dylib"] - else: - names = [u"libalfcrypto32.so",u"libalfcrypto64.so",u"alfcrypto.py",u"alfcrypto.dll",u"alfcrypto64.dll",u"getk4pcpids.py",u"k4mobidedrm.py",u"mobidedrm.py",u"kgenpids.py",u"k4pcutils.py",u"topazextract.py"] - lib_dict = self.load_resources(names) - self.alfdir = os.path.join(config_dir,u"alfcrypto") - if not os.path.exists(self.alfdir): - os.mkdir(self.alfdir) - for entry, data in lib_dict.items(): - file_path = os.path.join(self.alfdir, entry) - open(file_path,'wb').write(data) - - def run(self, path_to_ebook): - # make sure any unicode output gets converted safely with 'replace' - sys.stdout=SafeUnbuffered(sys.stdout) - sys.stderr=SafeUnbuffered(sys.stderr) - - starttime = time.time() - print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) - - # add the alfcrypto directory to sys.path so alfcrypto.py - # will be able to locate the custom lib(s) for CDLL import. - sys.path.insert(0, self.alfdir) - # Had to move these imports here so the custom libs can be - # extracted to the appropriate places beforehand these routines - # look for them. - from calibre_plugins.k4mobidedrm import k4mobidedrm - - k4 = True - pids = [] - serials = [] - kInfoFiles = [] - - self.config() - - # Get supplied list of PIDs to try from plugin customization. - pidstringlistt = self.pids_string.split(',') - for pid in pidstringlistt: - pid = str(pid).strip() - if len(pid) == 10 or len(pid) == 8: - pids.append(pid) - else: - if len(pid) > 0: - print u"{0} v{1}: \'{2}\' is not a valid Mobipocket PID.".format(PLUGIN_NAME, PLUGIN_VERSION, pid) - - # For linux, get PIDs by calling the right routines under WINE - if sys.platform.startswith('linux'): - k4 = False - pids.extend(self.WINEgetPIDs(path_to_ebook)) - - # Get supplied list of Kindle serial numbers to try from plugin customization. - serialstringlistt = self.serials_string.split(',') - for serial in serialstringlistt: - serial = str(serial).replace(" ","") - if len(serial) == 16 and serial[0] in ['B','9']: - serials.append(serial) - else: - if len(serial) > 0: - print u"{0} v{1}: \'{2}\' is not a valid eInk Kindle serial number.".format(PLUGIN_NAME, PLUGIN_VERSION, serial) - - # Load any kindle info files (*.info) included Calibre's config directory. - try: - print u"{0} v{1}: Calibre configuration directory is {2}".format(PLUGIN_NAME, PLUGIN_VERSION, config_dir) - files = os.listdir(config_dir) - filefilter = re.compile("\.info$|\.kinf$", re.IGNORECASE) - files = filter(filefilter.search, files) - if files: - for filename in files: - fpath = os.path.join(config_dir, filename) - kInfoFiles.append(fpath) - print u"{0} v{1}: Kindle info/kinf file {2} found in config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, filename) - except IOError, e: - print u"{0} v{1}: Error \'{2}\' reading kindle info/kinf files from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) - pass - - try: - book = k4mobidedrm.GetDecryptedBook(path_to_ebook,kInfoFiles,serials,pids,starttime) - except Exception, e: - #if you reached here then no luck raise and exception - if is_ok_to_use_qt(): - from PyQt4.Qt import QMessageBox - d = QMessageBox(QMessageBox.Warning, u"{0} v{1}".format(PLUGIN_NAME, PLUGIN_VERSION), u"Error after {1:.1f} seconds: {0}".format(e.args[0],time.time()-starttime)) - d.show() - d.raise_() - d.exec_() - raise Exception(u"{0} v{1}: Error after {3:.1f} seconds: {2}".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0],time.time()-starttime)) - - - print u"{0} v{1}: Successfully decrypted book after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-starttime) - - of = self.temporary_file(u"decrypted_ebook.{0}".format(book.getBookExtension())) - book.getFile(of.name) - book.cleanup() - return of.name - - def WINEgetPIDs(self, infile): - - import subprocess - from subprocess import Popen, PIPE, STDOUT - - import subasyncio - from subasyncio import Process - - print u" Getting PIDs from Wine" - - outfile = os.path.join(self.alfdir + u"winepids.txt") - # Remove any previous winepids.txt file. - if os.path.exists(outfile): - os.remove(outfile) - - cmdline = u"wine python.exe \"{0}/getk4pcpids.py\" \"{1}\" \"{2}\"".format(self.alfdir,infile,outfile) - env = os.environ - - print u"wine_prefix from tweaks is \'{0}\'".format(self.wine_prefix) - - if ("WINEPREFIX" in env): - print u"Using WINEPREFIX from the environment instead: \'{0}\'".format(env["WINEPREFIX"]) - elif (self.wine_prefix is not None): - env["WINEPREFIX"] = self.wine_prefix - print u"Using WINEPREFIX from tweaks \'{0}\'".format(self.wine_prefix) - else: - print u"No wine prefix used." - - print u"Trying command: {0}".format(cmdline) - - try: - cmdline = cmdline.encode(sys.getfilesystemencoding()) - p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=sys.stdout, stderr=STDOUT, close_fds=False) - result = p2.wait("wait") - except Exception, e: - print u"WINE subprocess error: {0}".format(e.args[0]) - return [] - print u"WINE subprocess returned {0}".format(result) - - WINEpids = [] - if os.path.exists(outfile): - try: - customvalues = file(outfile, 'r').readline().split(',') - for customvalue in customvalues: - customvalue = str(customvalue) - customvalue = customvalue.strip() - if len(customvalue) == 10 or len(customvalue) == 8: - WINEpids.append(customvalue) - print u"Found PID '{0}'".format(customvalue) - else: - print u"'{0}' is not a valid PID.".format(customvalue) - except Exception, e: - print u"Error parsing winepids.txt: {0}".format(e.args[0]) - return [] - if len(WINEpids) == 0: - print u"No PIDs generated by Wine Python subprocess." - return WINEpids - - def is_customizable(self): - # return true to allow customization via the Plugin->Preferences. - return True - - def config_widget(self): - # It is important to put this import statement here rather than at the - # top of the module as importing the config class will also cause the - # GUI libraries to be loaded, which we do not want when using calibre - # from the command line - from calibre_plugins.k4mobidedrm.config import ConfigWidget - return config.ConfigWidget() - - def config(self): - from calibre_plugins.k4mobidedrm.config import prefs - - self.pids_string = prefs['pids'] - self.serials_string = prefs['serials'] - self.wine_prefix = prefs['WINEPREFIX'] - - def save_settings(self, config_widget): - ''' - Save the settings specified by the user with config_widget. - ''' - config_widget.save_settings() - self.config() - - def load_resources(self, names): - ans = {} - with ZipFile(self.plugin_path, 'r') as zf: - for candidate in zf.namelist(): - if candidate in names: - ans[candidate] = zf.read(candidate) - return ans diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/config.py b/Calibre_Plugins/K4MobiDeDRM_plugin/config.py deleted file mode 100644 index 9521540..0000000 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/config.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from PyQt4.Qt import QWidget, QVBoxLayout, QLabel, QLineEdit - -from calibre.utils.config import JSONConfig - -# This is where all preferences for this plugin will be stored -# You should always prefix your config file name with plugins/, -# so as to ensure you dont accidentally clobber a calibre config file -prefs = JSONConfig('plugins/K4MobiDeDRM') - -# Set defaults -prefs.defaults['pids'] = "" -prefs.defaults['serials'] = "" -prefs.defaults['WINEPREFIX'] = None - - -class ConfigWidget(QWidget): - - def __init__(self): - QWidget.__init__(self) - self.l = QVBoxLayout() - self.setLayout(self.l) - - self.serialLabel = QLabel('eInk Kindle Serial numbers (First character B, 16 characters, use commas if more than one)') - self.l.addWidget(self.serialLabel) - - self.serials = QLineEdit(self) - self.serials.setText(prefs['serials']) - self.l.addWidget(self.serials) - self.serialLabel.setBuddy(self.serials) - - self.pidLabel = QLabel('Mobipocket PIDs (8 or 10 characters, use commas if more than one)') - self.l.addWidget(self.pidLabel) - - self.pids = QLineEdit(self) - self.pids.setText(prefs['pids']) - self.l.addWidget(self.pids) - self.pidLabel.setBuddy(self.serials) - - self.wpLabel = QLabel('For Linux only: WINEPREFIX (enter absolute path)') - self.l.addWidget(self.wpLabel) - - self.wineprefix = QLineEdit(self) - wineprefix = prefs['WINEPREFIX'] - if wineprefix is not None: - self.wineprefix.setText(wineprefix) - else: - self.wineprefix.setText('') - - self.l.addWidget(self.wineprefix) - self.wpLabel.setBuddy(self.wineprefix) - - def save_settings(self): - prefs['pids'] = str(self.pids.text()).replace(" ","") - prefs['serials'] = str(self.serials.text()).replace(" ","") - winepref=str(self.wineprefix.text()) - if winepref.strip() != '': - prefs['WINEPREFIX'] = winepref - else: - prefs['WINEPREFIX'] = None diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/getk4pcpids.py b/Calibre_Plugins/K4MobiDeDRM_plugin/getk4pcpids.py deleted file mode 100644 index 1614a53..0000000 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/getk4pcpids.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/python -# -# This is a python script. You need a Python interpreter to run it. -# For example, ActiveState Python, which exists for windows. -# -# Changelog -# 1.00 - Initial version -# 1.01 - getPidList interface change - -__version__ = '1.01' - -import sys - -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) -sys.stdout=SafeUnbuffered(sys.stdout) -sys.stderr=SafeUnbuffered(sys.stderr) - -import os -import struct -import binascii -import kgenpids -import topazextract -import mobidedrm -from alfcrypto import Pukall_Cipher - -class DrmException(Exception): - pass - -def getK4PCpids(path_to_ebook): - # Return Kindle4PC PIDs. Assumes that the caller checked that we are not on Linux, which will raise an exception - - mobi = True - magic3 = file(path_to_ebook,'rb').read(3) - if magic3 == 'TPZ': - mobi = False - - if mobi: - mb = mobidedrm.MobiBook(path_to_ebook) - else: - mb = topazextract.TopazBook(path_to_ebook) - - md1, md2 = mb.getPIDMetaInfo() - - return kgenpids.getPidList(md1, md2) - - -def main(argv=sys.argv): - print ('getk4pcpids.py v%(__version__)s. ' - 'Copyright 2012 Apprentice Alf' % globals()) - - if len(argv)<2 or len(argv)>3: - print "Gets the possible book-specific PIDs from K4PC for a particular book" - print "Usage:" - print " %s []" % sys.argv[0] - return 1 - else: - infile = argv[1] - try: - pidlist = getK4PCpids(infile) - except DrmException, e: - print "Error: %s" % e - return 1 - pidstring = ','.join(pidlist) - print "Possible PIDs are: ", pidstring - if len(argv) is 3: - outfile = argv[2] - file(outfile, 'w').write(pidstring) - - return 0 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/scrolltextwidget.py b/Calibre_Plugins/K4MobiDeDRM_plugin/scrolltextwidget.py deleted file mode 100644 index 98b4147..0000000 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/scrolltextwidget.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab - -import Tkinter -import Tkconstants - -# basic scrolled text widget -class ScrolledText(Tkinter.Text): - def __init__(self, master=None, **kw): - self.frame = Tkinter.Frame(master) - self.vbar = Tkinter.Scrollbar(self.frame) - self.vbar.pack(side=Tkconstants.RIGHT, fill=Tkconstants.Y) - kw.update({'yscrollcommand': self.vbar.set}) - Tkinter.Text.__init__(self, self.frame, **kw) - self.pack(side=Tkconstants.LEFT, fill=Tkconstants.BOTH, expand=True) - self.vbar['command'] = self.yview - # Copy geometry methods of self.frame without overriding Text - # methods = hack! - text_meths = vars(Tkinter.Text).keys() - methods = vars(Tkinter.Pack).keys() + vars(Tkinter.Grid).keys() + vars(Tkinter.Place).keys() - methods = set(methods).difference(text_meths) - for m in methods: - if m[0] != '_' and m != 'config' and m != 'configure': - setattr(self, m, getattr(self.frame, m)) - - def __str__(self): - return str(self.frame) diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/subasyncio.py b/Calibre_Plugins/K4MobiDeDRM_plugin/subasyncio.py deleted file mode 100644 index de084d3..0000000 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/subasyncio.py +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env python -# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab - -import os, sys -import signal -import threading -import subprocess -from subprocess import Popen, PIPE, STDOUT - -# **heavily** chopped up and modfied version of asyncproc.py -# to make it actually work on Windows as well as Mac/Linux -# For the original see: -# "http://www.lysator.liu.se/~bellman/download/" -# author is "Thomas Bellman " -# available under GPL version 3 or Later - -# create an asynchronous subprocess whose output can be collected in -# a non-blocking manner - -# What a mess! Have to use threads just to get non-blocking io -# in a cross-platform manner - -# luckily all thread use is hidden within this class - -class Process(object): - def __init__(self, *params, **kwparams): - if len(params) <= 3: - kwparams.setdefault('stdin', subprocess.PIPE) - if len(params) <= 4: - kwparams.setdefault('stdout', subprocess.PIPE) - if len(params) <= 5: - kwparams.setdefault('stderr', subprocess.PIPE) - self.__pending_input = [] - self.__collected_outdata = [] - self.__collected_errdata = [] - self.__exitstatus = None - self.__lock = threading.Lock() - self.__inputsem = threading.Semaphore(0) - self.__quit = False - - self.__process = subprocess.Popen(*params, **kwparams) - - if self.__process.stdin: - self.__stdin_thread = threading.Thread( - name="stdin-thread", - target=self.__feeder, args=(self.__pending_input, - self.__process.stdin)) - self.__stdin_thread.setDaemon(True) - self.__stdin_thread.start() - - if self.__process.stdout: - self.__stdout_thread = threading.Thread( - name="stdout-thread", - target=self.__reader, args=(self.__collected_outdata, - self.__process.stdout)) - self.__stdout_thread.setDaemon(True) - self.__stdout_thread.start() - - if self.__process.stderr: - self.__stderr_thread = threading.Thread( - name="stderr-thread", - target=self.__reader, args=(self.__collected_errdata, - self.__process.stderr)) - self.__stderr_thread.setDaemon(True) - self.__stderr_thread.start() - - def pid(self): - return self.__process.pid - - def kill(self, signal): - self.__process.send_signal(signal) - - # check on subprocess (pass in 'nowait') to act like poll - def wait(self, flag): - if flag.lower() == 'nowait': - rc = self.__process.poll() - else: - rc = self.__process.wait() - if rc != None: - if self.__process.stdin: - self.closeinput() - if self.__process.stdout: - self.__stdout_thread.join() - if self.__process.stderr: - self.__stderr_thread.join() - return self.__process.returncode - - def terminate(self): - if self.__process.stdin: - self.closeinput() - self.__process.terminate() - - # thread gets data from subprocess stdout - def __reader(self, collector, source): - while True: - data = os.read(source.fileno(), 65536) - self.__lock.acquire() - collector.append(data) - self.__lock.release() - if data == "": - source.close() - break - return - - # thread feeds data to subprocess stdin - def __feeder(self, pending, drain): - while True: - self.__inputsem.acquire() - self.__lock.acquire() - if not pending and self.__quit: - drain.close() - self.__lock.release() - break - data = pending.pop(0) - self.__lock.release() - drain.write(data) - - # non-blocking read of data from subprocess stdout - def read(self): - self.__lock.acquire() - outdata = "".join(self.__collected_outdata) - del self.__collected_outdata[:] - self.__lock.release() - return outdata - - # non-blocking read of data from subprocess stderr - def readerr(self): - self.__lock.acquire() - errdata = "".join(self.__collected_errdata) - del self.__collected_errdata[:] - self.__lock.release() - return errdata - - # non-blocking write to stdin of subprocess - def write(self, data): - if self.__process.stdin is None: - raise ValueError("Writing to process with stdin not a pipe") - self.__lock.acquire() - self.__pending_input.append(data) - self.__inputsem.release() - self.__lock.release() - - # close stdinput of subprocess - def closeinput(self): - self.__lock.acquire() - self.__quit = True - self.__inputsem.release() - self.__lock.release() diff --git a/Calibre_Plugins/eReaderPDB2PML_ReadMe.txt b/Calibre_Plugins/eReaderPDB2PML_ReadMe.txt deleted file mode 100644 index 69a07ff..0000000 --- a/Calibre_Plugins/eReaderPDB2PML_ReadMe.txt +++ /dev/null @@ -1,42 +0,0 @@ -eReader PDB2PML - eReaderPDB2PML_v08_plugin.zip -=============================================== - -All credit given to The Dark Reverser for the original standalone script. I had the much easier job of converting it to a Calibre plugin. - -This plugin is meant to convert secure Ereader files (PDB) to unsecured PMLZ files. Calibre can then convert it to whatever format you desire. It is meant to function without having to install any dependencies... other than having Calibre installed, of course. I've included the psyco libraries (compiled for each platform) for speed. If your system can use them, great! Otherwise, they won't be used and things will just work slower. - - -Installation ------------- - -Do **NOT** select "Get plugins to enhance calibre" as this is reserved for "official" calibre plugins, instead select "Change calibre behavior" to go to Calibre's Preferences page. Under "Advanced" click on the Plugins button. Use the "Load plugin from file" button to select the plugin's zip file (eReaderPDB2PML_v08_plugin.zip) and click the 'Add' button. Click 'Yes' in the the "Are you sure?" dialog. Click OK in the "Success" dialog. - - -Customization -------------- - -Highlight the plugin (eReader PDB 2 PML under the "File type plugins" category) and click the "Customize Plugin" button on Calibre's Preferences->Plugins page. Enter your name and last 8 digits of the credit card number separated by a comma: Your Name,12341234 - -If you've purchased books with more than one credit card, separate the info with a colon: Your Name,12341234:Other Name,23452345 - - -Troubleshooting ---------------- - -If you find that it's not working for you (imported ebooks still have DRM), you can save a lot of time and trouble by first deleting the DRMed ebook from calibre and then trying to add the ebook to calibre with the command line tools. This will print out a lot of helpful debugging info that can be copied into any online help requests. I'm going to ask you to do it first, anyway, so you might as well get used to it. ;) - -On Macintosh only you must first run calibre, open Preferences, open Miscellaneous, and click on the “Install command line tools” button. (On Windows and Linux the command line tools are installed automatically.) - -On Windows, open a terminal/command window. (Start/Run… and then type ‘cmd’ (without the ‘s) as the program to run). -On Macintosh, open the Terminal application (in your Utilities folder). -On Linux open a command window. Hopefully all Linux users know how to do this, as I do not. - -You should now have a text-based command-line window open. Also have open the folder containing the ebook to be imported. Make sure that book isn’t already in calibre, and that calibre isn’t running. - -Now type in "calibredb add " (without the " but don’t miss that final space) and now drag the book to be imported onto the window. The full path to the book should be inserted into the command line. Now press the return/enter key. The import routines will run and produce some logging information. - -Now copy the output from the terminal window. -On Windows, you must use the window menu (little icon at left of window bar) to select all the text and then to copy it. -On Macintosh and Linux, just use the normal text select and copy commands. - -Paste the information into a comment at my blog, http://apprenticealf.wordpress.com/ describing your problem. diff --git a/Calibre_Plugins/eReaderPDB2PML_plugin.zip b/Calibre_Plugins/eReaderPDB2PML_plugin.zip deleted file mode 100644 index 1cee255a89c4c82d26176ef2aab4ec5b563d5ae2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15437 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 T|13SI-&Ydy diff --git a/Calibre_Plugins/eReaderPDB2PML_plugin/__init__.py b/Calibre_Plugins/eReaderPDB2PML_plugin/__init__.py deleted file mode 100644 index 62562a5..0000000 --- a/Calibre_Plugins/eReaderPDB2PML_plugin/__init__.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# eReaderPDB2PML_plugin.py -# Released under the terms of the GNU General Public Licence, version 3 -# -# -# All credit given to The Dark Reverser for the original standalone script. -# I had the much easier job of converting it to Calibre a plugin. -# -# This plugin is meant to convert secure Ereader files (PDB) to unsecured PMLZ files. -# Calibre can then convert it to whatever format you desire. -# It is meant to function without having to install any dependencies... -# other than having Calibre installed, of course. -# -# Installation: -# Go to Calibre's Preferences page... click on the Plugins button. Use the file -# dialog button to select the plugin's zip file (eReaderPDB2PML_vXX_plugin.zip) and -# click the 'Add' button. You're done. -# -# Configuration: -# Highlight the plugin (eReader PDB 2 PML) and click the -# "Customize Plugin" button on Calibre's Preferences->Plugins page. -# Enter your name and the last 8 digits of the credit card number separated by -# a comma: Your Name,12341234 -# -# If you've purchased books with more than one credit card, separate the info with -# a colon: Your Name,12341234:Other Name,23452345 -# NOTE: Do NOT put quotes around your name like you do with the original script!! -# -# Revision history: -# 0.0.1 - Initial release -# 0.0.2 - updated to distinguish it from earlier non-openssl version -# 0.0.3 - removed added psyco code as it is not supported under Calibre's Python 2.7 -# 0.0.4 - minor typos fixed -# 0.0.5 - updated to the new calibre plugin interface -# 0.0.6 - unknown changes -# 0.0.7 - improved config dialog processing and fix possible output/unicode problem -# 0.0.8 - Proper fix for unicode problems, separate out erdr2pml from plugin - -PLUGIN_NAME = u"eReader PDB 2 PML" -PLUGIN_VERSION_TUPLE = (0, 0, 8) -PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE]) - -import sys, os - -from calibre.customize import FileTypePlugin -from calibre.ptempfile import PersistentTemporaryDirectory -from calibre.constants import iswindows, isosx - -# 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) - - -class eRdrDeDRM(FileTypePlugin): - name = PLUGIN_NAME - description = u"Removes DRM from secure pdb files. Credit given to The Dark Reverser for the original standalone script." - supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on - author = u"DiapDealer, Apprentice Alf and The Dark Reverser" - version = PLUGIN_VERSION_TUPLE - file_types = set(['pdb']) # The file types that this plugin will be applied to - on_import = True # Run this plugin during the import - minimum_calibre_version = (0, 7, 55) - priority = 100 - - def run(self, path_to_ebook): - - # make sure any unicode output gets converted safely with 'replace' - sys.stdout=SafeUnbuffered(sys.stdout) - sys.stderr=SafeUnbuffered(sys.stderr) - - print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) - - infile = path_to_ebook - bookname = os.path.splitext(os.path.basename(infile))[0] - outdir = PersistentTemporaryDirectory() - pmlzfile = self.temporary_file(bookname + '.pmlz') - - if self.site_customization: - from calibre_plugins.erdrpdb2pml import erdr2pml - - keydata = self.site_customization - ar = keydata.split(':') - for i in ar: - try: - name, cc = i.split(',') - user_key = erdr2pml.getuser_key(name,cc) - except ValueError: - print u"{0} v{1}: Error parsing user supplied data.".format(PLUGIN_NAME, PLUGIN_VERSION) - return path_to_ebook - - try: - print u"{0} v{1}: Processing...".format(PLUGIN_NAME, PLUGIN_VERSION) - import time - start_time = time.time() - if erdr2pml.decryptBook(infile,pmlzfile.name,True,user_key) == 0: - print u"{0} v{1}: Elapsed time: {2:.2f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-start_time) - return pmlzfile.name - else: - raise ValueError(u"{0} v{1}: Error Creating PML file.".format(PLUGIN_NAME, PLUGIN_VERSION)) - except ValueError, e: - print u"{0} v{1}: Error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION,e.args[0]) - pass - raise Exception(u"{0} v{1}: Couldn\'t decrypt pdb file. See Apprentice Alf's blog for help.".format(PLUGIN_NAME, PLUGIN_VERSION)) - else: - raise Exception(u"{0} v{1}: No name and CC# provided.".format(PLUGIN_NAME, PLUGIN_VERSION)) - - - def customization_help(self, gui=False): - return u"Enter Account Name & Last 8 digits of Credit Card number (separate with a comma, multiple pairs with a colon)" diff --git a/Calibre_Plugins/ignobleepub_plugin.zip b/Calibre_Plugins/ignobleepub_plugin.zip deleted file mode 100644 index 1cbdaa1c4ff3b912e59ce530651550685152db19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42116 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 diff --git a/Calibre_Plugins/ignobleepub_plugin/Ignoble Epub DeDRM_Help.htm b/Calibre_Plugins/ignobleepub_plugin/Ignoble Epub DeDRM_Help.htm deleted file mode 100644 index 2c719d77dbbf396718bda3bf4774241f5829c6ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 225 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@p>Qz@gD*)5x_AdB#1TW_e-Eskd7HZ z?1`q05g{&`oS& -# -# Requires Calibre version 0.7.55 or higher. -# -# All credit given to i♥cabbages for the original standalone scripts. -# I had the much easier job of converting them to a calibre plugin. -# -# This plugin is meant to decrypt Barnes & Noble Epubs that are protected -# with a version of Adobe's Adept encryption. It is meant to function without having to -# install any dependencies... other than having calibre installed, of course. It will still -# work if you have Python and PyCrypto already installed, but they aren't necessary. -# -# Configuration: -# Check out the plugin's configuration settings by clicking the "Customize plugin" -# button when you have the "BnN ePub DeDRM" plugin highlighted (under Preferences-> -# Plugins->File type plugins). Once you have the configuration dialog open, you'll -# see a Help link on the top right-hand side. -# -# Revision history: -# 0.1.0 - Initial release -# 0.1.1 - Allow Windows users to make use of openssl if they have it installed. -# - Incorporated SomeUpdates zipfix routine. -# 0.1.2 - bug fix for non-ascii file names in encryption.xml -# 0.1.3 - Try PyCrypto on Windows first -# 0.1.4 - update zipfix to deal with mimetype not in correct place -# 0.1.5 - update zipfix to deal with completely missing mimetype files -# 0.1.6 - update for the new calibre plugin interface -# 0.1.7 - Fix for potential problem with PyCrypto -# 0.1.8 - an updated/modified zipfix.py and included zipfilerugged.py -# 0.2.0 - Completely overhauled plugin configuration dialog and key management/storage -# 0.2.1 - added zipfix.py and included zipfilerugged.py from 0.1.8 -# 0.2.2 - added in potential fixes from 0.1.7 that had been missed. -# 0.2.3 - fixed possible output/unicode problem -# 0.2.4 - ditched nearly hopeless caselessStrCmp method in favor of uStrCmp. -# - added ability to rename existing keys. -# 0.2.5 - Major code change to use unaltered ignobleepub.py 3.6 and -# - ignoblekeygen 2.4 and later. -# 0.2.6 - Tweaked to eliminate issue with both ignoble and inept calibre plugins installed/enabled at once - -""" -Decrypt Barnes & Noble ADEPT encrypted EPUB books. -""" - -PLUGIN_NAME = u"Ignoble Epub DeDRM" -PLUGIN_VERSION_TUPLE = (0, 2, 6) -PLUGIN_VERSION = '.'.join([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' - -import sys, os, re -import zipfile -from zipfile import ZipFile - -class IGNOBLEError(Exception): - pass - -from calibre.customize import FileTypePlugin -from calibre.constants import iswindows, isosx -from calibre.gui2 import is_ok_to_use_qt - -# 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) - - -class IgnobleDeDRM(FileTypePlugin): - name = PLUGIN_NAME - description = u"Removes DRM from secure Barnes & Noble epub files. Credit given to i♥cabbages for the original stand-alone scripts." - supported_platforms = ['linux', 'osx', 'windows'] - author = u"DiapDealer, Apprentice Alf 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']) - on_import = True - priority = 101 - - def run(self, path_to_ebook): - - # make sure any unicode output gets converted safely with 'replace' - sys.stdout=SafeUnbuffered(sys.stdout) - sys.stderr=SafeUnbuffered(sys.stderr) - - print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) - - # First time use or first time after upgrade to new key-handling/storage method - # or no keys configured. Give a visual prompt to configure. - import calibre_plugins.ignobleepub.config as cfg - if not cfg.prefs['configured']: - titlemsg = '%s v%s' % (PLUGIN_NAME, PLUGIN_VERSION) - errmsg = titlemsg + ' not (properly) configured!\n' + \ - '\nThis may be the first time you\'ve used this plugin' + \ - ' (or the first time since upgrading this plugin).' + \ - ' You\'ll need to open the customization dialog (Preferences->Plugins->File type plugins)' + \ - ' and follow the instructions there.\n' + \ - '\nIf you don\'t use the ' + PLUGIN_NAME + ' plugin, you should disable or uninstall it.' - if is_ok_to_use_qt(): - from PyQt4.Qt import QMessageBox - d = QMessageBox(QMessageBox.Warning, titlemsg, errmsg ) - d.show() - d.raise_() - d.exec_() - raise Exception('%s Plugin v%s: Plugin not configured.' % (PLUGIN_NAME, PLUGIN_VERSION)) - - # Create a TemporaryPersistent file to work with. - # Check original epub archive for zip errors. - from calibre_plugins.ignobleepub import zipfix - inf = self.temporary_file(u".epub") - try: - print u"{0} v{1}: Verifying zip archive integrity.".format(PLUGIN_NAME, PLUGIN_VERSION) - fr = zipfix.fixZip(path_to_ebook, inf.name) - fr.fix() - except Exception, e: - print u"{0} v{1}: Error \'{2}\' when checking zip archive.".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) - raise Exception(e) - return - - #check the book - from calibre_plugins.ignobleepub import ignobleepub - if not ignobleepub.ignobleBook(inf.name): - raise IGNOBLEError(u"{0} v{1}: {2} is not a secure Barnes & Noble ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))) - - # Attempt to decrypt epub with each encryption key (generated or provided). - for keyname, userkey in cfg.prefs['keys'].items(): - keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname) - print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked) - of = self.temporary_file(u".epub") - - # Give the user key, ebook and TemporaryPersistent file to the decryption function. - result = ignobleepub.decryptBook(userkey, inf.name, of.name) - - of.close() - - # Decryption was successful return the modified PersistentTemporary - # file to Calibre's import process. - if result == 0: - print u"{0} v{1}: Encryption successfully removed.".format(PLUGIN_NAME, PLUGIN_VERSION) - return of.name - break - - print u"{0} v{1}: Encryption key incorrect.".format(PLUGIN_NAME, PLUGIN_VERSION) - - # Something went wrong with decryption. - # Import the original unmolested epub. - raise IGNOBLEError(u"{0} v{1}: Ultimately failed to decrypt".format(PLUGIN_NAME, PLUGIN_VERSION)) - return - - def is_customizable(self): - # return true to allow customization via the Plugin->Preferences. - return True - - def config_widget(self): - from calibre_plugins.ignobleepub.config import ConfigWidget - # Extract the helpfile contents from in the plugin's zipfile. - # The helpfile must be named + '_Help.htm' - return ConfigWidget(self.load_resources(RESOURCE_NAME)[RESOURCE_NAME]) - - def load_resources(self, names): - ans = {} - with ZipFile(self.plugin_path, 'r') as zf: - for candidate in zf.namelist(): - if candidate in names: - ans[candidate] = zf.read(candidate) - return ans - - def save_settings(self, config_widget): - config_widget.save_settings() diff --git a/Calibre_Plugins/ignobleepub_plugin/config.py b/Calibre_Plugins/ignobleepub_plugin/config.py deleted file mode 100644 index 9fee73d..0000000 --- a/Calibre_Plugins/ignobleepub_plugin/config.py +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -__license__ = 'GPL v3' - -# Standard Python modules. -import os, sys, re, hashlib - -# PyQT4 modules (part of calibre). -from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, - QGroupBox, QPushButton, QListWidget, QListWidgetItem, - QAbstractItemView, QIcon, QDialog, QUrl, QString) -from PyQt4 import QtGui - -# calibre modules and constants. -from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url, - choose_dir, choose_files) -from calibre.utils.config import dynamic, config_dir, JSONConfig - -# modules from this plugin's zipfile. -from calibre_plugins.ignobleepub.__init__ import PLUGIN_NAME, PLUGIN_VERSION -from calibre_plugins.ignobleepub.__init__ import RESOURCE_NAME as help_file_name -from calibre_plugins.ignobleepub.utilities import (uStrCmp, DETAILED_MESSAGE, parseCustString) -from calibre_plugins.ignobleepub.dialogs import AddKeyDialog, RenameKeyDialog -from calibre_plugins.ignobleepub.ignoblekeygen import generate_key - -JSON_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_') -JSON_PATH = 'plugins/' + JSON_NAME + '.json' - -# This is where all preferences for this plugin will be stored -# You should always prefix your config file name with plugins/, -# so as to ensure you dont accidentally clobber a calibre config file -prefs = JSONConfig(JSON_PATH) - -# Set defaults -prefs.defaults['keys'] = {} -prefs.defaults['configured'] = False - -class ConfigWidget(QWidget): - def __init__(self, help_file_data): - QWidget.__init__(self) - - self.help_file_data = help_file_data - self.plugin_keys = prefs['keys'] - - # Handle the old plugin's customization string by either converting the - # old string to stored keys or by saving the string to a text file of the - # user's choice. Either way... get that personal data out of plain sight. - from calibre.customize.ui import config - sc = config['plugin_customization'] - val = sc.get(PLUGIN_NAME, None) - if val is not None: - title = 'Convert existing customization data?' - msg = '

Convert your existing insecure customization data? (Please '+ \ - 'read the detailed message)' - det_msg = DETAILED_MESSAGE - - # Offer to convert the old string to the new format - if question_dialog(self, _(title), _(msg), det_msg, True, True): - userkeys = parseCustString(str(val)) - if userkeys: - counter = 0 - # Yay! We found valid customization data... add it to the new plugin - for k in userkeys: - counter += 1 - self.plugin_keys['Converted Old Plugin Key - ' + str(counter)] = k - msg = '

' + str(counter) + ' User key(s) configured from old plugin customization string' - inf = info_dialog(None, _(PLUGIN_NAME + 'info_dlg'), _(msg), show=True) - val = sc.pop(PLUGIN_NAME, None) - if val is not None: - config['plugin_customization'] = sc - else: - # The existing customization string was invalid and wouldn't have - # worked anyway. Offer to save it as a text file and get rid of it. - errmsg = '

Unknown Error converting user supplied-customization string' - r = error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - self.saveOldCustomizationData(str(val)) - val = sc.pop(PLUGIN_NAME, None) - if val is not None: - config['plugin_customization'] = sc - # If they don't want to convert the old string to keys then - # offer to save the old string to a text file and delete the - # the old customization string. - else: - self.saveOldCustomizationData(str(val)) - val = sc.pop(PLUGIN_NAME, None) - if val is not None: - config['plugin_customization'] = sc - - # First time run since upgrading to new key storage method, or 0 keys configured. - # Prompt to import pre-existing key files. - if not prefs['configured']: - title = 'Import existing key files?' - msg = '

This plugin no longer uses *.b64 keyfiles stored in calibre\'s configuration '+ \ - 'directory. Do you have any exsiting key files there (or anywhere) that you\'d '+ \ - 'like to migrate into the new plugin preferences method?' - if question_dialog(self, _(title), _(msg)): - self.migrate_files() - - # Start Qt Gui dialog layout - layout = QVBoxLayout(self) - self.setLayout(layout) - - help_layout = QHBoxLayout() - layout.addLayout(help_layout) - # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. - help_label = QLabel('Plugin Help', self) - help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) - help_label.setAlignment(Qt.AlignRight) - help_label.linkActivated.connect(self.help_link_activated) - help_layout.addWidget(help_label) - - keys_group_box = QGroupBox(_('Configured Ignoble Keys:'), self) - layout.addWidget(keys_group_box) - keys_group_box_layout = QHBoxLayout() - keys_group_box.setLayout(keys_group_box_layout) - - self.listy = QListWidget(self) - self.listy.setToolTip(_('

Stored Ignoble keys that will be used for decryption')) - self.listy.setSelectionMode(QAbstractItemView.SingleSelection) - self.populate_list() - keys_group_box_layout.addWidget(self.listy) - - button_layout = QVBoxLayout() - keys_group_box_layout.addLayout(button_layout) - self._add_key_button = QtGui.QToolButton(self) - self._add_key_button.setToolTip(_('Create new key')) - self._add_key_button.setIcon(QIcon(I('plus.png'))) - self._add_key_button.clicked.connect(self.add_key) - button_layout.addWidget(self._add_key_button) - - self._delete_key_button = QtGui.QToolButton(self) - self._delete_key_button.setToolTip(_('Delete highlighted key')) - self._delete_key_button.setIcon(QIcon(I('list_remove.png'))) - self._delete_key_button.clicked.connect(self.delete_key) - button_layout.addWidget(self._delete_key_button) - - self._rename_key_button = QtGui.QToolButton(self) - self._rename_key_button.setToolTip(_('Rename highlighted key')) - self._rename_key_button.setIcon(QIcon(I('edit-select-all.png'))) - self._rename_key_button.clicked.connect(self.rename_key) - button_layout.addWidget(self._rename_key_button) - - self.export_key_button = QtGui.QToolButton(self) - self.export_key_button.setToolTip(_('Export highlighted key')) - self.export_key_button.setIcon(QIcon(I('save.png'))) - self.export_key_button.clicked.connect(self.export_key) - button_layout.addWidget(self.export_key_button) - spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) - button_layout.addItem(spacerItem) - - layout.addSpacing(20) - migrate_layout = QHBoxLayout() - layout.addLayout(migrate_layout) - self.migrate_btn = QPushButton(_('Import Existing Keyfiles'), self) - self.migrate_btn.setToolTip(_('

Import *.b64 keyfiles (used by older versions of the plugin).')) - self.migrate_btn.clicked.connect(self.migrate_wrapper) - migrate_layout.setAlignment(Qt.AlignLeft) - migrate_layout.addWidget(self.migrate_btn) - - self.resize(self.sizeHint()) - - def populate_list(self): - for key in self.plugin_keys.keys(): - self.listy.addItem(QListWidgetItem(key)) - - def add_key(self): - d = AddKeyDialog(self) - d.exec_() - - if d.result() != d.Accepted: - # New key generation cancelled. - return - self.plugin_keys[d.key_name] = generate_key(d.user_name, d.cc_number) - - self.listy.clear() - self.populate_list() - - def rename_key(self): - if not self.listy.currentItem(): - errmsg = '

No keyfile selected to export. Highlight a keyfile first.' - r = error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - return - - d = RenameKeyDialog(self) - d.exec_() - - if d.result() != d.Accepted: - # rename cancelled or moot. - return - keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8') - if not question_dialog(self, _('Are you sure?'), _('

'+ - 'Do you really want to rename the Ignoble key named %s to %s?') % (keyname, d.key_name), - show_copy_button=False, default_yes=False): - return - self.plugin_keys[d.key_name] = self.plugin_keys[keyname] - del self.plugin_keys[keyname] - - self.listy.clear() - self.populate_list() - - def delete_key(self): - if not self.listy.currentItem(): - return - keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8') - if not question_dialog(self, _('Are you sure?'), _('

'+ - 'Do you really want to delete the Ignoble key named %s?') % keyname, - show_copy_button=False, default_yes=False): - return - del self.plugin_keys[keyname] - - self.listy.clear() - self.populate_list() - - def help_link_activated(self, url): - def get_help_file_resource(): - # Copy the HTML helpfile to the plugin directory each time the - # link is clicked in case the helpfile is updated in newer plugins. - file_path = os.path.join(config_dir, 'plugins', help_file_name) - with open(file_path,'w') as f: - f.write(self.help_file_data) - return file_path - url = 'file:///' + get_help_file_resource() - open_url(QUrl(url)) - - def save_settings(self): - prefs['keys'] = self.plugin_keys - if prefs['keys']: - prefs['configured'] = True - else: - prefs['configured'] = False - - def migrate_files(self): - dynamic[PLUGIN_NAME + 'config_dir'] = config_dir - files = choose_files(self, PLUGIN_NAME + 'config_dir', - _('Select Ignoble keyfiles to import'), [('Ignoble Keyfiles', ['b64'])], False) - if files: - counter = 0 - skipped = 0 - for filename in files: - fpath = os.path.join(config_dir, filename) - new_key_name = os.path.splitext(os.path.basename(filename))[0] - match = False - for key in self.plugin_keys.keys(): - if uStrCmp(new_key_name, key, True): - skipped += 1 - msg = '

A key with the name ' + new_key_name + ' already exists!

' + \ - '

Skipping key file named ' + filename + '.

' + \ - '

Either delete the existing key and re-migrate, or ' + \ - 'create that key manually with a different name.' - inf = info_dialog(None, _(PLUGIN_NAME + 'info_dlg'), - _(msg), show=True) - match = True - break - if not match: - with open(fpath, 'rb') as f: - counter += 1 - self.plugin_keys[unicode(new_key_name)] = f.read() - - msg = '

Done migrating ' + str(counter) + ' ' + \ - 'key files...

Skipped ' + str(skipped) + ' key files.' - inf = info_dialog(None, _(PLUGIN_NAME + 'info_dlg'), - _(msg), show=True) - return 1 - return 0 - - def migrate_wrapper(self): - if self.migrate_files(): - self.listy.clear() - self.populate_list() - - def export_key(self): - if not self.listy.currentItem(): - errmsg = '

No keyfile selected to export. Highlight a keyfile first.' - r = error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - return - filter = QString('Ignoble Key Files (*.b64)') - keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8') - if dynamic.get(PLUGIN_NAME + 'save_dir'): - defaultname = os.path.join(dynamic.get(PLUGIN_NAME + 'save_dir'), keyname + '.b64') - else: - defaultname = os.path.join(os.path.expanduser('~'), keyname + '.b64') - filename = unicode(QtGui.QFileDialog.getSaveFileName(self, "Save Ignoble Key File as...", defaultname, - "Ignoble Key Files (*.b64)", filter)) - if filename: - dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0] - fname = open(filename, 'w') - fname.write(self.plugin_keys[keyname]) - fname.close() - - def saveOldCustomizationData(self, strdata): - filter = QString('Text files (*.txt)') - default_basefilename = PLUGIN_NAME + ' old customization data.txt' - defaultname = os.path.join(os.path.expanduser('~'), default_basefilename) - filename = unicode(QtGui.QFileDialog.getSaveFileName(self, "Save old plugin style customization data as...", defaultname, - "Text Files (*.txt)", filter)) - if filename: - fname = open(filename, 'w') - fname.write(strdata) - fname.close() diff --git a/Calibre_Plugins/ignobleepub_plugin/dialogs.py b/Calibre_Plugins/ignobleepub_plugin/dialogs.py deleted file mode 100644 index 8a1c345..0000000 --- a/Calibre_Plugins/ignobleepub_plugin/dialogs.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -from __future__ import with_statement -__license__ = 'GPL v3' - -from PyQt4.Qt import (Qt, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, - QGroupBox, QDialog, QDialogButtonBox) -from calibre.gui2 import error_dialog - -from calibre_plugins.ignobleepub.__init__ import PLUGIN_NAME, PLUGIN_VERSION -from calibre_plugins.ignobleepub.utilities import uStrCmp - -class AddKeyDialog(QDialog): - def __init__(self, parent=None,): - QDialog.__init__(self, parent) - self.parent = parent - self.setWindowTitle('Create New Ignoble Key') - layout = QVBoxLayout(self) - self.setLayout(layout) - - data_group_box = QGroupBox('', self) - layout.addWidget(data_group_box) - data_group_box_layout = QVBoxLayout() - data_group_box.setLayout(data_group_box_layout) - - key_group = QHBoxLayout() - data_group_box_layout.addLayout(key_group) - key_group.addWidget(QLabel('Unique Key Name:', self)) - self.key_ledit = QLineEdit('', self) - self.key_ledit.setToolTip(_('

Enter an identifying name for this new Ignoble key.

' + - '

It should be something that will help you remember ' + - 'what personal information was used to create it.')) - key_group.addWidget(self.key_ledit) - key_label = QLabel(_(''), self) - key_label.setAlignment(Qt.AlignHCenter) - data_group_box_layout.addWidget(key_label) - - name_group = QHBoxLayout() - data_group_box_layout.addLayout(name_group) - name_group.addWidget(QLabel('Your Name:', self)) - self.name_ledit = QLineEdit('', self) - self.name_ledit.setToolTip(_('

Enter your name as it appears in your B&N ' + - 'account and/or on your credit card.

' + - '

It will only be used to generate this ' + - 'one-time key and won\'t be stored anywhere ' + - 'in calibre or on your computer.

' + - '

(ex: Jonathan Smith)')) - name_group.addWidget(self.name_ledit) - name_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self) - name_disclaimer_label.setAlignment(Qt.AlignHCenter) - data_group_box_layout.addWidget(name_disclaimer_label) - - ccn_group = QHBoxLayout() - data_group_box_layout.addLayout(ccn_group) - ccn_group.addWidget(QLabel('Credit Card#:', self)) - self.cc_ledit = QLineEdit('', self) - self.cc_ledit.setToolTip(_('

Enter the full credit card number on record ' + - 'in your B&N account.

' + - '

No spaces or dashes... just the numbers. ' + - 'This CC# will only be used to generate this ' + - 'one-time key and won\'t be stored anywhere in ' + - 'calibre or on your computer.')) - ccn_group.addWidget(self.cc_ledit) - ccn_disclaimer_label = QLabel(_('Will not be stored/saved in configuration data:'), self) - ccn_disclaimer_label.setAlignment(Qt.AlignHCenter) - data_group_box_layout.addWidget(ccn_disclaimer_label) - layout.addSpacing(20) - - self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) - self.button_box.accepted.connect(self.accept) - self.button_box.rejected.connect(self.reject) - layout.addWidget(self.button_box) - - self.resize(self.parent.sizeHint()) - - def accept(self): - if (self.key_ledit.text().isEmpty() or self.name_ledit.text().isEmpty() - or self.cc_ledit.text().isEmpty()): - errmsg = '

All fields are required!' - return error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - if (unicode(self.key_ledit.text()).isspace() or unicode(self.name_ledit.text()).isspace() - or unicode(self.cc_ledit.text()).isspace()): - errmsg = '

All fields are required!' - return error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - if not unicode(self.cc_ledit.text()).isdigit(): - errmsg = '

Numbers only in the credit card number field!' - return error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - if len(self.key_ledit.text()) < 4: - errmsg = '

Key name must be at least 4 characters long!' - return error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - for k in self.parent.plugin_keys.keys(): - if uStrCmp(self.key_ledit.text(), k, True): - errmsg = '

The key name %s is already being used.' % self.key_ledit.text() - return error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - QDialog.accept(self) - - @property - def user_name(self): - return unicode(self.name_ledit.text().toUtf8(), 'utf8').strip().lower().replace(' ','') - @property - def cc_number(self): - return unicode(self.cc_ledit.text().toUtf8(), 'utf8').strip().replace(' ', '').replace('-','') - @property - def key_name(self): - return unicode(self.key_ledit.text().toUtf8(), 'utf8') - -class RenameKeyDialog(QDialog): - def __init__(self, parent=None,): - QDialog.__init__(self, parent) - self.parent = parent - self.setWindowTitle('Rename Ignoble Key') - layout = QVBoxLayout(self) - self.setLayout(layout) - - data_group_box = QGroupBox('', self) - layout.addWidget(data_group_box) - data_group_box_layout = QVBoxLayout() - data_group_box.setLayout(data_group_box_layout) - - data_group_box_layout.addWidget(QLabel('Key Name:', self)) - self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self) - self.key_ledit.setToolTip(_('

Enter a new name for this existing Ignoble key.')) - data_group_box_layout.addWidget(self.key_ledit) - - layout.addSpacing(20) - - self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) - self.button_box.accepted.connect(self.accept) - self.button_box.rejected.connect(self.reject) - layout.addWidget(self.button_box) - - def accept(self): - if self.key_ledit.text().isEmpty() or unicode(self.key_ledit.text()).isspace(): - errmsg = '

Key name field cannot be empty!' - return error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - if len(self.key_ledit.text()) < 4: - errmsg = '

Key name must be at least 4 characters long!' - return error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - if uStrCmp(self.key_ledit.text(), self.parent.listy.currentItem().text()): - # Same exact name ... do nothing. - return QDialog.reject(self) - for k in self.parent.plugin_keys.keys(): - if (uStrCmp(self.key_ledit.text(), k, True) and - not uStrCmp(k, self.parent.listy.currentItem().text(), True)): - errmsg = '

The key name %s is already being used.' % self.key_ledit.text() - return error_dialog(None, PLUGIN_NAME, - _(errmsg), show=True, show_copy_button=False) - QDialog.accept(self) - - @property - def key_name(self): - return unicode(self.key_ledit.text().toUtf8(), 'utf8') diff --git a/Calibre_Plugins/ignobleepub_plugin/ignobleepub.py b/Calibre_Plugins/ignobleepub_plugin/ignobleepub.py deleted file mode 100644 index e58bf1a..0000000 --- a/Calibre_Plugins/ignobleepub_plugin/ignobleepub.py +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - -Ignoble Epub DeDRM Plugin Configuration -

- - - -

Ignoble Epub DeDRM Plugin

-

(version 0.2.6)

-

For additional help read the FAQ on Apprentice Alf's Blog and ask questions in the comments section of the first post.

- -

All credit given to I ♥ Cabbages for the original standalone scripts (I had the much easier job of converting them to a calibre plugin).

- -

This plugin is meant to decrypt Barnes & Noble ePubs that are protected with Adobe's Adept encryption. It is meant to function without having to install any dependencies... other than having calibre installed, of course. It will still work if you have Python and PyCrypto already installed, but they aren't necessary.

- -

This help file is always available from within the plugin's customization dialog in calibre (when installed, of course). The "Plugin Help" link can be found in the upper-right portion of the customization dialog.

- -

Installation:

- -

Go to calibre's Preferences page. Do **NOT** select "Get plugins to enhance calibre" as this is reserved for "official" calibre plugins, instead select "Change calibre behavior". Under "Advanced" click on the Plugins button. Use the "Load plugin from file" button to select the plugin's zip file (ignobleepub_v02.3_plugin.zip) and click the 'Add' button. Click 'Yes' in the the "Are you sure?" dialog. Click OK in the "Success" dialog. Now restart calibre.

- - -

Configuration:

- -

Upon first installing the plugin (or upgrading from a version earlier than 0.2.0), the plugin will be unconfigured. Until you create at least one B&N key—or migrate your existing key(s)/data from an earlier version of the plugin—the plugin will not function. When unconfigured (no saved keys)... an error message will occur whenever ePubs are imported to calibre. To eliminate the error message, open the plugin's customization dialog and create/import/migrate a key (or disable/uninstall the plugin). You can get to the plugin's customization dialog by opening calibre's Preferences dialog, and clicking Plugins (under the Advanced section). Once in the Plugin Preferences, expand the "File type plugins" section and look for the "Ignoble Epub DeDRM" plugin. Highlight that plugin and click the "Customize plugin" button.

- -

If you are upgrading from an earlier version of this plugin and have provided your name(s) and credit card number(s) as part of the old plugin's customization string, you will be prompted to migrate this data to the plugin's new, more secure, key storage method when you open the customization dialog for the first time. If you choose NOT to migrate that data, you will be prompted to save that data as a text file in a location of your choosing. Either way, this plugin will no longer be storing names and credit card numbers in plain sight (or anywhere for that matter) on your computer or in calibre. If you don't choose to migrate OR save the data, that data will be lost. You have been warned!!

- -

Upon configuring for the first time, you may also be asked if you wish to import your existing *.b64 keyfiles (if you use them) to the plugin's new key storage method. The new plugin no longer looks for keyfiles in calibre's configuration directory, so it's highly recommended that you import any existing keyfiles when prompted ... but you always have the ability to import existing keyfiles anytime you might need/want to.

- -

If you have upgraded from an earlier version of the plugin, the above instructions may be all you need to do to get the new plugin up and running. Continue reading for new-key generation and existing-key management instructions.

- -

Creating New Keys:

- -

On the right-hand side of the plugin's customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key.

-
    -
  • Unique Key Name: this is a unique name you choose to help you identify the key after it's created. This name will show in the list of configured keys. Choose something that will help you remember the data (name, cc#) it was created with. -
  • Your Name: Your name as set in your Barnes & Noble account, My Account page, directly under PERSONAL INFORMATION. It is usually just your first name and last name separated by a space. This name will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that's stored in the preferences. -
  • Credit Card#: this is the default credit card number that was on file with Barnes & Noble at the time of download of the ebook to be de-DRMed. Nothing fancy here; no dashes or spaces ... just the 16 (15 for American Express) digits. Again... this number will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that's stored in the preferences. -
- -

Click the 'OK" button to create and store the generated key. Or Cancel if you didn't want to create a key.

- -

Deleting Keys:

- -

On the right-hand side of the plugin's customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that's what you truly mean to do. Once gone, it's permanently gone.

- -

Exporting Keys:

- -

On the right-hand side of the plugin's customization dialog, you will see a button with an icon that looks like a computer's hard-drive. Use this button to export the highlighted key to a file (*.b64). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

- -

Importing Existing Keyfiles:

- -

At the bottom-left of the plugin's customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing *.b64 keyfiles. Used for migrating keyfiles from older versions of the plugin (or keys generated with the original I <3 Cabbages script), or moving keyfiles from computer to computer, or restoring a backup. Some very basic validation is done to try to avoid overwriting already configured keys with incoming, imported keyfiles with the same base file name, but I'm sure that could be broken if someone tried hard. Just take care when importing.

- -

Once done creating/importing/exporting/deleting decryption keys; click "OK" to exit the customization dialogue (the cancel button will actually work the same way here ... at this point all data/changes are committed already, so take your pick).

- -

Troubleshooting:

- -

If you find that it's not working for you (imported Barnes & Noble epubs still have DRM), you can save a lot of time and trouble by trying to add the epub to Calibre with the command line tools. This will print out a lot of helpful debugging info that can be copied into any online help requests. I'm going to ask you to do it first, anyway, so you might as well get used to it. ;)

- -

Open a command prompt (terminal) and change to the directory where the ebook you're trying to import resides. Then type the command "calibredb add your_ebook.epub" **. Don't type the quotes and obviously change the 'your_ebook.epub' to whatever the filename of your book is. Copy the resulting output and paste it into any online help request you make.

- -

Another way to debug (perhaps easier if you're not all that comfortable with command-line stuff) is to launch calibre in debug mode. Open a command prompt (terminal) and type "calibre-debug -g" (again without the quotes). Calibre will launch, and you can can add the problem book(s) using the normal gui method. The debug info will be output to the original command prompt (terminal window). Copy the resulting output and paste it into any online help request you make.

-

 

-

** Note: the Mac version of Calibre doesn't install the command line tools by default. If you go to the 'Preferences' page and click on the miscellaneous button, you'll see the option to install the command line tools.

- -

 

-

Revision history:

-
-   0.1.0 - Initial release
-   0.1.1 - Allow Windows users to make use of openssl if they have it installed.
-          - Incorporated SomeUpdates zipfix routine.
-   0.1.2 - bug fix for non-ascii file names in encryption.xml
-   0.1.3 - Try PyCrypto on Windows first
-   0.1.4 - update zipfix to deal with mimetype not in correct place
-   0.1.5 - update zipfix to deal with completely missing mimetype files
-   0.1.6 - update to the new calibre plugin interface
-   0.1.7 - Fix for potential problem with PyCrypto
-   0.1.8 - an updated/modified zipfix.py and included zipfilerugged.py
-   0.2.0 - Completely overhauled plugin configuration dialog and key management/storage
-   0.2.1 - an updated/modified zipfix.py and included zipfilerugged.py
-   0.2.2 - added in potential fixes from 0.1.7 that had been missed.
-   0.2.3 - fixed possible output/unicode problem
-   0.2.4 - ditched nearly hopeless caselessStrCmp method in favor of uStrCmp.
-         - added ability to rename existing keys.
-   0.2.5 - Major code change to use unaltered ignobleepub.py 3.6 and
-         - ignoblekeygen 2.4 and later.
-   0.2.6 - Modified to alleviate the issue with having both the ignoble and inept epub plugins installed/enabled
-
- - - diff --git a/Calibre_Plugins/ignobleepub_plugin/utilities.py b/Calibre_Plugins/ignobleepub_plugin/utilities.py deleted file mode 100644 index 6555fed3e44628a21c76c99b2f02d6d9bc35a44c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 225 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 M066{q8UTR*0kO%=w*UYD diff --git a/Calibre_Plugins/ineptepub_plugin/__init__.py b/Calibre_Plugins/ineptepub_plugin/__init__.py deleted file mode 100644 index e37c051..0000000 --- a/Calibre_Plugins/ineptepub_plugin/__init__.py +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import with_statement -__license__ = 'GPL v3' -__docformat__ = 'restructuredtext en' - - -# Released under the terms of the GNU General Public Licence, version 3 -# -# -# Requires Calibre version 0.7.55 or higher. -# -# All credit given to i♥cabbages for the original standalone scripts. -# I had the much easier job of converting them to a calibre plugin. -# -# This plugin is meant to decrypt Adobe Digital Edition Epubs that are protected -# with Adobe's Adept encryption. It is meant to function without having to install -# any dependencies... other than having calibre installed, of course. It will still -# work if you have Python and PyCrypto already installed, but they aren't necessary. -# -# Configuration: -# When first run, the plugin will attempt to find your Adobe Digital Editions installation -# (on Windows and Mac OS's). If successful, it will create one or more -# 'calibre-adeptkey.der' files and save them in calibre's configuration directory. -# It will use those files on subsequent runs. If there is already a 'calibre-adeptkey*.der' -# file in the directory, the plugin won't attempt to find the ADE installation. -# So if you have ADE installed on the same machine as calibre you are ready to go. -# -# If you already have keyfiles generated with i♥cabbages' ineptkey.pyw script, -# you can put those keyfiles in Calibre's configuration directory. The easiest -# way to find the correct directory is to go to Calibre's Preferences page... click -# on the 'Miscellaneous' button (looks like a gear), and then click the 'Open Calibre -# configuration directory' button. Copy your keyfiles in there. Just make sure that -# they have different names and are saved with the '.der' extension (like the ineptkey -# script produces). This directory isn't touched when upgrading Calibre, so it's quite -# safe to leave them there. -# -# Since there is no Linux version of Adobe Digital Editions, Linux users will have to -# obtain a keyfile through other methods and put the file in Calibre's configuration directory. -# -# All keyfiles with a '.der' extension found in Calibre's configuration directory will -# be used to attempt to decrypt a book. -# -# ** NOTE ** There is no plugin customization data for the Inept Epub DeDRM plugin. -# -# Revision history: -# 0.1 - Initial release -# 0.1.1 - Allow Windows users to make use of openssl if they have it installed. -# - Incorporated SomeUpdates zipfix routine. -# 0.1.2 - Removed Carbon dependency for Mac users. Fixes an issue that was a -# result of Calibre changing to python 2.7. -# 0.1.3 - bug fix for epubs with non-ascii chars in file names -# 0.1.4 - default to try PyCrypto first on Windows -# 0.1.5 - update zipfix to handle out of position mimetypes -# 0.1.6 - update zipfix to handle completely missing mimetype files -# 0.1.7 - update to new calibre plugin interface -# 0.1.8 - Fix for potential problem with PyCrypto -# 0.1.9 - Fix for potential problem with ADE keys and fix possible output/unicode problem -# 0.2.0 - Major code change to use unaltered ineptepub.py file 5.8 or later. -# 0.2.1 - Tweaked to eliminate issue with both ignoble and inept calibre plugins installed/enabled at once - - -PLUGIN_NAME = u"Inept Epub DeDRM" -PLUGIN_VERSION_TUPLE = (0, 2, 1) -PLUGIN_VERSION = u'.'.join([str(x) for x in PLUGIN_VERSION_TUPLE]) - -import sys, os, re - -class ADEPTError(Exception): - pass - -from calibre.customize import FileTypePlugin -from calibre.constants import iswindows, isosx - -# 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) - - -class IneptDeDRM(FileTypePlugin): - name = PLUGIN_NAME - description = u"Removes DRM from secure Adobe epub files. Credit given to i♥cabbages for the original stand-alone scripts." - supported_platforms = ['linux', 'osx', 'windows'] - author = u"DiapDealer, Apprentice Alf 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']) - on_import = True - priority = 100 - - def run(self, path_to_ebook): - - # make sure any unicode output gets converted safely with 'replace' - sys.stdout=SafeUnbuffered(sys.stdout) - sys.stderr=SafeUnbuffered(sys.stderr) - - print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) - - # Create a TemporaryPersistent file to work with. - # Check original epub archive for zip errors. - from calibre_plugins.ineptepub import zipfix - inf = self.temporary_file(u".epub") - try: - print u"{0} v{1}: Verifying zip archive integrity.".format(PLUGIN_NAME, PLUGIN_VERSION) - fr = zipfix.fixZip(path_to_ebook, inf.name) - fr.fix() - except Exception, e: - print u"{0} v{1}: Error \'{2}\' when checking zip archive.".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) - raise Exception(e) - return - - #check the book - from calibre_plugins.ineptepub import ineptepub - if not ineptepub.adeptBook(inf.name): - raise ADEPTError(u"{0} v{1}: {2} is not a secure Adobe Adept ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook))) - - # Load any keyfiles (*.der) included Calibre's config directory. - userkeys = [] - # Find Calibre's configuration directory. - # self.plugin_path is passed in unicode because we defined our name in unicode - confpath = os.path.split(os.path.split(self.plugin_path)[0])[0] - print u"{0} v{1}: Calibre configuration directory = {2}".format(PLUGIN_NAME, PLUGIN_VERSION, confpath) - files = os.listdir(confpath) - filefilter = re.compile(u"\.der$", re.IGNORECASE) - files = filter(filefilter.search, files) - foundDefault = False - if files: - try: - for filename in files: - if filename[:16] == u"calibre-adeptkey": - foundDefault = True - fpath = os.path.join(confpath, filename) - with open(fpath, 'rb') as f: - userkeys.append([f.read(), filename]) - print u"{0} v{1}: Keyfile {2} found in config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, filename) - except IOError: - print u"{0} v{1}: Error reading keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION) - pass - - if not foundDefault: - # Try to find key from ADE install and save the key in - # Calibre's configuration directory for future use. - if iswindows or isosx: - #ignore annoying future warning from key generation - import warnings - warnings.filterwarnings('ignore', category=FutureWarning) - - # ADE key retrieval script included in respective OS folder. - from calibre_plugins.ineptepub.ineptkey import retrieve_keys - try: - keys = retrieve_keys() - for i,key in enumerate(keys): - keyname = u"calibre-adeptkey{0:d}.der".format(i) - userkeys.append([key,keyname]) - keypath = os.path.join(confpath, keyname) - open(keypath, 'wb').write(key) - print u"{0} v{1}: Created keyfile {2} from ADE install.".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) - except: - print u"{0} v{1}: Couldn\'t Retrieve key from ADE install.".format(PLUGIN_NAME, PLUGIN_VERSION) - pass - - if not userkeys: - # No user keys found... bail out. - raise ADEPTError(u"{0} v{1}: No keys found. Check keyfile(s)/ADE install".format(PLUGIN_NAME, PLUGIN_VERSION)) - return - - # Attempt to decrypt epub with each encryption key found. - for userkeyinfo in userkeys: - userkey,keyname = userkeyinfo - print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) - of = self.temporary_file(u".epub") - - # Give the user key, ebook and TemporaryPersistent file to the decryption function. - result = ineptepub.decryptBook(userkey, inf.name, of.name) - - of.close() - - # Decryption was successful return the modified PersistentTemporary - # file to Calibre's import process. - if result == 0: - print u"{0} v{1}: Encryption successfully removed.".format(PLUGIN_NAME, PLUGIN_VERSION) - return of.name - break - - print u"{0} v{1}: Encryption key incorrect.".format(PLUGIN_NAME, PLUGIN_VERSION) - - # Something went wrong with decryption. - # Import the original unmolested epub. - raise ADEPTError(u"{0} v{1}: Ultimately failed to decrypt".format(PLUGIN_NAME, PLUGIN_VERSION)) - return - diff --git a/Calibre_Plugins/ineptepub_plugin/plugin-import-name-ineptepub.txt b/Calibre_Plugins/ineptepub_plugin/plugin-import-name-ineptepub.txt deleted file mode 100644 index e69de29..0000000 diff --git a/Calibre_Plugins/ineptpdf_plugin.zip b/Calibre_Plugins/ineptpdf_plugin.zip deleted file mode 100644 index adffe4c87c3d0f438efe9f453c84a8e0f9592ffb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29701 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 - -# PLEASE DO NOT PIRATE EBOOKS! - -# We want all authors and publishers, and eBook stores to live -# long and prosperous lives but at the same time we just want to -# be able to read OUR books on whatever device we want and to keep -# readable for a long, long time - -# Requires Calibre version 0.7.55 or higher. -# -# All credit given to i♥cabbages for the original standalone scripts. -# I had the much easier job of converting them to a Calibre plugin. -# -# This plugin is meant to decrypt Adobe Digital Edition PDFs that are protected -# with Adobe's Adept encryption. It is meant to function without having to install -# any dependencies... other than having Calibre installed, of course. It will still -# work if you have Python and PyCrypto already installed, but they aren't necessary. -# -# Configuration: -# When first run, the plugin will attempt to find your Adobe Digital Editions installation -# (on Windows and Mac OS's). If successful, it will create one or more -# 'calibre-adeptkey.der' files and save them in calibre's configuration directory. -# It will use those files on subsequent runs. If there is already a 'calibre-adeptkey*.der' -# file in the directory, the plugin won't attempt to find the ADE installation. -# So if you have ADE installed on the same machine as calibre you are ready to go. -# -# If you already have keyfiles generated with i♥cabbages' ineptkey.pyw script, -# you can put those keyfiles in Calibre's configuration directory. The easiest -# way to find the correct directory is to go to Calibre's Preferences page... click -# on the 'Miscellaneous' button (looks like a gear), and then click the 'Open Calibre -# configuration directory' button. Paste your keyfiles in there. Just make sure that -# they have different names and are saved with the '.der' extension (like the ineptkey -# script produces). This directory isn't touched when upgrading Calibre, so it's quite -# safe to leave them there. -# -# Since there is no Linux version of Adobe Digital Editions, Linux users will have to -# obtain a keyfile through other methods and put the file in Calibre's configuration directory. -# -# All keyfiles with a '.der' extension found in Calibre's configuration directory will -# be used to attempt to decrypt a book. -# -# ** NOTE ** There is no plugin customization data for the Inept PDF DeDRM plugin. -# -# Revision history: -# 0.1 - Initial release -# 0.1.1 - back port ineptpdf 8.4.X support for increased number of encryption methods -# 0.1.2 - back port ineptpdf 8.4.X bug fixes -# 0.1.3 - add in fix for improper rejection of session bookkeys with len(bookkey) = length + 1 -# 0.1.4 - update to the new calibre plugin interface -# 0.1.5 - synced to ineptpdf 7.11 -# 0.1.6 - Fix for potential problem with PyCrypto -# 0.1.7 - Fix for potential problem with ADE keys and fix possible output/unicode problem -# 0.1.8 - Fix for code copying error -# 0.1.9 - Major code change to use unaltered ineptpdf.py -# 0.2.0 - Fix erroneous dependency on ineptepub plugin - -""" -Decrypts Adobe ADEPT-encrypted PDF files. -""" - -PLUGIN_NAME = u"Inept PDF DeDRM" -PLUGIN_VERSION_TUPLE = (0, 2, 0) -PLUGIN_VERSION = u'.'.join([str(x) for x in PLUGIN_VERSION_TUPLE]) - -import sys -import os -import re - -class ADEPTError(Exception): - pass - -from calibre.customize import FileTypePlugin -from calibre.constants import iswindows, isosx - -# 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) - - -class ADEPTError(Exception): - pass - -class IneptPDFDeDRM(FileTypePlugin): - name = PLUGIN_NAME - description = u"Removes DRM from secure Adobe pdf files. Credit given to i♥cabbages for the original stand-alone scripts." - supported_platforms = ['linux', 'osx', 'windows'] - author = u"DiapDealer, Apprentice Alf and i♥cabbages" - version = PLUGIN_VERSION_TUPLE - minimum_calibre_version = (0, 7, 55) # for the new plugin interface - file_types = set(['pdf']) - on_import = True - priority = 100 - - def run(self, path_to_ebook): - - # make sure any unicode output gets converted safely with 'replace' - sys.stdout=SafeUnbuffered(sys.stdout) - sys.stderr=SafeUnbuffered(sys.stderr) - - print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) - - # Load any keyfiles (*.der) included Calibre's config directory. - userkeys = [] - # Find Calibre's configuration directory. - # self.plugin_path is passed in unicode because we defined our name in unicode - confpath = os.path.split(os.path.split(self.plugin_path)[0])[0] - print u"{0} v{1}: Calibre configuration directory = {2}".format(PLUGIN_NAME, PLUGIN_VERSION, confpath) - files = os.listdir(confpath) - filefilter = re.compile(u"\.der$", re.IGNORECASE) - files = filter(filefilter.search, files) - foundDefault = False - if files: - try: - for filename in files: - if filename[:16] == u"calibre-adeptkey": - foundDefault = True - fpath = os.path.join(confpath, filename) - with open(fpath, 'rb') as f: - userkeys.append([f.read(), filename]) - print u"{0} v{1}: Keyfile {2} found in config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, filename) - except IOError: - print u"{0} v{1}: Error reading keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION) - pass - - if not foundDefault: - # Try to find key from ADE install and save the key in - # Calibre's configuration directory for future use. - if iswindows or isosx: - #ignore annoying future warning from key generation - import warnings - warnings.filterwarnings('ignore', category=FutureWarning) - - # ADE key retrieval script included in respective OS folder. - from calibre_plugins.ineptpdf.ineptkey import retrieve_keys - try: - keys = retrieve_keys() - for i,key in enumerate(keys): - keyname = u"calibre-adeptkey{0:d}.der".format(i) - userkeys.append([key,keyname]) - keypath = os.path.join(confpath, keyname) - open(keypath, 'wb').write(key) - print u"{0} v{1}: Created keyfile {2} from ADE install.".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) - except: - print u"{0} v{1}: Couldn\'t Retrieve key from ADE install.".format(PLUGIN_NAME, PLUGIN_VERSION) - pass - - if not userkeys: - # No user keys found... bail out. - raise ADEPTError(u"{0} v{1}: No keys found. Check keyfile(s)/ADE install".format(PLUGIN_NAME, PLUGIN_VERSION)) - return - - # Attempt to decrypt pdf with each encryption key found. - from calibre_plugins.ineptpdf import ineptpdf - for userkeyinfo in userkeys: - print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, userkeyinfo[1]) - # Create a TemporaryPersistent file to work with. - of = self.temporary_file('.pdf') - - # Give the user keyfile, ebook and TemporaryPersistent file to the decryptBook function. - result = ineptpdf.decryptBook(userkeyinfo[0], path_to_ebook, of.name) - - # Decryption was successful return the modified PersistentTemporary - # file to Calibre's import process. - if result == 0: - print u"{0} v{1}: Encryption successfully removed.".format(PLUGIN_NAME, PLUGIN_VERSION) - of.close() - return of.name - break - - print u"{0} v{1}: Encryption key incorrect.".format(PLUGIN_NAME, PLUGIN_VERSION) - of.close() - - # Something went wrong with decryption. - raise ADEPTError(u"{0} v{1}: Ultimately failed to decrypt".format(PLUGIN_NAME, PLUGIN_VERSION)) - return diff --git a/Calibre_Plugins/ineptpdf_plugin/plugin-import-name-ineptpdf.txt b/Calibre_Plugins/ineptpdf_plugin/plugin-import-name-ineptpdf.txt deleted file mode 100644 index e69de29..0000000 diff --git a/Calibre_Plugins/k4mobidedrm_plugin.zip b/Calibre_Plugins/k4mobidedrm_plugin.zip deleted file mode 100644 index 87e4a40e1767ab6dfe9684ec54d9dbc1e4b5838f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 230152 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�Sa+~01Gn74b2bWe50+TRQ3g9@4oXq9QdVGfw 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 0: - sernum = resline[pp+19:-1] - sernum = sernum.strip() - bb = resline.find('\"BSD Name\" = \"') - if bb >= 0: - bsdname = resline[bb+14:-1] - bsdname = bsdname.strip() - if (bsdname == 'disk0') and (sernum != None): - foundIt = True - break - if not foundIt: - sernum = '' - return sernum - -def GetUserHomeAppSupKindleDirParitionName(): - home = os.getenv('HOME') - dpath = home + '/Library' - cmdline = '/sbin/mount' - cmdline = cmdline.encode(sys.getfilesystemencoding()) - p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) - out1, out2 = p.communicate() - reslst = out1.split('\n') - cnt = len(reslst) - disk = '' - foundIt = False - for j in xrange(cnt): - resline = reslst[j] - if resline.startswith('/dev'): - (devpart, mpath) = resline.split(' on ') - dpart = devpart[5:] - pp = mpath.find('(') - if pp >= 0: - mpath = mpath[:pp-1] - if dpath.startswith(mpath): - disk = dpart - return disk - -# uses a sub process to get the UUID of the specified disk partition using ioreg -def GetDiskPartitionUUID(diskpart): - uuidnum = os.getenv('MYUUIDNUMBER') - if uuidnum != None: - return uuidnum - cmdline = '/usr/sbin/ioreg -l -S -w 0 -r -c AppleAHCIDiskDriver' - cmdline = cmdline.encode(sys.getfilesystemencoding()) - p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) - out1, out2 = p.communicate() - reslst = out1.split('\n') - cnt = len(reslst) - bsdname = None - uuidnum = None - foundIt = False - nest = 0 - uuidnest = -1 - partnest = -2 - for j in xrange(cnt): - resline = reslst[j] - if resline.find('{') >= 0: - nest += 1 - if resline.find('}') >= 0: - nest -= 1 - pp = resline.find('\"UUID\" = \"') - if pp >= 0: - uuidnum = resline[pp+10:-1] - uuidnum = uuidnum.strip() - uuidnest = nest - if partnest == uuidnest and uuidnest > 0: - foundIt = True - break - bb = resline.find('\"BSD Name\" = \"') - if bb >= 0: - bsdname = resline[bb+14:-1] - bsdname = bsdname.strip() - if (bsdname == diskpart): - partnest = nest - else : - partnest = -2 - if partnest == uuidnest and partnest > 0: - foundIt = True - break - if nest == 0: - partnest = -2 - uuidnest = -1 - uuidnum = None - bsdname = None - if not foundIt: - uuidnum = '' - return uuidnum - -def GetMACAddressMunged(): - macnum = os.getenv('MYMACNUM') - if macnum != None: - return macnum - cmdline = '/sbin/ifconfig en0' - cmdline = cmdline.encode(sys.getfilesystemencoding()) - p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) - out1, out2 = p.communicate() - reslst = out1.split('\n') - cnt = len(reslst) - macnum = None - foundIt = False - for j in xrange(cnt): - resline = reslst[j] - pp = resline.find('ether ') - if pp >= 0: - macnum = resline[pp+6:-1] - macnum = macnum.strip() - # print 'original mac', macnum - # now munge it up the way Kindle app does - # by xoring it with 0xa5 and swapping elements 3 and 4 - maclst = macnum.split(':') - n = len(maclst) - if n != 6: - fountIt = False - break - for i in range(6): - maclst[i] = int('0x' + maclst[i], 0) - mlst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] - mlst[5] = maclst[5] ^ 0xa5 - mlst[4] = maclst[3] ^ 0xa5 - mlst[3] = maclst[4] ^ 0xa5 - mlst[2] = maclst[2] ^ 0xa5 - mlst[1] = maclst[1] ^ 0xa5 - mlst[0] = maclst[0] ^ 0xa5 - macnum = '%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x' % (mlst[0], mlst[1], mlst[2], mlst[3], mlst[4], mlst[5]) - foundIt = True - break - if not foundIt: - macnum = '' - return macnum - - -# uses unix env to get username instead of using sysctlbyname -def GetUserName(): - username = os.getenv('USER') - return username - -def isNewInstall(): - home = os.getenv('HOME') - # soccer game fan anyone - dpath = home + '/Library/Application Support/Kindle/storage/.pes2011' - # print dpath, os.path.exists(dpath) - if os.path.exists(dpath): - return True - dpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.pes2011' - # print dpath, os.path.exists(dpath) - if os.path.exists(dpath): - return True - return False - - -class Memoize: - """Memoize(fn) - an instance which acts like fn but memoizes its arguments - Will only work on functions with non-mutable arguments - """ - def __init__(self, fn): - self.fn = fn - self.memo = {} - def __call__(self, *args): - if not self.memo.has_key(args): - self.memo[args] = self.fn(*args) - return self.memo[args] - -@Memoize -def GetIDString(): - # K4Mac now has an extensive set of ids strings it uses - # in encoding pids and in creating unique passwords - # for use in its own version of CryptUnprotectDataV2 - - # BUT Amazon has now become nasty enough to detect when its app - # is being run under a debugger and actually changes code paths - # including which one of these strings is chosen, all to try - # to prevent reverse engineering - - # Sad really ... they will only hurt their own sales ... - # true book lovers really want to keep their books forever - # and move them to their devices and DRM prevents that so they - # will just buy from someplace else that they can remove - # the DRM from - - # Amazon should know by now that true book lover's are not like - # penniless kids that pirate music, we do not pirate books - - if isNewInstall(): - mungedmac = GetMACAddressMunged() - if len(mungedmac) > 7: - print('Using Munged MAC Address for ID: '+mungedmac) - return mungedmac - sernum = GetVolumeSerialNumber() - if len(sernum) > 7: - print('Using Volume Serial Number for ID: '+sernum) - return sernum - diskpart = GetUserHomeAppSupKindleDirParitionName() - uuidnum = GetDiskPartitionUUID(diskpart) - if len(uuidnum) > 7: - print('Using Disk Partition UUID for ID: '+uuidnum) - return uuidnum - mungedmac = GetMACAddressMunged() - if len(mungedmac) > 7: - print('Using Munged MAC Address for ID: '+mungedmac) - return mungedmac - print('Using Fixed constant 9999999999 for ID.') - return '9999999999' - - -# implements an Pseudo Mac Version of Windows built-in Crypto routine -# used by Kindle for Mac versions < 1.6.0 -class CryptUnprotectData(object): - def __init__(self): - sernum = GetVolumeSerialNumber() - if sernum == '': - sernum = '9999999999' - sp = sernum + '!@#' + GetUserName() - passwdData = encode(SHA256(sp),charMap1) - salt = '16743' - self.crp = LibCrypto() - iter = 0x3e8 - keylen = 0x80 - key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) - self.key = key_iv[0:32] - self.iv = key_iv[32:48] - self.crp.set_decrypt_key(self.key, self.iv) - - def decrypt(self, encryptedData): - cleartext = self.crp.decrypt(encryptedData) - cleartext = decode(cleartext,charMap1) - return cleartext - - -# implements an Pseudo Mac Version of Windows built-in Crypto routine -# used for Kindle for Mac Versions >= 1.6.0 -class CryptUnprotectDataV2(object): - def __init__(self): - sp = GetUserName() + ':&%:' + GetIDString() - passwdData = encode(SHA256(sp),charMap5) - # salt generation as per the code - salt = 0x0512981d * 2 * 1 * 1 - salt = str(salt) + GetUserName() - salt = encode(salt,charMap5) - self.crp = LibCrypto() - iter = 0x800 - keylen = 0x400 - key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) - self.key = key_iv[0:32] - self.iv = key_iv[32:48] - self.crp.set_decrypt_key(self.key, self.iv) - - def decrypt(self, encryptedData): - cleartext = self.crp.decrypt(encryptedData) - cleartext = decode(cleartext, charMap5) - return cleartext - - -# unprotect the new header blob in .kinf2011 -# used in Kindle for Mac Version >= 1.9.0 -def UnprotectHeaderData(encryptedData): - passwdData = 'header_key_data' - salt = 'HEADER.2011' - iter = 0x80 - keylen = 0x100 - crp = LibCrypto() - key_iv = crp.keyivgen(passwdData, salt, iter, keylen) - key = key_iv[0:32] - iv = key_iv[32:48] - crp.set_decrypt_key(key,iv) - cleartext = crp.decrypt(encryptedData) - return cleartext - - -# implements an Pseudo Mac Version of Windows built-in Crypto routine -# used for Kindle for Mac Versions >= 1.9.0 -class CryptUnprotectDataV3(object): - def __init__(self, entropy): - sp = GetUserName() + '+@#$%+' + GetIDString() - passwdData = encode(SHA256(sp),charMap2) - salt = entropy - self.crp = LibCrypto() - iter = 0x800 - keylen = 0x400 - key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) - self.key = key_iv[0:32] - self.iv = key_iv[32:48] - self.crp.set_decrypt_key(self.key, self.iv) - - def decrypt(self, encryptedData): - cleartext = self.crp.decrypt(encryptedData) - cleartext = decode(cleartext, charMap2) - return cleartext - - -# Locate the .kindle-info files -def getKindleInfoFiles(): - # file searches can take a long time on some systems, so just look in known specific places. - kInfoFiles=[] - found = False - home = os.getenv('HOME') - # check for .kinf2011 file in new location (App Store Kindle for Mac) - testpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.kinf2011' - if os.path.isfile(testpath): - kInfoFiles.append(testpath) - print('Found k4Mac kinf2011 file: ' + testpath) - found = True - # check for .kinf2011 files - testpath = home + '/Library/Application Support/Kindle/storage/.kinf2011' - if os.path.isfile(testpath): - kInfoFiles.append(testpath) - print('Found k4Mac kinf2011 file: ' + testpath) - found = True - # check for .rainier-2.1.1-kinf files - testpath = home + '/Library/Application Support/Kindle/storage/.rainier-2.1.1-kinf' - if os.path.isfile(testpath): - kInfoFiles.append(testpath) - print('Found k4Mac rainier file: ' + testpath) - found = True - # check for .rainier-2.1.1-kinf files - testpath = home + '/Library/Application Support/Kindle/storage/.kindle-info' - if os.path.isfile(testpath): - kInfoFiles.append(testpath) - print('Found k4Mac kindle-info file: ' + testpath) - found = True - if not found: - print('No k4Mac kindle-info/rainier/kinf2011 files have been found.') - return kInfoFiles - -# determine type of kindle info provided and return a -# database of keynames and values -def getDBfromFile(kInfoFile): - - names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] - DB = {} - cnt = 0 - infoReader = open(kInfoFile, 'r') - hdr = infoReader.read(1) - data = infoReader.read() - - if data.find('[') != -1 : - - # older style kindle-info file - cud = CryptUnprotectData() - items = data.split('[') - for item in items: - if item != '': - keyhash, rawdata = item.split(':') - keyname = 'unknown' - for name in names: - if encodeHash(name,charMap2) == keyhash: - keyname = name - break - if keyname == 'unknown': - keyname = keyhash - encryptedValue = decode(rawdata,charMap2) - cleartext = cud.decrypt(encryptedValue) - DB[keyname] = cleartext - cnt = cnt + 1 - if cnt == 0: - DB = None - return DB - - if hdr == '/': - - # else newer style .kinf file used by K4Mac >= 1.6.0 - # the .kinf file uses '/' to separate it into records - # so remove the trailing '/' to make it easy to use split - data = data[:-1] - items = data.split('/') - cud = CryptUnprotectDataV2() - - # loop through the item records until all are processed - while len(items) > 0: - - # get the first item record - item = items.pop(0) - - # the first 32 chars of the first record of a group - # is the MD5 hash of the key name encoded by charMap5 - keyhash = item[0:32] - keyname = 'unknown' - - # the raw keyhash string is also used to create entropy for the actual - # CryptProtectData Blob that represents that keys contents - # 'entropy' not used for K4Mac only K4PC - # entropy = SHA1(keyhash) - - # the remainder of the first record when decoded with charMap5 - # has the ':' split char followed by the string representation - # of the number of records that follow - # and make up the contents - srcnt = decode(item[34:],charMap5) - rcnt = int(srcnt) - - # read and store in rcnt records of data - # that make up the contents value - edlst = [] - for i in xrange(rcnt): - item = items.pop(0) - edlst.append(item) - - keyname = 'unknown' - for name in names: - if encodeHash(name,charMap5) == keyhash: - keyname = name - break - if keyname == 'unknown': - keyname = keyhash - - # the charMap5 encoded contents data has had a length - # of chars (always odd) cut off of the front and moved - # to the end to prevent decoding using charMap5 from - # working properly, and thereby preventing the ensuing - # CryptUnprotectData call from succeeding. - - # The offset into the charMap5 encoded contents seems to be: - # len(contents) - largest prime number less than or equal to int(len(content)/3) - # (in other words split 'about' 2/3rds of the way through) - - # move first offsets chars to end to align for decode by charMap5 - encdata = ''.join(edlst) - contlen = len(encdata) - - # now properly split and recombine - # by moving noffset chars from the start of the - # string to the end of the string - noffset = contlen - primes(int(contlen/3))[-1] - pfx = encdata[0:noffset] - encdata = encdata[noffset:] - encdata = encdata + pfx - - # decode using charMap5 to get the CryptProtect Data - encryptedValue = decode(encdata,charMap5) - cleartext = cud.decrypt(encryptedValue) - DB[keyname] = cleartext - cnt = cnt + 1 - - if cnt == 0: - DB = None - return DB - - # the latest .kinf2011 version for K4M 1.9.1 - # put back the hdr char, it is needed - data = hdr + data - data = data[:-1] - items = data.split('/') - - # the headerblob is the encrypted information needed to build the entropy string - headerblob = items.pop(0) - encryptedValue = decode(headerblob, charMap1) - cleartext = UnprotectHeaderData(encryptedValue) - - # now extract the pieces in the same way - # this version is different from K4PC it scales the build number by multipying by 735 - pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) - for m in re.finditer(pattern, cleartext): - entropy = str(int(m.group(2)) * 0x2df) + m.group(4) - - cud = CryptUnprotectDataV3(entropy) - - # loop through the item records until all are processed - while len(items) > 0: - - # get the first item record - item = items.pop(0) - - # the first 32 chars of the first record of a group - # is the MD5 hash of the key name encoded by charMap5 - keyhash = item[0:32] - keyname = 'unknown' - - # unlike K4PC the keyhash is not used in generating entropy - # entropy = SHA1(keyhash) + added_entropy - # entropy = added_entropy - - # the remainder of the first record when decoded with charMap5 - # has the ':' split char followed by the string representation - # of the number of records that follow - # and make up the contents - srcnt = decode(item[34:],charMap5) - rcnt = int(srcnt) - - # read and store in rcnt records of data - # that make up the contents value - edlst = [] - for i in xrange(rcnt): - item = items.pop(0) - edlst.append(item) - - keyname = 'unknown' - for name in names: - if encodeHash(name,testMap8) == keyhash: - keyname = name - break - if keyname == 'unknown': - keyname = keyhash - - # the testMap8 encoded contents data has had a length - # of chars (always odd) cut off of the front and moved - # to the end to prevent decoding using testMap8 from - # working properly, and thereby preventing the ensuing - # CryptUnprotectData call from succeeding. - - # The offset into the testMap8 encoded contents seems to be: - # len(contents) - largest prime number less than or equal to int(len(content)/3) - # (in other words split 'about' 2/3rds of the way through) - - # move first offsets chars to end to align for decode by testMap8 - encdata = ''.join(edlst) - contlen = len(encdata) - - # now properly split and recombine - # by moving noffset chars from the start of the - # string to the end of the string - noffset = contlen - primes(int(contlen/3))[-1] - pfx = encdata[0:noffset] - encdata = encdata[noffset:] - encdata = encdata + pfx - - # decode using testMap8 to get the CryptProtect Data - encryptedValue = decode(encdata,testMap8) - cleartext = cud.decrypt(encryptedValue) - # print keyname - # print cleartext - DB[keyname] = cleartext - cnt = cnt + 1 - - if cnt == 0: - DB = None - return DB diff --git a/Calibre_Plugins/k4mobidedrm_plugin/k4pcutils.py b/Calibre_Plugins/k4mobidedrm_plugin/k4pcutils.py deleted file mode 100644 index bb9289e..0000000 --- a/Calibre_Plugins/k4mobidedrm_plugin/k4pcutils.py +++ /dev/null @@ -1,457 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# K4PC Windows specific routines - -from __future__ import with_statement - -import sys, os, re -from struct import pack, unpack, unpack_from - -from ctypes import windll, c_char_p, c_wchar_p, c_uint, POINTER, byref, \ - create_unicode_buffer, create_string_buffer, CFUNCTYPE, addressof, \ - string_at, Structure, c_void_p, cast - -import _winreg as winreg -MAX_PATH = 255 -kernel32 = windll.kernel32 -advapi32 = windll.advapi32 -crypt32 = windll.crypt32 - -import traceback - -# crypto digestroutines -import hashlib - -def MD5(message): - ctx = hashlib.md5() - ctx.update(message) - return ctx.digest() - -def SHA1(message): - ctx = hashlib.sha1() - ctx.update(message) - return ctx.digest() - -def SHA256(message): - ctx = hashlib.sha256() - ctx.update(message) - return ctx.digest() - -# For K4PC 1.9.X -# use routines in alfcrypto: -# AES_cbc_encrypt -# AES_set_decrypt_key -# PKCS5_PBKDF2_HMAC_SHA1 - -from alfcrypto import AES_CBC, KeyIVGen - -def UnprotectHeaderData(encryptedData): - passwdData = 'header_key_data' - salt = 'HEADER.2011' - iter = 0x80 - keylen = 0x100 - key_iv = KeyIVGen().pbkdf2(passwdData, salt, iter, keylen) - key = key_iv[0:32] - iv = key_iv[32:48] - aes=AES_CBC() - aes.set_decrypt_key(key, iv) - cleartext = aes.decrypt(encryptedData) - return cleartext - - -# simple primes table (<= n) calculator -def primes(n): - if n==2: return [2] - elif n<2: return [] - s=range(3,n+1,2) - mroot = n ** 0.5 - half=(n+1)/2-1 - i=0 - m=3 - while m <= mroot: - if s[i]: - j=(m*m-3)/2 - s[j]=0 - while j 0: - - # get the first item record - item = items.pop(0) - - # the first 32 chars of the first record of a group - # is the MD5 hash of the key name encoded by charMap5 - keyhash = item[0:32] - - # the raw keyhash string is used to create entropy for the actual - # CryptProtectData Blob that represents that keys contents - entropy = SHA1(keyhash) - - # the remainder of the first record when decoded with charMap5 - # has the ':' split char followed by the string representation - # of the number of records that follow - # and make up the contents - srcnt = decode(item[34:],charMap5) - rcnt = int(srcnt) - - # read and store in rcnt records of data - # that make up the contents value - edlst = [] - for i in xrange(rcnt): - item = items.pop(0) - edlst.append(item) - - keyname = "unknown" - for name in names: - if encodeHash(name,charMap5) == keyhash: - keyname = name - break - if keyname == "unknown": - keyname = keyhash - # the charMap5 encoded contents data has had a length - # of chars (always odd) cut off of the front and moved - # to the end to prevent decoding using charMap5 from - # working properly, and thereby preventing the ensuing - # CryptUnprotectData call from succeeding. - - # The offset into the charMap5 encoded contents seems to be: - # len(contents)-largest prime number <= int(len(content)/3) - # (in other words split "about" 2/3rds of the way through) - - # move first offsets chars to end to align for decode by charMap5 - encdata = "".join(edlst) - contlen = len(encdata) - noffset = contlen - primes(int(contlen/3))[-1] - - # now properly split and recombine - # by moving noffset chars from the start of the - # string to the end of the string - pfx = encdata[0:noffset] - encdata = encdata[noffset:] - encdata = encdata + pfx - - # decode using Map5 to get the CryptProtect Data - encryptedValue = decode(encdata,charMap5) - DB[keyname] = CryptUnprotectData(encryptedValue, entropy, 1) - cnt = cnt + 1 - - if cnt == 0: - DB = None - return DB - - # else newest .kinf2011 style .kinf file - # the .kinf file uses "/" to separate it into records - # so remove the trailing "/" to make it easy to use split - # need to put back the first char read because it it part - # of the added entropy blob - data = hdr + data[:-1] - items = data.split('/') - - # starts with and encoded and encrypted header blob - headerblob = items.pop(0) - encryptedValue = decode(headerblob, testMap1) - cleartext = UnprotectHeaderData(encryptedValue) - # now extract the pieces that form the added entropy - pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) - for m in re.finditer(pattern, cleartext): - added_entropy = m.group(2) + m.group(4) - - - # loop through the item records until all are processed - while len(items) > 0: - - # get the first item record - item = items.pop(0) - - # the first 32 chars of the first record of a group - # is the MD5 hash of the key name encoded by charMap5 - keyhash = item[0:32] - - # the sha1 of raw keyhash string is used to create entropy along - # with the added entropy provided above from the headerblob - entropy = SHA1(keyhash) + added_entropy - - # the remainder of the first record when decoded with charMap5 - # has the ':' split char followed by the string representation - # of the number of records that follow - # and make up the contents - srcnt = decode(item[34:],charMap5) - rcnt = int(srcnt) - - # read and store in rcnt records of data - # that make up the contents value - edlst = [] - for i in xrange(rcnt): - item = items.pop(0) - edlst.append(item) - - # key names now use the new testMap8 encoding - keyname = "unknown" - for name in names: - if encodeHash(name,testMap8) == keyhash: - keyname = name - break - - # the testMap8 encoded contents data has had a length - # of chars (always odd) cut off of the front and moved - # to the end to prevent decoding using testMap8 from - # working properly, and thereby preventing the ensuing - # CryptUnprotectData call from succeeding. - - # The offset into the testMap8 encoded contents seems to be: - # len(contents)-largest prime number <= int(len(content)/3) - # (in other words split "about" 2/3rds of the way through) - - # move first offsets chars to end to align for decode by testMap8 - # by moving noffset chars from the start of the - # string to the end of the string - encdata = "".join(edlst) - contlen = len(encdata) - noffset = contlen - primes(int(contlen/3))[-1] - pfx = encdata[0:noffset] - encdata = encdata[noffset:] - encdata = encdata + pfx - - # decode using new testMap8 to get the original CryptProtect Data - encryptedValue = decode(encdata,testMap8) - cleartext = CryptUnprotectData(encryptedValue, entropy, 1) - DB[keyname] = cleartext - cnt = cnt + 1 - - if cnt == 0: - DB = None - return DB diff --git a/DeDRM_Macintosh_Application/DeDRM ReadMe.rtf b/DeDRM_Macintosh_Application/DeDRM ReadMe.rtf index 4c3219a..8813e94 100644 --- a/DeDRM_Macintosh_Application/DeDRM ReadMe.rtf +++ b/DeDRM_Macintosh_Application/DeDRM ReadMe.rtf @@ -1,23 +1,23 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 Verdana;\f2\fnil\fcharset128 HiraKakuProN-W3; +} {\colortbl;\red255\green255\blue255;} -\paperw11900\paperh16840\margl1440\margr1440\vieww12360\viewh16560\viewkind0 -\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\qc\pardirnatural +\paperw11900\paperh16840\margl1440\margr1440\vieww18160\viewh16520\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc \f0\b\fs24 \cf0 DeDRM ReadMe \b0 \ -\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural \cf0 \ -\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\qj\pardirnatural +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qj \cf0 DeDRM is an application that packs all of the python dm-removal software into one easy to use program that remembers preferences and settings.\ -It works without manual configuration with Kindle for Mac ebooks and Adobe Adept ePub and PDF ebooks.\ +It works without manual configuration with Kindle for Mac ebooks and Adobe Adept (including nook) ePub and PDF ebooks.\ \ -To remove the DRM of Kindle ebooks from eInk Kindles, eReader pdb ebooks, Barnes&Noble ePubs, or Mobipocket ebooks, you must first run DeDRM application (by double-clicking it) and set some additional Preferences including:\ +To remove the DRM of Kindle ebooks from eInk Kindles, eReader pdb ebooks, Barnes & Noble ePubs, or Mobipocket ebooks, you must first run DeDRM application (by double-clicking it) and set some additional Preferences including:\ \ eInk Kindle (not Kindle Fire): 16 digit Serial Number\ -Kindle for iOS: 40 digit UDID, but this probably won't work anymore\ Barnes & Noble ePub: Name and CC number or key file (bnepubkey.b64)\ -eReader Social DRM: Name and last 8 digits of CC number\ +eReader: Name and last 8 digits of CC number\ Mobipocket: 10 digit PID\ \ A final preference is the destination folder for the DRM-free copies of your ebooks that the application produces. This can be either the same folder as the original ebook, or a folder of your choice.\ @@ -27,7 +27,7 @@ Once these preferences have been set, you can drag and drop ebooks (or folders o This program requires Mac OS X 10.4 or above. It will not work on Mac OS X 10.3 or earlier.\ \ \ -\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural \b \cf0 Installation \b0 \ @@ -41,7 +41,7 @@ Mac OS X 10.5 and above: You do \i not \i0 need to install Python.\ \ -Drag the DeDRM application from from tools_v5.6.2\\DeDRM_Applications\\Macintosh (the location of this ReadMe) to your Applications folder, or anywhere else you find convenient.\ +Drag the DeDRM application from from the DeDRM_Application_Macintosh folder (the location of this ReadMe) to your Applications folder, or anywhere else you find convenient.\ \ \ @@ -53,6 +53,24 @@ Drag the DeDRM application from from tools_v5.6.2\\DeDRM_Applications\\Macintosh \ \b Troubleshooting\ -\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural -\b0 \cf0 A log is created on your desktop containing detailed information from all the scripts. If you have any problems decrypting your ebooks, quote the contents of this log in a comment at Apprentice Alf's blog.} \ No newline at end of file +\b0 \cf0 A log is created on your desktop (DeDRM.log) containing detailed information from all the scripts. If you have any problems decrypting your ebooks, copy the contents of this log in a comment at Apprentice Alf's blog.\ +http://apprenticealf.wordpress.com/\ +\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural + +\b \cf0 Credits\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural + +\b0 \cf0 The mobidedrm and erdr2pml scripts were created by The Dark Reverser\ +The i +\f1 \CocoaLigature0 gnobleepub, ignoblekeygen, ineptepub and adobe key scripts were created by +\f0 \CocoaLigature1 i +\f2 \CocoaLigature0 \uc0\u9829 +\f1 cabbages\ +The k4mobidedrm script and supporting scripts were written by some_updates with help from DiapDealer and Apprentice Alf, based on code by Bart Simpson (aka Skindle), CMBDTC and clarknova \ +The alfcrypto library was created by some_updates\ +The ePub encryption detection script was adapted by Apprentice Alf from a script by Paul Durrant\ +The DeDRM all-in-one AppleScript was created by Apprentice Alf\ +} \ No newline at end of file diff --git a/DeDRM_Macintosh_Application/DeDRM.app.txt b/DeDRM_Macintosh_Application/DeDRM.app.txt index cb177cbc8404bcdf832eb0df2c28d90473a2ebb8..249a927fa61fe57dcfbe09527ed5c84cd8679d9e 100644 GIT binary patch literal 131522 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 literal 59910 zcmeHw>v9`MmgaBrDQXe1HZT(Ful8n>vY8LIXa2)^aW%8w9Ti6}zWk0)_a@ba zX{aMqlW|esGKTr+GM|no#rVnVc`e=2D9+&cL!$!0h6%WCR>0my^dY*M@&)#Yp+8Wk^! z9MGRu)x@{_61~l;(W_!^pMFsi>XWBO_Tl4aUlccgE~e?T;$(4VpB#*t&Z_EFm)wzuZ>&Gyz-Q_M4d{h~O}=2ZqMoMz`$o#mqu=#rW7 zvg>kwshwqz)vL0hAfOBBpDnfP?1OBuJz!_P-)5fIa}1j0^Q@@Ov%JavV>HRp{bGLp z+27H{Xi_zWAJcudy@d&6gp&WpNywZ=lOnGewKi`^v%z3Z&aglON#%Jqyh!nPFZ(>ZpUp1|GKnx+ zdoThMuzg-vSJ{Ie<{{8Q*4(7oYxh?_leC?@fXC93C?cfDy1h_vJbJ8l9^C78AZ@}>be}mv;w}e3gxhNqL38>IN*$Z*FfW5bQxR zgSt+D!}uB0DTUb&;y9O6+GrF9ztWmQ=NKSCh_HAYg%+(gwO|epy$Gi_2{Hp;rxTdyhIxZQq^Y+QVQ`9iGvs1O0TQ8n3~e!52>1 z2B!#Py__zt&Wf53bs{o_MfNelAEtcwJs1-9oO9uvWm3?b6DJX14AWkEJn-HBF?+ao z-?dW*R>0U_H1+*8;V5+7tI5`}=O|NMGyduw~^1l|_>Gw3_`u0BYS*8(zpv@E}XI)pAfTg>MSkA58d z_eD7${0wz>o)ZFn0U;7Ma$e41Z3hyh4fIh7oeD9kX5gftcEr92hN+Bz;A^;vlj|JB zxz0h0JZon82+z);P&s>OkE<)-Q6<1p7PEJMk;WjIzBO?a5tN$Lp?Cmz41`pR8e^)9P$eyee)k zifPi35ArtYhViiJq!mN1*V7b%8o+6Hvl%$-qy>x(QrCin-_rwYL*jzkwfZOt2(kmF zj~E26)x!@Zg1gt|dlNFR)q#ju=D%Vpg}mFNp7&5dey2 zom1~XYG36S#U2eAr1%_Cb_v;?-E?&bk|c~!%ITuW4yHE{{x?=Dn6}eH>em!wTEawA z0yb4$UYE9XQBX$S2z61JDusZ}j)R}JbG}0YOuyPLviM~{d8$_4L#!tnbUD(KW}DzV zd>Bz~H1K7vzP+bF%4xb+6_%`n?SrL%?a zAtGBo$mZCT4wiCi^j6+i+&XvYO%aRFqufVt>3zlKn@hd&DZfwg`TmN&_4qeuPr+m{ z9o088F;0?<^=j3}26Lof;G4fU+-h^!KBPbfVRP*IkA1EiVacQ%sT(lthAjW-5p479 z3@m(lPqM0uDY9s=$xQg-tnf} z*+*Qk0EO(Mpczy$GxBHx40=g^3vi%ncU{zWtKhJlL`ohU*M#2=knr2_iOHbHS2_(= zqwpEOGz3qY#UB82$8mM?piZ?oi>r^PCXof{(SB$g6=Z zO8C%JI-wHe!9A+rVRe2^IAAXZ&#DZGes~m%DSQEFDVennA`V|H9)XY3TD?ko4{MeQ zpg;?Jf!F06OE^@H{Ozsl7T1#U=9Shu!7$KZLvpzMd0l*1!=hpRIvZDHnQ96X%Ze@b zK0~qiC_Gfa`XcBuua`pr(kZ4&b@Nt_b{0kzeb6=#s*!Dk z(q}BJR_;N9!oQwg?xCB}vH+9{F{nq#Q44>jcu!CyrL4q}`L#}ex;NYNi4M)4^(3a*B^5nOH-4y?tW-icM3BU8*0!$Hf&t8YV z!Z+Zr^~Ast-uQqseUKQCHZFbHZ!~lgc)1$dG>>3X3#dV7Pq$(QQ<=(QVE#grscVP_fm?29(6oA zd<`BUw@JM4Ha%fyNUNu3#r2zk_1(0RO*6e+`czIJ8kBP911*AD!P&RsYTwNU82W)| zd9%LUM9>GigJpDdx7=U{jn8H%ceQ-Kkk5F}U1SL_;S03T<6L7V65#2O zYwE=`8)H8rQw1VlR~4dqkYxsKH_qfSnTsOmlJ7`2IOcT?NE*NPVg6X2(-(GyYB<8c zk2x?#7~14NwR%=!7s<)VQOz1+Q>>1$d~!(!hTkZOCKTMc#Kk#Q4r1S?Utyvol98Os zw7N!tZd3VbXJ;t%W6}+k)6g2@GjSfXMZ?5OfEmh4R<8hzR0pE?8my@xbyhRNSLjgp zt8s?TYU?-HV}X4%4>HhZR%2u3ndEY)nx_R2%`tW;h}r*MP}5Gc5$c<k?}%@>CK=NgXoCt}B|C!1*O`hf*gLCd(kQ`L1_3vsfcdsh_4~8NbGo z_!Z#?Tm#wvr>am@7}OzF_~xjmkcGu*={Yl$JQ!R;)&7B{gadGPO`@uL}iOkx)^h3 z;r$YWq%#00ZEwqs$oX~OuFi{-i#lM~>`2<77{;E2NZLwg*HJnxsRYSI!csbebtnqR zqBfUKc%;>>t}y~x=6l0uiCFeZ<*y|u=>%=2#`8M$DKtBHdb!N>3k?$Ou#aP=*NHZl z`k`Tf{gA{xA5W@krmA^aF5f%z{MYBQRB&3EqjEZ`>be-gk#?C3zi;RPssh?85N#JY z(LC8U{I!9e1c9)KF;+5553-U4 zBy|>+m;}`EqG4llWpC7yYA7=8ISjj@d22YSQk#ufEWXg<}+uq3dp3Y|NadzAx`M5`PYGm9FCTm~L<&yUO3@`{*ot3PTD zI$lj@QR&W?uvR-TUCZ7#wZc2&J@fm8m-sD~LGKO%jWfqhl`vAuaSs0)A`@(Ru-rn0 zCc!|hZ=o)6h6H?Sgn7^$syGw~wNrKqEk_g4j<<&?<(v!t3v!qrpq_sjCasWvQl z;5V30S&S1g4P>!H3-;Ipm0pxHt*QK2>lPo{qRI}QU6+Dk-@RW9xhk)U`3(vjVhQa& zwdO}Zl(S!Ffg~abcvzmPphqn3Fyb5d3`2K@MHexl+z{*V(JeMUaeD#gP7H*ujv4Y` z?4DZ7)iy%1)3?}&bq88yCYF!WHWO(Akm+itDMci0DUulJ3o@{&dIw{vVm+;I9wWSa zM)p&(@JJByJKo6VgYKKe766^glg8-u)SV#pE192;jCG8`9pr7_&c+cVPLl>p7Br=$ zoa&x6ZB3v%ANf`T9V**pcb$){aH72cy4!a0%58T=e>PtfUiVK93*XlBn zhE-jDH4PEMS{*0CCdBH~ZCma?c1M0)~9rfbFZ>a{D3 zp$vpRsKaNjJ{`%`y1N{eF4fsjY?v*xTw7~A7G)#_(9Cp6hO1pLWky<8u`KPYt+?qw z^k?RhDXemW@%^u&h%nAZx(MwPm)p&=m4XOb$-NHZEzS|00ked$T0Nm<@PiH?aqQveH%X}lyI=$6`SLMlJ$;QUtJb9^T zY8R@873x^ZBaeK3D~dWs^gY5QWV9`7PpQ&V0H71NK0{p~N=95&fNcfcpOnaSnE#tz zIcFE}>q0dmc&SYfYHYQD`Z0bP>Fk4e1L5qDyW=F>dBoUd(N%GAM@%{47V{Y?<=eo~ zQAoiM!o0VM=n@I-9n%Y_xb511AV%~_qj>t*jDU1h)n-!Kp;}8wSIa1&^a2I`9t06x zm43ceEZGYU@D%go2y5m=lcqj64&TayB!NUj98yy-WT7C?`#R!OS%;lralU~QkM|?62d@cDE4iPzsLuh6t zYzPf1sG}IPCvkvXr#`FlUpc51*i8v+*({mAxR-7i?6$!92b_S`47U>-oNe;)isW_D zZZ+N6ZJO$a82;zl1gfbCtH=A7A$03B7A15Cj?hDQ`3qN2Gm<>e{XDl-d>W8UT^gg# z@0>d#XNWfkwd2nc^T#{LzNvn;(aE>N73$i%OK6dY40>Ih%BNOqW5|Km+6q-vT6_n& zPHQB+JJ{oXhQ8PKJ_Dt^H{Xs9{boKqIe|GfMFYkVKT(6bh zXBs1tKu7H@FFt|6mmS*sO1E1a&wjtNcR1&E29+Nv(C2i5LY)b3fOj%QGlehTy-#W8{JWcmlTM|S<@QPm=m$q#{-fH%c}(I%>75g_ zKEpAJJ7>Byfv;8-Cy}Z6iLWIeCZ&V6pBQk7ut*W06$Wf$-_ zZa|^Cy&mD2J(t0M;6YoxFN7n7ZiKC7xL$+XI=gRp%So+b& z%U^wxc#P1T_F4y;-}WPopPo)fK(<_j5%9IsZVQZWDUXDMU<@@qG09VI%Ul;tylTX{ zv~6ha3P8V|Y*YBSYWb@G7|MP&g^(A${5lxaz-bA5Y7;27QAb#nA!nQfr6IposSR?b z7tRpC7buOx=6pyYT`^b4>fu?xOKI8eR35JA*5)HwtNop9ZXp-|hn+>!>ILUuG%vp| zhH>Y1nyqn)c55plY#4j?;j=1aZ)TT65hnH4a7a(LL1G9k?S<6H3QXt3N1!wQUPWcV z>WS<%@Mgxre;u{*-6{NzA2s0A2xn?{7(6q7Q22|O;_CpGxJUdvJfZmj_jE6DG7+3T ztpfA1KSfJB4&pxn^+E`kF?;HaKODq9qku8gu^grE36>tHqrW3_C*L!%9~6&}F?o&d z^*3lt^^bp6G>X^s$oVw!OI0h$GJ_^0lGA$pl>`<7kBD&gjK@NF(1!w^p@I3cjS5n1 z-JNiJhuPvsYpU(ntx38Mmd`MJ@23|Zxa$_=E-E=m$WJal>6@J#`jeM6rzkCTj^?B8 zB+X0AQVS+U_hIjc@2@rS^b_+7k|Ok7-pg`q#BMw~%oBqTBFSQdzc<8%eA15z-&<>k zBSAR!x5I#B50ue763nAMJotRWF|-r;!vA(+PYrv( z3*Syrb|Y=b>vA6v^%<`0aMzg0yJ)pmMg$$LpF{+D3rHBx^hr&}NCRkA&b4#v63o68 z-c|M8B2ufB{YlO4E2pUV`Q>ujm@hqf>?21Z**lw3$UN$!Pg*3DqpuvnVKObl=qc6c+}ULT!0hZ#j42z2JektY`{ue~ z@Ba>)xrzx4FrEqQBX5;NcMbJqq*Goz0yl}G#^)&yU^xH684yev23~pyx}WomPb4-? zjdOAc6M7gt!Tv8C2#Ip{@}wH?mnXR7vA{nlU6qcq;V1XA(IqbJ8}VW&9F>JVF*wdI z&*rG^+{3=}IUJ!=UYsD?46m#DRU>CtsVnWavEc2wKXj5?%gX03b>|%?g)<;aWNOBb z<%SlSw?Dkf`V1Y|4;R=ngR52qP<6M=F0B{aop-&fQ7(o&hb@L+x#85 zRcIh^=t_vBZM~p4^2j$XH_TT{%Rtn-h1pzP20~yVmiW)+pzJ8hdiII7_r(heFt5Ff znciFS%BJS1@J04^ez7BmlU}5R8D=l_x;@<>E9zK_(oE-KRb9D7XQoN&S^84cL&&7K z%@9iG-U*vb3qhv*9~i(qr@rE{mI)}74L~DOQf~^|#TjY1?rf3mJ|N$j?{#F)RSlvc zcNN}`Kaz+$bk2YNIda(6R{P*EHk0|tADkRO%0ae#3gp?QN1vVfv3v z=sB=X9?7**qkKW7B-jWM5-8nu$%jPT+!-Oo@m)#i0P~lXHgW=kdTfy(U#6c!&wU;;@YOz0S>R^k&?~A{UH~nfiZC?0&N>_aKklgH4KU%>QDAm zNSt3YD#Z3Fq#)wGJ0Hr25{#Dbm*NaZM{-AA<5U5 z*Z|$o9r>ofsTE)HOp$8(3lk<8%8)0`sz&GB=$BTLKs^5k|8*%={^`AI@2o?=G(EmL z)edMJvuNN95}(bN9`8&e6&t|F7@NnB)qO(>*`L=M{n&WGw)BuXPrUFb8f0=di>|j%*RrT(6!JUHL(W22?H&32Ggu(pV4|PiBx&} z-8%CE-K9Z4(UUp?zqEBGvAuD2Yd$^pS>Jed;g?XwMB9ZTHt1O}qxMXiZDgx80MCZ> zo88~XWsP$H9Z-5yBYY?5Z%MB&OHCzNx4Sd)4yF_uwff1VR~Y`@E;e#X?%w>n`NYUh zz4>>ZJacfZ>jY@?K0iR;I9DKP2KIdLsTi^$Dt4HS4_1yj3vDZR7z`duxzKH`{#(4e zTkWzETsz|G5Cy06>;pHFm~2{XZSSRUg{AK2C!Bu5d4;(&VzFhOxcM75p-brZ_%|9v z>*U{ok?uw2Z_jFX*k^4E9@%Q07~8deYd7ilDBE3H(&u__9%Vc6@TUCvVm@2UkF@|v z17W*1hI=UVomVF6;!5c$6CPEDr7Gk}B~Ka5{gzXfS}q0{xoN_lV-f4K#5L#y;7q`d zi=!7`BC{e_uJ9-*B&?9fYj8!%m;+<&g7s*V>RM`3Wd?fIOEOd_iDZIyTTh@1u@9A{ zh0D*9LgOTg&5|<}5$ok>HJAp)RvSe~la)M_!`X$i_my_NPjF+_J=RUTN zONir57TTg;@D;##$rDT+N1@0-aq)yl;!0}k5J@hyQl@n6{=uA=pHq4zjbcUkwY~24 zu_PnmPp*@W?H`sX(6xdP*P*|JT~hzlaZS*30b^ zoYjh^?h6tjL53_t$noVtGWPT^U#etHz=o{oyMias0{2zw$+vpck3~#8+(#1)F|8nK z&S89$oce9-70J0=>VslfrdLsO7kz74;X`@jArO(o=}(j!RiuO)ZDXpE7w2mh0q4O+5tPBla>+Shd8^%RG|! zGF^;LR1n8-tST9BDQZ}~Xum-^l$XMDhwndOP3eW+HNv0&uIk-_DLUN?O@t(mJNw7Q%!zj$Q2g??8FNJu(uL1K^mRyp?U*3eriGJjzzP;GR%#xbjm~MMDQ0>bDfQ_ ztbkLdM|nNgHHEA4;!?Ji$m`Y#E{g`5nqBN=PtVywyu8e9#R{lo4H=?f>Xu24km55e zH(ZoBmDp*0Hv=)a<4PeuU%>i4_ya>{Mm(}&0l;~THWU$yOj_{p6sTq|d(P|A!bpY8 zAXsu;eZsdcfykQ^98)zoN2Z2XA>S%yU>~P?DS?C^Id?`}ZgHSs2H0b(KS#!@_EAh&#AV4S_76h3rTfnvZvc@MJ+8zAGHK`x%+f*G(C=zz|evJl{nAb4+iEl&6SJI5oTt6-g=)7?!!{zwH2lN&J@55uYMRhvouPIpq579kEqQcK^lpfDbMv}|e{ z7X$VjC1(cJVT`4sL7Csk=@J#))7VxOl1}$tQJp^7I z3#<2VLCu8HGeBUpOo{u=f8EkElZP{*cH3}&0Vvg9ZSiTEg9%NNi^xpXDQi%XEwQy2J)?O9bR4zk4V-kK=i{9Xa4 z7m8a6@^1689Fi9?{+m|7L1%+2aKB9m2e@^PWqeuPSmLIQOpyc+A)vTN$s3! z_^hWx9x*$B#Pt*1(t#tprMG*coT%cFOwb6L8VkYKKU~svkDGK=>HGZc<2T%OvMwZ= zA+ocDPqDr2<^v(Y&F0jp0(Lgs8yEGxWzeq%zCUwxn;O#?-<2B1Apf|k=|{)?CQN## zIQxY*octpu`Mje-rh1cb-R)xx_-zI2y|FsDMTiAPPonkUZ`lAFx@(hIy=9SYPhJEQ z4-LG!iP1AOvqsPI-dpR}rA7}KH!=*1xRt4w2#7!vD6*`EOsDb-*Alxy0;B;|pIqlR4F;nWFm60yUWq4u zQMqmwVQMEP8r4|Ucb4|PG#CZf({s|rBe#~?+h@oktvVPe1kNr%j^XoF{)*M-*M6A_ z`wmkGeX4F&)bkRd^^bH+ADJkaeiuD`;#{{3dn$NjdNg|!^hCM|T+$92{4ZEYny97A zz!6m244{D;EUxhc45oK{=VT=*y19=Hl-O=56!mOJNK6bDVi0+r?i!O^i9Gk=QOH1q z*6T#vBAS4@6Lhx%W@6jVffENN`^K@+Dc7`@N6edr$>||(&KTSh8V5CPPztaW?ua!X z5({IbU8y!aP%afU%_VLWRZZHfkSN-o@wC=_$af9ftOCTwyTrM#gC2pvMU2)4g zQedFSrL1trvF7acYgy)zib`E>dF6bo40k}v+7^63UqJBIo4&j@3Al3)_>Zv{qSKN6 z!_jL8&10;lfBFfI){%o0hGo6?@eRp9E1@JK%brPZE4~6}9JPA`tdP3@STee}`DTIj!W8=}Pp6 z7Z~puB)_rcQqIE=Qb70He)a4#D1nv(h~>cw*%Rp}xJC_#07#x#u^a$gMtwV+8sDBy4)7lqFB7 z`~ZbGfAtiEAx=p~pi~R{V^d-thLq4CPCRB0C6!^ypctPGD)3V3T83 z%C&nbU3qh-r{}3un+{|tSkyJhtYS&pX72hod7}%ceC&YZ_h}G~vgD=Fu{3WSaCUB=ep# zGC%K9Eg2+fxGz%h0X4T7Q5T(B8jZpiQB4jxiRMz9CQ2#bMG_-W&69kDk}={#Of799G+KL* z6zgm)_ixCE@tvPzFYWMA%X7kq$JC~nMDG_6$k_KYKo*>zTajeCULQaGKy(llXW^Ag zh=KgD&JK%RGgeHj8f!yOTF6yA6+aCNhkTUc=e1nA&g3)I5Fx;kC6g^Hnauhi~iCq&iMegqI z%Hi19+VoiQUC*Na@o|mk~QWHY$nF2=( zEkr$__K^wI8$IcWUI;3yQE7+$g6EKB`*ImD977~Y50tX&IDzL@jwh||X23o^T{*V> z;EpEUm7+BupwN-JcLYO}?UiF|v%5ikTMeun*f+kT>9$qP%CYVChBuyipXpFN1j}Ky zr^Za0v@BJNqcD_*@N?b3gz!da^5%Sq{OB)k%6P#WtFW@T^T0}Y6L z=+>vOT|c}8hp#u9fO3$6J`@N)4z;dLfI&AQ1KE0Sg7e*1G#B6702Ak^1BRZvvx}@B z=SBPkYpoF}O5d>YWdck|&`zTRADKg9>?b&i=jMcHJj&-d{t`vPfBe(yt4ZdLxct{| z2M_k{e>>o{SQU?4!-KC*k9R-&cJQaqxBvKGj-DT$esl69gFlBI4kuqd{>#(D?AyWa z{=Rr~a_`;(rONyJN2f>G$zPtnJk8MI{{E9^==9sc<$OMSw7-9SeZ80SB;GwN^ss5O zkF|Tz*Mw~spX`n2*mQs~b*L76cs?#i^L_lgFAYA2MF_K$2~z2Bg6Nh9>|?=7>s_hs z#S)9xBnu)LM!qU>83)g>Bc=-22)dY;Mbg#%Z9P7*ACpOI+0ac-3Cn%xZ5#K!a;uty z!8Qflq~c+uo6zy=uz%_KWXy6C`0xs>_+FS8IM^y6=VIP(=8ze% zrJ&X?Gdd&#?lmmAG~t>MP5Wl{nbcCH2#gGW{D~(1r$_w%pW)^F_>-96pB~9S`Xn)o zKRvQP$$Pd@uwA~H_aL>A3gl0Z^k04EH5GvHf5u*|g8u1|)$Kn6QCnbO6MqCn%s&!t zXz>S`1Ns$|7a4r1r(}XV7(yl=vZc$--p);2{Gy1u{vPh#m&*AGv^0NgRO#;N&{5yc&eO+2#6nzO+3W?)1#txkf{H=qw=CM zLauuUfT&~aAyMIcN1#~w=U!=1CS9%YPN55Ws0Ck8NACzaReS*`rw88=Fkan8BKjwy zfPY1(bRUctI;->psuJA~(1Nm;zfgabD*bIy`A?_i9Bz`{WObFl7Ec>0T?12?0DG&- z=dw*p(}u`Um>-U|N}S0dIoIC=rT7MGJeUYO%> zXI$tB3t}&pkJ2p8)*FO}DrEOj2||2Grw&|<{6GFqh3tOA0zC!zXE~PY@w5ZEhqT=f zU_9NVA9$sffjkE(Pcd~N%w(BIxCwOT{;#JrDMKE!D%U`u=HPg@5E9r(&A5eA3m}s zf-LwLiaS76wUCad6$+dDPKm)O&Nh)<_zzV4NDY*S;6hD`DfXh1jXXrlKIcw&O0yj| z3Uq&$09jy{C~00HfjSJ35e-%XhNfe_Tc1_Tho}&IAU-h{cf8u{+?2L_4d;y*&)u*l zao#d2dUD@#8{0B^!}j>uFk%SBh&XoRs=4r|1>hI&;phrS2| zn8Cf(ZO!4O!en^BfJREUic-v5_37ul!Nl1@TVnTE&iq+g%Pr^Not6&B8P+Fv19!@uX&V-PR5C#?7g)jx1<9KuKS(`L!maC zGUysBEKvxx(;lHSofF}P6z&bp1K)7|?TsBR@|eEFpyQya2$7hXxYyjh5yAJPTK;kXORnHbKIRB}57D!-p@mh?>W*+`u&Lj&b17 z7}{JMh>p0d`#pIxv|U?X!WV?DMWOI+11g1YWVU1vm74IpB{!!q6F4R;*$AbJkb`jI zlsf^%$c`(i4V~(AKT5U5M=D?PPP|a-bb2pT;u&u?Z_gLf_>&uEh=e4HkSy;=94hBc z;guY1U_2#Ax6UaTYPZqBbmQ3#o)51Ca>pXLA6jeAuncoBAiKycUNKA;R20w-jz)kc z7RW%>5T&Kxn>$tSEVv?itP7dOQ=3IPNrtM>tJjFF9aCTum#D=DG zG3G1<1$y5LHsa&dF0zLtRIhN}qdP#U8ZY43%6%k?vc2u2YWg8hHO5*U#xJgbic=mr z*`ftdo4Up_D1dJKjbOTk1V3vTMT+gyPj<4yFCQPB9^!Djyngk9@g|DTMH>oRn(SbXOATN=F_qnyxPY)Yn3UKK=;os6ET^N% zg2%m`+Ls$5gGB3OYyHR1qUu@elWcXIg?O9ycZG#- zMyXg}E%KT{KYu{&`s{Dq<_dS;`7vtKfpXw3i9kS22J-`*FEJ@~nCpG{M#u?cNI1lU zTd8uWM%IGa_XAmh3KonO98(OPdn|+v zE&3jgOUxMh#=0Xk&Y}}xBOwGOr@^T#oz3}M^o86123=01Lxr(>YzpWwr)9+z7o3TS zam)dbX_zG=WdHPGFj?efQRA?|X6QUa&!nn(9_)YW4wFJlE-3dmduW@+cnk8Qgz zP(C?iMiHVR<$h2YYP)spPi$k)$j7v;{hj~8wzmro{mno1%>#zQA91}{7K;^wd`pLh z*ZxX5g-xJ#wuG8wvfsM^kpzEreW6Vy7?O>C5RzVQh~5Q`qc|&P)#z1$Ra9Lo42P%gpe~6!-?&+Gr|+OnF%a737a ba+;j(ezzXZZ>KL*IxMT-PCOEAd;9+Zy3$)W diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist index 5d79f98..646912c 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist @@ -24,17 +24,17 @@ CFBundleExecutable droplet CFBundleGetInfoString - DeDRM 5.6.2. AppleScript written 2010–2013 by Apprentice Alf and others. + DeDRM AppleScript 6.0.0. Written 2010–2013 by Apprentice Alf and others. CFBundleIconFile DeDRM CFBundleInfoDictionaryVersion 6.0 CFBundleName - DeDRM 5.6.2 + DeDRM AppleScript CFBundlePackageType APPL CFBundleShortVersionString - 5.6.2 + 6.0.0 CFBundleSignature dplt LSRequiresCarbon @@ -50,7 +50,7 @@ positionOfDivider 0 savedFrame - 1846 -16 800 473 1440 -180 1920 1080 + 1616 -35 765 818 1440 -180 1920 1080 selectedTabView event log diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Adobe Digital Editions Key_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Adobe Digital Editions Key_Help.htm new file mode 100644 index 0000000..ee9edb2 --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Adobe Digital Editions Key_Help.htm @@ -0,0 +1,55 @@ + + + + + + +Managing Adobe Digital Editions Keys + +

+ + + +

Managing Adobe Digital Editions Keys

+ + +

If you have upgraded from an earlier version of the plugin, any existing Adobe Digital Editions keys will have been automatically imported, so you might not need to do any more configuration. In addition, on Windows and Mac, the default Adobe Digital Editions key is added the first time the plugin is run. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog prompting you to enter a key name for the default Adobe Digital Editions key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys.
  • +
+ +

Click the OK button to create and store the Adobe Digital Editions key for the current installation of Adobe Digital Editions. Or Cancel if you don’t want to create the key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.der’ key files. Key files might come from being exported from this or older plugins, or may have been generated using the adobekey.pyw script running under Wine on Linux systems.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Barnes and Noble Key_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Barnes and Noble Key_Help.htm new file mode 100644 index 0000000..ac1b693 --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Barnes and Noble Key_Help.htm @@ -0,0 +1,57 @@ + + + + + + +Managing Barnes and Noble Keys + + + + + +

Managing Barnes and Noble Keys

+ + +

If you have upgraded from an earlier version of the plugin, any existing Barnes and Noble keys will have been automatically imported, so you might not need to do any more configuration. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys. Choose something that will help you remember the data (name, cc#) it was created with.
  • +
  • Your Name: This is the name used by Barnes and Noble to generate your encryption key. Seemingly at random, Barnes and Noble choose one of three places from which to take this name. Most commonly, it’s your name as set in your Barnes & Noble account, My Account page, directly under PERSONAL INFORMATION. Sometimes it is the the name used in the default shipping address, and sometimes it’s the name listed for the active credit card. If these names are different in your Barnes and Noble account preferences, I suggest creating one key for each version of your name. This name will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • +
  • Credit Card#: this is the default credit card number that was on file with Barnes and Noble at the time of download of the ebook to be de-DRMed. Just enter the 16 (15 for American Express) digits. As with the name, this number will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • +
+ +

Click the OK button to create and store the generated key. Or Cancel if you don’t want to create a key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.b64’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.b64’ key files. Key files might come from being exported from this or older plugins, or may have been generated using the original i♥cabbages script.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_EInk Kindle Serial Number_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_EInk Kindle Serial Number_Help.htm new file mode 100644 index 0000000..e79abd7 --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_EInk Kindle Serial Number_Help.htm @@ -0,0 +1,43 @@ + + + + + + +Managing eInk Kindle serial numbers + + + + + +

Managing eInk Kindle serial numbers

+ +

If you have upgraded from an earlier version of the plugin, any existing eInk Kindle serial numbers will have been automatically imported, so you might not need to do any more configuration.

+ +

Please note that Kindle serial numbers are only valid keys for eInk Kindles like the Kindle Touch and PaperWhite. The Kindle Fire and Fire HD do not use their serial number for DRM and it is useless to enter those serial numbers.

+ +

Creating New Kindle serial numbers:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle serial number.

+
+ +

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

+ +

Deleting Kindle serial numbers:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Kindle serial number from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Once done creating/deleting serial numbers, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Help.htm new file mode 100644 index 0000000..69edade --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Help.htm @@ -0,0 +1,73 @@ + + + + + + +DeDRM Plugin Configuration + + + + + +

DeDRM Plugin (v6.0.0)

+ +

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.

+ +

Installation

+

You have obviously managed to install the plugin, as otherwise you wouldn’t be reading this help file. However, you should also delete any older DeDRM plugins, as this DeDRM plugin replaces the five older plugins: Kindle and Mobipocket DeDRM (K4MobiDeDRM), Ignoble Epub DeDRM (ignobleepub), Inept Epub DeDRM (ineptepub), Inept PDF DeDRM (ineptepub) and eReader PDB 2 PML (eReaderPDB2PML).

+ +

Configuration

+

On Windows and Mac, the keys for ebooks downloaded for Kindle for Mac/PC and Adobe Digital Editions are automatically generated. If all your DRMed ebooks can be opened and read in Kindle for Mac/PC and/or Adobe Digital Editions on the same computer on which you are running calibre, you do not need to do any configuration of this plugin. On Linux, keys for Kindle for PC and Adobe Digital Editions need to be generated separately (see the Linux section below)

+ +

If you have other DRMed ebooks, you will need to enter extra configuration information. The buttons in this dialog will open individual configuration dialogs that will allow you to enter the needed information, depending on the type and source of your DRMed eBooks. Additional help on the information required is available in each of the the dialogs.

+ +

If you have used previous versions of the various DeDRM plugins on this machine, you may find that some of the configuration dialogs already contain the information you entered through those previous plugins.

+ +

When you have finished entering your configuration information, you must click the OK button to save it. If you click the Cancel button, all your changes in all the configuration dialogs will be lost.

+ +

Troubleshooting:

+ +

If you find that it’s not working for you , you can save a lot of time by trying to add the ebook to Calibre in debug mode. This will print out a lot of helpful info that can be copied into any online help requests.

+ +

Open a command prompt (terminal window) and type "calibre-debug -g" (without the quotes). Calibre will launch, and you can can add the problem ebook the usual way. The debug info will be output to the original command prompt (terminal window). Copy the resulting output and paste it into the comment you make at my blog.

+

Note: The Mac version of Calibre doesn’t install the command line tools by default. If you go to the ‘Preferences’ page and click on the miscellaneous button, you’ll find the option to install the command line tools.

+ +

Credits:

+
    +
  • The Dark Reverser for the Mobipocket and eReader scripts
  • +
  • i♥cabbages for the Adobe Digital Editions scripts
  • +
  • Skindle aka Bart Simpson for the Amazon Kindle for PC script
  • +
  • CMBDTC for Amazon Topaz DRM removal script
  • +
  • some_updates, clarknova and Bart Simpson for Amazon Topaz conversion scripts
  • +
  • DiapDealer for the first calibre plugin versions of the tools
  • +
  • some_updates, DiapDealer, Apprentice Alf and mdlnx for Amazon Kindle/Mobipocket tools
  • +
  • some_updates for the DeDRM all-in-one Python tool
  • +
  • Apprentice Alf for the DeDRM all-in-one AppleScript tool
  • +
  • Apprentice Alf for the DeDRM all-in-one calibre plugin
  • +
  • And probably many more.
  • +
+ +

For additional help read the FAQs at Apprentice Alf’s Blog and ask questions in the comments section of the first post.

+ +

Linux Systems Only

+

Generating decryption keys for Adobe Digital Editions and Kindle for PC

+

If you install Kindle for PC and/or Adobe Digital Editions in Wine, you will be able to download DRMed ebooks to them under Wine. To be able to remove the DRM, you will need to generate key files and add them in the plugin's customisation dialogs.

+ +

To generate the key files you will need to install Python and PyCrypto under the same Wine setup as your Kindle for PC and/or Adobe Digital Editions installations. (Kindle for PC, Python and Pycrypto installation instructions in the ReadMe.)

+ +

Once everything's installed under Wine, you'll need to run the adobekey.pyw script (for Adobe Digital Editions) and kindlekey.pyw (For Kindle for PC) using the python installation in your Wine system. The scripts can be found in Other_Tools/Key_Retrieval_Scripts.

+ +

Each script will create a key file in the same folder as the script. Copy the key files to your Linux system and then load the key files using the Adobe Digital Editions ebooks dialog and the Kindle for Mac/PC ebooks dialog.

+ + + + + diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Mac and PC Key_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Mac and PC Key_Help.htm new file mode 100644 index 0000000..c714581 --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Kindle for Mac and PC Key_Help.htm @@ -0,0 +1,55 @@ + + + + + + +Managing Kindle for Mac/PC Keys + + + + + +

Managing Kindle for Mac/PC Keys

+ + +

If you have upgraded from an earlier version of the plugin, any existing Kindle for Mac/PC keys will have been automatically imported, so you might not need to do any more configuration. In addition, on Windows and Mac, the default Kindle for Mac/PC key is added the first time the plugin is run. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog prompting you to enter a key name for the default Kindle for Mac/PC key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys.
  • +
+ +

Click the OK button to create and store the Kindle for Mac/PC key for the current installation of Kindle for Mac/PC. Or Cancel if you don’t want to create the key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.k4i’ key files. Key files might come from being exported from this plugin, or may have been generated using the kindlekey.pyw script running under Wine on Linux systems.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Mobipocket PID_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Mobipocket PID_Help.htm new file mode 100644 index 0000000..00aeeca --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_Mobipocket PID_Help.htm @@ -0,0 +1,42 @@ + + + + + + +Managing Mobipocket PIDs + + + + + +

Managing Mobipocket PIDs

+ +

If you have upgraded from an earlier version of the plugin, any existing Mobipocket PIDs will have been automatically imported, so you might not need to do any more configuration.

+ + +

Creating New Mobipocket PIDs:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Mobipocket PID.

+
    +
  • PID: this is a PID used to decrypt your Mobipocket ebooks. It is eight or ten characters long. Mobipocket PIDs are usualy displayed in the About screen of your Mobipocket device.
  • +
+ +

Click the OK button to save the PID. Or Cancel if you didn’t want to enter a PID.

+ +

Deleting Mobipocket PIDs:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Mobipocket PID from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Once done creating/deleting PIDs, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_eReader Key_Help.htm b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_eReader Key_Help.htm new file mode 100644 index 0000000..c1c78ad --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/DeDRM_eReader Key_Help.htm @@ -0,0 +1,56 @@ + + + + + + +Managing eReader Keys + + + + + +

Managing eReader Keys

+ +

If you have upgraded from an earlier version of the plugin, any existing eReader (Fictionwise ‘.pdb’) keys will have been automatically imported, so you might not need to do any more configuration. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys. Choose something that will help you remember the data (name, cc#) it was created with.
  • +
  • Your Name: This is the name used by Fictionwise to generate your encryption key. Since Fictionwise has now closed down, you might not have easy access to this. It was often the name on the Credit Card used at Fictionwise.
  • +
  • Credit Card#: this is the default credit card number that was on file with Fictionwise at the time of download of the ebook to be de-DRMed. Just enter the last 8 digits of the number. As with the name, this number will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • +
+ +

Click the OK button to create and store the generated key. Or Cancel if you don’t want to create a key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.b63’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.b63’ key files that have previously been exported.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt index a0000f4a703729ead340d367470fe9bff9a5f4d8..009e52d9ff2239a44a87893fcb02562e9f54cf38 100644 GIT binary patch literal 293024 zcmce<2Y405_dh)K0=vwG3#c?DpdhGJ3yKv)EJ#N|#S$Pu1d@;h0R;C)P3ie)iX8)hFliW)*1b@%-zTd#ky}Nhzv^nR@%sI2Oee%mjAJ=n8 zUe``tyU>wljHw23%s3NFa(rP1-}!i4r#~f_!Y`Vo3<`02a#6&N)d^AT(uJ9l(tA$LSSsb8X6P{#uTd? zM=TSfXw!u?@G>Z#FuI^Lk%GU_C%NF|knwm^5J;mmYeaY(XINuk_&>=(u!f+d3ERP- zNGPetn#O;#9YYlDy0FZ+{G!nl3Pu-9EiWi4D=aQ5%U(Jnd&#gJ89xTCQjhJ#b`mHA zYs#7#6iH*%gIt@ZS#u(?MTWINvlT!Xli5hYnxSq>wzENz)I~F}UD9k9s@p2VTA^)9 z&}3r-+Zi?USZjkKsTs2RtWBD=p_;p9*se*HS42Y+ND`Ls=0fH z?T(uH>`XRAu(qh#o^>!Nl9~oBw+H@H%{?=0Pf(iFWL*X8fVz9Jjs`_iH;uOIl!m}j zw{wPd2GnxUdZu63|%?_rzhh*3xm2w>^;=dTG?ttS^c9=mSC*V8&;y>d*;@^4vCu2PRgNom&=3zK` zvR(!SFG00t_;2cVS^cX+b{Bth~5*0!{`eCqr=};_nE^ zF*uH8{S1mMkp6=82as>$Z^HQ7gz|~SBMVE4M~yEiPvE5cWzRjRZwORB90S-ugCYxR zkYIxV>g)KcF#bAmf8z_u;7STdCy-3v2+%+rgV_*+A`57!U_$|DOT0OZ zw64`wrg8G_?DcDzB61v5;rVF2@G{6!dl$(nXy z!N{V5lF1_zAVIJG1p_CK^dP<<5Xa*f&Q35WvLH?r>_mY0Jl+(>pKrwys7atyvIKHG zpiKnm1RN)^5e7vT(8+?G3_zd7pN8>giCfGcT|Ba2E3O*!qzhX!_9+1yf#Vc*szH$j zcA8+P0oW(;$6@?QLRA7R%bQ6+<=Fd}0G)~>pN%vqvVh=UMgh=A@y0OzC=ql5qoB+; zefDH%N`5mNnxoPoXjcrYIjm;xMQ z**JqD3kH^62rwJs_rrKY(q3m4qOY2o00~YkEa_7?)q{ASK#aq2Iva0LWI;?2=#)hK zUi@wtzn7RqNon!e(t@%w7$XY@R-V8TMf@%S8INNkD>5ju7Whv5cKjBP-y!3Bn~Jxn zW)Y5JR$@?O(M=L;641RFzY)f7vie<^g07b_1r;w7@f&no364@$W>92rLoZ#9+t$bH z!gxJPcVT++Xu3}y*E_j!9o<-lV=_C#pvc|`FFyr0z8=38#;>!6@J)$fl+h1;4T@}=Js&?8Kg;9iskxq`;#sOW6UX^%mO+t4 zc!6LS0O8vBnJ`|M&lD$Zu5fM05}31)~!% z=J2Xh4`?+3nuFs~c9}tu1$4P!mjlp~@e^VEWMVW4JEMvx7nQRh;pcGrF5)K$#AP_H zU{@LxSrBstn+p)D;>W{yRni2N40#~+D>uSC6mj?B!g8}-=F!RtB4;YFgN13iQQ~aWWg*FY!Sdb5Z@oh4{IpO(|Dx8S&q z-EL51jp4rd-uNCK-$!X<>Omc`?L6x8H|jc??FDGhSR-{kAZ^jTx9I>Xen2!p4ZM+o@PW zbFq7w9F$b;z$)1N@vR0Q$?QyGVEuq#4*=$a>>-0fl%k?!_1VL0g+T$5FsEZdd<%Po zJxU)UR-ONrr4uQ#*5g>_~rl~Dkv!^ zooLufKX%1rF}^8?Z(?;rX!9B6rIQO%@y*1{iX7hy!+0TUgw`PJm_qt5gA35nJ_NEK zV~-mY2@8fbk8fnF*b@OhJPRb(qRA5`#PPWa6MNv#po$oYQ-ksQlWes?k+6hWLVQCQ z-|$Z{8@AdLOjCn3X|{$2+fQZKQ@|gj*b`v!diFGXCcuXZKqLClr#(mv<>Limyr4!7 zQtTPrdL3KKo(=G!pauEm2B(~+!i`yz_}U=87Sf@{C@3D2mtxQ2hHKb!@%#WED#$O( z%QNgbf5Q%J$9P^4&%HevBKIziqIG&H;o}TwYYQgg2tJn+i+yEb5NTVhcm;GBv zFL(}Gu$J+aVSHtc9Ef->Dd5#4%lnxeoXD8PSHzdcmj&?^fS->+KfG`r3EuyDC8O^= zzMSs7j7;WMqVsMXFS3^mimY*68ebC6;qj$Z=@KgDP|cTcyv$xPC=%n^84CU?d(EK8 z8rSUj;`pL4o=pRhx}zo(~*#-zR=*K(qNji^@6Pjnm5>+ z21V9j-ePYX_LdhU8O#Oj9riAL)Mha6ctMiE%nIXK+cB7T(Zc7m_u`oWKB^4ny_~_E z7sTgPGnkpg%-bFZBpja`Lf30Hm^Z=F`)q?jQE4zu;&a#s?85*bo`o{#*}rw+0}q}I z}erwpAyDXYNSQPQ>mTLB+;zP>E#*m zmn1GG(Mt+K5k~lV5o2a;*cUm){E}^s;V-|;DdrZzwgAsp>}!J}tC-)gZw>p#OOh0G z0{f1APam}@=65;893RHxYv@>0?0dB7>FkHNFu+HZI{uJT$8kYCu9`ZcyEE+DoH~vT zTK z<475!7f8jUsPTTn@mrj4*l(T|QpeNS@A0VtK5A3P-*f7CN*JF~BP}96m0CBSM6)@k zjwi<>;*)~-kk58mZCr~k*YW|7iFZQ=V zk*H%^1j8a`4T`Kf4vUYEj|<~riJPQ=NtHGpPgsv5dTmvVw+C~AIRK40F2`Q?Fpl7y z3&XjWE3k8!<`O+5R~fDVfs33n3=QL<$yk!`j4Ccd@UgtikLC`qJQEzKx#lUuwKoLC zy7M}`ZalU?G=u4b5@$H2OaeSnVkEBbDycC&17Ddj@eY)JsM>d}m*8XSPdxSP&nE>wcuuljv`nYn(&F_|Wa? zS=^t5(T}tZv2wmke2C$@c$Pb`PVvFKReVqoA6&_DjbkL<%A@SS_J|J*;{$7CS;PmC zF&#oA*3B7zkNALi{~+!G_}d;M9YA;PPjn6;I+4%dd2x5c^B6}{B3|5sw>G@Brvf45 zc)u{-Z@Y|l2Q2nCV71}98r~-7NcN5QiTCF5zJzceD)uI5k>mN=3QY%ku9 z?{0WIl2-B;cZ<8mUBb8CeRn+FU33ZPKI}6959fKNyVLmxHB5Qq-<)5;hmTOq4Z1KiQ|_}_$8U9 z@XlT+nApS}!?1V0Gi4(70; zgR2HG&H17HuoxP8sIMqlhW8Y_Co1;hha29DSmc;`$~cer=11^2kFol^H-hqgMi-Wq zOvs;>HyRo_{EOfIqtmU3g<3JR z)e+Pk^~vx)h!%}bl7o~a%ttgYFFB_)BGPv_Ym=n(kUYfqj`)qPqRbqhMiXR>C62z_G7|N!V6&Fk`7&Y{W;X|utu=L$#OQv8cw1`#odLr`J%iNA?G(g2Z8hW+aZ}R8!*Z^5$9RXhNf7T?t83kX zFg79FtqJWRIF94T8-AQOyB4fP+&FF&XL#J0Dm9`aLp6~b;lpC|?!!ERE!fU{xZ%Td zU08!4Zcs_!nEVNdM5DJBygQB)_=$#};4wf#aXL0}eIBO?xS^sx)jSc$NqmIiCwar} z%J$(W^HU5zIcL}*KQ#`*I835Pj7;XkQh(NnRLG3`2aPNk1~8@&ZI~4g1C<1$a&CEj7)lr;K+IKv3#82V{?j};)Sse z;#94QT$oej)A@MAk-)$>7hn~ikmm3X6?|d_m#Ql=OwIs(r8?H*MZDPXqMRbDAXZsL zF3u@(Ni1UwR*{IPQshaz)bL3;Mdks9w^h9h@)T8y%tEYqpa^+Q0_3rz#)GdBv8EOr zhoj8JhL`1(xZLpatP(pHIJdPDJAgO5AgjdAy2$+ZdSG3_o4ef=~C(LWK~67`bNtsg!=)c zxF1QhXICk92Y#O5=K;`6e!k%|s|FsD&*B#tKFdo0Z14-y9I1{9eo=-~z=&Uv!}(q4 zzDqI{)hRY~x)r(S1IxvHw&551iGX75_#A$T`__G9_#7sVNW5eneks4q@JqAG=DrTy z*V|yp@XI`f2%hrG)BJLx@QMt-0=);uNtbvo1J;ILDL7ISd@jGraO5;7iW{&7{AxbW za3mUvsPh0<^Z7L>ya9yFxUT~D6%3$!>gWlEU*oT1@rK(HxGlI&V^zcFCD(=>xEE zy{8TJ`9gk^;R`(tjaU=+W#GQd(sq--jtHy!B5+?+(kA$IzSjgmp*Ok}u}B z7`_-P%jvv1ztw&2HW_}a_XBk0Hh#O|x6x>lW1UNL_ZeRjxX%D|RAD(LD996#Tf*uW z_o;NB#xU*My$p6_JGoCn_sKTei@VRsBsP%(-I9~q$D#Z9KPb>5@N$Ry$Z(_{h?kww zu6Odg48PNZ!bHez4Bf^W8^G|pa-v+yml?j)i>wuE?LG|LhgnfB^VfG_t=tEJ`=Cmc z?jy3EZ;AeI$fRfExZ7Y{ zQ~n4LKE@w6{IM#Z(wVQ~Pq^3JYlb7SQRP#f@pqe=_D7U*B(FB$%#M^8TGW&VocFXw#9t7-l! zvG7`kzvfv$5SRQN{`l*Bo#BY|6Ak23UJTreS=!e5>*P~j2;2)*hQMC}*7f`i!;uv5 zKBX;xlfPv+BI=_6Xh*gyf1AH!_}iq*8t1L~yY6`hvAkR5V_Ng~`1^*x$7FXz%XWed zKFc?7*xR!}RPJa2 zfP0Qq78wWv(wen#PX+EN;PbPHw{jw16S_6q)jecF_=gU9^`RF-JGLj^$l;zgdO+>i z?(WIZJy~Ph8U9hO6+Y&l82+)Bc6+vmdm?a8WLx1Af1Mo4s=%$PY6Z8NZ18pB>NRo; zkK_2%!4f|8?x+jv#y>OsGfxW^>bb{4_t^HBa*q?N3LKmG=Z0^}Iir>CQTGUUD+%GF zR6Ig8KgaO}|I+X;yfZqO9mY5FEruhoTjh*axQE?Cp<9tO4V)3J+9_jo;e}|;PML6& zb$1U@(`>2qCTcGKO7O1${A-TE!Pj2Ea`Z$VJOzfbe;NxOf@@E@Svf#Kif zn(@KVJ@}8@HU9=cf8;+I{-Xz~*iQUs{)^#1du3HHp0}`z6uE5=e8l#IRkL2zFs&PNn_$4RN zJ41J8(vJDakxm?0P|E7|9OAzTj;w*;LKp0Eipnf z(Gy7NN=no*BIQxgh~oCp-M$SJMj+%(#9|gL>edx?S>3~MMt|JhLB$f#D^!l&+d_BS ze_3@Y1Zb}(0wd~q+IL~CMJVbU5qgXm4G5DK2D&EF89}ROJ0pfshR8+dBwjKKQH}}t zj&-SsZ*)e4V;Z6j;}GE}GNOKtqFY0EYxTvWA^`3NqM;F$5%M-{Z;=s=+%0ag5gCRc z07KxVgJ^67;^SmiZQu+Ri6-vm&@KA+oL4jfz#ZI8M(p76?#gy^3q!ZCI$n1Z+1ECd!!(*mL73ehYhn!)krn68o0opOxc7`hw(f$$b;qQ$@} z8sca!S{TvXi+dl|U9=QC8&SDH8jFR+E@`m~VQ!TXv_QHW>%{gp0zvPpj`4=j-M})m zm_AvDONM~8+XTJ^jy%!Yh&(@2-=FmpZN#qbdL!C+ga@+TVmHy&h}}q{0?Uefxdoz~ zyDo4GYMY{qc7BR}AUj0tF4`M`5H8VkAUnui8@g+&aco58itB^e!Jhcj{FObtkbTtBtE-ByCpIs-qiM`!iccl^CnCO#S8!z?|`x;DeD$h?9`-$#G z?B_jIe>Ozy@2+r{8?iqVhj4;2L>wS`7=b7+wRe9uz+D!)%W9Tr4{tvM*kEyBS|FfY zAr8ujgDSOnU+%6T>0M4O)ZJq|o}DBPc9*(Kj5ye1q$`JrLyb7ZV?3S>b8|vBr)G?Z zDU-zxV<(Ek(&8|}*fRqk>+NPg?k**amk`E%J;srELZg?P?JhQ=m&Zs~4i~+RK+1`D z9LYwxi$Zr%%@})ojHB?>!VzflAedwfP5kELmY5;n?(n~9W>7z~)_iD6=R;LfAoeawV%BZm2#r?VOETr9~;>5t6gL+sOU24P$zTUa)d~s4*oJ2@QWW)&Y-y2*fPyVFDiMaD@ak85c zxU&fZOx=i+{hb%G*=~B^rXzY*R$fTc1D0|#NHs2`;sVl-zBw;-R_M-3(lb8Ofd$%= zCzO+yfs+=exHFA7#gA{Vf-;?I#Hk(&mYlk2ftyw>Mt3IpskwyZN`im{l{ii08*v)x z8OJ)$1#YSsDMoQOmBCMqMCaBaZ%RR4{)8#{)5`Lu!@^FH{KWtvi?iOVNs)r~rO*ijkce~QSl|o^X z?4>C8=D(QTDJHu~4v-MIrM?+gT(LOA6$P%i()>$H%E#qnJ#=FGD7^Wf;gw-AyG=|< ziz&qC)Qp&l2`EXK9*OG)`AxB<^i4Bf;eRkO_}XG94Y zo+hA?SO!misDiB)XNl=XAjS*8IDcHs5N8`P!!!H{d)!S3+=MK{XM2V#*dyW`H{PKc z&+!c7iYpZ7x^aOktd-$&J;N33L2+JMoJS1L%!rwI%xpX!wW@qfDoL>Ao(BZmJsy7*z4i~aiI|xc;?rzm&HW_eal6j z`RCcoZcO0DWSPI%GrxvCFJ`*}H`<8Vo_Snxqr@CHGH|16Wqyulehqs@T#^=-5c8L2 z#HE;2j8EL@XtXmufma9tRJQj>;<nvA#xPNWb$Nf8E#BNN8QgZXK= zLQjZRvOj`2Kb4A8i2W;b?4K06lakm#EzeU4JWe3471tS28NvR9{U8WxZ0io69}M-#o`tt7W)?e zku!0txXp;laQTlc61NLXX%PV@xAq5%+|a-c%`&~jGyNm`L)_tpxWPu;;hDx2H%Q#+ z1_o|WtxO}lO)dT-`$gQ97IzWTOEY5WKNQ`!cV$ZtBwmM5F_;*>EywVH&<)s1(eXG< z@)T9>v7F>VDsc0AoYxokiRDJzm$1$2^7;DAkbVP9?Xab;mz}5(WK@D zuyj)LN~Vt?e)~~@WhqA7n`8Ru&>j8Xo~;vigYk#N!$x2|JscaBs^y6l;t?Yd(x&br z!&{0+#Y!U((nfppro5#)DsV?-8DHrc&+w+=F?XcvV}xIjk2{;XBgEsbci@hwmGQ?t z;~CyWtV)Yj#P|~#@dVnN#+anqG;By7Ev{m{H*tL=6`0-_@koyK!$Ws?(%!W`2`CV` z7f*`SMm*`+Zq2)hHR35F)_AsC^S#8=;u#~J_H4K3d%0eLqs3^x_r~IV#CUjXEM!{i zdb-1mSnJyxSKOiES$9a_4y~2#XFc1k`EKI5v_Js7LOh=l&nLaNXSQnfMrC^+Lj3lm z;xJhwk9Soz?QxqF4=WuE0=Hk5<##>HJ^4}MJ-4sh#|T95F-8NVquk!&eb+5; zd)LY`;`PLGPu^Q>NQ(``@&_650kRKgg6R^Bi3^iSRx&>8Mx5?T#XiLD+c|c-hOTRE zPl5{MBE*McqY*wjk2N}{iI2p`MkH}}hVv2P6Y;4LKEBR}^AWB~;1D#ZROnAVtAqG( z@tN!FIvMeqXBAgmN3qH66}XPIvbxE$I*1PypQpv=#OfCr@dXybXXj4nwFhEYO3SVM ztg{R)oewdT2)7sU-I81cO~zKQ&5@uT?32&{f5KQfWe6+gS(+^$9- zFi#qWE3S?BMf@7LHkD$pIS7DoHEGyHULt-=i{D7>zh}hnY*7*fpqWNAFK6f6Em zsJQwz6G_}fLf47Z~aD1R!{Wt0&vac7eklGRZWpMlU4W`bJ#ASIXVf5?O)@ z**+uNMUtV_MA^T6Q7ses|A9x6Sk><8$_{dmz||$Kr+}nH9)rf(tN2>Er;vL> zha-y_w5 zN0NJhs+8PY?i08a`3nkZN<^8-&am9VY3Ve1B&-^DO71H$hM^UZ-Xrbn>%Gihliky@ zJE7h`BloZFk&p;*QXb$$;IR6#(jy`EPZ-wow;T@~_Ga2Dq=|4KcOex4sr{}wkA$Ti zSnY+!wEq#(l&v9*9yT_zhd0@cu#p4hLDpGohxYFp5F2@j=i@W}h3uJ@JxKz+GO|~$p^QAp zd!(=UH}Y^Jkq{upzv5rpzXJQ$)*i`%Ic_cN-Nt0}jd1ER_$HBsl)dEP z4v~H2k@ipfhmn1}NBWgJd6bby`60-!0Q9>&+Wr>W-)rzl7zM~1<9Ymz|7m{- z?JrwRXSWfzvA+_1zfr>+nfN2*se8!2LiPp7V`V=hk!gTG!ewrMmi^@be2_otkNjNA zfA}N68Aj!1HQpUjra=zO$bonWrFM7JHyJee(9}RIknf#yM*Tp`AUW9J$#t4}f|lLo z5INMyA&E1>d0Tm${mK4l;^%?__z3kv{Q& z%Yi&KEs-Fokf&wjX*ul{@)Xp~x8E6=?*$VGBS)s?NUA$3BS&r54cYI=4V?t4zLle8 zL14cnCy}_J(H>+Y(b#???Kk9xu#nk)Eyu{Qf&Ciwyc-(h>+L9-$#H3kD13!1%*ev( zZU_s=?N{=2yCtx+4%H8gd^jKZ@>X_pU^j2=hU^xy#-FJ8k+dB-qRI)P{W7#)*5D0< z91LNMw_g}JKCx5L9;PutPPCufO$J6m10!7PDvM;Xk%;oc4dJ|_ERmCpEJ@su=pZ`U z&jL$JM7R5$}{bUq1{-68$#$?o@GBU@+{BeVd8MRA+#H|7eBQh5Mduu zvrP3)sIQnMrwch90B6Xvjhx{Pzpt1i&ynXEiF5$wLZYuImgm{`?R!RIV;guux?3YP>*WnbUhiE(shA>flnaf#(Yu5)F~zx%)S`f7i&OlBr*pWXoxA|OnFmUBHCXeZ_db@a}8zW0`C&e7U#-EMlSL< zoGs3=F9i05YA)dw;`wDVx>u?Am`*>!H;Lyxu`AM&9mS!fY|uJ}Z~lwV{2s2A8k|0PnER7>4AJ4RnOS6}wvAEAI>J z>RR0aLgFOe`QkdcJS~@#cq=lp0$UVSO-icV!9PPH)eXK{^!a~b>{u;npOp8@2Lk&f zDO6(Y_j_Z%LEI`I6!Jlc?IHQFkq>z$ZxA=h6=}JGn0zE7AIa&Ekcf86N9_|vB8X1{ zxk)URE7Ni%)qN}@AKSjMKS9R+0H|6eAD62FOY3sIvHR$~SR(GQk4uZQlw5^+kI5(G zlYzxL^-5!Z!lPa)?vbn0ay6k|laXtx8~c;EbESOBJ{s7Sgds8Zr~IAE#RK+{z=E;d zG{n-BIiYe=*1&KdiP(5|S#=7d}dVLWXixTn1}JPtK{My|CF*$0ipx^^=5$HiLt ztb}zu>y7p66wM!}H<=TM^ibYQ~QB!`wbdCiO5C&(rC1_$HCb zlCMbkGAz2sG(@~1Tgunu>vp-l&&b!jvA-cckn4rt(c85v-PPNpwDl!_(0JBdO&( z@?9g}@h1O~l=3~h)ZS&JkGG?Sw0Fw)<%YoCS*ywWcsoMhpUMx?@&gj`hZ*@H_Gzjz z`K^ckG!gi}j03jLv~QJ*`(L<(4KR&6?iH{~=<$WKxCbGyVy#ObN-X7RQBA}zn5x?g7Gm)myHjx-kUxkY?QPP++o$9f)Vo!FCBF{rt*Gbwe}u>h^)KRg`Au44 z>QEuS&B$-7y99*m?Je>gvDeEOR2bvH1FM@gh4w}x5lDqgz_kYQC;79HKP4^!=b`*XVs`#Z z;u2&X8QL2Hdjqvi;u3yM5TjlldwpoHuK}@GVE)ldt0VQ~qV-pPs#)F*o~LM)o>; zt&xbUV@iOSWIKs4j7?ku&f3~*q_guwdrb{4!2w`w=NXAWJLX$*7unig9onn^Th7_e zBl6}`<3x#DK)h|FVnX4vLiXDztT}*Nz~uo-DrFQR?U)$gyr0tcDm&LGM9?Wbf-Ck) zl~Q#Adu45IL8ZLhI>^0L-Lyiey+YN?sCw9puF5U+#7y5O+5fLjp~m$5|G*`vIxvkZ zRG`AZUO{R{EnOH@%CN9E-%cy46T!KPC-_B9Z?d-tLAq?aaRC9l4 zZ$#WK4(!F%T*7QJg{!ET3$0Ts=MpXo?L{?MrceUHXkjljs)e_ifpVm3sdly(*jYv) zj!rINpgckCqFNcXi+2eF<#8%cwKgixyM#fAUt!96KD7sYM#z)xd4WBznoGEVc%DV(b|Dql z(do7LCXrTCZB;v?+IsfJ%H?Wz)!v?K&oK(odvXb5Wr^xwR0r=8#>!%Qw%Wta2<_Sb zb_r?^0Nm3~H)>DM<2b}v&I;{W+so10=|tEJYL@oi8I;Mp)m}pF1%Mq@C!-KUCudM5 z7pTsvi&34uGboeSs;>4-JI$!B-WlMEovOO2y#qV7R%g)7ORP+uq4r6ueMrRnX4Jme zIkYBcFc3k@J~hS!surhgwPfLcVfK4N{imq?RQJG6A=OIEem`&a)8u(-f1$97Umc)& z80ACwa+;j34os^9iPeKL>Y$u93DpC254L9*b+8x9ba{?CB&`rMuTY0()S=rq`!mSw zyMwC9>M+$au!uZWn*CuOH_Lt2##YHR>2|_Segs)v>CdQOA0-zd_z? z#|IYS#Y(g9=S>391ABUCPp<*7QGGohH_Ka8|Fr5)5*UzC19A;z)Y0DTm&iNSK%)lw z8c=^ zRA5gf1xt*7q&NPjw-Dt;Q0&<1z|6HdY0kg&Kpph4vJq z3Vq#YTho9U<)qGJdS8 zw({Cj^!j*m~nH^>@B2H`w8U z9bV1&PavhI1<*F1bPVXLG6TaxJFEs96d3voRc4Pj3XX}U0h^$ZxbO)&~VH5eD_Y*AAcIw8ckyW;$Fxy23%>=0_3q|cw`4Pz5#TZ2P8xCX>VAuLa$ zo-Ohlb!J+fNfJ0Kqt41Tlu?tt@&6!yQs`u-`x|JEGAOWvsu}-r#Pd)xuH&f~N2g=S z_>uTfGt}8e&G78~t$M3-)VX$`9bnWs-uVAkN}Xp^5_f0vZzXMiHPiMBZT}jKeN0HOTxI$> zbEhTbv_fhcR#D_~0#&Oq|D7GEaspK~%Kdr^maN~9s7X4PGQ@A{F z3d*P*)RjVA3DM3~R~a?e3&N;|>gu$*nglT~qvqvwO{l9-cfRdo)O=sJp=zwINh<{1 zE7Y|ab?x?@LLYJpSAeP`)O89I)g#Dc6Q^*U2ia6Lv%RH7PoGi?Q15Vcy~6DIaMbfo z;d)=MrD~;aOsg9S^}>w8BfS`nRXvEMZor+r)J+y+4qBP(ox)B2&Niy8JuI+?RdWhG z$rxxYhdr9K@8X^Y!5N&=EQ1LC#dQowb&kP4>D>|;uLVLyShc) zY7~NRa0)ozTivE^H|n;;DPY{Xw>>bh2U6Q4PT}?hG3s@;Jwn@~2E;}oFb}5yNc*WJ zX|;qTa7RYnk!vWU7AH>g?7q}2cYCKW2zI?(sO11xq3$=T!aIdQYKnS5 zJ!lld(c}~csmbag+s$@0>Y-#jKv!%R^{`qI*e$u~aKyBAwMr^;lp#llmp& zg_Yhl3{$77$Ax+v0$!z_Flv<-$1ruGdNQq^Byp_HsMR@*6Y2@nU1KpTTjT4Vs7_W- zr4>T-73%4XdV2e=p%b}=$3Rs_^^95@*p6hliEDVqgT&az?j`MB)CIP6U|Uyn4Q+|%-N^XbQL#Urb|=?>M2ULK z<{9;thjj%ykhhI`+rzp-U1?hdwpAr8dVhnkdAN^%iTmDB?;4dv^RZBjF}sW1*|y|% z7XrRB6)g$FyExuc?;G_V6NRYOll4{`)CWc(*bN6wf3}7C&^8Zk3))sDJ-KKCUdTlc z>(RbQ1Om(5)kfRQD1^eR26#9$+ve2RA0!S3 zBe46`M?zu6y!u#uV${dvV0c2sPU=(j8Mj!DT3>yNow#-yHLhUP_`JgM-OKRIED@AP zI52(0W3q}O?rKv;ZNd;>RI>b$mSWNqYvpWrEQ6+pVQE>lU#dw9stc26*g6UI36OuT zzA)p>u90A0IsjqH%1}GJ_wK%+eLk=zOy?R^{vNVhwY%gS3el_ zed1YJ9oE=3Q9r7m0^0gT{VhJKTPj6%qp+6j-8+eV>n zwB2?}sh?oV8TE_$HLw|gNj8mEzj$%rEr7P6v<=z8DfKJrHBi6VbYL6!dZkAF=If~aAoctP z$M5P7qkd0Z1Z%}g)Sv1vTi4bx>Q9FK0~oIDq5f8pQGfe=30ko>$|`4+^)$9(c{UZ= z)HZ2!p2s}aTE%IFn0$q18BJU6^@2(aK#nV`8j(kV?cg=n!f5VMv}NtA4z1o63N1Ve z?D3>!T1!HqGFkz}P<8|x4!s_XPsGrT`pX+rM>augp*0garRx}-@*0JGigjIG&*-`y zVn^0V2WgF{b%hQyI>deoi9Q=$FV{jUw2I~*y1cj~|4gQb4j9<;M4{^dc71J(#+L7- zzg<~hoz@MkG&=3E?ZbNMhB{+(L$AO4u*0m-jdbI{;%%1O)?eMo>+e2nf6H}~!15~n z)lEEE`?2m8%8kvr5a`G{mKyv_N;hUQiuDe9#~_NU^jGiT**}2wh@6bjf+@Wt>RG*0 z6a|s3(qFxkuZR6sBBX5oW-1j$&|i%heWkmL{tBbN{v{ow8)P*%`ZM|?`aOvLtW9$x zT0Iv1PMV7+CWJOPnnu4F-PCLDv1rd`x_R_#^o!BWyc!+L2Iv;LrO_=sHF&3D^m7>f zTmv;NJsVv=(e7UA#7;$ql|vUHdT7poFIP) zBdjaM3z@d@<}i&F%(|W4-RO3nrs1qWx7QtvZtwRe7|!zb9(qrs5e-M^0d{e+-b;5h z8iN^Xt>NsX==(7Gew%MwGrFU%iPt7Z--VIiXS6o;G8zGQ3%7bv6{Irmlz9;nVI5)cI7;g41KvRnO|wyiPycMPbh|-61ElZ^P)@ZL%Zu?vPlQ z=o_QEBx4BlbmOA0dGs~u+Ba1E3WbY)p>MyTuyslQ>foFD19x`S-Hh()Wj%?VrT5nR z7`=Bgkiy<2)AYW2Kcn|e22zOBO^dz?B3d?@JfW%g^CpZvPNFTkdk}5Ons9edK6WpO zHiyyX?V7OB`{Wq@GK{`VUZPvARg%5#GucZtz!*rcHPhX|#{T*MqY;uHfM%M`7U>@P zK%;wjZJ)_*)&~iF5UL%l4>20+-Vym=Guf5;P<@!uhx!fDX0pq5Pum!WDoSO9ELN+Jb6hxcA^{DcqQlqgj6jLnRd13UK?h{0xW#xew zI%(%Dc0u%M7=5~3dGP29YPHYF5BbPFo5L=PJ_({v5^UHIP9K(&*vDb?vENfCzZ9?h zIMvS=(Z>1^97jeU8GWSZdM<=y_zY@O z+LJN;=zgt(K6p`WL1`zk61<~!C8Hx2}cVY&B4chTeHz)$h0!NzM%&@ws2%=e(AIx zY-^}J*jB8h@xXC_oSt9aPd>3~Lf!!Hv#yWP675+-zfvU6Kec!iCiIP1JCCGuC63Np zqv*U9hQ^F{X2h$|2jCc_2OI4lb6|_vJ$i^9YBbt~`iRABnLbV*Z}f3q9k82=9+uX~ zr&Q?S8I5cRwqe!B`w7u)Y-#k4J|TKLjNbXL`)2DCK*5R8TSlMgwexniBziN9-rS~k zz6H9Yw@F2Z=JffEFnS~L45ZHmRj&zW|Je0f4+gT6^a!I*@+N&Rdsv^WPcb^l)i8E1 zdoWtBPmR`v(fVY$$ac5u)u#gFY0>LOpXRB#k1da03!~SzN&o9a|2m@olpOu9hS9dR zz!iD~P~_{8M(6v%&I-0!kJ6)~S9F2VqZsz^Vr&I_S&z|UjUJQC>~a2t9;XY99_Nv) zU@N1S!|3HC`n~PfWg1=R8+s*MrB6?5O10?m8I7j~jYf{-9z0xaKbg6f*udz3xXLVT+J)3o}WuBIGY<;vg zjMmoF0T_*B4-t&N=$SBjCW#P^E*M=pv9gZ{latDKk3_E!r3IeS570v8da}`QXhi7; z>&o@*l+qQJ>6(*n?&}%h5e#u=(CNU;lXZU-$YM_(Ua9S zrZT#6^Q3Rs&-$F`iD;G4=Xl2H%DMVHqtEq>f6so79uK0&!CvwL8hxIJ`wja(dMu0{ z`w!2v^5_Zb=~j`rk!h-Gp_O5@GSR=XaRn15RP74}_RhpHQ=f12OooT882g>K(zBvR z^#w*FqXWIdZm`Yuh590+FHD%mc~gC{o^ABSRp*WL9DRw=NYelveose_gwZ24pfmcC z#C~|1XY{3MeJR<`Wf^@Lx{5q(GKn~g(X$iT@J4(meYw8EXyigLI>0-(c8XR6(Tc2W zuJGs@@y5}^Vf1j~-~5h9Skjt|>2e#z(0I=1i*oXKD2yJefxs|&^gqD4z{B~A+33MA zda(K({>{h!!MmzgKI`)#I-LzJ<`;n$fpb>JuhVM&Io9XMImgqZ-Ug9;N7e89xsqZrSPOkyI z_>s|_(H+r}FuF5AjlPxM!|q=gTp!I(?_*ESM05wW{SuPtT{$9d52M?Y*<9|ndbxY_ z9Ux$-US{;tq?^RshYI!G`kv@EjaI)q=@xNqfWA*JH`-@^=nX~DtzmTQHo+Rb+&4g9 z-d|Uwbp0o|>en3BHG;%(q>x22Q=$2@4v?z>jN&GK3rB}xj*(?O3 z^aAE;&TzfdN9Z5&0%!&HVG2ZZB+eUk9q`nd`LfRG&V?rzvd(OSiM3&Vl*~L z^5^;bQN7Y=JX=9pK7yYd-4sSQZ4?%;#gG zh0%@C4Pmr!I~?9f946L*d{&heUmr%-Z<7R}vCWlUrJpc*70o9FKb@Z*Er_m*uI14J z(l=Tu7|}{Wjf{_eQm-}|52BEzpU%(MYxGmmH4&_TjkomEd9i+4KV$UMUIuuXPc$!# z=53PzqkXc6kLN{tZCbA-89bZO&ywJu@`5kr=jiA3^F}}C1zpN#=oj>hM!!&XK1IKz zUpD$BkF=DRMOTN>)ioHA(Jya%zCgdF-!>W#P5ASx^*j1qqu;4Ize2yK-#7Zbs`J@;gZ{wi z4W3}U;U>BwjIOAG45N_&As=`FzgT~m)*q65HfHojs3auweiC!wv-#!vqv-PJGNV88 zvZ5;=>ragS*vo1TzdX7$h%U{_>JyK8HlGt+5=NK&=eP-vE+@HMM(XgcC+!M;mHsrX zKPA#W%jnNMX>WVduIAV2P0^ePBZ^I)G`jM+{=(?bJ!$j!b{&4vW6=0_M zZ@dRt%$G#7qVuDfVKggAp8f01jM4ezIc5@9U*)(uFO1Hs0kP1V!PSrYC!>EPp>w{J zFOAOCKkHw3bS}f>{AWy;izv~$^_%;)9xL|9Ym+y+U`#%?xXsHiDw|SJnz!}Oc_Sy| zWeG)Pd1tj5(6`NuY*l|buWR1e!ZYyZ`@G2|mD|&H?E)oWY5fby;Ma`)6|;caw@3!XQRbx$n^6PQt!w8YZ;^*xlM1o3chwF{ld|b}TDTMlGG{fjWy_zlK%k^LSZ=?V6DzuE> ztE04zNPISaeQrx6)LgU=W_!B9Sk|u?~75ON<|0crxZR%D@Y?DGp zs>;<)38N{=aC&sXsN&I3m?WCdOz+CmBT7q)OGOILn50xno0Rfsp5)J@QmHy7mGWqw zZgoJ z)%Rf6^5;|ObSh0?8)Q-q2&~D0og7A!lO81@x*Ty9RxcrVD87nR2qY`w0NIRG$Dv4Y_%f6q?+fzjSnNNXGOZM zcE!m2KlZ)@N~)sy_ud}qRMUfFLPcQ}5ELY-fC`EP6-6>AiXvgj>;k()vzQgdgb4$f z02N(O6v2d96cr<=n8l2!D7X76uj)3lL)cw-|8w5^pYxq>IkRlv>DyghU7hMzRgFBZ z$@eq7rmyDn@H@UguVwiDUXDKxzllf0!{cEPkJ$F=?07hd@h~E?R=(n)5D%?LR`$c1 zYV!iaYx|PdhJVLH_yKVt#NO6=tKrNMec}hkgAGRnj5Yw@hkx)oysqJOa_RNF9zV$N zdb#v3ygqMWczw^G@57(?!5NO=O&LEV%MU?aXMVW*_-uaGqruJ_B=pmTH1Qya2W?Nk z;RpG0e+hr%4Ko~Zs50It%Nr#tGxx9@-8~Zzgm_@3V!-0T#4|GH;05?OG#+61p2@$+W9x#7)%5KUe2aeIE4;fE!e82S(K!x=vuGabQO z7=A=@T44dJ!&~xJasT)%!&@dwJ$zP^AIXn0{K#Y@f$3`e==jXIpW#O*cXcOETJtuB zw@w&>=~R3M#AhT7DJ?D?FshJjE0UqoCSeF&0u!H}ifOkTpNZ7P{YW6t&!P>w7E87d zKZYM`_%Xgl$!hSnao_kf!`mi97<1H!PmTNV<8+*h4qQBBNXe+;qM)BDh|RD~tDC^*7m$ z#}#WZ=jdG#_u|LLJ$3AZ`3}dy=#e3Y!Cm4W5ck+#2zX3UcjLbF3spacAM0zb!S;^3 zr(&F=3~%Lor53BrPhcFO9)2S4WH<&v!d(Qb#cIXf_(}ZaFh;AyG(Rb56*S*w7tvq~ zJ{JrqDWG}r;DUqv?qT!XOFIFMxJ()EoaLQy9j|&P&>&f>{q+TfxO!8Bw2{fmO&1&# z;J1Ysm$Nh=6TO4*Q{hNq9H(4%=>Ei#vq-8Dh~!;3=E2(z zsKs?z-M9iHdBbqU1zyN;uw%F-9B1q( zb`>AWhs7rujxYkk39Jpfh!1CcIA$EdM;boDbF>W`#7FVbh9ka!STbho&x_(t@ri~P z`56eG#3%4#K1RnUY~Dmv=upFpJ>%N2w(;>0AD<|lDyNzAF*wO| zY=OAio*mCiG8}P(GG3bHr8K#X!~7lics@bL7*)+%uX5DCqX{?b#Jcl|j8DYYP2!Uc zpX7__#5(gS89s%IIVa1{!8xy2!r}t_KNqdEE6FwEsFLUB#_bJ1*T37Db>-(}IBMd{ z`1x6We))XaF_{Y}Mi3eEVi+?PwR9-OxLxzve3&}AM zACv6bwu!UHN8)>z#JFNz;@7>wC_q%lI`}PB#=( z(gTJg9zcV996OIs4snD$r;Zk$E|eS3dt!=WM;Y-ym4%N+!ErJ z6_SHW|J<3N1;mN1`nI!8+?qIhG*S?^A@&Xn%J;fQ#D~X+>G+5$_PSw=1{EwmjLIO1 z-i0aU++18HG7KR$Zv|9$IT4C(eF5}W{>fk`3%ERn@jtFtJw|w7JjSYxA-Pq z&904`Lfo{1$AUHoptQD=_ZYD~}M_wZSU-{X0HE1MY~s$;UxMgxYShNGSw z`AN}q;zkfRs*u3DJ%KaX-EqTI+z^e0_?^DGd)dQ$How>K*}l4a**tz9zu$1LOUD2* z^WsBvOvc*2IQ3ah)M?j{096yz#lZ+E738y{das0pKJIWzn&~+-|%_-A;ah8(rfs`{1L-ZzfJ4UVz!#k z=Z_kW`eC1bpFhUS3`ai&pMHlg;0q03kW0VDALmaP{&+6^5?{ohG~6p|vAm^meTeIC zjrVc1+o!pCDSMGW6(1DWGyEyfH+r&|KW#Ybo2fz1u@~dII)brqdwu-+H7sRy< zM}0GiDm_`oUo?D~ulfVFDz2sDTIE&0=&OF8eGu;t@&5l8ddC9dL~Y{4Bc8O?>@)sS zhNHf^jK7@aFMHA+@}#X{U-MVu{omXUxKOd5+4^{|c+Yqbi1(^Q@3<#si}#>by_r;urKYxIGsQ(SUBmaZh%0#PF~4a+roVy%TDpFR_|$__u~5;DB2gj03OucYLkk2rN)FyQBpFKEuDK zM*fiHKajMq&DR1D!}iB%#=pg4f8;+I{-ZBer>gUx`7eh5?2FYY!+*_i1OdwUx-4Hu z#r~2nRzs{SSG91&8~AU0z2UzlXNJ_SsXF|3{s;flaP+dk!z{*B-#b=(Lo9Wi3;12J z{%}K5DaBxq1;nDlPC?^6!~Y1%_f(w!6<5;myFmA59YM#cZ>`BZ={ z`I~Pv{BO^vg46+VO2?_Klz|)bMKg%mPW1A6WLU(l;gPSVZmJ=7JT}}VBOz5cb#NTU zf!hQz+9x&*B)P+&86w(CvKVJI=FkYx@VLBU_b<4AE9!WQHT}c?HT)l6a-&ph_YdFX zVsQUdFvd_zE&}I_z&dc-kvcThN`!(Lfjc{&ZXr@)7b8-+baPQna3iXD{v4WWDnv#I zlp`UtLRP5^6sQx&5twS4YUV6ByFL9z?BdJCpg}@qgrahFR_J886sWqV_gkb|x(HlU zd7nB*JVVYg{x7x=+(siXpb$>`7#6&Z`&*=i2_1SVq(vIfV*75RDB4mP&rl&G4AGIv zicD}g9`?x`zOpM;D^~EhjYLXwB&E9h%Lw!42=|$|s)G4Bd*xQI2iK7E%J6Y@__B8_4+{DBa zQ=QzO;Qp+_Q^5#Sd($M;DRq+jBjx@;iz=~q@;WWG?ssri`AIOb7t&PItv8~kr>P5) zx}VtJ2vk{XJm%%ZhqI zQxqUl0&T4tqHDHt3Zh&HfI^fVya&~Y{qsEh1zZ)54{klmjo1x82Z{Pd9F*viQ)j2f ziU#6fBN~uMSHpC%IK=(zelh|>{L}P{Pu!302hmWwA2(}WD%AZtTu-=Yh#?xj7mdWB z+I^23%tZGq8u{i9P7M`}GXnMIWui$|G{FI$^YYj_z5zCl3sktfwW6u}PP?^9NvQo5 zO+Bkeq(-`L!F{{^sORoG+@Cshv)W=UV_q7qtywsPb zritcE(2zPz9B#y6UcyRK=ZPak3nPy3QeT>yELw_IMzr)ql%^)SufTnksF)@W7*~Y4 z&_TuHi%>0gs!z42lo72w2^jL)eVKA!lH|9@_u3cWzSuz#OdO819qB$d;z&>1`AG6n z;%FmKg-_Cde(FlmTC_2ubuN9WI7S?6#4)+_RMA!(XGB|1`}wJh+!}CelD+6K?!%;)%G;3izA0~l@Bg0ujXP6!xevg7 zP-*{n_xbKl-Q(T|_x?`we^>v;tkiw(J#g;@&@>QZ28wszI&TawP)jB@c{g_3!WE5FVWkGUNkMT zgpd{PE%#>VR?yV)7X5k?bBf;h=_5`xqEEnvW4?~TiQ+WT*9g4K84o7Oo6E)N?hSCu z6N_{2Fg|ARKpG%a!s+-q!@X|A8Tm%P2JW?_(N($sF!wsX@5owS^i9MXd;eq6kBNR* z=I3NOY_C>_9O|Og3VY zrwKjA-6C*{Dy3<%Z&N{VfS8gIgq4VMvI1`+M|7i0Kv-fo{5LKrF=C>Z^?Jb(;#?-q zMQY9y=NoaJ@7{XBA>smYp%E7(Q+R-m<>Df7u@M(}O3<;~Jpt~CDmSYaduq_R+&!Lh zXr^n#g?Z*K1h=q?*O@pUX__i7F=DExsbSDuTq-Uz0mJeWkz{*_zCQv14a7e% z-!blCag%lrmygh!JiV=hHtr#CK2ms9bE^^8=UX@r+`OGu*fN1PQHz_!3?pt15(nG% zL7})s+-d~kDF}iFCj^7VZA{#T*=`qi7;(FA?Fm6|F;m=W#7ysMdP2}s+$HWd;;v+C zj<0nU_qe%kjuH2Ge$bOyVzv>pyttkmbafAE_aL@9aj+E#Y!E+A2u^knh|8p#s__?`vhl+xo(!b$B4PU)%0YZc*ux(UJ6bR z&T@BahrzJCgROYTx4KVoy1Pp}tleGZt$x^3cv{fc-3ji_ooMweYV|$T>N%drX9WY? zOzmctxB7v6tM34JM?P8I;4czTJ z>tHJuAq7u5oN}J@(m5g+>23jcOQq6zE6v2{XJJHHUY=)wn~{u>s?KsuJc^Y)B^Dcj zcp&PXQKNN^cv>tm0x#mGEpSON+1)Ibx|_h=oO1)C63GRf%!mSV13MlcbioH*@c|P{ zvB+l}&h*cCYD$Cg?gnr-R7(GiL_fl-Mj${)GaLT6>%m=L*&AXpR`INO&WLCIF6P`| zmUv#g;HHaZMm+BwY|jmD6fcUGjCe6Y#?di;s(4wvV#Le75_FVz*MYk(IlouopebJQ z9eqJ?v3NBj5Qr-iuVuw+MDI)9!S=G?I)P_^*FDQF3$At7iZ|ReaMvb!>}?|22}Gd8 za(9gp%RMER2UoeP!Ck!rN|?Kb7&VP5M&y!uYesOJcvHM(#GAgP8Nn^?DsWd-G<_TK zR-U_8g1fRxtdP0sRL?SB&rIa+3h}lPD|`_%gS*`o;I7yK#YT7}FzL|C!By=R!NhaO zn0LgxM!e&zogI{kmEt`kR{E{h?BG%HzWBfhM389fH9L4nd?@gA{b4RWS9~m18S!y0 zeZN>OJ~3joCwq2que%J~WmUG^h);a(dxQJjrQj~DL<)^StpIK1?+@mPPcs71s50?c zR(yur-u`I4N1DKKc+8&$Hrl#LFrA z=jdRR5%2k;uwpkA+*HCu#hB5fXiz49&|qW&y?(?O;!7jG@T^=Aydb_3s5kq{vt~i? zocKn3YXss=#L5N167ii_Ys7cC^kVV7_`wKt)9~LvA$}C7S^UvgzaUuXE(Uk;4p{k< z&%H2s++76jqDtHSgKzf}!BgVrjQE+_{YzH-QV}aRqh5=Hr`?6%F08c3Z+($Vf@j6A z89@k_SeF&+HnVbYFwlrROy@2DcR{id9yF?Oz_^5&D*4m16X7}Wn^N?#o#4(9=P)=ZF}U~{&Mh|h%*A=qB8MMR{T>DJOB1Yz8<{c&INaFr9~n@ zN5Z~5SRww+h<~ZbO75L2auArm66iZy*l__Y6(UnR7D-V zI`~eer7<#{OMfLZvbvEOzad^7d?9z0StAkmX@>dN1YfvG+D)PjF@;2s=s!TmfYreo zH&O1U9mVJ;@icNbPx7b1XKn(x2~~@ZtnPDv5q#;!gBxEd-;D3)uYzyo?isl|@okT+ z#Jjn-nbevX33;BCfnMj~W{HahtII=R2BWh7!I#HU|^b*@A^iuv#PgwPT3 z>4)GKH%`{pj$-4yG8n1z=VTt~gmbao(OnL?--7Q;Mb=&#}FbV+YDQMxqH6qJ+W5 zFe~fIdalTgHnOhY(`*bwd62AcBqBn@rH#QR*+3p_WCPD77i@B)v>S!INUY!_A}Yj- zjfnM*1UHhlCwyQLMkgqt|1mf~iIMfa1Z)ZeHzMUm;5IqzPJH55VuqNS%!K$xy!wzA+FxkWjoX`0Z#~&+)JE z_!nV&WESt;ALxw|d_E?@goopIgz}NOIH_c|G!)O_fQ^kjEI)(_!4+o7zIQ zG_pk!4kO$<)lar^gXNJ%A~=OQiLi0%RCyGW2q(#-Wosjk_B?4EwvcV)F-Bq#FydU} z@NjvoY-=Q10wZI>CgI_3kUUPiK`0)BiU*D`5-}rWZ`eFM%neMrfv7r@Z4(OdbzYVEpUpBs5hz71!CJ3GNeHmhfb7Z)WHXC|Na(`IX=wViBlWIIo5%kVha zL3T8ljOX~BfI!EVLS!dO?Ef3TQWGq_TdTcH0@3+ADkYE z!S~v`Q^B3O6O1$xu^8gQ3E_#ZPs*VSkCCVN>N|(MWe?fY$R57>&S6j4OZGOhm#@BS z*wgjaj=X&Q+|b)|uXEVd^#a#xCwXIJPftS6u$SwZa_F{VyoTMg=E@OIIgs~cvJwJ0i0f#2pu9Hq3cF$9N{@TG#nwvWF!I=WpZp*jztwi zfsu%jAn1=F55~xG?iAPA$Z?(=dQu`wjV$rxj0(rNleIg!oSafm&d6|-I|tH0J4nzz+IZvK%N=7R7-*A85}ofway z>qta(AfnFlL}3gBc|k^AKtx@bl^1%V`gx+R45!PB+;Oh0kr#QQ=*h)$s*#9d5QnY_ zr@LddJGPvtsh+4S!)x3z;EvhJQ5w4Ah_JRq*y%|LxC;ne8*ptZGPRSZ;gG#VUTWke ze#p)UAC#BL%Z&MGI>K*-hgMts!hpu9A#i@kHW1Z5ftDy<^O#w0g1SYyiwj{aY9zueG?eFt56jy!@-|}9?OA#I4s3cQ>gH+Q zcsP929R}{OihAGS@qoD_X!m#%e(sPnjl9E4H^vf>cgnkrL==Q-eY9LSwq4Ky z*OUlsLIlpn&%N?KBk%PDz7W15@0Sl4dA}#{g>ac`tX<WM0X(KAQ#Ceja=lbSsVT;pOTA>+#JMd zZTPdR;|_EOfUC2ub+9{-gy#Sva&f-m0&oQt$>oz+)6;T^kzUImu4AFAEtk4l;A&Se zT2Z4fpK<#e`HUZ}zlHzEXXSH7KATHN@_G4!k(fgnzpI!0op^{YJjv%iR!el&@qYD(K7Pt6BM~Ut6E^??++mYJ#g- zMW60ZJgY?mZV7%~ldl{3TCy@Q{BirrH{|lr?Mo}e8#wrPWF0J*6CH16<(vOQ>tOjh zQt_7C$H=#mQwC$We_kQqc6+-TMxyE+H#5-)Dc>`4rEjoe%IzuNmmh=<-D%SDeKgzXTu?f0azSZv!MO271%t;GkDX41SU~1ysI9;ykRD^U64Z#H)A=YeMH*02u=y0VIRo}hkdYq{i$2WC4})8g zquyDW{`ZqB#SS22SvsbV!F9`f(R-I?@<*pDF1!=8U*pCgz(z-N`YxZ_msYa*uz3=a;=fy zQ8!e>bS?S4+r#Z{c9TE2taiKMCJ=ps@nGZC<*WwVSN@ohsFE*}KV{`l zsM{t(n+^e5CSj~&7&&CzX!QFp2;Ckyd%E3ec0lzxE^!!H-~hL)cDrJcy*i%O%Scq0 z=jQe5;HoEjuUwx8vIF*hJM3m7QD;u?S7*D*pR3EC|BHhE2cqCcevw~CGtRiQc9|;H z(a;$b3701M`Z9TwHDO0MkiR&sT~#-n82O8rCk%ohf6YjOY2>=BT!%v39!LAu#`I*I zh|xuGw4;b8b40r>=7^l)Z4i$9&G+mvr;#wZ20y>a^+uwf67Kt13)aFZ`Mdlhbc!as z-x01mrJ$&IVgY(@73U_lf`J1Djim5k6x+N2jXo3m%7XDFXe(Zj8xRGwe1)t~4Gbu+&!i}N$bbD?L$DCVU5JZtTXr9eQEI?Qv->0Y~qnTWf?Aajy zGIE2Tv|6x}8rzF*5eueKPAN|CO5*7M=tTV+@}-ra~8LM;EtHSgXN>qXtlm zC>~A{6KC|maYlt+I!|Vu(L)QJi9+T=l9)|F^Po`yM$#BKU|oixmov4bdBN={cyT4=wt<+`mA z=J1EPf?z}<02F+LgoH$i7Pi8mF_Zt$BCmEa3Vjnv+PkxXs+!_T7*)-8Fg=k<86|xO z_hSR>Ci}1bN83%CJ9zB);iY+YO!pyz?7!GC_8;seg?JA2Qg_zZ#!71&=XyzLzccC0 zPO}cItE89GiU-F9N9V`U#Nnex6;Q1{I?aF~rMQd0&^4P!>s9fL4K#LH7f0Q0fX2yWNk)OH_8yd12%+RpmtSRqY&hyJ=h3#zS@nc-SEZT z)gDIe?l%V`SgG1m?Pb)So`oaWNE?BTb`p#L+x!;jYNmUidl)>sO?7V zqU06}wYTrQk*wJMt@hCtZ3)+?J8g)QM9YC|xfmwB6Fr|XUngWF84>JDvvh@L{0Ou|8 z;UI)DZ&$SK(I&rLpuj@gZW$Ug`x7qv|J?{g~}`b+AI-dqkST zz}U55*Cx}!W~a7_9P-p5p0T&G+w6BK`yE1*3c>EpM;H4o*l%}G1XBo>tA_R)qZ)eJ z?naUusY8uITpIBpb~jt38mlHoHKql$8m1ShruJ+5l~D*c4@z<@P|Z|xqnhR3n6C~~ zhZ}|NhrWb)>Il`ss3UUe2UJVd%BYsP^nL0`b(B#@`g!bbHrsv)_RC}*tJI}W9p!V+ zX7}1JzX*I#JA zqVd_$wg+rK|18eCj{w(sW>4K-}CX)-5?5$Drb((!!#WQj8#2Tri-3%s2cI zfdcOp4k(#iFnsiw;&HSI#0>56(xido5Rybah-ya-XrEQ>gE`3It@R)|zItV|H!G-o z&{J-@S%|hHw4`b`Vz==fi5E+ zh~E@4)fRcyL3K2$gWu>ZNu8pOS0|_wjXK^B{%2DKsuNSF+f^s2lZ`@ToU|U#vQ?_H zI>jhN#%Xvw%RW$DR9B-A8TaXTRX5e$sBXFRa@9liGzy_>|NX0~m+Ea4Lf0gw&$1U( zpN#55OguHKPDSKs5FHDR>YeO>*bD3xb(-pH)M-cYA!6ryKk>Wr*913`hKky}%cKNMa0P~;I3(A^WToV}y^sWXl0 z=LvX|y<Ml4=GfRwA#AS-)exgF)F6VmNXU2geKpj+2loB#wa*Gsdo|3iG-{Za zhELd6YPcF<)Ns#}PuLnYGNTZ@FH@tkYSa#}A~nLZehvH5z695 zEVT$fC92e@5?}HKhP*vo37Z_qmSyL}7nTNO5F z1<^GjPuH7Z->ihLQlx8=nrzf0-#soR>~b~5z5#Z51>G|Rv!7#MHwy7~8mw_DrOs97 z8Fj8_P|P-|^D_#;^fGlpR$Wk~@?V|j+p;Oe>}z0OtC&RlI(5$*)IF2&bD_G(s0)*M zJS9`ozN#)(Q$tJMvg+cXPO$$rLcL8_Fq)935_y+o)g@@%Rkc|A0iPG{Eigf*5XD!Q z+E=%txf zc(p-L;I-^qFFCl5(3!Y&+<+1s4Mg}gMEJCelM&*8iRs z{{v5p%)UZheL_%vAbLjKW|wOFOqBys>h6a)VChvKH0~?K3?Tk-l)fX?juqy>_V^$E1f9j`+O}^t?UA@3wGi_^swjZ zk*U_IEThV3YFUs~3xa-Cp1^6Nvo&PlDA-4<pA z4#GuhGV+Rmogy^T@|qB`;GTp}=-86WJqr7P;N!+jp&f;K+CE~`(@E@Bj5F1h*+;Nd zZg1q6t3iM5L%&X^WMBFV1IK_HOxv7lTU$B%lX_S)tYsetn_T_2jpaO(c)C|h>_bK^ zNe)PII|FdIIf)@!43lOucB-GC#V`P8F+{ z>|BeZ=_S7m;}iR!eL%ge?Sq?lf)$2wvJYSwC-pKecK54S)T`Rwk0O$UaZ+d_K}#8i zaZ;~k)N923*R$$%j1^D(B>5!kc;Ykha@(jN1iEAR2F&Y$B)mR`t5>m}`_vouUTw*b zd<^1ZM!n$$7=t|7*DL?**%v)!805*$O4(WT2rW2h=ET@eYB^KO zk*ja2w~Ttz&rTTINv%+C8@0mEoEY0ly`$bW%G*TXYZL7~VDH(%v}e@2zGjT=WbaN{ zoOg|SJ3m0~0(;jEieTz3q-~|W)2Nl6HjM40-c#=zg*F5<&tYsQ^?~}(s1I`KOVvl} zW1~LGrKhS@YPC_TJl`<3lbs26W|bq;sMS6<#&)uIfUV4L-KdX!K8)>TZwGt(PRx5B zdY)ixC-q52p-!(%eVSFD?sRM?^?sg%w}HK_%7!p|CyqJwJbpe?YmEBLlZ%0x?5$vL z-JwwnQ;6)U&+RQneeOkOMrxt@f~ha?@s|qqbzk~!nUT6feXUUA_q7+98L8XUx9U5i zywyW$M(P$j1MG|{0)rTZx<(p8x1?^hH>WJ_HjVlw-`JbL-c-fwOrZscT5E4KYOSYf zCX)KS`oXC0y(r8~m8l=qPe%Rdr-7NNN7T>u27A3xKl??Np8TSIHR_k#8*|k<^_x-a za_RfkdiA?e2%d-D=>q$w&xb*z?6qL8-3dYa-E$LzNU6Uw>TeRXjaju3gQ8Tfar6s;zh_~v zUoe0372ltlW2b?gmT$^7=7>h2X#sWL+|k?o59**sJpuZNoEW$(`NaLIt9k8qH&iaMDM(*`WZ$>K~(GF93^D zaaCZqoKLb)il1Q+ShpvgkA16-6^Y_9@))lLK&Gui{ysl}6HT8y_ z3U=x?@yhgOk5a-mE(Uw?4oOA+Q0G1ql%E(bvKQJ5w7sZ`6GLb(B(b=Fgl!)E^$`9N zry{#Sr;Sd6k}@PAu;<(J?75*mpK_i@zs|*+I*lKrGe(<$4aaPqg3h|S-qmOXrcj4Q zKlU7*wNt>JlPFDmsItN_<8!gfbQX))%}zFYw}c)n~&9gEyU?`brm!KnGdAF21!HH1d$ypn>q1;Z? zmV8(fuT72Ko@hpZKfBlodS7iP;5UiIh~C!|iMKD=@nFaAkVvBu?aqzRQm~~v?bgEd zp4g0Z+L*0CA7FHWZ>bkm~(RGs<9Mik&gKUW%XEZ`iMc7JuQeQVPx_&a%1leGBJ67AV$z)W7`5JhBm>_G% z=!3N#Q_hcree0?RyV_!~#XICjXiG?VNFS-|`Pz05_OM0T7A3V|&>vkV&#}>9M^_Xz zg6RXW)rZ(oMx$#d_3_@wjE1_A(TJWQ7KZ5peW-41GzR^|!y%??=_Yoh9bt46-)ef& zR5vrash5KNf?9UCw!@K*#2!I6^R3=H*v}5r&9xm?-f9Gfs89C|YTBV-hwenHal#Gl z2x@g>-|AXHZ97EUA?2-Zly7w**uqNIG-lDb$>>_X5R49|538;Z`>zVN17}>f$L&+^FLsVKHqmMNj@lzVoO@fxXtv=4^w!Q^T zf+K8y-Oio`w*Srr{n72P$oBS3quYCGng-2mKd}8OrTkhi3(Fi||LXNizTG`WWUwc|;>HKc-{2toVuvm>c3w^vk!RX_C`&tD@>l1Y+qfsS? zdq8~iNPSX9pG4hva#o{fBzkmrHM&!tl2gH+nrsvj4;r*K!y-?>PiK9K(VdBaFlZgL zwtaLL-8Ho6c$?N;g0{g?hyag6yT6Hr1*6ISZ^-aTXfZ#zU`%mI$?$=r3JVZ?NbCkj z6^_R1*oK!5OEe?2PA7^HjX+hJWSMCWZL^_+TK@r(i3)>mEjT50bb8t%K3J zr|xBY>)uB9^s$v%2Pf-3`c$L)_&5ZugJbn+y06ivc@AQzKHCdyujKq(MQkPA*LO&p z;23>+MiaKG&&X<2!WeyO5Td^Wy5x7#{ftJ3Ng7-2f)i~|eWvXJwr7HKZ4+BbpNZ6; zWxE@V5Gk!37_H5A1KVu}lrT$%{4?2WT9j1N zT5!7Usx5i>`n?QxAnj$k1gF_9dXTnV%2%;Ler4-gQ*39W(RvXFFxu*$stffH zqYHEC-g>AWX7tcpx~CqlaU~t@ThlG*Zche#az!h((Ib4O?m-WG64;X}8AwJC^Gxp< z^wJ|Uns8G+Dyv5YX@pI@P@#U(=pnwi-a#MR32dhw&MTokg+^d!;^Eo;U2LK~5$uVZ z-bnNw^E!n_ffsp5~+eC~~89k-z^Ib+H~}G-9p@*`Vx> zv?pjwZo{7SV?68o2gB|08aGtOm$QDXXZ?U+m>y?4+73pemo%}So|I_Z1eN5{L-cq( z!RYb1^k6+vPcnLM7gyLa8rqNHEkM2llv~=ml~?wjGF_MfqN63%2c!dqJbYg+520YxFt3CyIjW^m+Px zqtEkPDGH|P3-pCXUyw^*t}oIT8;!sxakVIzs;BBpjGmfHpQkU?ml=I&E(hsiIez%0#L?a!LyT%e^6K(Kp%_7B?_A zdeZ30P5Ne|5lW>Ib475CJzU$v%Sl7^74iS_;0k*f*u!=x8li1LBppE{A(T(=;*V_( zws}SN2KrnSq#61aqi1+QnjYM#Z`HRMeXAFQ>A@ZPc72D@h>MZnOb>3>GxeQD&-8^) z53aY(z&5L(aHH?^Jh?u&N#B*xh<26fyR-W4atCsKhhHsj4sN$iZ4=uVY}4dWyxpDk zwh2x9jj2_)G8B-+;S=+4_Nuet;VAU{*i41IrbS=ngR+!`Rt_!B*%7YY(9YHKgqd zf_Zw5o@?|RPwd=azHMOZ+k?P1*v|Rb)~ELlqW2K8)ARI0M$hwI_h|6Aepo+Zw8zAP zM}q}=enumvR;C}#>PLxrkK~zG4{W_;lEh($=C)}6h8y1?jRUVErFvnCX@mjwW4g@f z$9x?a_)Ra+3yogjIrBuY$kx@i?v@VD8sRKzKK|G`VCy8RWk0r)dIIo+JE?~0GOXfp z{e;nvCtyslICw`d(ogEAj9%oA^-F^n^kSwLW5%cT5~I->mbP_EgQfOBy;MIF+5-dJ z)-A<7(*MSVVEP&2@UvO{?0@)$V0sDmz;hNAE6*4DOQGu~C9U$}nW zOT^OP8Cwf%t%}C1txbY`00}8xf`}WuM1J=W0~EL zihRmT((5Q&%a~q(N^AR(6+{w?&$jUd?kB<-K*-sV-X)^`U(8J zp_d!|hOg({;A8!!e#_`L{e<#v@S)w)?qPQayXUt4=ynfcJ9(VyxAHab26ngYAwi}Q z;?pbi+eWYOC9ev8uvz_%-4$#FH^S+6F#EfpU#vAC5fpV1$9 z#(y4srB`P(qH|^XldS&4FVgS%_rDIlu?DQ!QTN*F#JOFm1K!5Zr}{IaKlL-ykHL>N zt=H(!Lz||VX$_v=cI1_=5g9AfUu5+c|3j~I{TWj6rT)rjbnT>bH&FprTNPTMJpthr zRuR2l;pc1pjnQ8R${?1A(jP_6)zWtNsV0o1SX!Lh}VEr2Irq?pP77PAf z|6nv?WpqIJHTYZqsDCp0#{@dT^dI_X{fp5*dtUza5;f(%JY8H8B~QTyVZ=*VNh+o+Q-uh&_O#%Fom#OZj_ z8-qRwq~{>>7>$@5_D`4!cZnQCZU;lj=)V&ZCb!2h(>oGrMWf*Ou$q9i=oH9cZ zYG4^)L}V%ph;|_oXBmEDL&~tqAhNm+ZO%Ph{eJ#(MAI(Po(H}vO1{Kr__TJ`Bm~P{}!*XM63-TY~wK9M#0A5s9^@T9qNDqYlK&k-J7&T@f zvHmm|0|-Om_`~}5gA7zRkn!xR5$+4SW&pvVGRS5ji_U)et6-Ay3{=mv@OOxQr~SAf zwO7gTq4)<<+jIC(1_*D#Zm_$7-I85fxPRCl_JBR3^#(k~6c&U>!Cp|qz+TB_0n@Fb z-(YXpM@PTma$e~bFyOr&G5rfm}eK5p;$C|>rVZG>Ah;o;}Rj#ezuuqVR zeu0{>pN@XPVv;Lhpr&WW!C|B5=T!7_P@4lfFGfGX{?U&*`pM@TXJCJyuSwWE`XLql z5bVdJA5qAlMxI08L-c)x95S$HklV#XYoqU?Z*{b`id{??eMge_Ep}S8oDJE#S< z4b<|Y)FJE;eFFt>Kp3H8Od1OC5VF@c2Gg5+#|zQ{)X4{C;Xs7ytG1LbMEw?tQcn~l z>{^7+pbpeEP$yX(!Vck;P!A4@zK*^!P%pW92A_3;`q01t0%SDOJA@shFCqG}5?(a$ zoa`8$2nS~XA+jOJz02SYx)t-2(OQI|_a8N*)eb_m? z6dE!>j0+mUp#~ax!N;JA&={H+z)^)-O3c=u2Vig0~4&?MjWYam)v#p?_XMVgw!VFsFen)-x;;BYv?0D>2|D1?2&{?Gzi8t~u+ zrq6&@aHN4&p2j|5-{>=lKC66DfFpg*zTxT7rx5u&;mRRlQsHfb5F2Re+jK^F795oU z0!HBIEF7Jfb5wjm&34laPVjI8GB^ym&>GqpK;)z=wt8@QF&qQO8aT#J z3&X;TqSeqAj?>X<93PdMu0z{IcNh)}$49H6osL%FI7L^j5(DjMgj5Shg{9Cw`Z)T? zK>K8wPM&mtjs_AWf^v+5KA@SQqv!6puq0Zkqm@`@vW`U`Q;v_&=nsy=iRN86F?vTw@8Z{qmoy;Ufy$q7 zQg~kUwvOJ$=ZS@T^bVDItS@tLSO}e}L#O{DoBxT(CbYp}a#FOy0D@h#9hn+l8od=p zZ_%Q#f_{BXBJ>rl4Ct~8CqrigCzIT>@T%~t=*?((^hOxHNtu?@uQw=XXZ)N3T@0M! zXY#AU7oaP2i(ZHB2D&B?5x#u~^njiQdL$4Lrmuru(Az*SKMt-6uZ~`W=(S`IR|P}_ zy}g`X9bOB4GSG)+mQ%BEDv5B<1R@G=2ycVa4ERg?Fm-G6D)fzBf#}slA+QZZ1bvbE z)1#LSAlyW2%#Gnq(Mu4$v;#_5gswR(B5wgeKSkOG-4)JT77#>K9_`=2KwsR0;hg9hh@RQup&*Q2AR&65c!-{n$bI^WmO`{N zLCQB9E#*<7U2{*$fuiVjdbzvrfHD-k;V{C$aNhxC;d3w&Mj1d*i)OxO!sntTI$BcR z0VvlrJ(q>gL{GzL9X(y%0i%5fEDV=IQM5RE%0Q84Fg+;-?7ZS!`e_&oxQ!c|OD}>F zC^b;xnXxc@JbDtMCwCxD20XG8J{~?1ErQ73u1CUf-YB&_5-INtzb zP&DdZ3*UkZ;6eiz_)1<2m%~LFxQHsbI13k3gD%V$y8xms?&90VER@0dSo&1B#K2TP z>#Yb^L}k%q(W7BhM*MkkacdZOA!#b~ms|{S` z+rA=v7p{S62CngKUlG0?J))yWwp8`Ow0z?qhUno$5HXV9K#bg1lo%SMdySji4pUud zW6$7ftmIm_&cL<4l9k~{FdeQpfcO>l;>z&7=ph|Fv{faDMCFF>Jc#DyDj6`icwk|9 zCC4SHq>}5fk{jSg12_0eJ`UHxO>nb;oBS~PIQ#`>z%2$4Frr=T$KhJI6>c-&0V7O* z4Y$J`25wI(#`GuAT!`jwjT{0ZKeT82B>W0yMsuPE4b1dY13kGD?lN$vpBmPLUquh- zh;G$OkV8Ni2^)lOu8Ho4=>DWZ)R5A`lF|e_OcS?yVJblnqd6oP50bDUazt$UI{Xgq z&cNN&&-Y~E9_;o41GjjBFm@-*itdZ=>G;1d|jQ0^q=w4yq=6vtm1JOMdDaHYzLbwm^H*lZt5sc~y4*+uP0pA0^g%0Mx zTmy4*=?yRs9x^b`bLzKneRMZOcUMrjfrmU#)`x$>!x?y(c=AXV9w~?DU~Z!64L5`~ zx+}UfnhDWe6+?6p`3OWasZ|f=TXhFScT`X@gZr^n^Wjkg^Zh9OH~crc9Ug0|%@Vmw0`HG4r87W_xVc!o!jwF}{K1O9fq@LwjQ+u(`lR)}uf9{mJ_4`5M*BYKgS zpG|BRcoJ}7ebURuCdOcK1{M>Op3VY#I-+S3MY$P;|F#MlfXY7{Nr<)J0L74}sb~g7 zGb-x+2+i(UbSwUX$MLfSmKs1`tWNkqu}pMxbW?OAL^p4TenvOZdt|r|OY!pzJZs>Y zWK>|F%RS&Zc;3Ks3Dp$%GP*%WH*ASa!t;5-ydI+KlVdB*8y=TbG--HL5}w84Uw~x> zUhu{5$@Ya8;Uxp!4T|l__J)@;fPhgMypn}vxA{`O^yv_7;jXdWVuk<|yb7-wK;NwH z*qWNGDZCDEz;Xl0<#Y_=e%6VugEymVb#xsbiz^K(0B?G3*J8D!X%J1TklWYNpnM}J z*GF9gZ$($@=$b0@Q3mpGP;?bUSLKiR+qNdUnubW-ZrqpcSA$gD7sQd zS8lZ?y`5*&6%bufMK`>LjCu#&HGohO72k}tf|c-|0St#r($b8zh%S#Vi!O!e@@=85 z=rYU@T}s4lhIVM*bO}V4RJ40Rhzi~Z)C|1uOFoiyil)Mc(Zvu=tzgi6h}l1iE;8U9 z#4y-lNB9_48TdFEM3`<5tKky^t8?jN;Zyj`z^9%s7#tDSWMB=+&*xeAyh>;bKJ%U2 zh8+`K2+@Vx({BJ>z;JP6$Fg?tMFzg0a=*;Nmws_u<=@A!j?o1W`3uw%ncuE2FCw1d z){Mai`1uOHHt(CNzwW64SX9$=<|?q#&eJ&7hp6X16pP24;(D|GUVCXl}8 zchvWchdvop=?+*Mn_||nk}RJFfE42--Lzx(@M9FzhYlma0s4yUKX>9A%=ep#GaSM>_YfA zDvCxM*c{&zpG2dgk+4ZeqpIX3s(LwWLavNR2kB5pBXYbex?!lA%0?P!e}T&Lo4FvFk&Tb0wb)$z(2mO z3)w}{kW@5;Mu`hpx>}l>bT!Y|OW74^k(MSceBMjhWl^Dy3b$lzTILx$7^1UF+d=d?a&Q51^G@wexo{fx6 zXOKPp)78_v>WJ=bN<5L%hyxL0uVXi)vzc_37`t0Gy&GPf)*H`4Tc3x}4wa{O#Zt~n z?;f40qqA~Co8H|s`DQjF>IYH3ikOTR=3#^u@?nJM36oCydS|jbqcc(wD(_iZ<7bcP zbd%mAAf-Q>#pb2=Wa&Ne@m}c~CcT&E{VeuCdhhf;CcU>WViubn_0>_|t$4prp7*Cg zbXt!0l?ipa23E3fbgD`3>nnK>>#mvJ&!jzy#2#dGqCPt6vsESguM!&jJ&I0@#kUr3)51^c3Qf8NQopjwW>JkL$be*7a(4gEr zzCMO~O~T7#T!3~1#uXKo;LR#sipfMixl)eK%;~x$9rd#5dWa->KypiC`1;9Cu>dh1 zIzQ9@K1O2Ix43OqJ+SnFNbf=E`X+slpSBmKrllLC4~|ZWI-4{iOEicVvd5#7Av$>n zoHpr$lgruIlc_7yheRi(8=CYXUZ&nkU6O9Z(v7gPL(`4_4}0$cWku114fo8wfZm?! zFoFsyIp>T>&N&JSNX{7~ilSl$C74lEFlWV86fs~@FymWWEbt5s>$E!im z5P}9yF}C{Kf<{4O2pYxXM*Q-lph?ga0z^QXqL|=!htq`s;UsD@cKAEfZ4&7=WX*_Wk;U##ED7590Y~~5-g!y8vFYv@bb_E`Ce4G+K^F)*XVRsDu0b~l5Wd020<-mk?m-U-y62_+ zzk;4YF9>>O(z!wJpbrGSGwFRn-=H4^eO+O8`#+>x^K|QjgA+kNGK>=b5B}buf4Wr~ zg@l1*>;~c|1A>7N3~)l)&Ua7N5S!cUY;H%g@&<@4a8$M~L~ZphOO zk03bGgji}!EIBkSQ7VxNMu-4o^*O;v9gK7=b#g56gbGHb8>G=<-TIFNJsBO0fnc;_ zDM+Yvy;QnhK1;YR1WgRz3(|FYy6zDMQN45nVyr$f)*;RTEs&+_@N}Jm##})=RQ0jJ zI0(kZs-7sFs1%G3CO|MgRz*x#2qp%TAefj*mklNdQy`e^*ejhVldjFvwF}4`f+=xj zCCVg@52lI$qry4CG#yOKkJ<#2;z3NJY@&R+R=Q@o22a;2Bx+L=H7AXeiXm{oL|m%s zJYBs2!hV2YMld~?0YQAoo|mYcsGP1A%nW9E>1xz>(3UU%mrmviW>K+c>tObOMbsvk zfucP#m;(VWg~6@{MO!yrHJF>O!qZg`AAkmP@%4FW?8WCf{i%|u8O#qBK!CslHo}Q2 ziR!^Z5iBGjouz}biiz3;3!K_jPt-_P;^|5S)qc7%=}Hy61#|FP6r2sgBFAjKMB{YD zbcJ+zp00R!)P|<^rpwcJXXABFuo!}KoK-YQoE)4RoCm?Vj_W3grs5~rfrq0Wn z+lf4ltCAZsDDuFpU@?+8KUf06`HoD>MBCtk;6exxd?4ZAc2U7aBDjczbFmICCiTBC zOXUQfF5)<%Uw2}r&C4LDUOQ$G?2j|co5tg+y=p|)L(junTeU{ql4RnJG}JK z)L`F!1W}v-5ssYTP95C&A4YKkgi?aL(l{!{jjnK*gIp{L?hfurmrCQv`R+K1gU{v! z_d;;5E9A_?nduTdU7}d+f&kG5bTJe26N`iU{NO$$b${>x1ou0Yo}V~7crbVff(M;w z=O@kz9u@(uiV4>1U_JJkL-EY%Qz3XLYcffmP9CzVICuavek6@9IwFlY>`I)ISnQ`0 zBxsx@>ZME4Z%5Is10~zjZyj-yvUJY^eE2#sDgP<|*|g8oKAHWYo0O&dP&U0Wo1g|> zIl-e4@iIs_!X)n#}KVI6Sm#|gvEY6bkgGcdtEZ6|SV@}R1lS6~YgD33Y_Adw? zXMR`Ydu8ILU}Nwk1RLWCADF%-*c3bk!6qm9m5EjMPj3G_xcm@2<>a?2adq&t2%aYS zJ);BMFD+h^9X#p2#vPmNAKbbrzl8^jAb7&n+S=sc;8{PwAbzkpcn*TiPEFS)*4hKX z^T7+AJwR&uJS)qNiBJBav1kleRwS4Y4FiXtFAy^?>fptA`>V|PJ(=NVejEr@J#VU` zA3TQyU$SWkUWx~V3F6~rYlBxHz%V}P(}raK;8j0(6<>TUcpU<_h$FEfu_JgR*aE>D zuF2St_$qiacnbmyfa8z^|Gq8Q8oUj`)=c`N;GN)I2;Rx0-wECe-iH7K&hGs;gAala zA^0GZeku4U_!xqZGU?}nPl8V&_{0f#Lt>*f+?qp%ET59xN+dQWHV4~mWOE_d<~($I zvOV|=g6+;7ek!rq?oZkM`R?#%F5iubr|j?C{vI1#el#Q=wLmQI7*(Z%k8MQyhLfHl z_}J;hbBPy&&qeS#Rl^rL_`)?;7)U3UUP^2UzO=vDeGq)>!I^U+XpX?_Utdj($B<_13(fVB|Z&yivZV2C8Y)^b?zfalk^I7`Qv9v9*-G0aIcSkyUu{d+t zvp*1HTjCtZm9V?H-CdB+5g_go{1ohg;3wCL?o9j|{2crO0mhF>Yj-Ao4t@>xLhx%Q z{avsx_zi-6j=i0UUG`gUzbznh2!3;wwJWhZ_+11T49^Mn>tKI&^nxoh$SwFTvB!R6 zciElXepB%1#qPpZ&+epB{gN%!4sLf8K-drVV5xG02!dP^zn9pX*lWKIOkh3xHN#fM zU})<9#R|f}k_^&1NdK3wAPgd`fdj!G5FBt-yf<;ceii&_zvT9-0{pW-@%6v#7ZCjA z)NEfO3jPlMf#7eaLi-Z?feCbUyd3Z}c*PBJ{&Cv5Kap!c=l1i0l*E2PD)lAxrWo4? z9})n#xfSUn9&u(rv)k=9Za+J0kYl&gciZp=3A~a}0w5V1Ptr@4gpyDSpk&N7rhWTq z%6|IqK@K2ZfK3hk*iX3qq*%Yl2Sgm;C^#D6C`YDL5;rIVT>X)9WJ)CwF%S@ta6kh} z34mv*e9Y~~g}ab|Py+~%00<7?ASVgQ%Ahct5C8-HJ(!Hvv;|DxA4-~_bB_&$>}64Nf|g6 zpp28#Ny+l|os@m&--8@DHkQVqGPgVvXv#9yvM*$^#&Hfcl%PmuzEShYI#JZeKs#*q{QwUeUe^P%$>PWc_4Is05V(DrM3w zpbAt4sFF!Hfof14pqgW`ezFnN5Kx2kt)_;WMGl6bddz>aQL?dph1*vS=N|x3g&D|p zlVo$KC7>4NTU$fzxCe#G?)w(WlkLmgzFb7zze=)vjSLep5~u@p0qVrs4u$|B254ws1ZWsL>BvQYXatSz3-)<{M)6<>pLK*L z08LyW+a^2M=eT{YSS#WS3-bXzD{#B-IR>12l6w*(KQ%TENKwEm$ntF3IlD zQb0>8(kU8F$sY^>#_cnvwVB(^2M-2(XpR}Tvd;ow5E}K(QgkO(> z&d>#*vy=F+;VeU*YPqTInh3musEIq z=$);#$GLs{2(s}3p%Un4Hvsf=JWfZ}`@;YL#5~Z|OHNNNgn@7>z`#s;E)0Uf0E05= zGvPEi9pE%qhUv*!_AzcBij+Io#&NIg%y>OK!^rL!YF`|PW6^2?|{)hjK;@fU@X8GSFOvF z*TFa#4}c;3Gcf<<$*W)jOaz$V=q*pKvJZ0WW+4}Gup3Ndu?eh7UTGgl*at}M#%INO zKeujytOyyScr)$Zf0vX1cd;Os=taaeG&x3WtLO>UnNTu7z0w2xx%W8fLS$ z*g?>wk_k8iGIRbbo#sm0wGpmO=LEQu1P+@YfuMTIv-eV~bPuT@LO2-}yp!8Ii)7rl z_mTRI!s|?!1Ar?U+OS0O?&Je77tj}&>xy-E@*aB!w|5lOm(Ft~x+i%*%ol(dK@Kd? zu;9>%{yt!29~Ro%0Tw!SdN}zSoaMt=_;?YV4Y0^n*~7_=a1Ja6z(78!)5FQf;9NKl z00a4?z7HpJ>}}lMR>TTPfb$$vImt)utqFT8snX)CSk`g7u87ZlKrjK$w`&2;cRW3b ztS*5I0G2p4dNTPETxf5xHv?Sg)P|m11Q!Eblu17am%ya}mt@ks=hOjvQdAd-Lh!GjDT2+IU4qbj>x z!{xCO7IuKep*wH8)2u7vS=AG8>cw2Agtw3q(nM`QI3%NlH*kAHp~dv=T2w%LJAKp1 z>BSc8MX&JT3ao?WumWJYtAj1c4`3y%0>Dr|>BW}hJ8&gj1%PW5NH4Y|x7yX*t}dct z0Wi={=C?KZw!J=KuP41&mF4t0Zm%oib01b9PgmP(0j_pDeTb}H1DL+X>BWc1@8CLn zjlCMc#r>1?DU2ucF%3cY8k^gbX%ZJHba3ib%xY23Khshmq6QE|@lu3UD zw*czmEt&LZunukoSeHp}gWCYj>NY2b50jtRRot#BROA4--hd?bN%B*>lG~MqY8KiJ zy|*p7-LBwv#Sv)MS|{Jnl3&6d0w}rzXAuSnS|@&+-Uy^1vPO46#;?u}i^-EfzHyNIQ`HQbH9KDL_I&}&!IYuCmk<5BYE z-2Q7)@*#HVTbd~j?eMw>?ghAq>eWx~N$#=B>{5G~XO~f)OX+qQy?HNQ_gQQS?u(Zx zC-;;{!Ts<6!2NEpySK#A_7Zpy9!l9ua7X8W+@-sE5QVt6=ZFUG>g%akEr z=ujfLKlvxDw-?z90oFU+q9>044$>cS+P6P>03Nj$*d+juy4>)IJs%!R+4C{CcrOHa z%n9G(9v0_udtP3x7rqyQXD^__E+HxAu-Lv1B>%AIrtG=-)o~HMaUsqKgojwdE`|;E zoRnRRe~yjgHoGVJGdwQg@&7GT{%>5SY%fJy zNeQ%-CtxGM6R}mr*0{)?WfyvO5or+4J@)KEvMPj_;7Qm7@Fer6;Cp>oe|QR>2EZ-c zdeCLC@T^52=h>{~&*gS*tnWo_b>Q21 z_`RJ^x`|*F4$6?L7htmwn=#Ah;CTSt#S9(2n29;?0=(#19HRyBLb02)z>CyAy`cAJGwT%jAZ0ItQrCJx`{b|$=^vb0e>)fWK5Fyv3*F6?#&w=;^Z zq>}I+HZ;@W1Hd5Sbj&8+pani~f(RJcX$d=xc_jhCBsvQtu)=6>UQ=m&q~-ovfF z?Bs;S-RMhN)G~l~vhtb4?W6+a1F)6l#~LTv33hzSPAnqU=vmT6i-Skc&L+Kl6R(fq z6M&DM5>;Ro>^S%ows{uag#bQfC$KVyY|rAV2D>y2S#P7--L7Fft6j|QEODLZ?acz8 zAlc90bAZp{SO%-WTEZ9br5$U>03hzx7S*`|s|;Vk*8m8wQEgOU742wlM;9oDubl`h zvP!T+00C#PQ^QVn6mE~6r)^(4>#4??!7d+mAqU^Uw*cQbEvkmc+U|z$0CvX?AAVL7 zzK0(GzIW8CvFdgdx1);i*Z>ghBF)Fm)a}TG#epoqciB1|!R?45KKJ2U@ow}ZJId;~&5 z;EO5%f9xP`2OaUwyFMV21b@O`0EiLw!|yw>QSdkX1Ms&~*KTYi_EQ2&EIffwhUZG# zjSUb9kpz*5eJ|FH^%EsTNf7bgUL`QyN0hRs+JPWSIeE~Nqr}l5j$*Nr_F{ePfRx2u z*D(^0XMqSrN~k&P#(LTQB9*fJGx87!#8Byau%5ObxBZHhhi5UC>e+$VhKZ7nS|8Te z_DxyZqdboLi)2<}eYovY(Do6&@Uhg~_6FR}jpB}MAPNJaAP|8o^*}aU2q8frxPt)~ z{QEGWY%kjrgmR^(Ct8Fcw9|sq*f858WqTkW@mU}ubfq51PP5&`F)7Hu7G=b-Aj&u$AI+wVw_rg9MN%XitQ{;vYoi?98ak@g0n!xNytHY+Yv;0r=1vlu^qVWP^flx zq?Wi7>G|BWj7-AQ1N>YhJ(>i8?~mq3Wxv zMcur4XQFmik}bGxaWG)xi<+2iJ%JS+ujldDVz$^e7Y#&1&*HL&Ks3O;6N6A+D^kGGhu6-`Am+srlv(KN;iuo#z!<{+B8 zx?jvLwoOC}+nC!XF|g~v5roa=l4x7tb+T;)A`jF%mo2dkxowySx#312ICzL>dLiV7 zDJ(CoQ1NXes_({B-_2a7x|FREEq&1vGdxAK0&$9~tEFs(Xf05YT00+bDZ4_n741N@ zb(OP}Ewc@{ZBT?02cn&;=Vk12TR&kDWd+eDTetPNtyje7zG#I!wHF;gw0AtMWUEC- z(Fp{CHq;!fWY>w#q6>)5neQa4A5qLs@mMvF0??t=zucoX={P#>Ac1p*cw~Yvo)#OYtgM4nI}3o zzQ9FnqL)CA!fiT+TjZ~^HEeZT&9gP=rRsFUB_O`&jaMJh7epUd5$o7`(NFXTf%qcM zaKkSj5(5PKR|A}9@c?_sR!!NelOWcP?Ogg_K8M-10uI6HXrE#Yucb}zfnmgly7tTsiVm!7Rm z!mLDg*FRgACvkhy5zhAWMPICh5n?2W5v~#*VULMXVl;?Rj^{^Mjy*ADPyF{3Br!Tm z>;!I4IJ7ApiFu9@V?j7Xk!@g`#5ge?#5kAd2DVX55CZYU95GRgiHBlKApV6DmgBbE z;W(8q5E>Md#AFZ-8e~tg=fo5-6$IjC)D1kvo)y!Cz?eXen6AZi64KNx-(|Tin^pKj z;?TaBjJeMcGeOL7-O=;xd3(G)&K~R8<4NYn(G3?w_+lnrvjl46tayGfd)}KS&a`C& z`uk_Pw(w(bqL}LoT!$m(iTNO~b0AmyW6u){#6l1Yoa%kd{t;)1MIaDCqjub&Y-w&wA3Q%;;8GQG^tZ9E#ijNbi;n%J&K&8x3SNy;#L*YX?XS+l3_^oa*?aD9qb#iOb7z7#N}FCj-6;l5EnRxzGXj(E3C8v z1VTyFKG2ipVg-ohj-lP`M++$n`3$Xa41LRX+ko33HqXq&k$=w)mc$4S070DZ82O3) zB325qk{DT~#VW_hxsH)v*?w`QB=5KEPF0fRH@QK^S9UyKe@q4&4xH5l811s^M)6UXf8I#6MSPD`SbAVLp59%opITY)~BOum0W>4@c z8f%P+xUq-L5;lgu!vz$+cm%H;@hFHKXFQd>s^T%R0R$p@*wcBHyvimwWpWSdq7j12 zvr4m{oBgpbQRGrcfe4~_Ts#5daYv?_S6gfpPlDL!$W-%cicLanBH=ux1x}j-@nn|D z@7(-eM2GqW=Ki#J1_bWjg(!np$7?H|6`RF#Af6?0_+EXliTO=DZ}z3kZx~=NbR#SA zypwu;uYuXi&E5i~zK^)WB|-z^hKZS9#S7+_l=-!Y$UTS`vZeW%o1Y6WjroPLf6mFN z6_(^h@e&BcdZ;>Dd9BT!l-cv|S;FF_Y}P+<k? zZ=l)9&CVj~^c#}dw`6c{;PtWi1cZZZydmBYvqO9;ws~d;wd^9-)O^9s7sVPoh%aK- z)EnWA6<_({DOD z{KjktfpVo_^%!rgZ?=<+zrvLHl79P|CjOQw#4iIe$5D8Ry=t~`vn|h|bgR2!+~wej zzhX9${8sD+@h$boKJM8*-F#|3F&}&8Q=<6^-9DxoMhHrLXFdYqHVeZyUl8AmAHsG& zU+fdVf!OEjXtp=ke89~IM=;|S1Y$v?*>k;l=KX|0ivf`bL}9aL-s9%IBgn=VzaWpl zn|DF{?sz;KS>G>mLF{)HdbW3oh=c)wPzhP|+1>@hiZlqDNuMtch(ACaaAi2#JJ-C! z%{#H46*+NN{NcVh*E`R=&CT0|j*!#tz4N^#W-B*aiyiucFz$;Byo=3S+`JXnQg-65 z$c_I@t-pDbn>UMP)i>{wVjwOk{uFYLcIY2h zTPwUPB}04y?O%FYdWVi~eSraK>6s@DF=jQbyqFo@5c1&I8U2k4X80-x|mWn@*Me`~*uNLvS zFH0a#Df0@*l;dd)vdU!u(rqZ_t?}-VU|u#a;Q}D1Ec8T32~uRz>!gwzB;rM+Tx+~r zWGIgT8M;!e@oq9Na`R%gWj+*Al@2HJZt`w6FL3ihVM-*m%kdU(t$CiC=ZjY&=};tZ zop-w|Eo5n`vNBqh`Tsq0(!7i%H7{WYEQ74HpX27aLW}8}SExyRgF5Y>oL=1Py&#YE zB?k26aq@VOh*wY(bFcT1EGx@_EbH{*Uhe^Uf;&cohDSyR>m ziJ^LzeoWSubwJk6q;q6lSr24gCx?f<_2vm~o+wo0AnUm|*L#nc$GLgDP|ZRxfh;b^ zd(>>;X2TI^RxKyr$Gj(GeIYSOog*7)+2H?h=A^9Q2ygVBG>>ufShgsKM65toa|Abe zPnkzk=20Br$0v%ICy{Tnku(vZ80t-)_BP9gLJ~G18)=D~km1ZpgYLX%HqmPpVv=$5 zki$(*mgFIJ>6@oXVevQ+dh@Vn9-)la)9qn=Q(|~nHkHjl zHf8=4d~X07B%8|?AoCCkd}JPyCz}Vkc_?;1C*vr8`h>h$Uh-u8yrp>nWJ{JmzPX>9 z`{P;hi~&3Im-D^54^%>%^ggH*Z}v1uWdNS@+Lge7Dv*%~B*0{w_T2W*s-{3Q#rJRRg|t^}1?Z8<~^1?i5rLBZ8DH_Bn=25xRVGCW=m!z|A* zt3jUOxT(Ubn(Mi_zEJ*G6aP05|3kC`FuXE-gzS$J}$kTXe3XK6VLW5Tmh zOOeHCjzlBYRL+)Xf}HJ0G-8d-Roq;41SHOMBpS0Oa*mKVR?U%fwVaC+B4?l(jAdA^ zDUL`>)>_V!^FhvYL|U>_%$3|+c?3k}J0hpBR&s%m3y8=k_PFFK4xmkGxM9y_Yda_>fJR#2`BIj#)K9+;9>a#(Pb0o+eSRyX~xx|%Y02^pl zaB~D}RU|G^qHb&;J5^pN)6V3jLS9NlF4OX|d?HOjj&vTz7dU3fm&@ekAeTAoAH$}~E97#J2x6Uq z?2cg*JiKf}1PYF%6l_A6ritJ8RZ7oT32|F)1n~&LA?EC(PyKw=Z{J z;#0GXn`H%m>C4NJlU4FckgHtFIgQOTOXXGOGH#Z}zQ&Z9<7Us9HEGU-xpNusF>_r1 zyo4{W!cVW3X!utgb=d*Loh4OlH0XG-MppBdOKV#O|DH)&edi-RySpsskbJB1Eki0?O2=WF; zd;wc%&gbU*A{{D_H#*5KWM`T4Qs%roH_A6lh_?&qb`dc+3a>TtCXfhSkuoh|m&lvt zEg;<@Crn>p&gJIZBT%MW9K{RR#d58XYe|{bX}KY2p$XlIGEoFDg z+kJUEKE6ZV3Gxo7Q%l)Z@-BHd$h(|Q;Vc_@k3^sJ9u_;vILpQ?=4Nrh(g%63?X5FK48w`W>GOZ^#FeQpnM4A zgO1cS>{_#sn}vny)I<2e!)5`)8hRf_xEV9!j#FJ!)ofGoxVfgM85`)uZe&Gd*Fj2M77QD-J2uG;XF9 z{G~5(*^PWjz6=s~T8tWJkgqyYPqC-XWNs!Gs#LGx z2d^7+NnUp!Jk2(niQG&qgf}yZDhCi;qs3(fL}1F%jRO zw)$oQG59oIZ_9T;A`U|h)!Xa?`L28qB;qg_%)s`nqA%Y;S|6H`AQ64R;5g1L`AvT0OT=L0$MO@9A3L4;n0+NbmD@mm>U8R3 z_L$r*$l7mNA)Pkw3{jAb)ZN zrRwV~e>T0i=^f*_c~PHP)5lMsc2Xj`B7ZSGLH@$><32sO=@Bb$Chp_jhD_uqPWlFy z3;3oN`A&PBaxykw{_0BvXyjhG59D5o{dmX%$lv7ecyr21v7Y@h7bKpsLX&GKvJ;u^ zrW?ozV?Fo*Ju%XPL@c5)eowI;jOfr}1Q*dk`~>Gj;(JG#E;5}mT}ZHadMU`XD+a}S zI&;&x*kX95I|&m-^K*|IEi|hPX#&!0g z8vh~x1o?+kW5G_4f62c={^is-WaZ>P3e^S=#UV8g+40IV9Zd&No>OCb;;RHG->LDj z7#V7xGVL?UsuE6(@kAHXP9;-@j(UjISS6hrmu6*5TW;DOff{!tHSU0Ftne3V9r4Gs z;igRtH@K61V?|E6-<>M|?Nk}pZ>kdb-~UwkzfzSEb5$i(DNrTdRN50+cXgC$t&RqT zkSF;Sby+8s@>L37~c(}J6p zF=n0_>5dsUZ_0uROk@VT9pbcaPNrU?1?j1X=P$5kthsMmk@lW~e^LQn$}|TR?{Uaj zE7r+0Q`$7;rrF`Rh0^$XXqte+)o?VRXwBNGV^nES4%@_Z8`GGZ#_>F`d6TEi9W`a% z1oXK;At*_{R~y#WG)fsdFT-`sO^8A4U3}9VXHl5ehkuFCFBurF>NO3yX;?@<;j2=} zTN%>;R2e7s9&Elk*3?(WfjZWSeJGo)j`tOUeyXf02dbLgGnIk69ABTXGs+tlKw&Jl^dHWjEAmHR{|_OWc7Z|afQ>yp^Z;Z@$$1cf*w zc}SBnuuwx)Fx9!KQIO-HD&PkdO*K#zo!~JTttu(pp|X;b&J;G)ROP1X;o__81V5Ec zGgVTC))qLyS0fg26@zbTlHltf{^fBl>)x!7smx8~B3d@zG{B7HkH};dRTWf~tRq#) zR5TSlQ;CXRk!}_6O;r`IYN|S@YAkl7FqEZgD3nJHCl3^fDX(golej4#Gd6D4{F(Fe z1|X^yeqGy~2r9c4%ACN>2}OE`zQL;S%}G=#H8UPmGgZe|buhcSsvfAi`RJLduTYWd zXFMpO8mdNsyAEW~Gu2q35yU8A>`|$vrkp7Y3emus$UAyes+mHoYL-RMj!&86QTQ=> zrkZCxs^e6PlsOLn68l;Tfj!c8@~DpG=GY>On z%GsSl-{=_C#)RA)bEGhoYJ-`!H5yb~r)!9*8O4n%MAv+y$q+-*+SXa^l-$T-$MC*F zs9UvD?Li@wO(j4eO?6NmK_Qe)EhzzMLUl60jW{wGN_E04I~(kV5$h(~BN&Zy!wcm< zApU{)@0jI3#Z9WPFI0OZ(M5Fy)rDF{55cm^=4jPTb@$BCj0LJ2?yFM!kliyXQ-jbK z&GeLtmGKC=ObUOkjB_2BP~9dXpv@5e_s=pdw zN}3X&`ZK>vEY(_SpgI-QKvyl5Sq+oqCK)eOaYOO(`RroIH1AP9yK_OE>b|UjU}l1w zM6n79YJk&2^vu*CH5e3vvJ_{m%NnTD)ajs3b2%b}XMAq_c*fnlS@XtB&j&-)>8|aq z$Lbp|VLXfnsXRm%Gcwqs<9v>Wj34xsZ*bL$XG)MNmcpCD*+puI8VU;WSe!MAU$W?* z=_Oy%gJ`SKNMnMU2x@}!`;x4#niN?z z8Pp`FE2UWtHAPL0jG6{256mphj#Jas3{Yr}Wb`=piy|IH#gGFv!*Px$45^ty5hSZ- zX@yyUn(7K!j-8}tt2066fw9=0M7cc5CC9F$D+w#<$^Z)CS0ax;(S9E7FNVAyp)P=$ z<_J~9a?MewwR7C$hKj73ny2Q2nwLpeQ47>UPzbmZ5#019`khC=7efTpLRZF0tg<>w zD8yoO)FQ1Gp;n=Xj94yZhG2d48;^b~uvBxirP{}%eZ>&uku5Nn$u5^t?5JojkM_nL z(zGcwkIG3g9$>3p@e?Oc8fNh?wr&! z;ZO8q^h5MLkA944CcsF7y>Hf>al&i$PtK zHKSD}&nYtX*vaBgx z5$#sXLE#>T!!QRjr4?#r^sQP2YK4o)lPO)Pt^#$XBSfb34UfJlln|(^vPN{ZPzcB7 zsB5&skSwT`StGhuT?Z-;dL<*;#iL!c%rk-9vjp-D>bh*%cJj!rizu*c(YKU2E`g+G zhz#d?wHg#+u4ChLHFbl!5!4NtbQQHm-2`fl%bpBp2ak3XQKFl&CUdh;2%_ewTeP~x znG9mG8I$>%M_(UOhSk|Je8r=$3MIm$-G_X++;lY5#V*ZKF34 z0aUlEJ3t|{OC~UZO;&fRyFlHUHGxl~Poj@`^l99+q6y3&pKk+zHZZtz)(Ac!Bfy0Y zpzg{TK{Iu?ukJ=N_o#b8-IFzf`_%oQ?sJtuM(}`8xEd};J*d@#l*9d5A%DapJinnK zOZ|&<>R)u#y_o+)>S0j0E94L?MiOH%>!T0VBcRr2%%GmiQIAF+sK-DdxJtkjnZXA2 zIH(Pd6q&*MJi-$l3MB>V@vI>{Aru0oIclR;8;N6F$VR$aj#X4os!gDtbYshMth{tU;_@-aWffLWJ*zf@de&J`6;?+*r=AD(Tqa#z zy`WwM^@1Zny~kD_Z7qTTs25#1s$#eHl2EwzEJwYp6(W|@4L$F~QJvLRuc%i+A!bVA zsKIJSZ>iT((OdcAc+F)~lhumeOhj*zIP!2++SM=#Nvh~28U)K*Y$Ia8&8(%b4CQ1Rx7 zsCU>~ycoR@J

T;~+$ysm9F<&ok7xm5E*;Gku3H1@x>&IHfhW=qz;Lq{sxvWU3Rdae8w`}iY-k+#XL4A@n(QVOY zwH?&9tciZ6K98PN*#3Q%HPJ8CSD?OhWXMFH;n6dNkO75QDMc;G+51|kuZhzgTJ4~+ zex5bYooW}TomunzMtutkk<5&FKCO1AqNnrqF%P9A^L#21p&5h9gE`4OH}PmwmY+k+ zGrL$VdXh&^X5TwlJkhhn;TKuc{7!uj>bs07)=@vGA3-6ANu6I6R$cw1_JG3W8kt^d zBab!~k~t{EA4w==mOl&iGYRDvt$uN4i7`NmfRS1Ls`i3Hcrs&_PpEyV=!twW>~qN#;Web8RUG`r|Tbgxc=PB>Odv-Y}#uS?*IC3Pv#B^@iJ z*@^lneKhE!NN32`EEnCQQ>iFkbujm=iJ()|td(HLva*^-cSm=D<}M~nPXdi6Dg}<$ zW7%=hojkfTcC=$&^Nx&X`HL;P(rN{bFbgR&9xfZ*k&5mh?ZhbqUUWBA&0Sb}orgc* zOVRB-x;^$=#>}2QeZss&v)zIY=s?Lqn4~;?jYxzRT7niXpnMXmtCiNEl`Ci^R!4{W z7|@8Kkg-%^wRCA+26Sl`F0O$laa$_74Vj6<#k!0WNF}t3TlKN2=vMp-#e+Z}>jZ)} ztdEPMBBJ=*jWAEa>B%K&ZpLg-5p(%RcC`P9$jG(aovo=6sQ?Bay5nksOm% zh?{s+*nD$9^@)Xh5-YFENnP%LLFNC(pt6>z?kDIILE}MR5 z&V#vd_gP&<=ql8FRn@vGX=?>%bxl}vT}@X9UCm`oP58Aux;AdY$(jyvRkFFWji*3o;>RP%sXhg24%f*@Wx{j_3+AYY#^eNHRJi59_ z5}@lkbHZ8lx}MPWsEqZsu8$&5fzHFi5P^-Z;?Y%wma1m9R9Euo$|6bn(Q3p7qkD^O zMe`<5Pj^IPK|V9(2cSl@ABx1=yESwPI`9*-7Y8PYm8SD-4ryg-J>q{Og2w9)6GFQ%XYEL zqNUMgJX)3sd*(%(vSCjbY|3=97+&$C%c$a;=XbKYg|Ay6sgrd}&?h^6z_6!2MYjTd zimO57Nw*dn(T^P6M(Z||L#u4PT*{+MV-X%iJ~)WBMg&K<)$KsH&33cxqf2xL(CxF` zY)4;r#1}j1&Y%(JpdO#P*)F;(=q}lA_F~;F717BJ@mUMHTeh3+9$ge&2)cW=o9&@{ zg6`qCrEc~D9$gUkDvsMsKMRgsJh#?$v^`zXsiR$zik9T}Di=`&T}Tq>nw7x$JUYMF zp32vqv1q+?Z_tPi^uwZ2N83mD1>MILl{(sfx=wvQlI|6j`qK@qwS6AK12@%od@wyN4qdu z5Y6|Zg`_eI=r*6)I)r%iuxK9WVcCxM3_U!Wt4DywkT%7usG}XJM}Z#cl#DvsIXs$E zOv?j$lv6h9YDWt_ni{b&T8|-p9q#Ooy4taN9OyhOhq~G`d30u>`a3SG=d*bO;fPUZJ6@wNJU-L8w$&5$B+v*0WIEf)dJ5<~IDtCbSv;Cm3=z;%Tsf(`ohtNH zD(5t<5qqKTc9P?my4#sNnptScCS*%CgGV!pA?io-sKdSF2-?#QE@SF)r}Jp~!C%CE zZngz>oo+i+is{ib(9^S>?hMcfXwk5rI^C%}np!M}IGFS`PIS>T^(@dcv)%5LXmT{k zi?DC?qRDidL~qW*YqmZU^laDd&Sz)oIeISWIoWP^Vl*Kd&m-LFwILHYvK>1Udy#*Q zY&-VFZY0y`PM}VgkV1_plN;I2(DQtapqHMn7l5Ac^nyCwh59Ved1w}Lq!$Uji0bid ztN8@6LoXZ^AQu;EX z3FpyEwI-ZL=Rrc{SPi{QUk-Yi)Bkd;n!Z9W2Yp2*T~V*l=zAf2L!(a&DC<@FO3G>SST3MlJ5xP~HDBNGv}7oe|nTvNnq1dm3<0hCyBtVAp`&?_CMR$mADT1UGQcAmra^{EJ#>*mqE-epsnRf*0>MA&wL z&I5f2l^MpPVFl2>JX^0rc{H?0nfg)ObY1MUrZ!spYJCIf)lOQqSxbGRUIY5ZOuDJQ zN#6|mrcAoAzD47>8=)R*ZECZ6dY!%%bRNi3o7IVi@MuVpEP%e%l@gZ*>)V9Bjf8c( z*0;O1W~~!eJ=RFyq3;BZQC_O3`m9lOy1pwF(NPtyqV96pG++&*(-IN-7ohKSqM+7& zFpmZoAS?u{$PK|2!1`{X?dHfjo1j$ZpKcI2I>1#(V%?V z_q%MGvlh{*iRe^@6?LDZ-IO(p2J&cN0km((R@49F zQ$jyQ)%Ud4Ph<7f2E8#W-|jr>USw8&)Sp^ybfkU#AYRWz-9SI%Bs~BdwrBO`sB6>( zG-5m?=>cr0eoj9R8ZjPfNCvRe^$Yq%(1`Ig!t`Kvdek`;bzDM)pkH#5 z9>@kqo%AcIs8hbAUvXtRl?{qICL$ccfPUGP1Xof=9eC8C07*aZK02KZiP|Tk_9W@e zPSV5K82ze#4fLx{(!<#({knbwG{P;^{tss(qINuLSEP7Azu^dsU?cSwp|_Bv-_-g| z=2xr;8d0W9SJIY8ZHvsxkGhhiyHHQojXM0X1r+BzmmziVZFtlso+05(gOwaRlR89S zFUD$mD{2k;E!U+_V>9$t&|BT7)7bQ=6^~jK!%J(b@H6pxTfYMu@gEA};7@c))G|8R zi%ub4ThfhYlk0czdRM;(`rYiCEu!X8GcRgEFEyuIGkOzoAN{`m0QCE=>tDnc>ksuu zpz(049z+3YG}RwRO?cEacA&89cevP57|wRknEn_u`6R*t{wG-hH{wyFxKQJ9QqrtR z^QO$h!_#=@I5CJ4e$<#`+k|ug@uk>H@LTFneT`v#y-jZiz0Iixc?qBC&q06YDi@j8 zUkLpLRqmHsg!*TgS~nm=)F!1$FXwyH~l+kgjuK= z!}x&SFZ6!OAy?~M7O^fkOOWOa&SCDLfJONKDY#9`ES&Y&ApUJ~JdLCj~2=ROJnb7MC{V)Nc?>NPIXJJx=7*xy&OX#o!o=?~b4}6$||7hkY)ls%~ zu~r~NV2K)EauTcYs9I5~8hVZh!W&^p5tbw(rF2+|t-;Dp;lF~^jZ})J)RJ0I#naT< z|9eV^ZW!Wmnck%;kE#}{41X~{JSwUJA!2D%1+`e+@aQlF;nA-2wOH+ti;z?4104nj zDMOgbQmf1(oF|OKvf`AX3Rb2@h&hB%KnRX32KYl6DhP4?5&?JhSlduXl_IP%P0b#G z1#P1WVHh5hiYnx7mpmSu^f7a%5!><4pe{oOK^Quo$d4`0qw>W_pk#OqOGGDyrNc6* z2+@Yrcsf=qEbTHO|M)~6op?w~UNXd`L(vK0vEgy4=mh*|?7W$CAv~6O=(e#&ta*66 zA0CfIEE|@CFb^ift#-l_M0f&8@3&!azdI=`58+9! z2GHFOD~PZHeOFP36>-T&2huV>L?9%r6d{F5j$4YJl;u&`BdUgSxOOBw4vTSoSUIec zifGLVqLp(XM1+J?s0DiN$MFc;U7S)}SpQiv#3ek@v0>E+#dj=;Z{l<5spdMN4t~?H zdRQZ@8PM)DBWaLrgBZ$;S94;vz%jl#wdHgd|` zhYbpwgiRqt0D=77K5SsvENl*8Gsjb3bWLR{lE~A%SlgOAp72P!NbpD$$P*4VGKLL2 zfs!l7(BNw3Q|#kOvJ;R z5J3haFqoYdaUStQ2tbICM23MBk5c(fCw)C{GK(k1x!?T|;f%0NbTou*T+NL@LA4Fr zMMs70A#CevZUh?}b_hE{*uiCt-f~omN2Q9$7{ZROW=66xQOQJ95|7jj+qt@!;GG$E z^21I@xpUYBLJawn7$&f(Vb`!5ga{f?o#ITxu)7GmQ=RtEA$pe(cFUHm1dmF@bLitk z7qY5|5J=cF>;+*@m+dq*JM10yfv~sBb{d-*_7x$9*K@*tI_yW;_Q__O{}GU+AZY2oP* zo|Z{34u^z8Asph!B5D;Sc$7H!xRY?GYhUNFbHZVfA7S4*%;^U`IU^hn;TcXp7P509 zmWt3xb;q5A!(G1f*uva@cM0M@|Ra2$kVouj>sU6Y#* z$LCs}o2Fq`YT+DQq&jaF_Bzx$VH7!>kZT~E;40v9wkn($PJ(cvE9~WLML1c67);Iy zr|57>F^4OJlN^gH*vj09=SBswm}`)5t|jW@@R}MGbh&I)HkILmdQtJ%%Dx#5|)`%}5OMV&Vgp6M7_&2Gs3o#*~uAS3%psI#*|{f+1T zcDUU@h{p*HL|*VGcV9RscW)|pUr|RAgmbc4{>pQIjg=RzWyV|*dG21KI@8(v-B{qc zemEE9FfW`BAx3qn)OWK7!Uf?%2p70oxSQP zhZo|g;@@6;|9Hev5&if4kz|_WHfn$ z{>Rvc+&w&Z&q0EMaB;STKk?k3if(#xeGB(fX1I6z9Ty*58qh}Pm?HD4azULYCZ0>hF_q!s?1L1N3#k0u?@8BwAfa4}*EQj_5MD!Vl*is+Z{&U( zUKd{P<$lXp5MGD1R@})5;q}D8Y8|fr4^Ku2G3FiK5Z(yk4a9{XbMZ~?uH2no?l;uJ z?V{UG;umAj;hNkX5Uz3k?i<)C-W1-P`*nB=gcyjXQ?TD)Z-;Bcbr7y~l6Zq{$^DAw zes#DcAYA7pxrJ>FZx!LKRFKXd5>p@o!Or5>gww1>R(lNzmk2GWM6U0eX+ML z`9WyY@D zwv}W@yGN_Nwf4)5{c_tjk}X4z7kf+W7m@wq-xcvKz%#yuMG7PfuyvUkV^>6WMY)9% zLH1>+#~8buWXCuLeht-oGy9hPJUfZx=^)arrvfB`Chju&!@8&A-{-!!F8B$-WcXMU_sSrntVm z+50{FZgwikzMH?d*=gDLNOqdz{bo;R-;cBJqd0t!WIup8VSbton&~}9oc4_UG_s%W zR11=w>N0_Yy|UBe>~zfJ!zBA5Ooj?aKROkFlWB+H^n>57h6y#!?TbMzAhLq9dxwwY z3m@b)DayX%W$eQ2jO@(NE(AGpGqV|v;eUABva^EhEa2lub^*zjp~ruCe`jaM+1W_S zoFqF3)^W7=P7mw?oFc)dY<7P3=Xrin7PdvRpJYGD z&I|1)kj_n|K5^*+ziM`VoSlyaEJ(5ofMGcGYXzHko>`Qg2XD^JF0>zqb}p9CYY+_D z3*DR5{m9My|OE^Uyv+d zqwZd2zs#;ASqPFwc4U2?T@`0nVKrAL+0~%C5eCD#Z3)<~L!jBNN)eHr!I=W6m2XOr zqm`)~`P>)wqsV^rFFE?c6)OEbvuon)8Z2~el3feCQkBUO$u4(U?B(xmXGL~axqd>j zfcGNRb^PM&x;VQIGx#dWeg)tVf_dp28z^?WIu8a>D+nHl*-~hj`x^55F#CP>htPhw zUCh3BFE;cW+36WO9mVViNcTZ@WA?|;ez0B4Ho9~N`Uhu!inBjq0h^NSrt)G2TaVfI zvp?JSLi_%9G5guQ+0;MGP7Cd{f|&V5_B{}@EI{+wU$UD?7VucGul(kIo9vcsj${Ev zL>XxApOn>EL$VHqg!^Oc)W}Y)Kp6s53(64Ai)xv*K^6kpvs>-EB)c{L_=N1QK^DUF zvcF}2Cs~Ix;^|WMoyfkkQ}YMe-yz{2b_&V<;Tri^|2R82vXjd-a$u)mUwIe%3gE_h z#Xl*slm10ukOibU`=^~qvVcosUE4yp`YQ|bk-r?5+WMzu|B18zAb+4!Pc!!I$d3QF%|$bi zyoxO)6aY`Cihq`WwjCGQag~}wfi1<--^Q{6_*AuH39afB#JT>J_AOdOtA+Nh$`k}G za*chi--TAEH3+Tl7;>)PnTBx2Jurku35{T1fz~Pd>agw0pxYx}jyO63qOL3DZQq{o zygy*)h@t1P@_hGi3{UYrOo1975q8{Uy({cefa+u@d>fRSh7@p0j4u zP*dmxV`xoELJK3j8y#p(CxI9GU1=OpK%M9wb~K@TxJq8=UqWle6acGInj{pEBsV&Y zhHgs<6QX1Mf^4*pK0*U>-o8R5Op0Qw^6j1;f?I_A95ACRYx1|6wV!9swWmLpe zU;#3rvRt>NfHd0IsIsqy7MC}qqXSj$%`5!A_Lb1SQs}lYI>3U2z>dYsS8&-{9mVcM z*WQEu`|QiKHr+F{FIU>$4zlzI`$OqoG2II(+dH9q!@dmp7DDd?oU~px4tGmiW!Juw zCPfs^leaI?I&`1V;^K*PT&8s#=ZE>%)4Bnz3!E>uFA`epsyEEPmhKzVeX;oc61rcW z^DiRjVM8SQ0^Oh13oWjHNXKOg;oQj48~hvX^BMa*a=spxcHa?VLZrr5oPCm^Q^qG)ri+UEs>}AfV|``y`?6^mP9j|66((J={KFA14%$ zN|+nKvlr+Q^hiPhsl@W1@kiRnBKz2OOs*`}YKK*@gdXYW80kMxkBaG0NJsO8f(w{X z04>3#>c8xNMUM_BAd$2MJ%-R0DP{qWKcUCcm(Lq=j|hSc^DfUz*vwQ{ImB& z_MQsm7CJ8zy&GDxE1;o(^b{Wmf9}^29)9=jU8u_-aLu=m!Z&&hd^*`X z2!)6uh?(=}fpDEe&$YMP+Xy|!^|yKcGI}08pV0GMf1BqoqMhjlgm!lQZN9(A-WpmA zWOx1T0w?eD{Q35l$lg*R-2kj&e_P})rCnkQFli~hFrj#=`3{UH6!6%AkZifXnqEXN zCiEiL?92Tx?9G9_8M$d$`K~;BT_SLyM91sr!MJxXOR; z|6p&7?2Q#xzI%b>8zOtd&UOy%3Pkj@*Av>)waR9o?J|0~y^i)G^fISiHv5)dL3b&|xt}M3G*d(5t-}un8beP0?h@2Ov0|Feo)}P_v+i4>vSI!=@Xg#mOuBiF?2s z4br>r>9n>xga_p39&Q#=UNh}pSK(nC?j7_$W63ykK@$tdR3j%s$OabvMrNa|C96G{zP)vXL zH^3Vd&>JBAO?C*OH>K%=AgD@jj_J*q{+5K^;wfMp+I7g3GvO_af516?zrYSb?FG@Z zb}+q_-WJ-yK$Fv6x4O)#2Q}=Vj2(p93lK{?klt>u4DCQj=d{=DE?o%L^&K(20}H(~ zp?8+oURPqj0!-Mq!%(;e7leF3WCv8(5g-~luf6))eztFD`&X*H0P6}Y>J57he4_*4 zbC>Ny=v`?)3F?9%-%anaz3ml*-koYMc-D~KOYbA}-n0Y5eLZ?VeSlEV)y*K2;-H@G z7200dPN}uDm7VUEpRnB{o9;7T4Z@w$y#=a4=vTV0 z0DS_oc+z$w^vOc|b&YJ zz|4Ko6kFF7y>3U=)3wP?({>!0JKF7kz_{winPbguaoACOl*G zP5Kt0Z@O$D=F4`DZ0B8OOXypUYY_28$HsIla&25f$02Qi<$_#6DAzu;G@zwW{@Zjs zp@5Sj10eE%PM{MBo#1kSh%Y)Rrjsy-$qAhdkzEyq;Giaf(}+L^;o)4pL8qX)bF)sI zwV+x=J%e-7@-bX32rYwPp>%tGWY6DC@JK+%1I<(Hd4vLViZnwk6@7=kOXxd}W{9Pt zQ)3F4XDOYQ&}pE43b9o5-9p=(8`*RJOWcM%4_g+RhtM&Odk{-S-wP8vrdUO{3h|pP%Qi!FZvtx=ND4mngIpD6`IhHEV zLv+c|j~wj~NoCK8>^YSPz)V*F#8J_YWBM@`FgKxdVZ8gF#!>xmHSLE5W_OBgr`LKl{A+WCdjIz+a^e`;D(w)A!Q zd`cG)3TQ4$6hubR#dHawi&FyzZ$o>^c8lU0 zmm9=I*|w2wn<7oSjEkb*LKbc42HQHcctCWDnne9ZI!XD5X=XUl5f#=wP#_c zUg8RYME2y!o?O9D9?(TlzwhixgaU+&in=8XAm7s;=tlY@p=H6j5En&%qMHc)DYYSB z(%XjqOn)Kt=hTM4xG38)v@NlbQXAqIS1`my*%KpsVg&^gy2+6baZz-0OgAIvw1o zLjQIoKva}HHnhhA329Um1+W(F=GyEcZx-{IZ=17#FzEMfp^%HbJ}kqk5C%XmF1&>OHd$3xL|9c<3`9uT zqau6ME{h?o$hFYL-X-?Pj6Kq;PFNL}8H6;mY7FkHxy-tIJ?s&YJ))A#9LfuGl*{bl z8GAUaW@NsjzP~q$)nK7Lj75aiaBfkEeP%ToA*`k=0Hz`K(8wN|&h84E%@Ic2?-1#1 zn?<%+d6qKRxdoNlQ13C@l*Me1&^E11sWE_S!H|RW!&xns5LPRHe;vy*N|*y<;rDA8 zWXC{e8BZ7onN5c?!l)zX8t+nR43lChvB(XTbLK0=Abum@oigQFXxKX>9M9?Tv)gNf<<|da1AS zU{G7EHssfs?ZfJZwlUKwL@d+`qMPJ2+s9t0C6Ru|G8$cov%p*;}Nr4uGr?9$!k z-OKii*?w5S{t4T^+=Pkk3vV`J^=!k?Ho_9nSIO$RHy`jGvJFDppd2RJ5MqXAKC0I8N-CPkJx1hO7}`0G(ocKIuKn4rB)rcA#sXCn0*Neq`(a zOPZiU*ae^QM%n`+d%#Z32S`c2gVu{|y`A0;SOXxVvE83A0A`Vlmw>v1Srftzc6EBm zdzBp$vqO*@O%v7>E7GKp=YEmhuUv_N#qef};3o^5B#-uH*?n0vc4%n#tyGemxgtk< zZ?VH-b{H0Uc)||%?%lz7-5GLko*K01B5AhEg$wAnM5FhzbfS%rVtKsse+J|;*v#G* zvm@A%p)KAnw15}Gz=?;Zv7-V8A*igmtxH&QS0xBxVn@g9Xsl9;gtf>EZCw;vI0)PB z!;WE~cK6vXw8yv?Cwh}?os6x6LVGNv+nXK7jt}kL+lBTxmu|B6E;}J+fIgP86BBk~ zd7%X`+3v+!T5x+{u(lK0mhR2>yy+IYU+r>2yC=3GEMyAkMySb2>}0}Da$0nbw}`c3 ztqFs%8^@11-h9@EwI!^L8$Ukw=35n745m(pRo2!C%N&TNl981a4Pgv`VeH!Ty-(RG zF#|lfl%1NeQ+Htqv6F$O)2txuG^dQ0`g^m}*%_8wMi_*VVvx^LZv{J(wIl3ISN>9O znWd4Xd2L^Y;}`aHC9IvJVwty`wU1eQq~ffEp;5xla9ww$uh`iEI~&UHz&aAvAqCyM zmA=n9v2$#euuiTQt?_gu#vksNUg;-Gg;z7ld|?N;?Gr zw#b_`-dC(k%(@^|7bfgN@6!KEFn(S;pHRdu0I`YLMeO3x#@L>zcD~37`g(68yCh%$ zy|PPLSHdoJWUlwVW!+-d4aw}Du+X31I{%kc{WUGc20=Fvx z@r$raRmCE*@QrnZPag}WPM=hU{QyL(FY9MB7R;f(XE8!+{_Bj16H|5jG@kcDS!)wgm<~|Lm&mTr&Se=AWI17MsD!0`e8uDtO^|i{`OEaaFJD*JIbQ>j}HgRlV4+XZ{Y& z-%$0`QfAk?s@L_4&0mrEtHP>ZTOjz)$oyG;++tS)2{)KO2!l;-U{c{X0LpG;!_DvP zCciAo-%)j_e*_y5GXy}{g9&@^{|We>J>X@GW)HE4L!+@jq`K-M zC$vZU$FoNQ2KXv_ls!h+qmB_r`bV?JV+Pn~DSIMePe2#g5x!@SLHZ|6jxaz~K?VCq z`^U1UV)hiKe>!1L?;1G{Ob+$d!$8v(_6!>tnk_(+(_7ED%ueu6G@CO9rjSK!B&7R= zJ!^gr%`cG7=`8?MvCx)&EB0K>5Nl=6C+zuhddvI_Da=;9KyN4P-hzN{ip-`8JHg%C z^_Ka`{Af0Y=BLW^miZBStl5Y~{0iR~L_4z=%nyV?%mMb2b3u?_WG|WT&3A;o==9dP z{w3^X_6lJDN@XveiySLG_bO^Om8`e7Sf$(zKzVc71I5R<3|_& zVm2yfqmUo3C+ziIHv(ZVc?jQQ7)oHi#~OTxb@>4=zazVDa=%~U_YTY-@YJ4!mrLM6 zABAeZ!A2AI#&-DLd}F>g>wSX}$L4FitcR3rG4U(0iS_&fsr;Zo<%-CxNKw3UFPA^|f&nnh zrn3(To9@g-fc4o7Hq$I;vj_t)7?B2m_1Q;kHenyR%mLOnpGW5N-DFPKY{yLi_t~77 z%|UK{oUo6PPJn&Oz18-(%8KW_u@Kl(s%$#zHhe<0kumALJ|_u3cS1Nh829$kQ0OK=z9 zp*ZLm=mqnw|Gs3rGIs)7P-v^qBJEx%LoIA52Y5|32ZT2LfB%*C2%LO zr7>HITw0c}WuOiV?gUoA4$acYEd4KVr&)$_wH(`PmTNC?C$P@~_8Cy}Ia^K`#Qq{B z;7(vG*cXJk*k5!furJw4!T`?2`8q7kW~xx;9~Jz2pDoPAK1I zm9-N(9N22dOK>=tC6QUOThUzU2m!YPTNkr+NXSAP$Qo zvv{}SupAm;y;(%qde;cxf?!{>ZwLcm8#@iSAlSDt`xfiAAz^Up!;a$cO`)_;BlGEh z5{E^o(?5jIckFw@zH`Nb3xfT?HWCKG$7PGN*^g$Sf!>>*XPmkq%zX9}+Z3All^S6` zIhw!)Vdh0<-flQh#5RF#@Co~w{Sul_(1yTOA?#MnmL61=_m$AgqaEMVkA7%_Rc#)ZbWBNk8EI@Uz z(G>!T%=E}iufQk?82B34HUr~Y8K~XT@60{!^MGdv%y-hE1soB)3a?5y;LwPefFptz z@oIzvR1Lul=!h`yhXzB^Q^bTm?@E&Qb8ev1IAs3d78ED2H^lSqsZZtgLxCe4|bFe@`jn$`5~cseLJN9I%6Nb${T7%Wek}7 zgg0@Ng6(2ni_B{kQaTzbeFG^4XdE*b=3UF1#=I#~+AQJCfYPIV^EM_c#bmWzU%A73 zj2{~CLqQr2XxPkr-?_PcsZ%+78j+Q&TyUnYSdG$XYxXo%6c&}FIGTLU|=d0n2DGg!q^eNeA0W{yugp=CxqsO$_6}s zyek;o7yQJSpNIvwOn6K0x}8kc%FG{(QgI=DFmi!`TG8%A1&|+8JBS|xl<`e8kcWa< zi$Q?Jpm3WM@e^QBc%GlcPY%uVAaLpM$WL;^<4EsC-YVdLaP!vYIl^1JDvb1==WSx% z2CL9E;cd%6eDfTPQ~YGe?^%8dKQ%OItUO|r{1o@%OWw<7WX6nyxjsJ?(mlgZ+{oGx>vkW{EV0b*j&obO!%4Q=KB0}c=KuA&O8+w43kemeBREz2`&@!WN4n; z5yUr7VVg~Y3lHGao}Wc{d)GTBdhheIc?ZG)$;Q4o(R-J7#QYqr#JLGScNazkKMQC&&pbvr?8%5q z_d`GA=kw0yQS%7l=Q|MpLvJ>}fOjGM0$2Wr-VF0_WFFo@$(G^x<)(aucX71L@IK-f z#{5F0<)VZ`Oc>#vU1y&QZE+k$2Y63@S!f=pv@7&4hi@c@0f6V)1MFu2% z003w^g8dvYWPYW&k8r@NQ4cTmKIa2t4k&dgAC&Mx{)&Tzmf18T%X+HS#wip zZra`_Z*+8T_O_Vekr`eg-GGWCKVYdbA0G4J$d8*6ep7kI6Mn4|^}qap-^_0z9MElS z_P@M;%#DG$5xE4AcAiT&MCOM7Iv|-_kO?;uWetQga&7_^tCtx<;8t_|z zO}Fve3BN6+2Ocwi2fvf>J5rXweU{(F?g^FAonQJl4&KMU5Sf1Zwt|8o=klm*X9q#{6TDohY}95LHK=+1$F#$_`?Bz7)pMGKT7x`&LL38 zKbb$qA2&k@2RIt^kzee$;7{-;2~YPzs0#PZ`BUa9GlcM`QhkI^%wYaBe#B>WZVCObL=I0Pv3SIt1eUv=pl_y_XWVh-qaDIb;aQM<;X z0|QN0#GeP6uH>)tH$rnI(ByR6>n^i{{U&BW#tcB+2B5R)&qtenq3I9loNgQK(jDR- z%E!cf3>Nxk!rv^f+dy;p<|@1lLE(C`Anbi3)3?G7@pwVE^)bE86`|= zST-D(%drL!iXRw2?E?dAAPB$T{eHgRIWX7Y(+}{n3N8$`zTlJj6v8K?84!SW^h^)a z-E{L!56r1MUH}IS_!RiO!`~(R9WOwKz-`{0d@7$t_*Cqk>7VJ!-!qp+rfVMi?muMk zfFXl>_V3f9WMFz|bo=x{oAg1z0m0_)n@b3PztEl+N9N*6fsepkg4AD%6`SUa9?$!j ze-Lm8?B&z>hlEdedLLW^d7dLK%&oQ#T@X^QvOlGKf)Yl7D~P-G8d&`6#Ytu zmXTZozUGMqEQQbJa|oa9OsXp04E`~nYc3@GV@F0c?;ZY0zyS#7^Z0zi0rYJTbJc2I z!WZy`gfDP*Rpiw&UCafhb7;DNME319sC(D$gRkm0q)(r1+lG7FwvF)cyKg}30@E3( zT6pr_V^7I2 zIBaehiujH!; zU+HG0a8NH_&DRjVI)8rvU(44KzSgyAv9~Y(D&`n0%-1J;Jy$8M`K493qbsKDpU$=1T6gyhOBe{N)kDJ9IV&2_ za{jexZ`u+5wL2XKpM1l=CA`@LlJ0+Ld&nAEHM351L_1p&3qz%qhEV2GFGe2QLjb+!79$G9KdXBxFftH`5!U=1DX0~!vFNv z15F4e->RlePr6X&aM(xuTu>;E1#qLm6as5C5W-nrMA`t+vqfEl7 z3Sy5~?18z}N<=N_MB9C!fjJQjO;H87aDqrgHZ-`HAT=OG;#djiE12UWs)9NST6wL_F&T4=mnkx^C%$i5_r5`fA@n*xAQuRy+s`&_IA@@*!tTX9h#%D zjS->}WjK60uf1s=ndTJ~OvGM}{EptaVxL&-gAA;jh`Rri<{&~kv*rTtDN!u;HAfLq z?5c5*_n_EM>~D?~^@!NdRRi1v;s8;fhyxs7&`oeeWR6JXc-I3y5%nFZ;3g0aVgZtvuw#6jk8a~Kf^xgiywG!_RF(Kw%CfM{Y4HO+`< z;<_PdFw@i=A^>*JFESW3xM!cPa4Hh;989d?WhT}kC{>4mNHh^m&B38*0(>7Zuqn%ZT@ zfH%;#z`$?Zd|=0}xTF2jq{tkMvUw<8nj!ZNcJvPLt~8B9(-`XE%!R`-#bKD@z=8-L z6q$o|(^P>u5?=!U3ywcSK?V*JhZAv_WBE|;0da&m&@>_f+y^j8fD{jiBLzqegngqg zd8l`vXl@#s21GP>jRH?heRF^S@vdK{8!K*<1F%t!hDNC;T8LvpQ*V2tl%f6CdN+t; zV{t4t%5jM}?*BK9B0zPR{l)QSztHRtRKrZTI}yiw0ki@{P~Bnn72sId7k)ueB;o|u zB)56Do8rh6@1{wL%zoII&{=%b02>E9HK;gYXIWD>G1t-Lu|{X3x;<36wi+2QCSucck~MsU4Zx6>7VaU9DgAUJ-3#(FTQ} zZ6ezK?+c9Z@f3&2+>}g{u=Zj^cqv+%t zhQ)S-iO1eG&>7RG>(#|>IIW;`aG;cma}se5>>yPG=1yoZVz^b;)O5r9{8kh@?)z1q z7Q<19&IiWuxdri~CTo(=&`QNGi*F_|cyNMv9! zLVly?0Ru~VLX6^hxasp*_&qQ&=0osO3-fsw@;OhOPsDl190!WjG?58?Qxgk|@Df5w z0S+C}SzJIwXDr8eB4L zuva5JjHnZQ4Mcay{c@8b0^C5Ipej|M&|XBqY6Za8yc(I#;)+0A0f~BxK1B3(BtRIY z=qvgW(bsVe!zcse8!s|J8d3vX+wn{=JnMePbNP&qb%p$i=(n9xy)Dw)QXcL2YP92f z0vcEJ7cklb9ElDL2%!{Lih=qc0m}JGr^6tGQVbSDhyZ5|>Lv)G)PG0%?@F^KVu<4= z1W<~rVgU}EQZY0ULy<;s6d^NUcLXsk5W|3mtHm`$T(e}b~Mh3xT#RuACdm!zl1^QKcUSuY~)VFAjb~~P!zWY z0=y;SHgP)<&Rc>3isBA&ClTN+0U#0s6vbWQZX)i=-`5lOh&^6G=(?IycdgT^{Aow%03uB~XdIaFu+uf@eF!Xxf=bp$*{{~qbz zchmgfvO!`XNKrfx3-G0siV=wz0fQ8tFtf9fSV0q}grEY=&yZ8dfrx^iNBR*X?&^0WC8j6R+!$dsfD1=Z$@klHlK?)yD#G~aK_TfUqZjJQT|J1O*qGB8X zpU1@GL^$^j>}7DMctSi$#1pR7;OtrPlz5tmr(6jTIH+x;?QZHrgmdnAaQ3WtCKk^i z*&`D%GLwV0+p+x)fp`dvk-$Ac5XFH5jnZ?Rx~0}Res@#g#_+8WI-GCyVi?76&vpzZ zEML0Y=2wWAz+M0c<* zkRpeFmghCjSrARl@A;IU<)9sau`0!29k`9D5Iq}Q##1aYpR#-#6tLMIQ0k66?g<=q zsBJUAu#iTqiHn}e$I>7-9o^XW$VZ3j=I2$F^QQ!~>k!~607j5=`|WwIqkj>vh*v|6i=)y2Xz_~61khRibEJRXrJYqIVDBisNxUXTg?bab z?vOC>*rJ63@x%J3NdHu+fmkG9e}4U=cwM{^>K}0emO_f)wM9trXh8Nx2VykvYm9i4 zh%s)kfUsimRxI8^tvfamV|Nh*CBUmF#)(oQ#<}+Z<`i$o0$iJ=VtgXT=i_+;0iIJa zL2o2tf}{Ny?^yjqq<{ENBh5wx3c#tXzZVnrccK0s8Hs^40^FuJ{GQ;Qs5fNv1_*=J z-+^JPHC}RPbiClogGBnTe+6z>fEb*R5a4yS-#nXePhcGc@6y}rUJ?ledK8D4ww zK`cH%woOmO^gP>$nBq*Pj=>o5VIaUYDQ1Y7M9gqv-O;;1%n~0FG0V}^(K}zv7ITQ0 z?P%)cov*(N^;bYs8ek&kIA*|Ut9o6e*HuW;i$UPlD4U|11f zh%bqN{ee&q^z^P2EA=Y9l8BW~55N=srT#*!3iX%U!K)rU|Ai=OSjtr-R)I{e5Ucg_ zP_F5!y%;Y`ktN_G?*JvipI#`w*9$_u zuoBdPi0=!mnjh);UIg>{JSGEqF2FpOI?=x!B=QHbQP0z#5b=ZOp8|#44j93YMEvM> z*SX!hNBkr<5%H7D^>*(LJvY*G%jZf2_*k*sASzq@9E+ckoxddF7q4b&AC~PVOvFYf zt`B&R=#Rx_Jtx#3S2}EglNFo&0dIt!9qHNSOAYiKWYRnoo=?!Kp9h~U0!Bx0YGPHM z_FfR02<>{!)86yK=#TU)BEW44z7zQUd11v?BCIRsY3~_5Gtx6F>E&BpJ)iNO6Tij+ zJa(nxw?zB~LvdqYL&%1&XCWo9#z*|FXAtqbtMJR-d-_B1hxjwpA68mnaCsshU-n)T zf5qZ2%>VC1{0%**9auWfe$QJ><*m}4w`kefRzs`Fxh!|Kz#4+>-UyBf2EW%XF1n^4wB zWDS@AZudOE8}Q~-8R~aKJrzs9eSu_|`)`u>j(#W9@9Y?zt=~n7nSotkzEi=|gE2A+ zWCZo9DG8A^oeG}r&6Tm-gGkutsUO6NPWR@>S~4NBmK&pHdUN!YP)~tE2M_Dfhe&Yq zfujS`&D4`aJsGP3J4+J@{=&TCniT0tX_triqQSj-0LlhmI-S~TP#|GJkjzR-BrJ-- z5#ST=Gsz?;k~uEGNk~$}QXm&(BB3R`#zX=*i?qR?RI)aa%F(dMTc#(5dg6B4YP;tP zyhVCKs3(-s7D!nABlnbh5eeQtEcJ75joe$-ArhCy_;|lc?xV-+w~5@x4b}Lht}G_9 zt`{5*aPV?(l`fV0hPo6o?cQr}Un2K)6o2Wh)Z;RG92}G+iyaR>_m=CiksiCt?&a(8 z*n{4N=8<&@e0wX>Z>8@5G}&)R-)<1BRRg}ZOTPvZmIlfFe1Wl zb&#vq2Jd_QMn=B@%VK0>_vi<2lYTv;U*Gl*kq0`m*Lv&ps7Q~hq^fUXRmWge!Oe(W z>1S_?el66mL5b;!vhsie3to-%tEuQ93%d4&F%KC4Ujhk!NqMkrLL{u{!RlM@A9;vu zO5`E#bvU6~zY^(JDwI4Tn-*lKnLLz8a3!J~|L*;*VN&rj5aZ6)Gxtv zl%cErrBEi3gmd-Z6zC1>c)Xxxkj9Z+APmYzx5qWI>UdiL-2}FV$ z3)a=Z8`b5BvL%rx=5webPts58r-&@`@@(^~$dhF&BEeGwRRu*>ML!wpC!tE|VmAri zAMCQ*d`~|S=_ht6dcJ-dEB6$(Vav1){VIMn{dh*hQVk+cND1;IpUKv;4Uw%=g5bWE zY^xvBj}qB76~FY!De_bzPjLj*^lRxyLjA~gg22H81VOr*`r$}FTnRysAwiEKLEv}- zq4I0_R6mr_4|$-g0zgV83AJij=Ji`%$PtKI>h&BTM1n>jLEx7{f{Oip^?ezApI6=2Bk{*)@W&Qja01*k z@|()`@+>0TJJK5YP2}17UVRUdXFJmHNe9`H$PSLQ1N|oY?oi`e1lM>S9chjH1NB{z zzN^AcV0AA=@tULL$4kY>)F# zk{8K~iM+^Vdz^owyd;*FV78Yg@>0weTrl~uH5ZuhVB1}?CA(<@1HOGNEl1{ID*>yon$|KgT9_fSlj~BSU9n$lk6`C5ZT`mbe7*q zUl;1@wi7hK5!Bv4OJ5u5Ybzn>1|;ZuB&e?=sFQ!5z9yru!7c+%ClrNCf;RHXK!VFf z4wQq49Ef!J{w4k;`f52?4)HYvGS`%Yy#u_u#o!Gp9(;L8@k#aD6+`P3_Z-;2FFfcq zsCYovUIWoz7fW!zl*+3Tc@-e;#p&Tf2t($PH3dN$7U^LX$tU=ITcb*+Dc?h|U*!7Q~CiZnjdgYg19AoBi{MgFb+UAlLqd#Azf=~UN+MW^P& z9_a%Y=8R?pk@vdH@AmJLkH+#*Y}UsT3GNX%5?0<_;QAGjz9Mbd9kTSI9kL7LozMu6 z%O{9@+%>|({sj4?gaP=;bk6KQ?2psEq+hQqhm@qW5pbWLlioT5 z=V{39899bq`-Qcyy{W0=6`8<&To4NZ@@&)-K zkuSJxANQZoC6O+vaKs=I09VwFPx!CNmvj%^oyeD*D#9l(%U6g5$n+>MCZ6iG&@d3# zv5sdG{b_QXzEF1|a-8EmJ}H$jttfT8pXg7~7exAkN}H5O0BBJFrub8J=SX)>Q}2p= zUtfqk>VnmNGkp(g?dkI)eSSsb=4hzvcsYT{@vg2j{mpWsoJ8bANAXPmCplS8A#!s5 zeuI2RzDp!5H$iEd>93blX@_vHITzL&pWAwQ7QiTogczeIj0XAlYCsC$2* zoGE7!In&i~raxPs7wPkGi@Tx$R}a3tKMZ?B&T<@`?JtlY>2vitM1JJj0-wy5bBLVn z+G4K1Kz9mtCuj>;t9vDp4ny^4`*U^2NOw#f04Y#)SxLY26!n^E=t0|(e(53V`dsAR zIasD!p5ia`7t4=h`7uh^+(ZIU3XXg^-4V3JUoJn<9rW2m!uk>%q4CK)IiJXRj-aLf za(z~)&)QB9%)hZQm-tI{`$)I1u-o~%1Cntzk^#Up_Lmj@O1U7G3y_S3iCpN&nC8e> z<$onV)$R0|M1JbXz$c63Vj>qgGFJOv=`%u&>lGYd7CSOl`K$Hmkv_eWKGzOOITJ~F z*O9W`|5h%Eo&TzZWZY^*pTs+L;4Rc=`pyZ?|?GHR0G}?XpB{sUleL}a-`i>^E=mSIn-*M{EEmF z$PI!_kkKdUmik0rpM=fO5-%s>h!23QTra;Sa(z0uK*~Mz3Gy3#e56nK_gR+m8%X}G zhUw$CDLaBHK_oZG?}*%xwkh0Kli$bkd#vgYiTnZZ;KKRf1-B(`bbz}3F}j65I?~5@q^VbaP^_EFE&8ZXH!lMiONNznM<4;iiSf^Y z3R_a{L;Ah-k&!;KLV}ONX8Og;K!3Fy{VsTpE$NLbDzg>BCax zyi4OxAC5(APDM6o2({7D5UE`oGz=Q)LqmONnc)Xs3^2z`A^T>LZnm@Gw+T38HCnEX}3F#D?$i^f4S-BcfL{+KuzB7Fc+Q92h6P7g+? znu_RpDkiF?tKR9s8G8Rn?_XY?h$894FK8bORC@$!56G#ON{FiEq^o_|DO(_l|=CrP!Bo;mnjh_0a;7EFHti8xJ0Qy zDR^94?MW11x7Z9Ff{wa4(!~`HlYs&NSM80MlUX5Jt2V;;Ab;yI28~jWRVXxLVUl(@M2O zkpfU$XH^q*NT{FY+`V{HaI@YcqrquXq>g}eu{u)0kQPI_)GMTpbm?vh zZdc7?)f@{rI#EZL^9re>;7y`h=$fG>SOR*5R15d!UBSIN3Uvg7%l4D)HH1wE`T)E< zi=%*B5fVHcjM1SwMjadKu+pYJ#%29*@R&L-R>vVx$0zD|ZdP+u2#S z<9P}@2ae$q9T#$i>l3kwF^Bxw3i;hgaTOzCLbwWY5V-RSfmL}_DKA8YP^|(L`Ta~? zcvx3(6r%eOPnB#^q>cr4)=(#?6GL5Ny8xWv1mN-D8PzgSEkOWI($$GN$+6<`;3;)- ztN>vzRjm@$DlY)lQ2+p$*VR;O)h5&!M(zZlwR>@7@T@M%=pqz=Hju8WYO78Ob=BTIF_J#Gdsj0+}cKh!>Q2cu}z z*{+9;4aR9N(iLtAuiCqsOb8~c4zcQhHR+hBj=Kn2QfC59opPXlJGr50Y9>_Y1PV}T zb*?&(sB_&QH#Jj5ov%9Q{>lAK)cNVADZ$iWy1GDhA?gB0*3@8H?yo5KSK9I2@Z|RY z-7)-}s4kAcX~75T!dP911YVS=i%=N?+6}m9Ff-$+ivx8r&~S;mlqk2IQ!q35L3LH# za(@!l)hXrK!8+Al^&rY^=M>Bi)~J%)AGzO&a@#rKliY8rr@Ac6{Z?sb>*=VP9n4ji z#|l8?Qq?O_|M#|Y%KP10>^2hjgdzn9dhSK`irvP;!~MD4ttlLEwBU76cT)RnH{3xY*zV5|mW`ay}>c{``v zR_tQ1om0-L!D>jDv)BPJ>P!uG87vK!{Tw^XTb_J zG*&~gpkawBznxPq2Sa=A54`-20s%ld3@P}R+Y;rrq|*u)&_A$b(2zcWP7>A4%g-os zn{&V9ehzb+E16OFxnF>3xu3C!KjE9Y6h2qyHWB5va|$+s@Li*>&Ha@7k*I52N8K1` zb)CANsOwxu-5C6$ZcsN8b%X1uKL)?#Hio&4*fwcL1vDFn!i~X?xgVn34;9jVz2nC( zK~4>i)o|p;O^MohJ12Fm6ZNgZU+QLc3sE<_X5Sk8mis=)eUBWtrNE`{qTF{Cn1?~` zC#>*~SoKYK`3GOP|GO*st7 zvg&^I08s!tgDT9#nQZQxF!v2`I1S!Y52PeOx;XcBl>53u4&PTGbA6OsziToT;Pz@n z?kl23r0OoifyxKfL%DV8VWJ*P)g3(BQ$3;{CF&7ZG|!0K+9h)N?j*NIC zQEzzVcZyP@ApPjv7etMA=^JDYRAXW_2GhTps5f`LNl}pd0@da#K+_8KmKq!8Ffh`o zO+dF%HV)1-$t}<1mZRDPU_1A@8khSl%wdS4Q=8*lxg{rtN$xZ3 z&a3gV3We+0g5WQUa?2|09M5>$)#lRNlHB4jx3p5VxdeOiVk`n}8TAx=#^)9hHQx1@ zRv^d|)WqDUxrIaldIB?Ubs` zcU;eEm1&)uALZs(NcUvNk5e;esCQ!pTBTG?P1Mv~Hv&-;)0L;0vodD~xlgeM3$ZR3 z51Cts?0VS!etxENkoyXr>Tlp;(0CIUKsBeS_lQcN;2<4|=H))g&GmEhFeeBQ^mB6| zr2<4=y{|qX>U}Th1?ledMyToPL!zdqP*M8k$7)7yPL%sN-Ea@wQ(b$M48WC<=xQJ2 z)dCMyOMC(odJH@r6etL7Rx@+6iE{XTn#o5|?xWPi+SPUsL2fn>l$(Q9`_S_{;alD+ zHH)ZOsnUS}nC0rDKmo?DW~(_w%}!MeJg%ueR&$B^*il^73v;t_GjlVd+^qb9#FXN) zZ8~v5VoI;O4{|fH*cn*t+=2jp809`p$=&hQXvg;ytYB52sCh(vlFE`tyoPGNT9BKr zK$hmGvINg+sZSNi+ovvT;>EcSqTC0SW=#~}^U%w@*xN%bj@4q6mL-V-Stbgwei)EE zn5U|xfdZIaEmNNnwahUC&K6UjtK~#}?sA|WQ!8S%0(1BxQD1l?%Jz=QFCD?9C3sXb zE?;StE|S4TKk524n2Nh)O>Wm0oM$ymm!jaZm%-_*DnE-Vzocl#1tj_TR=R|x7#DWA zWl?UY7g$t76ey9rwe)_Jdw(~pF#`1&)cMOC2=|w+&aenmtyD0gtaNpTMVM-JtN^Yr zRcjKp26WEJ=?oEOaYQ+!A7v{yEy_*%FKZWa@1cZDNA53l+^+*oy*5y5fs%C!#@}_0 zk~&^JwO)Nq)cO?e@alN`sc+P`L;=ta@CV!%s}1TqqBb~6>v;R9?_-7dy80neKLEdX zUjF!hx_xj1Eah-|Zy&F2Zfca9x*K8q))5Q4cd3oB+K9ydn5Z9NLX3+eJAwG%^xCaN zDuEdA!7wSusM>!E2MSOVNQu*SSlb9`{s*E$)Yk<;c{j?vyIVm4Z;1LS2a5YA*E|P6 zt8G$06Sc|J2sYzVzr^YntkLE~Z7we;KNm`y66L1+Cqa1!1Vzn*&lZ&8?+S2i~}H;E{l+CadI=DCS#tNJy}O{~-g+UjV6b)dNkQO<4jzU!63MGEl# z+<5hy`aR6SfLCT#0IUx)Fz+C*srn;Oe*m?As=tW((=p{Bud(_&R(~T?{z=q7FayWE zfCg@l%V`OH31)79;Hz!5p-XIY@4@zBwf(p@0QIG{gQPYf3U1jN>>h*=X6;PwZBjeq z=!XTQxzZ?C`k#3EHrgWKUdWBBU8Q!_FgGr5W7MwVa)Toya$}?1*h)v2qS_EwoqMZx zQSQw!2irtCbEY;xE2wB;C0K4uCN~Dw9_8M|v2ik9CSi|rbZ+Y$NwQJN4Ye%GZbvF_m$b3`%cfLSqNPMG6%_n7lrHNAVw!Ep!A=lA~ee4dkCZ{}vYtE;Q4tG`uUomv&F zzONWIStU2d$&FQ1Od0j$LpCPXAj29U@3UE!E%Kf+@FU=S(Vra68iouYdbSN~MAh{SclzCX396%0CE{>Cnt8Pnj3C@g{;@9QKm~Bagb$$`sAz2Y67gb}OQwG3)VQ^g- zCl_w8qa|5^W#$jWmEo^?o;Cl^rG-fwA{NT#ully&qQSm2xq)`@kdtdlQwBAJw& zA1CKmE|s#*zV{}PBUqOVLs*`5&9bhre!|_`h21%aY=fx+iB-2EhI_@G&kR3zD;vWyzUAauzQXUC^@4-n*b`0 zoL)qZO-_%K)2q}bJ9)+|CMU36GHe%QOz$k~y@?rs?FcmWNlv4zkJoxj$s24}wp(&) zatdX;rsxA~fjWcrW&J4Y>+6RDu#=^6vb1`WgL&YboI*}#{WGjTQZgXR2B0|X=GD|$ zWDVOrWV-_m1KA#w0Xz-}1niBvn+;-nCMQ!i$SbaM$<1spwl`%yz?+;)Ze)X#ladoD z8|-@+?j$F$A#9&0IicDf9^(0PF1dgW&9I?J)vzoZMy>{BgWJaooAS~7FmHo9#Y~BQ z7oFeWjt(x2b@hn{&}CILpSDba;nUtO-$;D{HM^FueL%q;&xW%RQF1&=1tJV=xHkos zlgrt@A=?+2Ig;&1*+}2e<>VqZD#J!$L-)_J{b7XkFOHCq0ou++CrcO;C|S%7Vh2abVxS{M6_^Lt$ra?vp>EV0i9W zc1W@)N{)r+QdEH*;w!p}T+0s4utTw;!?Nr!Fx-mUppr#6bkOmgoQMJgo{oZ!IVMi3 zOvujmEb6U=$wtq0oq5pSCM;?xp6YL$`K1d zGny}O@-~~4VUv&_le27cWyVuB){mJ-$%|}C$ff|bN3f}s9pOjFqvUBejZLQvCL=Tq zA0>|` znQ<~J9rNqK2P7`6#M7B)CcHW;nL*hs->7HEv&r-*nZ91&OPI_+#sgczWHx>sgHrp#*XlybqnVK9CB-8L!uz!N& z2zZh~WI8Knb15q)A;KbXW(}Lipf|xsfHNxmBvaT?$>cbhLRxhqS!mbPDKo}Tn*dX) z$3?Qxy1mm|&^!-}u%n>Z`N<^8<`?-oF-|5{Yr2NXBy7@TY|@bxzzADF*#h6M0F1Ds zLv}P2zK|V5naAD{7-5Upv6LS;+n+#kI>^QcVvg0bi5w?UKpNwHAP`1Pm2>?gfiR>iGPV|K% zIC6NL99~1=lzEIF;SqLnh5@XI3Q%z>gDDDt`#I2O0FSWK z*%_3b?qv+%5q4&VorxtZ%d%xKZ&qHQckgcHX!UFiwoL$5& zrtG4^bs4*aT}s&{o>Blq*ku`Z8B%(AmR(*&E~qW-4Fo&brM`^_b{rfh2iGWE7khF5 z?qFAB*cC|5m05P>e++m0hr&SFiel#+6ekDOC<@D=1FlLAr0go+0RVTftJyV_UF};0 za0k0K!>+{^U6*CoRThP7inSdOCkJenD8O1bWQ*Z*J-dN2a8TeF1Gt0T$Znzxa+ct( zMF2P0&B^Fwf68t~MHJ$lWE8uF-5MpMsx`R4bAd_+;g0>{WWO3XP{M8nn_(oojolt4 z80+nAoZBkk4t7V#?f`1;d**lnk#he!QCj z5-4>^hQ-OSYUhj+_8=57ls%MyRXY@l@OIWio_K^ihSW+Rh@vFf2j{%e__aTdX>cbM z^!(sB8C-?c5waVgeGeyKQp5iA0^IQkdz3xK9;XZ(3TW;i-0=i^lCmd?aK}^ZY091| z!X0}>2}Xc>xZ`PGF~S{t#>t*lR7}~Eo_vHmR%h61Q_DqrYls)Qo62cwNh72Hj z_8fbjGVl%H@&MtE7ubvJCCXm#4!nW2VY@pD1#7s6k>!sUS+RQ_G%ICc%8jL z8RVZpp+>ml&16slD~~t5P$S$iFxj1f7i?f&sH=uMAojb2t%cqhz}`ywM+t-j<>8LE zeDe_Qcss)Y7GKHU$+C9zL zB)d@diEj;p96QI!&Q-T2*#&33-uSgEvgSon0dn+W>yn+Kq*pbI1DaepKp`SltF}l0p#eEbWAz~Nhf@$BYt(jcRJ(aXr6z^zNZW#{85J>$ngWq zQ3mnsVEDuJVrH173=n&GAq6?wM@jn%9b!Fo2y*NYCp%QBLjcytB@==iF2fu$Cdsm7 zQ+oe9KWz%Df`9Ok03{zI02XrqU$$pBvbaQ zrv+h--!kksq~-T4`yB=1XRn?R=J+FI0MfHR*29fiqun^|> zm&1#YW&{-!fEqkVS|!_29{4^+n4={Rd95gESzRCV&{G942d|yswSg*LC(G+VE}Z`# zFh_N&Ya=z4LK(akD9;wWgl`okEwJwq%HV+H90d(hec|9Adjy@dAh>mST zS4B5xo*w{ZaGBwNq_5;E%T;B@Q{Kdn3xG1X4!H(uOL-aPrG69ul);;E=tl4ypfn(q z(I`wBA@iCSnYT@xY?JP_t(YNFEQ3}|5h<9#%b@fYNkht8_&El_j4W@NG>DUII=0te z^pkoOt7n{JcuRPByQDtl+xdneoRNu=OeHv@J~F=nel^6erq~Tl@HcdsCGGICE&jGW zs)WbagERJqyKF90(TcaGJk8}2LVHOzC%(sPNM2z8omP*)jrvp^7ci3ZWSk6rF%2SOgm}}B+Leix5lr! z$oK7ikCC8^cL;e0c)cUyJmS;@Df!{+Ub*+BC&)OY7SlG;fv%DekyE7-Ulc~AKADwmM0_)bZf1eEXO2MXTl#doH> zSK)~|e3yi{e<_DB@;%e$*Kz;w-tO#?6>Jp&k4nYamvd;O~_8E^s?= zf5pz{h^_{RbAMys!~22z7wO#D3t=5n;{L4V{=`25`+@{IfbyQc?1;qf5BOK9Cn@jY z`>#PDd7qH?0mkggccXk)KjIn?!Ta)ll=sC3g+MQJzw`clK;(Xh25mA!00&SX6>|fU zb-zXKHy9Qb83OnKQp^3ycjp5mhk?Ush5)|1e*uzoyI&&r3%pQ~A%Fw=?|$ZcxSt}2 z5x!}L0KSKRp%H29evBMO^x~$!6896fxnF^w#3ivyQf)A=d_tO{pgi5CN%3+R=A0h} z=|n=l8?<~7-;?sZV?mPEd@sH?<$HNNLz3=lP@_l?&k|^h5=W48q za&Rr6o`>)eXJcnKFKGcE;@jJTwB*Awd>9Ul;aNT$I;9uodl%blVrNK)PNXsBDVQ*4 z!i;ef%6&G3wB769_Bj!J`=NLF2)-}nBm9tPL-yk%`F<|vexMvY2C#O3HAY81it>C) ze^_z2@A>}jyV!l7>U>{I#Zhz|f_V98_buh4J$10qci+VBn=Pl#eGB@=eTO{@UWuVV zN*6MmAHWZ!`~WYgJ;*SA5I>mmgS?>jAp5wl-Bm+!vAi0`8B47M5@b{CA)8!}*xVVdU?W8Re5H zKioGFva7n!V)t2%Qc%LjKrx^4v2I=DK80dt%^5$J^06cU-4FYX2k~(w95xWRPxyHE zapXS1M<8zj<>P%#eaS%gQS3h2Ea@q6A449A9|;U-*He63PnK`Ty7J4~l%> z33HB|0%Hqw9Pk0DfWKmF26^e=ThL|?NIj$pJ_0@v7C?He-;7@SE+~iH&%MatDP!l1 znX{l5S-;d?WWAGo8<%e7YCL zQDlGjZtULOV$DGL3@?=XlLPt844+9rEzZjFS&(FYFz^Cb!_$Bp>-$f=b&wAT3EcbG z-uG~1Oev0xcVhQW8V`%JL}4OM^=AXTQ?OXP>YN08n$71>KHKwYESbd1IgI9VPaA|^ z@_89P4{19x%fX>V`P^b%Z^!QK)GFKL4ss6uDt;87PdRv)P_!nK>3jh{nsRUvp^lnN zrt*auz7T6TCd-e(8jdd3@K)^Js$x$wpAW?@;>S|H$QL_<%;v}O#gv1K7K??Qa&B$p z*5-}cG%FEbTrBs^*u9xz1jVdG{8%V+2|u24@B$&JbI7Uu1b!mrC-|@w{CMbrbNP9cpX+&*CfiMU=1bg`Y-FcQ3~7#dJ=uTsY+y`PQFKmhp=-9GodD`6XF? zNkx_nexYA-K-OFLf_vUQ7rPe_ciT8ihI<~h&2z|7*pZT7__}9f_iPmvhx|Nf)usG0 z%3+JZp3sUFB8ggIot2~L9lFQsvv3sg265Z3-pw*~3FN4pu{5r}ZPZAP)4Y|=h>7HnS>pc*36M2~5$Zz5|Qx5JHG{A2qE8S!K7WZi69s|1uli*jG z`-114E4Px{+#|7jq)LJxMdsf`3W$PxnBVFiirm9c@FsI#@LP+W^v9 zy&ygSt+|cgPWf%V4;~;7x(6bMNoz6bS(^KT-(D>K{@C5Wp?bLiICKZUlXCF%pn7=( zAc2+qF3MMWPCr7PboaS?-953pZ^PUd?p|ax?7N^G96|+&TNS%iRVl|ip{Bd}D$4Kn zC9fuH-QD~icUSE0u0r6zE5z@0D=EL%3*0m0HGUtzpYr<(*K7C#{6WeeC|tkDAL0*F zo_E?jL!Rf4WcVW}kdJ2hqt)iV;17HHpC>Q4J7ag}#`IJEpl9-nBp@^zTJfax(Yr|@FyvM0`+eIS##fVxAUj?(}BC4!213v zm}_gweZj#Ow34sR^40%g?h6hZQ1~bsRY2NbcYW-x&pRaiu9=O)W+-3dpMRfx;I50^b(^W}19u}%Iya!aLeM!%`#SO^ zf0e^z2YxG5-RsEb{B`~Y<*)l1){#%$wXwUlMvB1ygYy3=`OIAtyK6R+BFc;YA$N7` zuCAe;(A|tJxCzDQR&2)ezQ2Be{(6(IbyvA7DF+7|8i_xU9DmDQ;V!2f9A!ux+;Nx1 z?y^dNMc}T$A}`0%z{`dz(FIN2rTlIFPUJ4ltHdhL1>tXdraAHlf0u(X`flO+7ydr~ zfb#eKh;ig6{$YlHh*J7dmVX3i8Er|{3V#mH`r&;WZnVKU6XPQm{ed!t zuo&Fy%;KqGIh^yfik)z;y4tOBfKS*YMCKM0z!LS+6q%rwzB~@)F!Pa27 zZt>VA*iBTz-yyZ!#e5zAG;$Y%HRYWH;DXx=c=>k_^3UKOXot@o*fXDdru`id{zZm^ zM{OnlGRt9sPll4cLw6Cb{6B^AR`9R**O6NR<#~`F{ApnR26ciGcVR7eA%gs0!*k2| zH~ibkEr;hk$p4Lhu5M6|f0yCkVFll3`S+DTeh$ttcLD#wogcXium()f!GG{?)(;xG z^CEX1%zzaMI^6j4D4Zf1vaGBuVzoZU)@wV{EaYK0y2TurXC+=K#jypSW z=i-a!;Mdvsq=Ap+j&e)FDexHDJqiDj^2E<-_~u#sC$}tiXVnOL{{)5o?7+4L_f=u~ zJR^2zR2re7I}<8)%W#DLSOkZE3HdMZ`mg*q%3R_P)E;;a_ z!w=>E3jFd44A5W^xTWr7DuN1pScIY$6=C6tI-<5a$(=|=ZRCCcWz=yeh&t~0$YE^q zCh=iWr@-*QEs5Qdn!OwDcocz?@asgNRMhfg0TJTGwcKL7zZAb9z?BO41-law;^W|7 zrS7Esp9+Lnl!T&$gkmePH5FU=DG3l_QCCD%)b-jJ5#nP-Eb2w>SZLBF5n>U0iVz`Q z6uCt(1S$|>Q4hwt;l4+R7hs#C0!N8EDt1TJ2-t-JoQ|S_$Wqb3w;T{+(NJtd1?;-P$run~ z(MU9=qEX?xh1ga!p<-KK6(Yn(#_q@(tD*wjVAvsu5YLO@UDgfar4B5G{gIqUTiV%w|w4V#;6*wapedT}<3n`QQ^!<|D+Sxn~F<#G-wD(f)r3@qZ;k3?AUX!Ez)Nuv<`c5FM!izb~#&03jBgL}w~G zRUpKoi|9%P_;C@8LxdRICSy=k5g`^`{mck>u;}IvcZX5Y%_~p5(_QqSqPrJHM2HWK z-Jx5o8K?jcCxV%P5Q`l%Vn+gMv1eBF1nsmwLcG3xPzDiq=t0g$)CKNvZ1G_@HaZu_ z#v!pgBpn-w2v>v}q#$t?Z&g?>DM~Cl0@0SnBJaEflvwo62=D~2 z6n(Oy57xFzv9^O_cW||fgi!Q?8g>=CQIU7v0!l3Uihfk|^&9|{SoF^baLuk11F~WO z*3hq5!$Gk-Xk#ED6uUvOyNiKTz-}z;WI&0<9%2v`c@He2#0N(1z&wnTqQqiQvD^b< zcR=M;cqj%!nR|-8sDK3=mI)}a*jo&yVsGF5fD(%#Vjn6Xh!yA7Ib?|#Duz)pv~ayh z3>PD)81Cyqlz4RPMps6O1?)z`wIyJ}Vqdqv8$|{9H1a617%BFn0z8{2n1~YZ7rFgF zFjJIR?B~lxlz3$9Mpibs(j3yoaFR5Mw1fECz>Pwlf^QZD4iI87DkDZAyZ6ru@P@*= zPwZ2H5R1{`04l&YiUc4+yl>?8tsvk4PXHpsBVspVvjvTc!9~^&kKOR9kUs%VZE>JD zh>8O}{{bTw2a7|fIN0+SFk*42fZ=#(;rc9bxEMpl;l6Ohh=;{)SQUj+F~+waFk&$_ zBgSI;$7RL13XE8Q2Nlf&#E6HwecX`Pr75wiz=-$3S$zmH^^jt#2FK1vE>{MpLvawa zYP^_0#du!PS00#~V8DPX>vY0}}WZwW-D~TgA0=!!* z#nh~rS_4Kb^8O>lhzG^4$`sZP+8sJrtcGF&e5MJQuBUlo5hLEi4RpK5ZjX&I;(_=c zfKZ{B4xbqUY$n))H5{l0j9APPvjrGov#=zO5f2dMu7BhP%KAlR2=Wi1&mlM&4{H~?kQPuiq}+&eftq3?iRalHFRPR%c}A7aGfG@xRc>q5mczghu| zSezx!cAdpJRGj6Th8S_D*mbHbKvejAYk>EDE6x??xsI*_73Wr9#NvD^&i4}wAj0AT z*WT?w#RU}@u~;rHq++?R0x{z4W4C?f38ad6L@EGh!qJE*al6>H+iZ;=xb`^p?0_;0 zUNRg-fD?-q;vywsJg_zfk<(i*tOYgs;B^0VPVDD zI(DsVtSfXKu^k;ykYGxr;vC;|fEJ5O#bvIQ+l~tG{^ikPak*>hT2OJhuLjZL=CNyD z3A_kgODwVlmUfv}j))dF6IX~UBiAgi9IHf&Mc#1;XtB6TTusGQo|TULBCZkFQgMwR zJAf98>oVdxl-KLC;`;vxEv{^Q764Zt)`4iTxYjok(c-e$!T150-ITwEimN?ofEJ4z zGU5g#?Z&LQk$g}iT3j6=Woi6L&FHX?Oqm8xWAw#b_&**4UmZ?dxz-7=BW5Q2Hx-cR z_0NN<{8VKoAvP?oB(+?rxJld`ISj;3v0-sj1vV^h3B@g-6>fEaP~7TS1lX{+EhE4o zxl-Jo6_7cGq}Z^=HUG^}o)UM6J0pi_!&7Wn+>ySRV#BhQ1K6WP+zHPKu~OU>IRVe5 z*sxgXp95@I+?^43V+E_SVpSz@sqtcu+h<1#B)u`wV_uBk{1?CU%X|&211%ICK1jG38^&luzielT@w97NX3)I=Fr$tlI=w3teNFg=2tWbD1970&xmKK zc*av(moV|1c%F*qJhgR66Y+w0kqYoOqQ&2sG;siu)~lcve0)f4U4ScN@lxaF=Zl>Z#x6|FEiagyX(;zv(Z0Ck(#nhlAvNEApI6|P8qF1ESU9;#do#mn{T0Oy_f z$^JmaPu>!$OFE06#V_`I@hcTSdnZ#}u&93%zfFCGq!w%^6}yBdq9;&(4V;Pw%J zWCS|X#GhI5C#=)cAX6%S@ocP5O2uEHfW1TFZ}ATm-~dA-vpy)ae>VR#WrV3rK+*Hng{XmA4AuVVYvhRpjKnfDDa zPl8cLf7I`&g2{(%~5*)OQ9<%w-dN@Z_r5+hP>E$dRbwI5g<#_4B~{R{?HI`_!BzFbDQ z{WP|p)<7_o6&^lf*Tr^S4RnO|3uMjrC|BT3#Z`ZE(%F6@BN<2blj;mx8ToE+PFl!% z8CegyUDB+it0TElMOSnAvSHBtlTDV)!C20VvzNrybom~**LNvLV2lGCmZ<}+mN>Q zgIX3eYl&s$D>7M_$6 zK1ymT!QC|l1oAp^qb!wWRF)Q$8nJK6X7-KPzL^)MP41YM&7iR6_H`pyi ztC5n>K85Ug0ol_YyTEJNN9As^Z)6{>R?F_@yB@V{zl`jMUEe<|`;#*^$mXzRx^-&0 z1|Oel;my^qJ}bl~v@7iEvyaFDa`(tS0(|w_bwE+O4h$vuYUCdFVJh?f9@MUbG7>yI zE9IV9xo1JUK8)IRcPQ^6xtH8KvJau|!^1e_UY-}IT_3DvA4KiCH$3-%94v=K_5pa# zYuCa4In=KEWaK_r!O*N6T3Ndefj94$!|Z*Ly&r2xwQJtxg4*@o$lhB?yWWR=_#%8s z4WHq11eL>!*6TfXmAyN#_n=~3guN+Aw_=`}x-b8Md`^iyM?pIJ~#NH+M zw<}|N7ik1X?1A-~9xg++hFlcs>1Uw?kB=N}@1zoZJO#PCBer*JI0o-T0#~AtjVfr> z(ei*$9sutjC=a4C@1#Mkdayi%N=Tkp(5kn~L+x#`y?wK_>Y-5RVfI!k5A#H!R=p** zK2CN$WBOJk>NX^*=y|a>$M)tL)m|vU41sexRj_cjn6lRL=KWv<#MdS48#-7&~dWh+N=t2T98801bHHr`Q2`v$u9CFc`}tJ z`2r!kmpwnW=cB82gVPJO0&X8wPd4?ZNkR41e%gAM@HqXk+v!KoLO!%B_&!O^cuQR%l9pyRl zTq@7;I-@(;(ViVy@QdXwFYt!pjMj~Gw`axHM-Eq`*6caR+4GRICl)!oEVj$4U_@vy zz^8A-r(p*)T3vm~XnUqSPo5vyGpn__&hu^TOZv$RGV%g!H zvT1H-OnoE4F9-nxkkDqJyeO0xL04UDq5m)TP3=zx$V)O3+;l7DrCAB8mY@g2LPT|m zTmj{sCNGnhNA@)6J8z9$=3m@{46>)zvZtaob~!wEio8Nz8QD|dId6?!;h)=+43<}A zls8JSFVanMz#BsB5_z*- z99th64H{zJj489{`SD6YKkS!Y`auiZ(c~=>OrZQ8Ieh)N*d9mVY|qGtsHPBd{`b^L zA#a73ZnMWy3BIC&F}EnTi#9dx?6KI;#VEu#6|B00n5jR~dxVk}Kt1 zRD#FI7aZ7QVtdRc3a0X|!gItfjP1fyr@`2(P){*j6x3lT?}X~^maC||+plnIgDrNC zyw@IW!6dlHYuMVPo}Dl6vq!~tehM^WSrvI4B>0Ks{T6Ht@Dt(6t`69t56B0pe85uz zLFIN{Z0A+OKPtiM$JUjQt?b;`&fP@oLVF~#?I>j1y#*_7qE>8dZj1<;FrEwJ8DIO+@TVW9PYMnx1^WZO2$ZT+9 z;D(!G0`O@bM-Am8K>HK&Nh+TxSfCB%Q}Ssl!EuEUetpuw&Z%V~1cu6|i@iHLwzCPI zl#b09H*?;Mxi}bL^P5~PVP(JC7q$%%@>%&DmCyRl+y>U!v*h!3W^89|_Nw4{DD(w8 zgUT0t^$;^}r^j~sCc6nN%g{oHQu$nw;Ayd)R-^qMN^p?L7v)P-g2xLdO|)TOmH_m; z>{|d9tDP#>*dt;)bu%aYHBjWMb_$iRdTJosteqU&$(y7f7ImRL0_lIHNdKhRPD+j3 z!dObpi+Xs4n#0=`FF{qW*@;xXMuL$*{dQ!ee4WbIy|lI?L**Nxd;=bOQ?8}*P2a?J zFrmIB-=^{{KZM$m?(!Y^E|q!bQajRBz9-+O68tte#M+V0@&oxHl^+zY+slvS$5ejg zsf8u7oeF}U+9Xn2 z+r8|bRBi2Ta=cSlMO4-GHu=^7m<)n{Fyzv8yo&rfzBbv~?xDa7v#%n6(8^aQFO(rfNM0)qvOzNO`!ar4&`Qd?`?>s#jmt z``^<2zj5iV06bJwWvHTFs$uh=s;?SQRo}~E1JcCySJ}w+M=33zKancPmWcs;4av5u zq3vh;Qq|DQH{RJsHKJ-8FW=jM39?&cck^$~q6&O;D8&$2Vt0-0u2o5KKa}FWD8&tm zL$^V*9~0Sx{X)V%sB~SaDNI>M&20 z*9Hmj)V9!atxBl^lpL+HR;05kQ_ZM?v%9e6tze4pu9~YBk?me>%fW|;Mr|w7+IEX< zw|vVX)zz#L1$*yoSJhH&7ul{AEpO>xK=(kG$abmJa@cogJF8ZA>4vnCW zk?mN~@=nuY4 z7pj22U}`|_xtXe~>So*7wp4ZXCQ=`=yXsC=-VND@46tof58FDnZPGmh8*J-TJ)p=P zZ7Zr^vlU9=u3%Gb7u)T&oI2YI=hxQQui$SS3S|u-s9tJksvrp` zis@i7*|xMT6bw4dgPd-uu4-GSZ2=Ra+6Ba`x$3R@M7BAIQM#>D_4W)OM)tMMB8$0y z(`}uq4?J9^c2%I2%HU?YtyAsln+W^UY-wyuYm|Z#wHp+pRbQ(jtD%^5Tc_&lw{;#! z#;SfLsvkTeReviYEAbJK466G3nhqj|TOM1!S<+Kt1vJxw6++c|-cJ@=mPT@;uvN+t zNvcTvr*`rT8ASF}1L~^*|C`MJ8z*zy4kypHFy0izA*kKeK&rs{LzOTq=&JTmgKSd; z=I9>Yo}NYK+a_u+yKQWnY`jiVdqEL<+s0Jw?X~7?GFJ^&L#P_;rFb@(V;jY`(H5%& zs)qOy0H?9r#1@VMf>`)X8KR+Wj0yx|o~Z(dH3kv9@LIwNq)KE2ys-b9*1Y{vu zXd9~GYD8cg5-`Sx1H?173>OIq8R6tH6SFjyO@Uv_^AOSwWsqJKbo35oV*qf1nC2N} zM@=XjH)e)^59f8fI|nc*C}Q%2vh{}B`Y4ndfl7VftlF2rnbr^r3kmqsfGdwBVR+Sa zxPwVk5X8n%EIh^;@A?q=nE+$^#E_U=1rMt$U{!dHX;d&g%OBQ^q4-CoNR>Y-VEy_g z!n-q})WWm=*t-H1lhe0mrR7hA-+etka2N5i3MxW147fW|?MKzfB6qWDl-fVAS>*00 zFr*q)h1P)vhn3O($dA!kH5!~jn~BPWYCov+0CgZ$;5SDDW+6FN9i$GX>L9Pa7LsFZ zgIcx$38^~R%Md(e>&Lb}*$`z@;Br@os6(kb#20oPS*i|Ghf|f`yLcQq$!63TOJkea zT$D|L>syVr^{4^|HO`BR$r2mKHm*U0>!Ao!6yd{*WJj@$YJ^Kd1@3+|PK~E(oNvb| z(p#DhbnNV`|E2|xtdEAxYPah6>6S3lB#)y z>r2#8YCcs*d777#3vKP#*4`|dsREZfn!*>7i`9aRT7Xi0bXFY=LS9DIkvKH!kW0wr zYN4%VK`Iw|ECBBuqZUzhjIZ<(a;Xhs8*C`0R4wx5!;Vup-5Mf|3+P)dROK*|r~-#O zQg8*iS{<8F$07yCWz}&&0a&neeEHXqYt6s0`L{-KqH0z}*O`A}^G~`f1c3JSdXHp^ z*VuWXngM;XSS_Jyv7b$DB+skk)d}Wr^A}a%HysG{-AJBLC#sXE0{7sc^m?T_nW~e$ zklsk{G=Hk4=8xF?S;brfo>Fy+`JJj$e5XOMjyhGHM%AgF+MCGD=C|1V_8-hOc_-`5 z8(9Ivnd~o_=V^)zz)ag{6?i;g;JZyeZXPBR3^Gg+tIRhGVrum5~ z@X4Y?-b3zJ%hXv^fx{L@%{}B^^J8p&tYKY4)mi@ed&zw!iA}Our2mAZ|BR%c;GxE+ z$?DMj4bo)(fjfBf=cse3I>$qeFOZkjdFp(szz>VWzCd0yHa2!+ z$vxl8<%{GcV`>=yM5#L0zXPwCTx@b1z7raUBtU?SxHlsM&K9gmF364?Q27IEj)Iex}GZVucEU2 znEa-0P&ZO_14?QL*FTwW)J^K<$b3^+N==(NWBnZJ>FEXPCK7f_-~Y^ft!|0T*Pw_z z@|gFq!hTcpRcyZ6Oc z-{t|T?6#tpJ!+aVUjMyJDZ4OKkcX*LB#F}-HSqCr#W+laR7A59W z91}Mdng2;_K1r9pXc%Hs3#h!;Hb*ioc`F+@|rRw2yU^HK2s)Y9)N1uiWL~RQ1w$|Zj#3ennpf4ck->cDew04z zTcZMP*2HGbW~<<5VBEfR|92J@Etar>OFrg_lDysTb`%**f>uY!HxK+q~^ZC;Aa zOIytL67@V(_@a8zK(Q}Ev0f>^m=5k>`(OtHggjqKDZhY>EXGTi=VJ3*m5itANncEp zps9MPzIy3@I^w@lM+^iV@v?e_DhMQjm0-{<=w_ZZ&zRMLfh{h9c?Q2$qZRoIeAXBk zXKPXqH9XliO{c2uva*QtUK57Z^yg6`(2*gUlf;d#nK7vh)^>n*<)N(g z5iD;}e~1?KM_Khz8bF1R5N7rDpc4XB80UytgE0@pjP#@~A1~>FtIBXw8Gu|^!Uo_{ zsNM(KKUSYm^|80A2+68->Qk!Lc^jO7cl|TZ&iygXRIMV52hHvT(=T zuf9}YMdp4`q?`8Jed(0|)=E=ePR`G}OK7YxPZJ?uB0Ve!H*z3y?~{+!L95 z;Dw^!4)!{mRq9)FcVt$<3*K+{t$(35sblVn%w2Fl_1l@dvCaqa>jCUNh^#@Qt}e-# zm9bfwF3!{5MzxNpBjg~!9v_&GPNM2l{|0vKow2!-wChB+!AA-Jf5A*$|0cfe{a~K} zkH1sjQ}vzaG5TYFP&ul8@bRY&Nh5PdXzoDT^1&`x)9tajoz&|@YR{T7zMRw^w&#HI zP<;<&8D*(5zN{t$@`S2{D(A~;LYTQNG`C?{Ns;PXV{CQZ$Mg_h0=ah zuq6J`mj*i()X(Y{svx`s;udi4ytySbw_s`c7!#!I=Gfd^Rd})b3CjCb{YKTVzPx7O zYH>SN%-R8AWK_H6yQvtN`r!Tz~X{Y{H|4{X} zFTE9MV{Qn|4On_Hz{Ff1o9q4D48e=jCV-1_%9v^C?zjd%k>I}RoxxMe=Z5MpsN-J^ z1wfbyuH3dK9d)2Xssmrg_N2YJE;P6UMTf-}TpOF3Qp1ND)Q7I6Yg3)yIo*lur0eJs zs_Xc%)rst=w=&n5tEt|~k1e=kuF_lUx{E-@EV z4dDx@PT-EYNH^5mMCPJuo7~X107AXYipZ>})Z}fT$rtKIW_e^TtY|VsIUr!S3+Zhx zhzw>7_u64Ow)PVIx)_@b@eTMG1iI_S8QmC^u--PSw}t440iZw!Kx&O4u(3Kl91&Vp zgP#&A)g2y{K*P7~df>L#8$gUAHUG^d(*?hGPhw9t}jQMf)x zD-8@(h3oxwsV<`$b|NG929e>qnK{p#OLa5PJ-B1e(am*>$edFx_nP}wg5%Mg9htM& zSH>Db3Cvl#rQR+wX91T|Wvug|1Q6n8mPKaS`pQ^CD1kXsw=!o$=FAFq=R*kwlOg8x z$edom?lX|n=i%46$nG-F!Qo_-IW0D)ZIM#JvpmAXw_geZQ z!JTVPjm@d4&=$~yRK3^3s|xL|d9f2uiOnfhE%J3!=(@JL9o21-^#M$z6U|b+z1|@( zO9`o`wVocV8vC{>Q6~NSrVo!IoX_KP7KV+*u5v=7wk6(bw~Jg z(w(V>$qc=o6NBS*7v0sIV2-D{3ra5BBlFA>-OVhH&6175TMaP^y1O}!>h2!7nM7vm z9(qTrdwAq#I+<;bjm)tiX6X)Qy<@tbg4Rqoi*(P(EJ8_!VM%pQ-`!KmG;>UBj@h!w z+#H8S;9`{At{wuM9~`T9(ja!=%SSKhvB4s}bEtO)f_KrqsfIuZ2&jZJw=dIu^sZ(h z)qVWvUqa5;yXn4E@8+Adgq*AU>Hbvr^G#Yt&NW9z=4c@N$T8CfQ{BJt+%i2t?@sjq z-^8V4nOUF*MrHvve%h2NR1fsS<1})n-Xo)7ckxO+D60p-5qiVOp3tx5RPXLzUP6|d z`FhXDU=nwDc_P(&dj6b5PBury=BO>=57iKEfyNd5m?L9zmy<{IU_Hdlp?a`q>s4fx-bW9m8vM|> zOY%WXnH`zg6>J?|c`+F`^#*dgnWaZYW>y7TM|!s2 zOm5TrW%Pc?)=^nK3ij>n2TaW~c3=PcRpbUUQ|}*{nH7u$-z&1_I&!_45t|uX$k?Gp z#!ipT^o^`Js$u_jfwj}jRC7dRrd7*Ykk-%~fvg2fC)5y6phxQis2=TE`zZNPAE*y9 zAWz`4g-6H}hAF8t zT<1t)4vWlT6&(Q1TK`;5&(Jfe29F`i_E#il4%M?FbExMSbTRlJ(d_w_{GexN^la>a zIaxhtgAUjmI-uhGXR5*Xi^Z)YUztNR4CO;AI-uOM@C)*#IXE^4Z(#?3>$#vr4vNh| zHLeY)o>FA}f#v`+Ix+`V%lZS5^`nvXha>C3^RDOWc~sB!tp6ua`bd40*`MkoQ`Q4Y z-$>8b3#gu-vJ|cx>Z3Ji^P^MN2brLu85NmP6|7%acrK%l(Tk`)CgoMIRgf|JX_%@o zBevJp$EK_gqJZk-GWs}V{o<@%OzOcl$QdC2$a0YOMZSO_*vgF5OCmF}g4s(_c46j3 zvu|wn-9l!A^Sr?95wRIj#lnv2ql)YuZibnmkr`esdtvuLXoeztaTkLIpT9m{pFs8T zDSHDQ^wuZplgvI;pXk}!Ea;|B)=Q~A*|V)#&_$o3Po?@4&)yC}7c(R>Ln_#NYT>yK z`ZRqy)u(yxv<^C$!5R$F!4>R1!?U+t&|aUJ(Ptuimu2-bFzAb!m@1fjx-X^~fUSG$ zvm (VP6Ox`YNW%i2AUR%iIr9~$18Jj&*o3xOWEnSP&E1Z0a>rkpsDl&YK*~7r> zKB!uT?|}>le}7>1L59O7X??anhw8IE!}|n>=yUaX2CRm2J;VD3BlY?E0;zAbP6HFZK-ID;T0L z$>>Xv;g@FhrKC|MU0%WRi+n+SgFQ??4U5r!6)g8Y*ENo@mz!OvhE2a<@&$*2C3uCt((Fw26`tv1 zg1P!C4eNXGxqw~{#sqWpHTqhr!P5r%JD3s7F})(wtAgp^NcPXo(AVkfsRn;CDBNID zFvIMmZ-@-Wta~MLgJ=2?!E}9NMuS6jrM@YvZ-Qh&Lt*>mTv!(1_rPK(8P(uX#lpq} zlT1$yuIQc>jKA5-`h;Mj*)cXdZXx5ZE;7DHY8oeR@uchk*ujSPmtZz>0R zV1Ve*bOp-I&iLCdXpHwtn-7TSLVZhpeM^AxQ2*CIko`B z+x^H1Gv=0W`9a!s9-g}Tr9=CFS!mUNc!Kt!-QR)|Ha!LcKhni)vlsm*wd0fU)w-rO<<14k=PkNx9Z!dzBOH%1}6k3 zm@cNX=@ghQ_z;dY1A7`meH(mk*LP5Td-2JRrh{o8n2z{R2mES}Pu>BaJM~Jcef$BG zxm4e!@1`2!4*)BL>yyk5q1geY@$TXX*giJf7rYy(qTdRlN>Z#*L*Rg3rSGA76{!RE zNN`GUufEr`)A#B7O_1D3-`en3BH+L+cH=8p3bYw8{-xK3KkHL+>O{O$9rA1<%^2A&lTxWD_bPdE%4ZdG!KaLo^T0cYe zYC=F|1h)jYQvHlC>*nAVqhh0~?jzF%9yhHad#`C%B;!7>Yflf(FtU~bxQS|r#Q^j& zI3qa62>q<#krAN7HhJuve%9B1MsTKKv4NbIok+b++XJEDNJm?g!+YTKoPM5a@EF6Q zEVwUtP`{vGq&n{>zAw1nG>uKuDjP&KxP1%OUX$1~si|W9JXH6RewpetRdN_S6g*_M zHH}T9z(DMGU?2)SFpZF~m*Mk@UPCpw0FkhVg2(i$`ZcOw^#kOg;1RP;XtqJw@a{kC z7}GE|4XdOz)N7!`*Yz7zzwQUf<3UcpX|j5)e#-!c{H7luuLR%dxAi-wz5$%sd-Q@= zf_Dwo@0xnCfwan)d;*}Kio6RNJa+m$6I1=3m&rB3TK&HMfa>?XOuibdHIe=>GEs$0 zf;SHM7Q7L>Y3jzNZc!LM@PAknylS?N&DJ%V8KH@Bh(PEu)$e#teGq)1Khhsl{gEf< zgWyyBiC#zbC!U-SgHO#?8bYeJsvzf6U+X8qI#Uvxk|H_l{2x9DJ~VY=Q>R99s0Pnp zVUT>LKd1ULKS(|c;CJsT3qB1#Gqqz=yXt;2^-%^gI7qTZLe~00@>KA&sa4C=!a?$u zA0$r)&zn$xVS>nn)eaKa(vCcTI#>*`$PQkui^v2>NduI|H{kQ7{)*}^J&#S0 z=&$uRRD)L$3pIhw{Tt{0t+Gi}f0I6i0-F0L&izw!)%q)_@LT;I)o?5+z@fp9!H>DW zbARRj400IenfnXB{zTHi4XD4@KT!R>C+)}JSDn)!ui*T{ndHad=iDD*?hlj@Q>5ef zIQM&%)Q0*8DA8(1we?5|)I!=%4j3xnFWWQ~h&#)+XHB zLI0|MqZ&MRy-6*&ZmfUTe^C89wxSMPXZ4@CpK?D^{U^!^N$>on|E3yTWoU`j3$wXI z{}bh)mc0J{C++&Me%K)AYULcMMfKmQkipCK^uMLhE^x2m%Ugx@a<(*xa<=etDLC4o zf5Iq?a|ZrZ2vjL>2LDhJZk5Z$xm*?N)FAg0GWkbj+#jBXY}lwY%#?ziwz9NVwiM<9 zs((u-(XeUQCig>W?cDcq?uU(aL@BtkO6%mlqos9xyII(>w4`(^T3X^sFAZDfzAfE4 z%6(fwy7$6`&BGSCZ))YhMNLb$^6h3}X=&Zkh?ds%FY~Z8_jPF;4=b6=D;h;nJDCz=4I4SYRa!*03HV8O)iRv>1-lL+q~qLg6;dw-J}KQM_i>cNq|BR~X-mOCgxZ6@g1>Vg#kr5FpgzofjCKDCG-?OE z-l()OEp6oa*e~3@blcJD#t-g%G?RCek`90 zX~ffuVR!+;3PqLWUZ_kjQ0#z45Gt&6 ztHHlYc(v*MqV!*3CPbz8NLw(!zQk($8izV)nHtqq(_n1{WWMdRt9K19RoA}8t)cnW z>ha}qLAWYG?w)mdd#0`QxY&uu9UG|qa+JKBE@Z{(I=CfkmZWS_I=yB(%i+~fdNq#b zF+=bw6Kl}9bKHf;ojsSfU@elDk{6Q~g5)J)&==|U0&!^o9q;t{K&36*J2h%$v7j#ZnZD zt%&f)<37F_S=J_bB1)e4mx_wxtic?j?!N~)a4FwZ~;(^&w?gHiI}zcz9Q6!JjaKe<0lX!GPnRnu#D+}}468$TrX zg~@%O88HWtDvA??mYqZ4gVVfIa%XZ!a(j^6N!)%1-EK$9 zARc35XiAR1Mk#Nl+j2@d2-o0v2#?|LB{}{8dpI5%599GrYF7G}+>+d! z+!Q6Zq>3q#uq+K(!)^zR?@o{7D1vS5ywXf^Gl6gu@ig4R+{jq#cm(FkeMMTf4^>>TORDBn)==xR@ko;C zqjE9!5db9?K`!~FwS_$)DePcv7r+*x8S59qB5#9?o(P#nrQ>9TObo)uqvJ6=9$gr5 za`D)B9FNEPAR0t8#^d7&JRVQYUI(pi6;DiVNUrDcM9(&OlUx^1iYJH3bzqxjBO2p6 ze=rg5+Az7caS%;B8612~yj#3`m|O!6PJ?LT-8=^)qA|HTOs;MmL=*3hmsiD8k}JdH zD(W|oxICWXGmwnCB22Ep`!r@LxsvL?;)y#FJl@+w(4MWA zTpT4A|2GJdONgnLQE!27I^HL_h{yZ*c#Ms}-TTHc z@qY1K9>W>ypNGWrVvH^5-TrxpxIC`lF`TacdF!|`-k-;nh3B4eRb0*ED!)So!WrY5 z;us#tk%(3j|U3g6(wh_5=~H?oK4B#2Of#0_hfzI#l`Vr6nAF4 zBsn8W&P>lUY8*eA!dT}^L>yvrdX${LmY(zCLUQ{n?XHu|z{lT)JPlz*L|7bmAuw)wt}9oXRbpyK!-)NyiraB@ez*(^>Fz7`}G((MAuJ~Q=1;k@y^lB2@pC`cR%KFY+U=r4yS zNAeghTpGUiVf!RUB!?%51<4VV`Ea@&M!gatUpz)=28;#hd^$cNMy?}#u?PT8mWBz| zD~FXO11+fj0z8>FBFCpV~H=}DrO=%BuWnXPx67sQ@!BC0T%JmZQ`T< z#~;+(vXuXK{Xxk^G&~H!bxeFLkB{+u3zkX_P7X>A43dM1We=j;ft2!CT*t-7^Y}Qg zc0Ix#k57nC{u?vLsm?B?qLNP&TMtENsxZGRYF^1&gT{V5{jpk&OlO;*;W& zlST0Hl|?K#E{(M(xA<-l<`rVNaHMX=E&> z!c1S(wa+nDZ*(B|Za9|K^3s zye29k9OKE{_|jy*Fqw-CUM0NLXP~LxoG_V#_g*F3k2q?7x>XXj5q3drwm#c9nH?pw z*Fq&cufUirnH43o{*%DX#0U?GFH0b|FY{{G=3ukS<12WK&<0{V70ivV%)|&_h_8yT z<}rc~h!l$Tim!>U<#D>F!|hjec+?-Rq{}_$DNo8sD7k z8zvM(N4^Fg-|WjHy=$K^p%Aw!>=|90>`SxkX@u)*!8QRJgVE}iWbb4z9^cY{%RQrH z&r}njBQ&R$&M85+43fR+wik(=t8p!lZ{;!E!Gw{m*zowa_;w!O=2>qmHZ<8InG)X- zCfNIS4H!W*TXBqi$CKUTJL9{;WOr&oMaeuK-|1V>hxJQ#3lj=aqan69z6*&b$9E@_ z!X%AGt188ae7DEQHf&&gPjP$?l1z;6jWOY#Ncqx1`(EEVEWJo3M9GAeTUQ+4hg{?1 z`;&2DGM;i_3c}<2eXgC@&dJy)8T+63t2h})*q%h#zP$mrW1?hCYKfh{B%SWCb>}Zh zC%&2ZR-pBP_(2{&;L*4X+dmndjEWx$lhJEL<0wMoLukOr_~H1GFrf%AkH&{R8nFZ- z84)HUJQ~4Rk09}`@uM*;GB~oyujh>)^$O4!Od1}KpWyN1sX-jZ#@%@QMB&@y_{sPw z9>W#g8zOijo1E+tCcD%X%;TpD=_bZc$ItNiX|F_$g=#lEOlTKcPmgCjM#iwQ$*?FH zwpxr7$5{BB42_>nhJ*=rAFJbkIE_hr-JQ*ipDT`^Lz2Pq^YIH|Lg8GV|DX5Go&t?< zP?%737TJi4V=M(t2F5SOFNMiKDlaASi$3wbY>MTokS~pGk6-moC}p#fouXu?RVFt(6ZwZwe|ZqsYw_zme$5lMid~TGnDmd|2ou^j zw0Viqp9uQ~D&HY~Gkz;fXoFBs*f%}UHEcn$eV9=6m6sTBCMVm)Z^!S12?biE3$S78SEK_T72 z@rUt8JpRxVb_qK;*(OYA!%Vc!9medCW4m>T<1*0dXc>%9$)HB&C{yhF7OlW6NPgr<@ zDepx`y5OZJZsG}Z8M`k2F8-d!-+AIP0$G;+pj(>}P4-*RL@x=YjH~R*5bE3jT;k_sB z??^1;KjJ^bg!bR`#P!Znb}PFh{wo{*Ma2C(7yrFd@OP8w`{EeeeveA`C1zQ;N2}w^27qQxK;?r`4yf8p2Vg_n_mL<_M_m~4cXDGLbreTmG^v)4tj zSeJ`p&jPQp*ST1?@a;9xQnca%4qxiuudvsW4Z~!^x`MfARY>=W2t~vNT(}51V=u5* zk`7_gfzlBR2=DVnT`wdXLO%!jo`(C zBT0La6>Y+#J(8p>Ah0-*n*AnwCutWZ?eIQj0fDubNlvsCxiHC5c_g?+Tc7xS_K|3p z745(RqJ2)lI=8x@-C~hL8EwUS2`X%hGE(A;^*r%EWnU!OD9NscO{NWzeLav}(6zqU zfQ$7#*}n@mN_f&*0AGBKWN%Gm?*MQjv7y)~Od@K3O7;zXlYU@7CSjO_)YO#h8zFHk zv9Z`BOj_ZkCp(;{MD}0UKVnm{85iIt66=4nf4JDJ@a=E0xrn)di<8LyC;K~r|G#Bj z!Cb&=>dW|32qC!;p6tJ}Ka+LCgo1ZG*`>$RFYMQ(I7*6}A^Ro(a~+|Q7GbguWlhPh zJlR(S?S(ED8cB*oUUUqTA|&x-_ny^&1w~0FOfq=y$=(r(1JOx92nAGLO7>1Ej)LN# zmFS!mor&ySa-s_+Fpbt86pJm8mx-=!MVP>2S4ZxyX)}V>K^yl^?O9>pvpriXWbiY!%v|n%IF(U%$eu>;K%@7!# zLie-S*8LQ^pDAlf;B8X^2VH_4#dgJFJ0$s0Y%g{Q-H%A(2@Gc%H5&^W+z+9nup3Wc zIL+MmqQBTNbl+2XDS`X@#Jz$(VyCRwi3q%NPVCH9v-+V}z;EWh69e40p`(Bt->V1s z#`Fueb4lcq)S$Qqqow;6^m0ED$-Chi=o}Ytd0{jUh6Hn+bw&&don0fz4Uv2hfTrcyiX_nVjL2GEXIooq5GK1OG!T7C!P}QB_?LYL?Zd5oS4-7Qh;JH z0p)xoCc6(q_YunRgrDr2v~MuoeGs`1{>_r?J|x0_2Esc>^Rz2cFc@~x7rV6)yZw&| z_Wwf@>`ZV&d_2U!?qUiTyOVh>gHe^a_uYH$-N3z%uH@dM8>UeiF$LEiVoxsiXh`{v zd)vJgIEspLh>8jvqMkAWUO%yy*qaOZ6Uj&Z1bbTSBlhKD9}+d`pLYe9Q>W?<4?qV?}2H>+PmjO zdFY-)|1W_xnhQh)lQlGA?L>up);+@o)_ay9E4`@{`*TrQNYPeQxu@MzTvYkmBi7bE zDXQHQp`+-R>Lt|`Rh2j{4g*zMIc_AtxPZTs+7+?Zq9!Y9NLDS#i3M0p(y-eGg;`Mm zz%1P9kjZLR7ebYB2;Q2f7jQ+=WV9pe>K=8ExQ9dcC>k|?PIbxj zlA48uaFP`(PG$5vaF0+;4^vGC;yOqi%mr3|l5uZKw!Jt+9LmKZ-txR9>m`DEtNz`;fnFPziu9*W#U zE3qyYa0?P@aGaPpIxCK*0*}dwV}L7)q?-ZsRx zdoXkl(m0c9Imh{Q*rY}rFHYbB{T!2c99_DNdqA8RI*Qz>DO)^@ixYk2eOW(oQdYnN zvRs^;6F8z2VSdxoHqerx#SHTrzW@^0EuO25@%t%v!{%p87UtGY&`5q^O*l>5R zxG;40*5l+t4-yU^6&Ga%{07U##W`^?0>`ScRBr}oTZfSgd=dTGAa{?rBy{)GW2DY^ z03WqjmKDpWh)Z+g(#9A$0~onXT+Ri|@`RC*Y+rGOxRMKu&crV`k<8s4xw}{47Z~cP zA@~zliL1G|%7eQH+sEA%y1M`a1mkX8zVMzKA_HR4(>uJO=LV0*Yb#dV>h?Ytm& zcje+bU&3TIMO>d1u+lFVH{`?(h{2lyCaB`#TAy_ko8aycH-_$x`i8 z;wH*^b57jcxS^M$p|`l(x$w)g*i`i4<>FQ@mixR@*)(@sk-Lq=1Z=~Fw%sO>z&3DTMu&}(oZFl(+uqTVSJ1g!c0Po3( zdm7qyr_VZ#&2+bjdqa0iecND6r?$;tW#Yc9xR0{lpA+{tYMZ;AfL`oN*pMlAvv?qM zH&Y3zoQ8#))Twzn{iuf$v3KIJtayx|d^{%}Ut2kSEeYTo=ypA|R+Qp$4$CEpv@lLDg|cIqrBEX&*_?&82Lqm-A> z?P5v^3%z(+U}SunrE17C?0NC5c#ex_3BT!|yGT6mE{vQ%JBU}rtKu~-UhxTw*b4D_M!?W2-Vkqc@rIWRq>H>I-sa*hPa5bV;+?E` zhY0;{PCz^3;_U{o&Wqf6=}w72e?=8dKUu4x^m7!2kBc`^`g`JiE?^KRsk1H%#RuX; zE)?Y6 zkG_^qQOj52Yc9U>wX}ia^NpzG;u~KJj+b?37dZ-*615GbpB1^Y(g=YRJ6?MXQ}hg` zvt~2mYm{q*eGFyiiUvld@#MG5- zQTDguJ1)NUWp`j3i|@q`Tzv1#?!Y#5rx&@?sq7yb%04Y}r=_t7^%(J`XX{Z?SN?Y> z|3~o?7qD{^?3=L7#n0jwE@00lLAD9o)SX)7PNni;r=~#$f9{mXowBN8n-M>uxL?I@ zTwnnb6&Euleiwgm@w+dMWW>ou?qn(sX6iz5Cq?cg*1i{OQx9%ISI&svP~@NDFD_uA zhEtSjcBuH5dHD zQFUUrd}hVg)2nBe5pw7+jcJ!KC{qh@YO6aUaz~_|)tcFJs?(lNef~%iJ;%`PXkbLP z@JNCu)*T+Y!x24D2xAZ2@s#Q~N`;ItAYehneA!BdT(e!NHoGoIwk?!U zCUfo}cOaKJmgyHTlu#zy$@W~f1KQK)Npd~8K9?{r_Xcvtu}SWL&>aA@d!()J$uo?N zlN-nmTyEgWGm4FKOG38<>B>rKs=4goN6=wVc^1nJL$?@TN@$mRxuI_`JiBgD+H3UeyTt68q@)zJD^ zTyE@vo61Vug3v7h2<7u}tgkzWsC6Kbn8K3WQo0>V#Dk%~!1Ohdt63c};9j7fw=)|g zH)$g``JX+Qo3pg+eLaboRX0EA_g^+Y7>1~jvZ{0ghb-n}A+bDWVg8h;!s4DbP_0_C z(NJtl>gG2U(CcZRzFjcoXvaFOX`6#aHMD0z-S!6V1mXtxw@9z3WCyrvxv8s)Ty@H= zsj#N*01lE^Y9Kdr`*R7$1?hqNvxRbV8FLB81@RJ&2y>N@t6Y`OW6w!dY=Nr?9c^8f zZn*6BC&mQsB6s2{nZ!T7R2)m`$|G04s=6Zn0zg7SxWG|J0dY&&c~VL3=F2>n%1hg& z>pORUJIykhr78&ZZ51LQhS+pG&@0VAv<%qg>T8x>^Rva zE4x4skX>`KE27#afef@tiq>|~$|qX6)p!mpF!iGIN}!SBPGoJEAC}>{2bb`Z6#C?T zk=rlTgi?bIrn}IDCXwxC5`JbJ`X!fn58KIT^_H?5msl%AVP_|^b7Xgk;<^`}&yYQ3 zFD`p}*x@mkTV>@|1bgqC>FAvRW>~uFLa&uOPFz+d0XRxznpRDXd zC2pOQTVr&b3a_$$?ds>$Amfvw%>ClatAjf zawY#}|C2i)bALCTOE^o2u5ih_X_1?@Dkd{-I#mhkW#sm_c9c7D39kvM8P~Ai<<4%Z z9KhwyUe~^x{UirwX8;PxR5 z48}Fm?an1)q^M!9puMByXt$dj!{sPHzQ4lWm1EsxH;GFuzyYd|>RmZbj^}cmAGcp& zZ_5dCB9{~V(D){M+f57|g`0V`3d?dxL3@S0DJQuJ4ml@LgEI8Sjgynz*wBqzqgv%X z8A$)C8xy%PD~qs<8%u4PKsU^qxE${>`ZjyVjSk)DCTi7WN;Qd6jrM5$fPLjg$=%$@ z$c-W&Xlp;}*KLpt6zzs@zt%jn5WE{9R<94T^Vd|(jLRQtMtT<+@|@dsPs2DqKwPLUgs&H>BHu@!%v-9ExYfk`tCHuQ|!iEaad1@S5? z0tM;M?I@?pX`!Qdu;#Xr;&Q5ojnemzT>o_a2PSOut09ewpAcy24_$o;sSQ+RGI=Spa(7~@a}(uZ<>R?a5@UY?WX>;^1@D~AwYfIHa> zY1uF>@TGx@M0*wf`MBu{ye~mIdXo-g_&$!&B4pYDn1(uf@6W=dorWvYa{VGZ`a;_{ z(c)oBIS~0~vMtiVa|V8sZN3LIp%6=-8)_Vlv}CQHj<02@8CA|p5s0l0BeyO7DB8mA2CDUo zTtClMWUQzv!_lKy`kqeHC!`MQeTZ#gEzig*TnpS*TrQycGKgl_!S#|0<)YB_suOCZ7$K)u z&jkbdztnXi7y1e*`k`m!dakj;Vz~(X+(Rywm=X0L$y!;7CNA~}7lD=sWaR;b@B?%5 zK%l$c`%)~IAZK@Zki?9xJ95sbDaTyuAiq^fr(jEYNJhe&ArE!XY!3AWb_%-4rCGU@ z3Op<)4}&T^2u$LSNv+DbZq&mLM!8$c!{rg7qiDU-ne%G6^nQ<^N6^!CEplC1P%Mu? zx-Rla*Ew_)s8>3tx{^zHM5sUX4*I$+LbnAZbal-f(sj`fv1e1pZH1e78E_pXF%QQ& zCJazP|KJ>Xj6BwLavixmhGlj_luZ9%pgc|<&*gC*pZ$X!T|RR86rar*ptwBV1F&N- zK%S75Cs0dI%*hi;93SgNz>we!c~VB61Q<@1r*L_)7Xd?pUFE6rG%n%6pe76nhRf5l z@^mWUjGR1!N;s{7V|C|y!#gU8G zj0&d+d*^!irT`6>$Yoq!;$`WSV7k0iUdH96h39?b7M@}Aq6`r0NW$F9S5qr8dB8-0CqgZu`WEeo!cugcfBeASn*EVx|0o|Ugt32)>iMS(~tdxd5eN3OU5 zjFd6FN5sqMS5W$!@+~gk^sT!pcu2l2-*M~6ce#Aq%jm0uYvp_LeJ#W zi#50sxP0G3cXe=$D=KnDB%iUn9W~$v0Q!OakW24$!Sl`XqpbXh8t`#We#{1}B;Wi= z5Ok(_Q_Znnx~(dm8#!$s=4o?P&Zb@>4G1yrHgld+>n#On%PgXNBi` zLl`~4fMzShc(}P`4;GJq~#K86i6CB96V`PNN4|v?26S$M~CEz z{hLeg{Rtik9<_f(_OIq^uz#Zy*?*`f!2=|}mEUpst*`5;;061q{NDZ%S%1iLQ@ab+ zHOL?A?_7FsQ1Eo{jQuULzctjA%B4pBJ^MS=^#|1jZ;<@a{>r8I24UmHZ{<(&XD;iu z>3T76_80k!{57<{tWgU8;z|Ev@P_wKe_zFQ}D&$CHr$^e{KM7 zrLM;1pPqg%1+U7#vhpvY-`_d;cY_4}-4}(e9PLk${i&g-mD*V>v9iMcDF2ZwLQCPd zUi!k^iTQW%cJKi#mkLNwf&GCisFI`wy&b%#GFg>DwW=tmidIs6?GGe{;c~Lys}^dV z&{CvsDuq=GU%im8Bga|*80M#{LtS^)cEk)?2O0#O|bAB0oWs@Qc zmMOO1Qg^FcVFKOBy2!fKNn!gd8sJ(1aMzOP2|u=Kr9!R{8BZGXPnppwQmw7EhAa4q zFy{__3Vu~wWx4WxB0T?WYa?5`7Vbl2^RWIL{9?Z;vfltq)!NJ9KQgrDK^i=}sXSKj zHK`3$2d*|q+X;`~MruQ~k^M?-%+-deJjS~swTar4t4-44@f_GMBm3oAwR6)H+Dwqi z*e{AK1Q}Nwr47OchLPG#ZO+wZK1p$=m5Q?}rUr?e5(plehzTyu*8Th$N8@0QJr5CI z-W=T>bNebxfc+eQWsOig38Ghb{|5NCo=BdW#O2$!0nzt@2#y z!gG7oQFY>~qlZ45$*C=}Y72tCb53lW> zMYes_HK)3+MnWsqz!{%L_S1hyhUx&$*iv=lDqW|*G8<=v{X})QA4m3+RVB58?Oye; zA8`c}J9L4}CYep`hmrm8-)piTA-Vk+H`NVSPt}VntX#n8kdc`!><4Nq`+j6USWTT< zA$f269#_46o!D^Fz8l$ho7S01vj)B&MUfd6v9=kDsN0O{g{zN!hpRrG@SV~9wpM+) z!UkioLu5Kg&hTL^V>4;%a2!dAu5}#&9*-qjpSYtbHM}FRWF69OLth&5X0pNA~%D2~pu{ zlutiCGr>L=+2_`vjb$t}^^Ab}ug0ozT#Y4HKqke*v-TPLbYLm8*FHlxgaK#NI9%h^ z1g^%j%p9b9fxWCIs!3d>dwWqvW}mW8+9x9WRNA(JZMhjAhfbBE=rQ9%NIcZB*(1EC6XPEaCs%J$MvcUaCyZXo?F06HuHf{5K8bgms5xpsuI6}_!Y+~azR2FU8kX`N0tTy;y|>8TOMD31Kg1h+ z1VYW_%KJ(16x(}3dru?JUB*5@417OH2`s=+^X%PR&GVT%qEFA~3T_qZ7#&$Bdsk@b zgkp-OnmK(Qr2XBLZvw7zRl!xdG{VcFJMA6z_Q2jrh2KH9+bLxQu1d8(SCw84y~18s zRSKOnT_AxwLmT8YC%JfTOQfvske<5 zh}6ufN#j1$LZn<|Z{Z5-80zd2_U6dmoFcNc0+EzHrVm~C7655)CHz$vmaGg`i`5c) z6IY0fg6a=Rvb{P$9cXW~H*l3MfuMIS?e+FLdu?Q|Un}u>9o2I!)pH=pNm}XAPaUKV z=IS6XPB&zI)gc)L4}v;WE#(S}4`93iPjpd-sl&NCEY&9P9IGSLkz5^7c-~AMrHKJt_SI2l7f``;`S#=xTvJzMkVSbbuw2cc?pe!i|tjRrEMS6 zl@$uEf^sB^StoUhI+d$aeB_!2V_vCF3+nhZlz6i;bIxDNrq9V@Dsk0jepsS^z&N=pSuDt1=bp_GR zRp)Vau5WQywxzu+vX`v}WpxW8sLAK63%EMp*VdbDZ7&V&r33}V+N%qElec8O)rIOJ zt}gWO_GG>7GIeoiml1Mk9f7*omw-J6)g@VV3BkK8r)JMLsKzZnl>wRB}mu zQ!n*dyR#nZvaGs{vRqxc+#1UKHUaYPN?Zs3A#oDVY{OHWtdg@Ah zk-d;BER-lgT6%Mpx|*x23MtyDYwQK~e6H%YHsY+EJx^V0&kZe|Y}{etAKX zZK-Zmx7m}p!cq*x2rqsiS`7pZud2iBs<<7XOE36ghMZuElA(y6v5-Do@1$= zJG{mhvCY+;>MpMCq!MwG1>4LXV~@5+h4vW2TG_&y{TDRstz5r6%pOf89YrPG)xc** zs=GsbWIdnZJQ<34A+EZ|9$_H}?`hz(d)0kh-CIb}PTg-0vrD-p>mN^v+f`9%6fQH<)g z20lB;9%v5;?LlkgGm49~2T=Bt@Jro{>tO}W_~8aVTVfa6MS)#Hi5Ams5v6v8o2SC6xlBi~`~t0&b{Twx6eQ5S!<+E&^9Lt9-( z-3mwqTJXmZ&sbPb8CZ;78M{BV(mOIx!!7D*^^C2wP#m77(&%p;TW;sud66woH!h!5 zR#Q_^F|V4n99~v4iGF1)1bfD!bgrK9V`a;RMz$>Nq-aE8V*nPR9Ro|tDr>M|Yev0- ztgqSFMkeHPOQO zd1Z6Umax{SYGnG9*7XK5ziBZ~dehgnDf;EUq20GhT~n#9X;jzixZbk+aD|mGlRy{+ zB)`qo+aBdx1XrtfG72sg^{#r4EAPQT=u3a~zWRWx_X)rZp0~Aos}I#jq20T#&#g9S zLw)FB!e(;n>QahMVj~zJd@UuYp&X^oL1Yd^1W{e&zxLs<)%ZFS z&)!R428-Uxb|q;BLReQ}X&q z7<_FWeveTKC~n;Lrjg+kA4LZ+(k_-1R$PPf=oEMIRT0J;aMl1d(VlY964#nEB}E$$ zrAlybOtt1=c&jl%MH14~kr)Hu-RHq5@&c$ITV;6P}14JoEzJ32T(ba|zL9 zF5ZZ=*V0$wF#nC(T!FM?%P*v$a+-!*Q{3DTq$`IIA>0yOi4yeN_o4Y{1M$uzeDOV{ zIa>R#p34WO9Nv^FgbAWcLrXoTsqK}3+~bJwR}DDow$#UO`r5cH)c$|3g}7`m8~pE3~wEerk|wzJCyIY2N|g2O7pD;vAxD)1F4pvyg+@;*Z-YjA%Y)lq5LODn#za z2jvi+rlW;K_iE6ZBoXDH`e@9e)I=*Pm*gWI*fS9HZJ?>A2esapQs_&>k-l^qef%g( zquKnr{!6VKn8HFe%>c&~Myc-L0+OMWn|jflx_;k)UFzixJ(aLQ@X_eJAccacI&O`< z%$H8Bp!WK4zaXUvSH8CrwLN5Bs{2+@T;0MHzBzz{4h|~tXHy8hL?kVNAS}?0Af>~B zNXnDMA_yAB0K$qNhgKfB(B5M85nLI2sZZ5sq1_95zjtSU>NTA%tgHGwt3D@9=Zl>B z0vMuRUEqU%l_JIJGnBrk`ci!r+C5Qv>V#Kcrmh?8r_oD&ol#g%tG-dSTz%s!#kLvB zWR;;xZBAKC@W-Q37`!s77HOSIxN<%%cFa)UX4SWp_Pd<=4h<#btX72r8vc*{%cum9 zd~e}0_})W8W{DrN>IZ`4$DI0+O#`#iz|crh6P^CgLBK@DVu?qw`U)7HqJC08hjt1u z?1Kt^@<43`1I+G4c6Yd<)Xzw_oBG904lQjWoJQg*tnnoa6qc;oNuiwtExRrf7rv{> zG;_7@?>OG+1SM?iL*h7tG>^rh?>UZ^ronXgv^}F|L?8tUef2zN@ z`qP_=c4R};-|8Q({`OY10c?mJ7us>eBeUn!aP^O`ct zkyR^zdd+g0H82cUfB3a8*eN4pVI2wVc$zjKK1Bz14ApJc&)Qqe45X0I^0O2cc>_n`B2ucI4_H*2NxT zY{#oxWpyipILztr{}$VFjTp1J0CFn3M@Jcrm=N7sbFN!^!|hZyQ)hJ>u6>{flFiU< zv$`$8nak-MI6}8+;D`~C9g$9eORMImE4W$9ArnTYzcQMm>~^|6*X_JzXBInBucz0y zyK=pruWdhepx!`t;2LXwM*yh(*do1QMk9bjZ)A7jdLutQ+m9`&7(g5glS4*h4YS_d?#%V(o@0*!0b?!fPIgDG<21mM9mP)6QY)^dhv_JGtnDA! z{>{RqJX)|Vum;&Rp(UTwd1_YOTF+D19lE3LWOuOJbKTK*j8oWodJEl|YwRmY=8#j^ zId(hU#cmtf?b7)@jB(9vlcBqy9bN4-N2W9bWhzYw0*#r=`gG7)`~7;m+P&v zdMkpbcTV?)N>xA17VBQf*<1I~TZgtc2^(6%q5JqQa|OFr_s!_Oz-m9c71#ZI1Fv9L z>us`n8!B+yoZc2b4vHeSTTu@|h=}c_x6|8)win7v2Mmp%4C*1*vFmNmA`7^R_4Y{D zL+@a_hn5zdqyvWb(H&U1bfX2fyEPdwx)Z5(AeP;peqnJ}V0WZn@Dpb2Xd+k(FMjTa zyzQUS{Q>rldMB=T^aA02_K4nD58!%d56%7T0lQ^rx2!Y%)Ko1f<9a|thwB>IuIX~2 zlGzn=O3F}+#)>pOP!HmIAj|BA20a>Fst4;KTo3j&KObDEhi3FpBparObBz_7u=%m) zgCf0)hG@cZYGe|6o~^K5^awpNv|YeavugIQESWtIm=}Vv0mv|b(QmFtcse}KzR;sG zdK8Kstud~Q_6>NRy`;xx^;n|AxSSpb>ued@6-+{Nr;%VI(%VSj(5!M0SSQ`aE2GDt zobh@B*W-OTFR@qk#H^l3ohRL?M*b*&+&>d%e&^)Q!d}M!k>Tm+O5z6mPTl^wg}LO8KYd^fY+l1_C40 z25JG#Bxm6wTMKElL-CECyyc17-K6w=QTlW}gX_8&iTButx+JShsPxjDE`{f-Db5R8 zv0v%GQfV_#TA78IEAy~^$Uf0Cvw9|#HY=xRVUK{ZP)q56P`ZoMIy4UuV&0RnovEjd zL=W0R&(?E7y9IiXAB*7frk?gSGkU+QhEIICo}1Hi5jZ#)l7(1+Mj;|8O?R4VkR*W$ zX1B5FRL(zbU##b#u1B0xwOe@UK{7IiAhy8mmK_M>!?s zR8EaA=QsAJUXayrkT2H@b9x~n0ln#sq%2KLON%X(I<9wZ==mzLYNeh(9Q0bG7jwNR z9U+4j!TEZLK0qI6CD%)63lN5Pkv>Qt%r*Si(ADs~t`(8R;*MUdxFAHhJ~#!8)@$lR zvicAL?9iM(^uP8xuD#m#!op6liMsGL43-JYUhdbToMiK_}M|1aVr zV>cz4y*Y_g`2O|L`WUXU$b*o$aUk`v`Z%t=%N@^~*-aw5$x28(&cnD_AoTHBeLTT< zLQbEswjvM<{PcG}+=Pxq+l z8T8X<>a)0pTb}r1|k=ehbkuFv&| z*)AApH_+$X^&{)|pa)_q=ahQpqT>fM`g~-$z^=#j1-|0#gB|sSS$!c@d{Itc1lhB; zC|S)Qk+JI$Le?jQoQLaTeF@hWdxQ)LM(SnyQm&VIgkZg-Z6De8DhE~d^H&kGqw$33e%{JM&yCMLEp&r z4IWc_2GjLT`ev?g@|fB)*vDogn_UT0H+zV%;!xj`)wd8t%X519e;eB1z}L6x+qh0w z+cB&zoM*Yd-L{S_Pj^EC3)Oq*XkQxahJ-Fw@1`3@uQK{}6my4-xW2;!RTj+FcV_jS z1k_zQeb-vB)f&d*jEx9ctqEDT;ksMj!}Z-BSrx%TeXqWc>w7)2DuOB-MizGVCUX2f z4_8&NK;NI$_Y+(X9uH@(PYrkGr8`Y|@@UpeeQC`uW-E}^m|q4FVIkLxG6 zhO3;U`H{g1`bqs1*H3y>VjZC^j%@KtsC>%9c}#G;embk4CODtT>1Woc1nDPG*RysV zuKk9J!O6kdwuOGq7DcuNQ`r9vsA_V$WgB3s@sXGr{TzyT-e$Od-UDz-aJqgWt6v}h zUd-tiLCb&Zifho)5E+oMMRZ#SsIZa{v>4Y*`em-+D2M(OTo7Df1O1AAHLw9=t@SIg zTXqDTbpuXkHKYti4>7o+eCC{43vkvob`KL<_3WoG)x}B58cy@&`n8;Xjg4T#q0Q8! z7D_TulTusFIz#NQsR@mBzO7&^?}zkVG8$fX{kndG>(?8=Wcp40R$!s=wbpM^!2pv+ zfYrm;y8*_x2*$T_`fWhsVH}5P%8>sEUGE0y;KtYQ=y$n(rye@9Lcgcq56lXJ?mgCp zX+W1AX}fyx`ZR#|K7sc^PJaN!(1SM_!2Nds`!oQEPyqd*{)p=j8vy)Af2=kI%%JL^mn&u(J1gxpqX zs?bIvHJB<9@T7^;bn?IPY2OCGKL_Ano4>gJx&iP%^*6dUFnlBJK{#XwJ5)$(p*NGo9E(@+UznWjn&yo2xRc4zxjnw=C ziDZ7J+ixVL#?Wmax>b_Af{K|@BxJwU-*NpdAs8ZuG4qr8(fkmYpODD>NVgx5Qh$f* zd;J5~-?I!tiP#71WBsH4iR&K;DxdRv{j>QlG~bhL5;1TUr4=O&QBrLg8C|*l*&~8# z`ZhA(rh%hPwzxIl5&qzWAX_tIBlIsB{R?XURRafDmkAE0_a@Q5>pudM5F`9fB7uxd z^QJEme!02m+)%2RUM*<7QJqx%gE-*NocO(}lY^9BD1UR6$%g3_8NGsK@+=>47+8UCddWb0R}TF$pHa3?DO(Y)7Ws8}zJH%b z=54yYMJeHl$Y=9ycpjT3khe#%0r|H1oO#o{!SijsQCqRD`F8pCJP&UL(MGY(=Jot~ z=C#PY{%=O@Jp38?_06k1zrODnn&r(ak$Gh`9phDk|26PN9?M<{qn%k7^Ky}SnO^0n z?hNbB`kR;X8{|8L=A|{6v-9wqP!VuF<~PjdH$<1nZ*R56WF5m3P5r%3 zedS0eT9N8ws=TA4p_@?rO=IO`b@51ot!7e~j&zN+dm8zgOoq}Fjg{CkjGGkKLn)h@ zC&+Eu)UxSQHrPEImop9!55w@i@(x)v29tQ8*b^Vs(4#otffbn-^Bdi}3aQrkOl8j;^K6lM7H0W; zN2Gfu-^n~3nrA2-?WmORJ4vDZ)k&S3-ct;*ST*7 zvSH>4^SF5|GEb~=EP9;Ed5msP(hX{6U=00oxal8IZ0CFzp6}c+3_WTdF%JjkQA+s; z-5y5DJS2F&t9gj$yEdeJ&^%!756pv<=mEOjPX#{&{h7w4Hf`aLEjRb&;R!%gb-R4G zeD{2he9wHZ{8sti`9Arr^L_LE^4sLM&2N|AKEFf0e}2dOPWhel1M&m&gYtv(L-IrO z!}7!PyX1GxkI0YAkIIkEkI9eCkIRqGPsmTqPs&fu@0Q;^KPA6Me$V_~`MvY|E*{LK8U{OtUk{C@el`FZ*I`SN^4zB0dmzA9gxugNbk_lS4$ z3&j`aZgZEp)7)WhH@BHv&2n>#x!K%gZZtQT>&G*_6*&1L3Nvn(+8 z;p7vvZ=SitTx>2f7n%#q`Q|)xt~tk?ZO$@hnlsGl<}`DvImMi8PBJH&6U_1EICHEy z#vE;qGDn&t%;DxRv(y}F4lxItgUo^E0JFp_HjB(cv%u7tYExzQHFienP#S%ea${*Z?l)#)9hiUnBC28X0n-NCYlLmycuW4nlWay z8D&PA5oTAjiy3Z)nW1Kg8Egibfo6c&+3aL?H2uvEW_z=p+16}h`kB6F>&RS^uJlbq zn`vH*)2_-GPakPgJO+=Exj2=z*ipZ-K1pkOYDjTWI&t)+;H34ksu^@x~gFIe(=AH8SU=OM=qqY61x>Ow74yB8u29yg7&LPTBnzRA5(ndRIBU zW;UffI}HbznF3h07^}If>Frr*#njY>cV`xi2>x~5e$nnP1ULc>_Rh|KBDXeyC8EroVL`Mipfx$`S#%%Oq^u2WgA7vuhYW$BE<>r)yf zFRNTo|Ni7A$!8XlpOm()@jjN3IWfgU(@i!bbAm@L?XO?Re0-sCbw=KrDy)D@8&@~+ zPG3akxI#!d**twB3Mr>)Z(WLGQ@(@dv7od*2}hE2?pc@Sn1UWeX;SMcg}_q^Dkw5X zr>jg*Mrzrqt0#*j>3pkD(@_POy^d3tj0oaQXN7b}7D}5@PHq4XHI+7K49z#|U^=2e zwiNDkZ9xihWDYMFH=EdbBXigq4C9emT7YhiCYQ(@S}2`ht9MaE=8ytorZ~VyB2{(D zm`!G#kvVv+jfjyssDSxGsZACiMCQN(eVfr6BXdBC&9d^6iqf*_)pSsMzpYu;KM$-P zls-phNm|eJ($a={29}l<0FTV#v>tqKR1Xq(!htH0S(MTPDN?GjmiRiOJpHn;p2N!L z?7yH+vVokF(?>6l7Nqr;R8%ghsYrztiw5IiQpGr0>k*lnW@iAAsrGpxXKKoDVj|A# zhz6$*H@9LeG;<3x)77ls3C(_mudA82MrIC+da-pYr&mo!`6TBM zgb$E`E))h{E~%PRS(82wr00q0b7W?vGkp+lc11bmn(09#v0qk23xBW)>4fxw*8W5W zE+mvn^0X3i)lU#vc69x-PgR-{&2t<2aas=d>;{?R)A-%5Q+}IOR-Ptloyv&eW#vA_ zjFhZ1%1Ioj-@`#;%Em32;lECAR0le2nxL)@Fs@HCEfovXODks3dYnQvZ3fZ{B&x4z zYFbvBuD&v!rfR5f-;_zx&t=u=nkd#f{fZ}F+dg&O424&g&P)Mnofa}~$S|J*OK^Iz z@PIkc02Zg;!#(F<{9o+9?v>)cez{*|C5y%tHomT`jLe=iBDYB8Vhb<2_n=W|9WO)I zsS}`6XcQ{;(wF{^cA^XJ-V|GDM{B^=sI;r?ww8xtM`m(eOR1axNMtuVC=lJw((;fRFGp>of zDl%i6-8w5WW72w?+dnljqf<OJo^sO6}(lOng*DqXebcjx5My73Ves9gl zj7WP?eI34xY<(qzNm+=@uB+~;9+_QMf4EFwhSSsnVS<4fO1B|&8%(!BbQ?&w0dzya zQeY^4$?QnC{&b_jCWFAHz-&i1gro%q!D)f%M>m9{1!il^SMuFhriJN~UsPoJurQln zgjpWEB%8yc&2dgT}AmzbUr9>J_(V@)(`wxR-i z35dH?w7Ax~-fbGFzrYJMjtz9kwq0 zm{2yeZGH*Mny#jc>C7H6TbNF!qsbd>l#xc5*lZq|u4`n(&~(8}w6d&feuyGA>`_&^ zsH&n82dT`ipx`R}wM>u52@Qq8pz89_P>{+ZcuPXl5wlgwQC2ZigoeUHVCus!jb96D zW^P+#6e|vmtSgw1LncXz`=mcQKP)t&?rX`sit3fW1}3K2B!U@orYGyV9#ap0QZ}zO z{9nt*F8i$G=a+u*QU8>+5!)C&TPzJ*xIy!s#}1n{eZL< zW0wI*>!e63X6q7?dJ>Y_vM)^=lg%HTKg93|kGvOa)o8MmG35I;S;7+HYfS6Nv~C7V zhX6~F2~8{0(yVKW%{rzOzyA3!m~`t2N@LWj$`zT_bLa*NB^Ss0A$u zH+*ez1AU{dDPn({j0y6G=9e1CXKX771|s#r&l)oZHV%9z)Evq(wJU1>iE3A*0+JG7 ziv>&qF=0$w4?ko26xIII4EmO`)&fv2Krm1F7>;cP-j4vl(l9>F0CNiCeRl zLvPuG70ph+v`Tq2WYO%g%i4fVw*o0@e+agy{l50Q{9*aSYrlxg= zPDO|0-al9SEo;;D<41aa+6|3c_F1=~1Z!`C^_yV3+OKQB${&$Gvi8fU_M5cCrY3}J zEmqI8sQn^;R8cLqDa_`N!st-@c~tv(Dpcl_SAq2qUZgEUNu% zjcMEFk7UKcsM=3!KdJq=_M_Sl!&*Ap+_&PBx>kg>AA^dtD@NJkvJ%>(q9C5r{VHn7 zMNs=8s95_Y+k8FN{^Mnzbo;bhN21@@vNkE9a60nru`{XheW>vt1pC&$U;AGE==?FY z??$zLCp|)K!BUc~eV>~CPX5@U+IOhw2uEYJZ%6-&z4ri*;@0|y$RLMSGbfPusq+cevl*g!&(n_g~u?~M{5gf!B7Z>0BLATTOJyEnb(`yI`$ zz3T?|{r=DM{-5uD$-`P2X*AN2&e3T)azE9KjW=}EXYIX#Bk6O$pkbenVSi$}pR`&p z$+`eTu693mKXN~GKXBhSTtxm24Vfa)(Zm_ZF`z=bbBtoxRAvEPMXM8HC58|J=gx^L<=OK+2Mh$T>p zgi)XS4uRo9=6Bz4Uw5~g?i;PtG~L%Vrx)FW4wP-wL%G{EA;KzKsolRlam(P0)Rt74D!Nd1pcn%XtBa z@Idiy{25=o)>+yQ1?wr}VK=Rk!w6(A$2{o1dxbS_6 zb)UB`^SkiB30RjAz@9VR=UM@S&xP7M$+`ppd)9r%ecE)NZKbB^KBMV&)b|r9*PxDb zpKb+Qm$LYn=iR5=Cu81rpKu>{A2VFKKiLBqT~h1;j4mN2fcf3W|NhHxA48UKEa<+# z2CXId?Ew6`Jr8p7K=Cg80sQ9eo~6K;Df2NlzOAIfMZDXpC|naUZrWx2|v> zGTle@_!c)eZn}@qvVNGraXIt554sPy+f4UCUA+vPSIxr8I;ciwcq!9;K&u8l*?Dzk z9bK&l5!&6RX<4+0l4M=M>SGSL_q+GG_qzAEcl#3Dt-cQKUG5fNrmu^yr+cTn+1=zj z!Z*s@=qvISyLb3zxf|T|zIpCCcddK7dz-JycanRndy9Ls?=1Hw-^K2YzH8kZe7C#T z`?k2(`5tty^*!xg<9pS;+V`G&mG2ApN}uCi;rq$=r=R)b+{^t*{_g(1{sI1>{?Yz9 z{!;%!{}O+l|6KpY{>%K=_;2&y?|;<)g#S7J>;5nOyZqe0*Z)&<ty_u!iB@ z8Y*q+nt8*$1r5`7W4br%oeIKB%bFMWrbE%ZxHm?~`K@SP+#56+x1o7)uWw89;$9c= z4T%3*kxPgc)T(ej6r-%{7sH2V=3LdbgEA0uwG>>t&F9Y zv5czKWh}F*jAfOvPGu|`L1@ZYP9p090=cN8{>b(+*44)6apnSF$tz>|y^9vG0_3fT zyp4RfhThDKLGiG5&1#L501zmhWwC-{7~c% zkH`-zE-YmQApjm(#)j+RA5q3eR5wCkWD^LiFJnjcF2nVsInW1aXlRI_CA+buQM#qk zWo%4DOJiGZXEv$&&HOH(Jf6XW0NCVn$mJhQ=7Nc ztFa}35zAy+89O$jrRgoVG^2S-eHvSusau*=#*T|+JOT*Ao4TuER_;TG+Z5dk;(b9=6w^Y}prAlHWhZ6U5Y3!Ho zCGN%6mDW}6MW%bHmI|AiMFZ|7#5P`NUF~;qxFuj+O>E;oP1iFp!r)Z5W(CZ?#O<*T z4cYO?`rM0&W4e;1xEHwRyXU#*y63oOyJxv)x@WkjyZ>-cb5C_oao4yfyC=D;-BqT0 zfu{KljkM6F>7K8-E(#(_wg#3krnq?0l;SZHP4_&l^M;|R>=f2+X7RMqb4~YLZIp{@ zQEQZg4Ued&TCeP$<8f_ebOTC1Po_B*XYbqw3sW;iJUx0N)m?7fNWJdn>?G&0Xv+ax2@-b}QU+ zcVW9_ZkfBlEp<=u4h~?cbZ!qH_n~vPKlcxR~A?9PL8X0C&ir-_Ye1&xU<}e z?$PdqxQpHKaW}d}?zp%o8*)ItoY0F(MjG=jc&G>}o)wTldQs!lCkZn#rI-K$-+sJ^-u{xJA29RI>_C!=14 z78fTW#NBn@bh7W>_C;LhE#dYalW z-nnD+G_`6#bVuuDc@X2CJ4!FchFacY92;e3bdQP_q=W87{s&2o1dUta&b9r%-L>1{ zi7Y-OI3%$45FA{H4e{&t#O&>s!^Z7{7!a;pwVUh84`?YvS6;tACWmFeQ`M#Do8nTI zwAO~yVM91bDqa%7E#pg&LV6cH2wpNJnRTU4m$6hZ)@j{}9xC>->0b8XS*VmzxDiZD zrd{+%u})_ik>LG3-Sy`my9aiZDe#a z9{Z0PJ&K+z-de_bf@?~oHwufMEMXn-q?fI;wpZRe)IuK{MU5?>&A#>q{iKZbvp0vz zit)U^et!UUxeyZ1og`=s(w!Pyyr}3YKq-D=8JpDr z%HyIyIXeoJb3&l>fLNk|IJY?v+cyE?JObkUFc7CMD3%c%Z>5|)iHLb_}r%F3y%lvPk!c>|olh#yXj z_!03X?r?XQb**)sd${Qy5#?AI@;3~)!-)?cYF+Pl5#c0YT~B=Y5Yru^$wdP@+XBz* zb78wrvaV$r?qTj=caS^K9pLtN`?-DHK5lQfms{xebbGkn-EOY!T5f@x@8-F=ZdcPi z?4WI%?qJOxuUKAJ0eu*P0Z*Gcy<*z5x_Z+c^dIov16$_32eit2_t#x(oA>rE7;c^S z?yGguD{87W(BhF84}Q#a`{*4{n{joCXVLY_dh1=Fp$xn&OVl|ko?3a5>GslWQDhBm zh)9a8MS5}5Ez~SpeeJ5ca?j7j@X{WC-&21HojQd&p+$g1%F&0s8a-O#&%0|W$n(}~ zr`@JZx0~L0LTd!dXx$-l79`mXd9ORR?s((VkX}2f@yS%J={8-fMWLlYPf6P%MSiQy zgz4t#$*zDC1xa^^s)f`Tq)azA%u(oDw@p{alL)|DDoQp zLP|m|jGFBe`nm}TgWY&H&TZ$$x_;M}up(hq!YK)7BwXUgB;4q-gxl5M30u`)>QD7Y z!b=ISsNWM@^_%)NVZZuC{j7dcKdK+p_v*X$dFtQlU+s@*KeGLC?dP^Xp?y{R6WgEO z{#tdQ{kHZGs{QR>Q~T83_FuIBx&5zdk8+hVTtvJINe4MddD1~=k`A)HETn@@BpqZS z>t=$tX=%!!^+-PZH91xi;~8!~CM0xI5EL&}0DIHB{D(uD^yG zj~X7wABU93@wWq{Tj%&=o5&&lHZ}K#>qEPq1QOE<2M^z>CazJY`nwqiul@=#w=Ht; z>d(fBZNkBu>W?OTxuJeXr@%ZfGSqLdXjCn#tC=_so=J)v9mwWpC~|b5yCn>TbDXW7 zm^2i5K#+C3qO!Uy?2)4x_nL)uh9VD$)@~dy)DQT^QutCC>U-29kk{0%u7uQ;tGzJb zj6rEreHTp{)V~kLrK^9n$)y|W0KUAkj=sDfDJ_gB@^DyD4`D>@4UMTKVZ>B>4u!*4 zt|pXia`;L$&R3Ur(Rr929xuKFwg=+L3wLhnx4$>NmPZVBV>aIg>kIup z*!kYez;gx)p?bBed$DdIezrUKy$s)2RDlT41B^RFfI<=h0{0?Q)vxH;VoFr^(|qrJ zx*cD8)=_hrXw#=h5%WhW>s87CgFeJ~_O+pg)v12O-|JL=8!zkB0FOmQT652ubsnf$ z(m~!6aEgQRl-P4^y&$d~-1|`Q`NTxSeu2L!V7n7h3w-{t*(`Am+#|uFQaRNLZ7;z+4Q>#ci!2LWV`Xj5TYh*0#J|k+MVdN zdraDF)_V@35wtI5lQf$<3DY$B4x7Y^Dd=z-{sy~2SRj^nGTL1Xp&<;*Y4+VASRUH| zvFQ;In}KnpL)g&3(P<1~=J71ug8~g)ucTS{$OIG}*E`g~R=YGiqDynUE@_E~RuNeL zKi@+SSE40YAjteclGA+hu>yzRYWVFehA^bp`W1V${Ttq5Kzkj3p9Wh z06=9_3xWalpe#}j7zQ~&Nh3)K#jP8x8r0?Y3_6D}*Qx zST{isP`gaE>!8fKPjM0iZeZ!^TeVZ|P~WJp)mQ3E^@aLeeWpHDpQw-3N9sfMfqGxP zr`}cXsJGQyrtdTOXaI)89%|Jstk8A@6t-ff9kyW4TJp}Bf)}HDuGZF6iMWhv5~>Xb@j34J7{L>mo8@UbYx)0(#59wNb^vkdDn&&-S?#Mlg93U z*v7{GfgZ%lx-|=7Q_v?RSmMmOHDi#|XC+Maez-=1kzLmqO=lpeGp2e^x4#nS7`#EY zpNV8>i0?L+Gt@hJm|&x5s&uC@4{sk_EKqOhsfT}qJ~lw7jJzWQN!E?5M!l)tFb1jD z)pqroFUNMeQFB@~!OX@|V%2=abP|vI9j7y9wjoZ|-#wPWQdfK>GJ*A#hPpHR@ zPmRyjW9m_pnLaZ~J)#~~52**$18SSPU)^W+G>5Bu)jjHNwbeY%Tx_l~Pc_d{cbT`F zcbku!FRLx)*X9m&r}?AWtTrY35`$`^x(x57HgQJcoW$c3mnEK*cuwLiiMJ)* zoA{);b}jU8$`tm<%KhYcMz8tP3j z76dFqy`fnQI7zD4kiIT&Dhx%}e`>B*J=-$ZtGuf@BM$_a>gncO?^7XOtYxnE$tWE3sV9gi zJl=%eHPvHn$wcbWMht5z6RAgNPU=qvqx>*ZT0~P1v95-C(972O)dQ@vUu{EH-H*Pu zDx#_TV7pP|0!5)l3`H(b9`j2sP#!b7wM{noE|f1pvZknOJQoQo`+V>bgA3* z_`(E2Pet^(B6XW4GYzE7^F3;yW!m>h-Fisu`7OGow%PNWquFy)-K0C%hIK&Q*rwbO zR8BjyaL3wyJ9|Tq|7|jK<;alR5V&?qI+T2HRxvN!0KPKbCIvgC62QVMaO$t`0dsB^ zzK%zU<~}gyDTO=MZ?N}+*`_wZqbC*aczuI?Ap8LANKz@OeUpjhO|jR7QmOVPodWv~ z{dJmVY}1LE2YZyUnK-aa&7x+3k?jPYei8V1D6BVwfy|!G0a1?LrJa z6yaO(m0VjZYcq?tz^pxhM`mmfO#o#RaLOFkARO@8G=;yTw&}QSc{$5+VyP>%ONDm|y za?q^sCtn8(-vpj%8lF(ohXD9=2}{-xh0Z?w2p}1X;Sz`c3;^&f{*k&}LwZ;UzQd#7 zdqfm`M?}Gw#DyRl8|i7YLlB0ja3ss2hJ%stJ&NEv%GO4KOyZs4DzXp*BmX5x0ARfV zsd2>98q_W{_M^ShqUh3uMMck+Fxx8|A6*vEZ(_z#!@opJVE5&)PcqnhrECJ^FKstS zWXF*Fm8`7;6KhEDN zsesY+R$!DG38NVVqnV8`N(GD(VP^pPL`nmHkJUrl2*HBEW(HA_@ad@x_DCt4-DH?) zdNgxFBPby;Bb1)oFq(N$qnRHyn&Vp>%?WLf29!YKR4I*TL9_9cg~vmNuM@&!AvY(8 zGvylR%CROZ2O;Xpm_~+^NOVJoC)M@pI_qZZ7Im$uZiq6CgkmlP6z+J9 zRo7Uz`V~UZ2CQ32BD&gCS8GDvmfYe~*O5eYGwYzPQdg=g)aB|jb*Z{UU92ur7pi}% z3)K0hy6T|qnCeQsA;QO$c=(#9M75{-$ba~5C(PgblMVIPs5%<`-RCGyGsR*Hn z`?Cg7qJd9ucrqT%Y3qWzs3n=@!dAHmQ~k3QCf-yRv?yksulwJYy&%cDg$?QOnmSLN ztIknptFzRZ>WmIM)#>UV9llei1ya?i>J+smkgZNuCk1+`)oNAX=)k-{WuQu}RQ0M( zov2o*+Q5Z@%K}#i)~e-!dsL084m_@^)H1a+@P6P!wL~pei#oE7sU7=v>~E;^z>s(h z`MF5xBVOtpF9m+?Y@`$dPPD9)Jt5cEkWPww3 z3fgwHhDu4>u1-E=S>U8Ylm$HBEX_r=>@TfWX^phE>fjhd5na^EgK%etA{Qr*GpwU= zkoSy2aE8`(>1sukOkpT;gYu+?<*i5!H7)4MtD8#=RUyWneedW zkQmCvdZD+?P%esQD1++Sm=_}Ty;Zw*@5Tw#kVgldK`mYmZy$qky`6mXUB;2{5uQkDi*FC9B%M#Cq- z07iXe18HnCq0*v{Jqo_y5xkuR-j6uL$KjfBS1HTJhDomHV6VCmUtpB7u4o&)AhDf! zrj;V?Vv+^~09e-_z8=UtL7dwJ>vC57^RfQ_IZnJJzP^(nxg&G+m zD4;563oEnM`c)ZiVQXm%TVSdMT4*4f=!%fy%?xFTQ2SIlZC|%BzbaKHsN+oqH<|t{ zT!oOdAw%^|1^qBi;Zgya+!{~End3Dj_vpb%zW~rHKM#tOK^p20IV>`aDrWuM{=jfA$nuipTE<@41Xr$UOl@3)A zb^6~_a}JrX%|0Z;W+=M-%Trd&YB^4Vsb*@}wHl;F&4|#)M#PO$)1#P@aC|6rY((`& z^{uI+FhRAD{k$U?K1V>-Z+q{;iM3h9g}c|$f^An^xDJ2fND!n1+`5X_OGqd2 z>lJgm(ce9xzk5S}_l5rM5B)uWzd0-qysBQ{NoWXZm{A}?tliZOjV70{lYxLKSmSL~ zOD$o?qFUNPssXVIQ7z*j)iQ}U1(J*)Bq{E=S4~w@taa9UHQ7|&s(Bv3X9pkYQAvE!h{&ol>iq87f6hal~8`MN~w3?vCn`+`g-!j$F4G5!m zX^lFQDJY7XptpC=sauyBUfL@iuQ#5ROP1D`A|eqSbd#+0%;@-=DpKRrST#nCR-@EW z>PR)xP~>P>j+YHJ4k-^)#vYM>gR`m27bub~Dt%r{+fZ^JBm9;C&s`Z6+ z;NF627#q@z@(`Vg4HF!29mNX)QvZ4!vNc`-3HdmLxJT0T^hr8i^;W&C&DNc&&{TcG zeQDF}*{6CFquh&TU^5auRS#2nE>BVKMIUKUJ+zqR)nIX+A9a#-C%RFtx~p!=R#wvT zq?1k6UBj+Q-?8ph*EpKwd3Ad)5~doe8{q9>noW?`m}a$sX+c%U`cq5>c%D8#@7rBi z_p!9@W7aw#cM0n#7(@HD++JrF-A~I{c!3y>B2X11ou%?sp0&lgOXZrXK=aM5dw%;= zJ^?9@fV2gPuBwZvx@r!!(N{d;REO$9OtYU(TljI*BFVZ7AH6{3sLm=|bxOJ_=@wJz zKrRunq72o!0RY(z0KjcCt@7qUmHR&dz$gMhR?`I$2Yp^VgC!SgUtrsc$ovJHWu31s3 zt8^Gm*_p_Cb^dB)XGpT{XNgIF%Rl8G@^|^0{8j!E>?D7dKjB`{KBoLL>f@S1HGEuC zC;3Mh`11EK@a1o90N;@0r=`tOQu}GqQ3go?X{g_Z{E14jdj*w`P4w36sHint=&a-2 z`hoNd;zs3qWE5QdXBDq?iM(y_$lD%!LueVl?JeW6m^b-jaESates68F9+2Oe^2hK_ z5F*1Kt~QMf>XQ`hMk3lxk_A(l{I~prJ| zZ)Of0!t8l*ZU{ip`+Ab~080#xko)9bxktKENg13ih2+5n!DXi07yWrXeT|>@=5H_H zt!ategOo-d>9#q4ie`w+ic-=Wdj14b-u!VYrTLTJ{U4pbaWsEUuwL$#yQ~MThvc`W zbi#P&#SHYOkMK^r6?>E5le=m5cG2wN!Xmj-?l9#}jdPK2nGvs;a)+iekv_^v)|`M5T#VYvNSGQq~HOaLe$s;&r=ffEL=CvepGAXeB$n5Pk@4 zjDAQQz!nchiU`D?2S1XZ$xp3^tw-c1rua+Ru+(-fu)rnTaWtX$HdY; z3jRxeWXg{`7F8dYT)A{53HaXG$(fY#Nn8MsWIfCh<%jYE`M!KlzAN96Z_BsjoAM3$ zy4-Hc58G_Plpm0mE0(rT7E66G<@;LFX=S^W?`ay=#&J&hu3krr5NH+t+7$~|Ax7qM z78oDOkI{KkzN2LiubqbDrtTgta&~f8`LcXTz9?Ui z&nNel&&g-yGs#CMPnA#0r{t5#$0sk5PsqpRWAf4DlatR%J}3F|)Vy>eUfUnxdPQc8MCc1m7K_muuALsQ149FsC7WxBjy z-j^~jr8?#0lrvJ!PPriE3RAwO=}>qPd1xBVMH%u{tbBb;PQHSaJ|-t$Mhe?nogrVM zQXG@>%NG&1M7{td(vG_bv{+VO6$)p_n0Eh_&r<_*R!)*9hdwJOpGAr$#V?;>Jxuv@ zl=9Y;Peo8l@H3uq-lOH`cae8w%tz zH$y?&4WW`?R-Zq2=|E^*OIeR~TdP-Bt%kT~LBF~VuNB%*O!lf;y{~F-nf8-~K9vSk z!bZTfPBr@5WQ`m^^#+FO4T9zshIFde*eGdKdthvb6>TeFR^gqHG&>_ZtIsJ0h}d(?$=RBQOb5p>i6DA&r5n01m<76*>i1?e&@L;CceItH4;+ zbxC+8D0YXrY&CU@$hh}!D%uTCO%d80soNZnHYdQ&9cpu8t8E^GHa-0ZnoGwf@aKEb zW{jsD;NFz$oMzbxz&{SlA16c$gBDMcx(W4N0CQQjdp$n~bYv(5KRxjBm5nQ~L>Ql{K^P>O%YAyNDd zEmHjT;V*{>KFPOUGRbyshv~v z&25s?o2UUzPH#lYBd0eY<&o3tnPJH5s0y9xm)GjeSuYhG>DiFipv)s-S2q$ZpI=@@ zMC(f8&8{HIwKe8MO}S#K{!dUYc3K2_c$8~Dxyxw!MaO@&15WxnkAP$ldB`O6&I+M0 z9r=Y>$Ri*@oE?C&WC2SD8OR~3fU+*A-8ED@H?npZ;qyWWpWlG+1$YJI$_^oCHxRT& zgvX6T4G3S@fbb1oA0;dj;d?b8d~dV~64p1=X1`Y3?B5jO|GEhXKY->X~fb$NC1f1I< z2{`ynb2(gTJG!Beb%>Z9`P)K^pAPW>SD>(m{ojyy}Anfhbuuks9ey8MScO`e*T zAWxBNs{wWEyN zNaO;MZiDiYm{N~il>8qd7t5NF3u1KIvpjG!X;r|gbWo3^a3%vcRb>KwGeJgDOIemC z4xYQAM;x+&m7PPxAqTVqq{1U5Vd9V*A`W>C#33KA6o5X25E%riTO)Dk&U!Qu2Rixh zaRXT`a|4A9#Gx131Si)g)MnpS+w9kjINS~5a5NEz+O((Sa#>?NV?8TD-)qB5F3KI7 zmR#|wl?ZD)UK_IlaygNSD(gAFtRgb;9FYlVB$l;_?mnsQP|rZgvQ#dSi{&CyE^YG- zQ!dfFF^)NV#x2$!Nv{*8TzpU>u&4#}PO_e5d1)`nN?9Sx({{>*X*_LT+IMNc$+Gl> z^u+Xza)B(BC&=UF{PZsA-Q~RW0dj8o2w5WM$l3BZIV*j9`Xo8ikd?rsnx*ySW#ubZ zHy$s%f>GL(6}od#V2r+JK$h#ydE*Ml*EQrqLNATXWrSWDnHM1CA#*9Ak4EMb5T0Eg z-zGAX-P=Rvc}T6Ot65=43K>J9RsG6E)#U6=rx_c9naC2a`EozU@g7rPcNqE3xAh3)YIM_ zxxkQ#gdsE1=gaBxSnGM~1v$->+6qtna@1+vfSgVkQEa{Fm&ME%uwKL!YI3TaVn`iG zrf$`8Q%-4ft^4G$w23~?QsiVgNgg97%A@53IbIgYadNC2BS*_o@+f(v94SZ0Bjj*H zPS&$ZEl+B*Wm6ubu}JH$Jg*{s`-VPCBq!>3TUVAHeNZf$a7bJ2_!e-{lto(nAp9oH zcRXRYR(g-q{zx^j9G5Mo+p*+WT@mCbD&Dav$LOJ9GD6`3+9Mf?6Cg+Hcc_e$;qgx|{W@%FEGH>gEXjg2s#x#WHm!OtX&A<)N?W zZkeHs*R|mqO3})pB3KFC#$~%AT@^?4FS>yGdJGvOwm`JeiwO zl2Mv*YQ|ZztL!3kWM`QzJ7ruevoh|KnKDDB%QTsq@mj`P8SiI&EmJb2OqM~JBs

KBW{%CAm^nRje&&+Q+RVDllVqYaGtbPtAoIG+^_g2T@6Ozo z`GhHl>E!|pid=I|)VhW|oJf(TgF}fFX*JOhq&$jv7?o-|IGC84L2c4OvTb{GkZju? zQv(%ah$8lDpokTVnp4ESsHgoEWFM_6ZQ&*=**kiz`XsE%hAhOJ9;eeYg3~c%4?Nc~ zhh=x9ba-h=HeelITG|LNEiGg{T~`589`BXUlKe7{bu?ryo)Oz+$gXI(Y*9rWtuRA& z!Sh9kU}s3!Nz6sn6*c&`%8+DVt%K#rFSC)7WLm8(tE*px7sKOa3^#Nl@0VGB|6}ztY$S)I#H#LbZo#qEy`ap4p zzkw~q4i(bBJp}#R!=!)PK)c&R(7!!ge21je9csP14qMws>}}Nt5H7;gv<0!RC9@pg z36NSL!(#vQHn-tW!Fjux-rtB1rPD8)v43XGW?6G^u}wDI0Xrv<8zIGMO45v?F9q-C z&_nQ}UG`}4b$^vx#vs1tK@CSAE{WM6I?N6Q9z@kpW;}hm8{)k`QM`Vhr;S74a>$wk zanOZ){kJq!ybJm`^t%xJa>r1*7ueiE zQ)9Fj=vePbAtG1dbP4&!;S4*}u;WPsiYJ(h3EBhnXqJsbD!ObUhJzQ5xfkD>WZ&(* zG>vAg7-v^{;Lv*0uHRDw)hFpACS!`G5T67YW9q#&rnI_gY@qYRlzK#gacrEIEdlE+g}K*@yj?8OkTlCk?l;`PH(%Oai=A-RRXbIFF}71EB(?Z zVR+zJoGPF^9xFp?kQ9r-^Y&{M|D1B>sxtkdiE1 z(IEcJd@u9U%&#(Krki;{{E_)*R*d*v{3d=Czlfi+lEhD0`Qk_MgZN&2C;pu^Fl$8C z*sS8LtALzrT}ZXCQzxKh-`nL!!PzRF-4v>TM=VU$ z8vrhZ2j*qy4PX<9P6tg+Kvd?V1&~3saV(S>SwKk$O`sl~gr~x+UcHBQgdFdC8r8e7 z^d=$?~S=%9UiwhTlxaEcM9e>G&@OL55a}v-~?8{m$_KH2$tJZ76HN`%C%!p(n z?e7+1XzN*ULiiHaNtJ7eudfe?y+BZ*tnGfG2tl_4L4`DhY!lIZVh#D`fT>)%_IoEp$b z`WaFll78AIl751E9+G|>!n9T|eia`@1IQ;nBsBei(DeNXYcAHB#?xrO7gKm%0g+3R zkqO1K`C>H&h5P?`RGmzy`fjIQ;vMm}^}6+jc*_*;wn@MO;vGWIH?24Q;!Q$N{4nu` zDc;aLep&TNWe8EmeBy0F$Je32d0lK5uZdU1E8=DGl6X;Kk*vt+n=RTIqn%*4q@68o^{>G$DSDNz4NN3I?di;!H7p8v0J>N z83_7lm~iW+ljuo!Yw%iqSp%q5p+UUVg6=@Ps26La8bG|zq8R@M8z`O^&xvQnGvaCS zlz37+As!cxb($s~?Nliq5f6)p#Dn4iu}$3HsaD+AX;r6F#l7Mlad)T7I^86;c3Lm) z5?jQbVzbyJHghz7cqmv^xi1nTJh;?GExLw?4isuiqks0DSAZlw4l!kbg zP@6E%2eK0{hgp`g*A;@K7MO_70g9j)D6^dVMBVt7nF7$}%Dytgex6Iw-ER{)t}bDQhW zCpHlU+}K2NHN+k0okz_n^aasyL##*2qw6?!;^`v9TFhJh%B48B#e9B2w*-l{ZV3vC zw_@_11B(%}3=&_vwckRP3sQ7v0jan>F*u$q1|Kw>4q6YU!Gr*6?M;S4cHjO3U_ywC z(RHc=5O)(<3Vb;=y8@9j6*5s;Z!kXOY4R|BGawmPLfD1F3G6Q5TS!97wh^WcDfpt0 z*sCQm9nB45RTmx4p{u8{g%qac;XEya<+FlCBsW7ov(PLm+Z0c?8;%R2n_Y`Hf8x1E za4$g0Be>@yCC+P;;CklnrUaMHmwN>FY@|GbOEzVX;F3+*Be-N!_6Y9jL~#ER9#M+~ z_cW?Z`ayAO6M}n6G_)d}@xYjAXFNeRXOGyP+zPQhsRd%Yx;e33g-*7rArvdyTzx)4 zDt%GcjM$!t-g(4!1yUZdrSst)v0YBj=t?$G6Gd#RiP(luf46iEKv3ND{}bCoAhuJ9 z*e=U{QY;lqtaq*V#9~t{(=r-Z$J&a@vigN(^_4>gGYT<{{OI~IIv)^AiQq1>-uH_| zL~!3Hf?H{dO1%tLF41QzG^sL?A%T^Mlus-n0{kxXiwaRL7Mh}>&HAP&_d;pZ)-OGo z6ji!KETn~c$$EYBo+VlDF+-Gz1)@}(Adb)eP|O$evUiHPc!*U*FB^iazl2GKAnUJ( z^(P>ut;B*%z^$qCO))%A}joAeK4*>lcV!Ali6f>eLm}0snC{(@GKqTT=y&1#2NWwwAZaNXU zX_Om}HlaTVL%`r%M)JEShqN&Z% zQPgGvQJe80>en*0IgSl1Tnk>PK~a^avp%qLFRtGWhUr5W^bgn=GH+e3RwVn{Tpwdh@LvPf96yC)M&5fY}(VynIkM)IL^r3nFg66rmDLfl# z!!-ItKbq&ySUb^66pEgrhv;q!NDuHuZm496!b6yA@6c}Rm~Dz48W}^)Hn+Kp?yVl4 z`<$hTZk-niyYs2S5(Oe(OuN7T7-z;)O=g#Xyw&*0XM5Zaa9rB8?+oTVM zAPX=N8AFf-n3yg@q z#okIIYq7`2Aku%tO3R{^mf7Y?>&r@_Da+sn%Cd`&_3d7dc!IbV8OQp(aDtElUn4VV zZ_oDiX$i{$y&;R%0Z)X4>x{-y}FvOIhujn*(Ur6Ngm6ampe zBns0MFiN-4TE|veGetnJ2`uFBtTGcB+E}KN*NQ+i*Z%N-L%N(|4-jjLm^S^rEB{*G z`Akgwz^+oGB zC{o${b)-L7tK*Hp3~@{~>?1nZNDNknPWYf8$Y6b!%-y)l-mtqH%qS4r>7Df?&a=jN z4;v64;6buheB!AYh&`D>D<-bl4Yn8~EjlhNTPCjV0}g*F9${)b))REHcW^h!^p+)U*3TIaw2=c)nz+o7ul_^-{@ zF#qM?YncD6msA7=_Xu9-0ij3n^6E7v|4B;$z?z7vEYO(Oh{S)?B4y)K4G3oPA6m54 zBw0IHZcZZqo`1*x&Hu#@@cn!r-^=%Kmn$y0$mz#9cld6;i+{^^@*Vse{x$z9XHCxO z{7e1?|D1ouKQ;LGSnY&S2LBEzP0{(kLl|K2f6+5KbjuHTsTBs_531YX-NWe$2(1a= zd-1%%yNA=UUM&-F7b&d?;B|X2iE}~QGP>h0APGpH7VEY=< zIEm-!N%!keXB$DWI)Y;LKs&imOp=Zi8{7u$aNjoQN>dYY2=5V3S6aAHQ^xchc3U;+ zG$}kv289-*M5YdPHfG7(Ein1on|F1C+OiV@+0wlh8}B0On2xxb9SiRWrJ+%UV|yq% z&Sp@{M~Pa#Sd4PG`k+hw3wN%EiZdBK3(_Tcohvb*95|$ODMmoGF5lu-hQgg&sm4aw zr@PK7##f4-Dq&slE~33Pyt}dS-KS<1-@U6Fk>Z&k#r%_;Px;6EBkNmh7yr=YpJ*RW zx?9wfmD*27QcFrc{xL*A{t?mFZ<(Kez~ATZnfwD**q^0P<*>OZJbRH3$K#<#*4__e zwr0J_%XBiuP~z{gcKun*Qfhq{>%rgU@9?+zTl`J_27jGz=dbZs`78Wo{t|zYztAO( zKi{Q0e~v%PpW#n;*~*{dPj;EWpWu)4$GXhwQr_jnE@yPPw9Cz1?&Od1N4om>!v=ph z3WeXnqV!Ps?I;v}3(q|ieiJDVh2KDmzupE4n|yndvsfm7jj${#n25<=ZGi_g`74^} zHmGM?kVs7avbXmfG=z=GUkXWoUif_7Sd`y{!Evlt)3S=n`YMyZpzF8c8_%ED`y!72 zHlU@6Oyh(;*CO7M*@|8;_%ldp?IVA>8RaqfQ&d{L6x5asS4b^2I2o>1msL-W;g8db zdkpS{{LwJ&Xh~HztEB^5`tL*8ydn_7&a(&XYoAZLnq-6aq_Ehol=4JA1y zCY5EPB!f!G7ao5)^)C8EdwOKE&P!k-i7e0Y%0F$byo*=P#d{#USq;eLK%7?mk;Scf$tlgHwx0(DQk81_3Tv>^QTfY*DC7qc@nE*!& zj97lZ#r^z#;#xUY48PCh_ccfzdXLj#-5SGDpsNv1vP9%`4Z`9i%VB2MZhR}hi*Mm~ z^38k`-^lOa8~A#IZzZIxtgA8jT|hv(wV-wdt~XzTYfkik3Cu(CEvQ#txpJVv$)rm4 z>MLs(g^%J;RodhYz8UqfRV+97CZtZPD_d#sjUY($242YZbF!ZD4WUNpY)kV-=pF%j zp}e}bzG-QYZ^K@WHMe$WC3ZwopsnAv45`@Sb{+TAlS&Zw+Ij1pbz@QxX&erjC)>?>bCJrALneM&op`EK~d{qXEB5P+?bl@aGFBLR4IvB zs4p;wb}gZShf~QhlM2ZOvcEcjf{q~eg)Stwy+AB@xg@WJ{*N9*Bjv*Xoz7wed++Hp zWbZz>xuD!TuZUPG;LG3$lZm>m)`a6rIsz#lLQS~-qb9;zAGA$40iz~Ph8(meLYJUs z?jh97(>3$ksLA!n3v@k%MhJhK2+bTKH08M`@P)k0+GFkI3rt?FXA*IlR))jKvc!qV zg@ecj_(EcDO09i4EL|;>Oa!51k!-qkT_F$Vl-sHzODNVBWvTQz| z&&yrO=kgLhC-+4@JNMk&^Z9YPSMXW6m-3mp*X6Fwy*2k!x76;}7j9%jj9U_bdZ{GJB8L{JG}VvskAknj6C9ok@IZ z?i+jxpKR^74)94P_spXh1s$uT_{H@s5sQFw6Db$qQ)nR^WBtp|kD-O|FIor_O+HcY z;PtgNl{)M(wq75fOiKabLHN;p0w2$d_&7e6kKv>FD1Ma5k8bvc$tURDC?a^W$;WFI zg`Rfr1no=;VyjQk@*=(cBh;67Jv1K|&f`cb?POy$qoYHC)m5&jtpm@lGt+g(|jYFb62M&fbB$6sj zJ~9$Wx-<+VuY5%Gkadm5A$xU>(2R@*nMWuL{eiJ$PBHm#O?^Vs;FTwa<{?zWJGt5b zRtbpYv?-Z`2 z(KL={5x-65R&asJh-n2PTHFas! zAV>7BW5dU~Mt(V$zWj{##D#0_5px(^a}f%KE_JfWiWfTDluZHAxMl$eKG>9uP;Oo1|8_A3M&n6rlwO>S8 z4+MRqR`HD?UfV;_YSE+GPWU`7P4n6w2F3a-p|*z?J*L|};uX9T_uq&CH+4GkCi7z4Zf6GkNAA;Gd5pw6%|?(;oRf*rimH zr)q>F%nG3_ihf{m`4v0`8$ojZLLM}D3NT?sT{%cfGNoXZHh8cNvK8cM+T4*^xU=xv`pI--H*_|1fTdy1oOkG*hMs)c{H4){CeJz2dp2hpLhq8C+Quawfivw zyd$v$iPq144i!wm`WfbZZgRuqrYBt1)>e5(KS8`a3wK2=_E?XK0|tm{on-xpM0=iK za-3j>wH<`1@udU}n8=rste;pikLPjucky;SHvhu>i@87lTJFogipS)y=Pdtr=WpjP z=TDQzAHrl9JPyG07|C`aYSJem_g@nsz)rK z^A{%E`IA_{4s2X18$mb?ngFX$mk7r*e*5_4U6B|cxRup*V*H^j>_NR$o$=o$lsHHApbjuJC3v4 z+2wre>~wbI|6S0&Aj$d0`MRL9^Of_Z^F={{^Las^f&m3XozDu23uY9|E|^zPT2NlF z$oaHjS;2DWlY%}}O*XF7Yd$W>0U8a#HvarJUQJ7wWp zmQA=#hIM47qcl5#@&*+^^npFYk(fTcH9G<+y)`==DZMp2WUSU(v$MN#YmV_dyRbDo z--gyjOIx$)>}-L*Hk=*w5gczc9q(fBinpdPP|zZ zkr?Mon&dCQH96kh-ayG#BpcKDOtU5BOKO*vgZJ_~pR#zv`2-)Tty;L!a6U$=d^x2) z!Y3E6JaI+&l4=~|%*|zN6xP)!MrqUeP^-@fo|QPVM{zwTAz?ZnXdW2P;rF36qy~yY z+EUZ;45cWIiUw*r?`hpXo;S=6v4$<3@HL%x!*>1fOnX(yOEx^+pa5YR^f0G zg*#Zlf;enM#`oS3T|osyX7Pq+I6lov!BnAUI*e!OV7y3$1Ktd=B}%h4h=m#91n+;usQnS@bLRbc<+zVPe+8RjzrZXOIRQM@TkzkQFu7Igbr-s`(r{6 z$Kv5Qy`AgWTHb|eMc@PfI*p!!Ql3DR@~wg&oHv~}tUs(jo!1TLtuUpms4Z`#lt~CB zu@tN2O}+g_$@b10L^%IoG0t|=+1{)?$@&vS{59uQ=N0E==OyPwE7N(w>f$_aG9sVxFMX$^8cLiI+Rh02wvUau=w;N?2}UxunH z@njrcD#x=L)S)L-YZ}UH*)lvS4?P*jrn4#d^mII{LD_1&UyYh8k*-Cmo|WR+5Z0IV z*Z-*9O8ld@O4(?1a0O~DMSEp!*3m{z`ucbrv_i^i@$3Epb|0LZ1@JSm^d``-vW#(Hds#-t&j?Uh5%C& z1_>nLZFWr1j*0R8SAm3(r2;FX5-Wqi5?UeU1P))&_Qe?gMc`P<76Tl$pdkd1D*Ri6 zCqx87V5uOm_=C3pzY1}p!9pu#6+jdMNhN_KHfYEG*CLL$PD0?o8NqFKyP)0fziOW; z1LYvJ2_sDi7>fxQaX~xoziMp|NhKtq%{dBHmJm4NgLeFX)!GOHfxuA@poG@OQUXRo z&`$WT0!HK7SOJt-6b8mJ0!I6w-JbpNU$otx0*+$^fUuOE90mj;gKx8qpl!q?{TBhE zQ83622^x#Rn-aRz127?$KVVfuS?xSwn|=q5#{t`9vCK}iJJSpH+#L^c_zDQplM7qB}}g<#MQvLryg2vDEGX5e#cSpR?>pu*&!os7a^cvOrj zIR+KxvMFet3R8l13JQmy;mHsgCgA_k?681UL!EluPW3yFLxXOoLW6Fn+35j0jS3#K zGyKkDRFFXhnRZsd&ZOo#1?^7w_(1UF3)xV1IIy7-=^^+x5WmBauYllG0a1pY9gaGO zVJr(#G7#fA4F4+dY=9P*V8YSw4hz^>)OdE#&ITAJq1tqOWCDh97&{Kt2L^09(C0jA zclJAvQn%pd%j_JxOTf;dH@gPyu6Sb*R^<@ooO_*n0(L&Vbhq8p@7&G& z0lO#jGrQ34W%q`I9(}M+(C&lCe$&vmRbXjzA$>+jx&a%CuWfeUpxqZ=>yM5O)14lS zG?qkfD(n}u`>{I@ii(r5nigWomf_zT)Fx@U5|AMIli265JX#JefkZBENqc1^`%*bc z&qNR#MKfxr#hy3qEZ$lOhz}0f1q6|;c7MOKl^}wPWtly|9%v5=*aK)hgM;>9xK>ZW zx*${=jY*h{6v^?^G<;^EWICQtWitczKzik{pnX_N@EJsfLxT1Y#saoQ-@VHo>UZv< z?+&H!9&Qh_hX-uj?!3)DB532lH+t!@2E;#mY~wJDWhleK9Y)ng1nm*j+;GZ_4B8{v zP5*1KZ?&(D(6(vRTkIqK&K4T=ku>U~>{0gUfPEB=U`)^+!#cM@`cMvmiBe&1RAMu>DLh-|he`<=}Mk;w#+DfU#mIABkq z@k|Ta(^$I3GQzedlxQkdIW}k?+Y&sAsc?GGp3XM?udNEA4$b;agfepK8llmHps~rG z;deF>G-ePqX4R)(tG0wvXtLZ#MKM&Fmj)TNF+vw+h`oXP(G0wg8a}UO0)ebFQn67;mU_MR0czW&5~G~!@(m?2-pj#a(U1$Z>T)Fp>lt; zNlY48NK_vXuuh~NUSn7Iooi@1D`+|^ovWRzoGYCxoXefdoJ*ZcoQs`{oC}?QIu|(S zJLd&#tt46$v=_14{;!zM(VEL35xsFTiSMY3ajvGhxQc$Rq@OG3=W_bFjDB!uS&VZD z{aj2x7tzm!^z%>pxqyDor=Rm^GV2Jgi-Y!Juz1b&`nl|Az;t+o`h7U~@@QMcaMU0% zpb9;$MX8tfYzU;l9v-mj=_5;m_7dXNv09^z2mfzB(if}0mMsogE9o;!gZ5H(_y71a z(Olwi>;)}xiNi63|Ab47gh{DZy3_zt|4&utj)Nc&MbVj%5JRE~JFsvzCv=J%fQ?xA z*G^5`3?0?oftB}&jRhxD4hiq%@$L|Q8_ySw{vxIgcU_mMcEO+kdRMX@B80iGmC3-E=V3_%353}?llRpa0&IFSjUzovnJ_Y6Urvy{@MY9}(Oq`q)irBGwA+mNom?ls zu&AIoZ)!o+ zLX;PvtcXp-Zxir+0)C@%}Nl1#^zH4Krp>A@OS6ihA6Ae3BX z@oDJsk)X+PL2NV|&Q1g#1!%Jrtrh{xNrHuFu@P%*kR>hVu=;Vt z(jl^rJy;{pgOZ{N1!V~re8G^U!1E#P+sy$(nxt40YPV^cHAM^mCq4+)7?|w9ni*sX zCJk82_;1!cMAoSXOHa-#o={XUp(hF)pFTCf%ZnP4qh zD}yZQtOnrgjw!YyA=x_3TBF+vz>Mi^ykMBl!8)Mk&TJQhEUDQL{n9DLI#JEeY1SDv z^Vq3uhG4s(W*64gAWLc*^xUraPc?T-v)zDcQj_%*tSjp7&h{|KlDaAMUAGh%j=J5` ztUI7q0M}Cm+XFRwu$~54QWG7`_Dr!ospej3wpRw~UV`;R-Ck^OgDk1rn5Ef1DYg&Q z?VV=5Gj)3jwm0hbVfz|nN!>L1y>AMlkGlJ%*?y=y72-9X6$-X5>h2%^W!V0{ZWGAH z0V#F>)jcrH4y@wqcoF}_P_-G-L9CxaCX4VLfAOF3AMq9*|H&AS|DbFO)$E7VpA9g` zcqyv2!oPun4P+wzJ^n3>e`i4tmQy;bVsc3_>c_v)O#_eyvB3se=B6Qn4Z-if#+$?V zSC-p@r6AsUrKLp$<@sfWr4`9_f4Ux%T#I-!ff|f-FgwH`%V7FTyea;f$G;Ggn<)F4 zY94}gC_Bs`%QQMvu%T%5r})P({)z3_gM|fU1$j`jijtBdT#QaG#^OT6KN66`kcP40 z23ZEk2*E}G$Pe+xF#aLId}_(~!qSrbDFqb?oYe5lwFkA4Kn+J4$wnDu8Bm7{b~r$N zAAc9d-zVm8N+Bs+Y2kzfk{Oy@jyiOZ2lO2Q8ih2PjWNhFfW`_o7J$BuzX{`S6RS18 zcuK*nNd?6ToQ4BN3@w;-a6z#L^9_L+gLDKt(jd!#87J5{fcZM!5XN7#mOWT7zPO-t z`uGG$FknQ%sOjT9hz$hdNTj3K(FR!t#4&;$0}x-u>%;h~#G2(zC>dX{6*7(bQ^D5w ztS4YcBOS|*GsrT)ju-5B0Q)ljB8%z3pkxwIS**SwK*u4Sz)m#CGJsAJ>?8nM z7q1QDbqRkG7zO3N#~LOeaOH_xOJGh!%46dVvJ4nlmwbTvJpL?@kVm~g0J zg3hQxLp+$z2+VjSj5`Kd1`N#EM1c7;{v?b)P1t;DA%>Wl36S8J!qOpyGd+k;2t)zW zBsSR~%YcB67Xrk`@ke3&aU#j3WhIl!3d+l&Lo6IsbpZtu@kaz?GSbOxib0l9oDbs< z;`e#{A?eHql)X?-;Uo3Wyr8TwuP6c5*aI7rlz4Ej6S!GO zr?JxwvJAM{g3SiF*Wy>h__ZqODJZRgY9yc_J-7mO9?Yu*=5(Yp*qH`drq^DHUyfhm z@hj9}FH`ms)jSjFEOxd*mT7Q~U~|ymi}4F#{32`KgEc59D=R5WT5B+vzWSzKAOL40 zox|oDWElYG3U)34tcsrx<5h{2&B!Y&E-apufC$I=3lHRZ0x}orJa)c8mH~2sU>5+$ zbMeYBelAhs{F14#>lFnP5-?_9^`!^2k^r5LbRnB(kYxZ}B-lj&v?6{sj8`OTlaP~N zGQGHh1qnR^>AQ%ZB@pwFE@qb)WEl{b3U(<#JQF`1#?K^OP(_dj(y)r6DlktIm`jl6 zv&#&!444IiEdZFO;wQuSsYJ#yBzZuo3{6#_o+MD0AzjWE8e|zzR|s|mKs^yZ9>!0w zMi`PRN-FY-3dWa|Oex1r@#A#oLZmC%RR&q+&Z`Bx8oxglKN`l5v8I?eW{}9<{V3gi z71A|qkwKQZ`&z-S#odp@4~Ow12`5UXSCme#fRbQ5WDWh5pL2@%VFI%V={k13L6!k? zgJ3rR%tP^mVf;`cAw?yVXtrFMS23A|xS+}MC|rp6K>~6;(v9pUgDeANv0#e<DHT&mav-*vWzlR#>?aTcw9+(u$;2{sOHT`x3F6cvP>hl33eMG z-5W0p<9k`ygVig|E6Xb=o`4(TWpvlANVl`423ZFFJ@MV~T|B;rK;KQ-T~u=^(jDwh zgG>}Av!FKYE_Sy;CJ)6m{^C2?J@FkOK4A8O8D)hP1r;S=2i<-T(y|y0En~c-s`~9= zd^UP~#vgBDSDGkJJYwJW=q-51|x@R2O5Bxc0R1zQf7mF#|lOq8Lb zWDVH^>_LMJC}AFF{>$hBjFI;P?MK;T23bOaVLQe*vd7sI0X{ql#Mk2KMMZIZRzk$C_%o;? z#^cgp;{7Ch${$|Fp3`lnOuX__TJlV;DL{UC=u0TQog&$1N( zK2!i4iw!OlkeGwV*M;$QwNjA7R^Zla*-G|YfDZ*J$g428dQ$1GkDUlz{~ z;st=8huJ!;a4s?4|9Tmt?>xSY?wn65a~t7#C(?`TC4(%ZT$jd|#254UQmS+bWfxP; zmylj&uNY*Ba6W*;@u#Mq%D&YYcnaGm;eMeD)4|mpn$a|3)-E6jUYg*hjP p>bBUNWz723Vo)gA%YVR!e7D#%ZePEDPDa;P> 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

xH1r$25SzcVPr0Tnl5! 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 diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py new file mode 100644 index 0000000..a9ac2fd --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/__init__.py @@ -0,0 +1,450 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement +__license__ = 'GPL v3' +__docformat__ = 'restructuredtext en' + + +# Released under the terms of the GNU General Public Licence, version 3 +# +# +# Requires Calibre version 0.7.55 or higher. +# +# All credit given to i♥cabbages and The Dark Reverser for the original standalone scripts. +# We had the much easier job of converting them to a calibre plugin. +# +# This plugin is meant to decrypt eReader PDBs, Adobe Adept ePubs, Barnes & Noble ePubs, +# Adobe Adept PDFs, Amazon Kindle and Mobipocket files without having to +# install any dependencies... other than having calibre installed, of course. +# +# Configuration: +# Check out the plugin's configuration settings by clicking the "Customize plugin" +# button when you have the "DeDRM" plugin highlighted (under Preferences-> +# Plugins->File type plugins). Once you have the configuration dialog open, you'll +# see a Help link on the top right-hand side. +# +# Revision history: +# 6.0.0 - Initial release + +""" +Decrypt DRMed ebooks. +""" + +PLUGIN_NAME = u"DeDRM" +PLUGIN_VERSION_TUPLE = (6, 0, 0) +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' + +import sys, os, re +import time +import zipfile +import traceback +from zipfile import ZipFile + +class DeDRMError(Exception): + pass + +from calibre.customize import FileTypePlugin +from calibre.constants import iswindows, isosx +from calibre.gui2 import is_ok_to_use_qt +from calibre.utils.config import config_dir + + +# Wrap a stream so that output gets flushed immediately +# and also make sure that any unicode strings get safely +# 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) + +class DeDRM(FileTypePlugin): + name = PLUGIN_NAME + description = u"Removes DRM from Amazon Kindle, Adobe Adept (including Kobo), Barnes & Noble, Mobipocket and eReader ebooks. Credit given to i♥cabbages and The Dark Reverser for the original stand-alone scripts." + supported_platforms = ['linux', 'osx', 'windows'] + 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']) + on_import = True + priority = 600 + + def initialize(self): + # convert old preferences, if necessary. + import calibre_plugins.dedrm.config + + config.convertprefs() + + """ + Dynamic modules can't be imported/loaded from a zipfile... so this routine + runs whenever the plugin gets initialized. This will extract the appropriate + library for the target OS and copy it to the 'alfcrypto' subdirectory of + calibre's configuration directory. That 'alfcrypto' directory is then + inserted into the syspath (as the very first entry) in the run function + so the CDLL stuff will work in the alfcrypto.py script. + """ + try: + if iswindows: + names = [u"alfcrypto.dll",u"alfcrypto64.dll"] + elif isosx: + names = [u"libalfcrypto.dylib"] + else: + names = [u"libalfcrypto32.so",u"libalfcrypto64.so"] + lib_dict = self.load_resources(names) + self.pluginsdir = os.path.join(config_dir,u"plugins") + if not os.path.exists(self.pluginsdir): + os.mkdir(self.pluginsdir) + self.maindir = os.path.join(self.pluginsdir,u"DeDRM") + if not os.path.exists(self.maindir): + os.mkdir(self.maindir) + self.helpdir = os.path.join(self.maindir,u"help") + if not os.path.exists(self.helpdir): + os.mkdir(self.helpdir) + self.alfdir = os.path.join(self.maindir,u"alfcrypto") + if not os.path.exists(self.alfdir): + os.mkdir(self.alfdir) + for entry, data in lib_dict.items(): + file_path = os.path.join(self.alfdir, entry) + open(file_path,'wb').write(data) + except Exception, e: + traceback.print_exc() + raise + + def ePubDecrypt(self,path_to_ebook): + # Create a TemporaryPersistent file to work with. + # Check original epub archive for zip errors. + import calibre_plugins.dedrm.zipfix + + inf = self.temporary_file(u".epub") + try: + print u"{0} v{1}: Verifying zip archive integrity.".format(PLUGIN_NAME, PLUGIN_VERSION) + fr = zipfix.fixZip(path_to_ebook, inf.name) + fr.fix() + except Exception, e: + print u"{0} v{1}: Error \'{2}\' when checking zip archive.".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) + raise Exception(e) + + # import the decryption keys + import calibre_plugins.dedrm.config as config + + # import the Barnes & Noble ePub handler + import calibre_plugins.dedrm.ignobleepub as ignobleepub + + #check the book + if ignobleepub.ignobleBook(inf.name): + print u"{0} v{1}: “{2}” is a secure Barnes & Noble ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + + # Attempt to decrypt epub with each encryption key (generated or provided). + for keyname, userkey in config.dedrmprefs['bandnkeys'].items(): + keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname) + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked) + of = self.temporary_file(u".epub") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + result = ignobleepub.decryptBook(userkey, inf.name, of.name) + + of.close() + + if result == 0: + # Decryption was successful. + # Return the modified PersistentTemporary file to calibre. + return of.name + + 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 Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + # import the Adobe Adept ePub handler + import calibre_plugins.dedrm.ineptepub as ineptepub + + if ineptepub.adeptBook(inf.name): + print u"{0} v{1}: {2} is a secure Adobe Adept ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + + # Attempt to decrypt epub with each encryption key (generated or provided). + for keyname, userkeyhex in config.dedrmprefs['adeptkeys'].items(): + userkey = userkeyhex.decode('hex') + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) + of = self.temporary_file(u".epub") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptepub.decryptBook(userkey, inf.name, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was successful. + # Return the modified PersistentTemporary file to calibre. + return of.name + + print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime) + + # perhaps we need to get a new default ADE key + if iswindows or isosx: + print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys".format(PLUGIN_NAME, PLUGIN_VERSION) + + # get the default Adobe keys + import calibre_plugins.dedrm.adobekey as adobe + + try: + defaultkeys = adobe.adeptkeys() + except: + defaultkeys = [] + + newkeys = [] + for keyvalue in defaultkeys: + if keyvalue.encode('hex') not in config.dedrmprefs['adeptkeys'].values(): + newkeys.append(keyvalue) + + if len(newkeys) > 0: + try: + for i,userkey in enumerate(newkeys): + print u"{0} v{1}: Trying a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + of = self.temporary_file(u".epub") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptepub.decryptBook(userkey, inf.name, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was a success + # Store the new successful key in the defaults + print u"{0} v{1}: Saving a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + try: + config.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex')) + config.writeprefs() + except: + traceback.print_exc() + # 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: + pass + + # Something went wrong with decryption. + print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + # Not a Barnes & Noble nor an Adobe Adept + # Import the fixed epub. + print u"{0} v{1}: “{2}” is neither an Adobe Adept nor a Barnes & Noble encrypted ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + return inf.name + + def PDFDecrypt(self,path_to_ebook): + import calibre_plugins.dedrm.config as config + import calibre_plugins.dedrm.ineptpdf + + # Attempt to decrypt epub with each encryption key (generated or provided). + print u"{0} v{1}: {2} is a PDF ebook.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + for keyname, userkeyhex in config.dedrmprefs['adeptkeys'].items(): + userkey = userkeyhex.decode('hex') + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) + of = self.temporary_file(u".pdf") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptpdf.decryptBook(userkey, path_to_ebook, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was successful. + # Return the modified PersistentTemporary file to calibre. + return of.name + + # perhaps we need to get a new default ADE key + if iswindows or isosx: + print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys".format(PLUGIN_NAME, PLUGIN_VERSION) + + # get the default Adobe keys + import calibre_plugins.dedrm.adobekey as adobe + + try: + defaultkeys = adobe.adeptkeys() + except: + defaultkeys = [] + + newkeys = [] + for keyvalue in defaultkeys: + if keyvalue.encode('hex') not in config.dedrmprefs['adeptkeys'].values(): + newkeys.append(keyvalue) + + if len(newkeys) > 0: + try: + for i,userkey in enumerate(newkeys): + print u"{0} v{1}: Trying a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + of = self.temporary_file(u".pdf") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptepdf.decryptBook(userkey, inf.name, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was a success + # Store the new successful key in the defaults + print u"{0} v{1}: Saving a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + try: + config.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex')) + config.writeprefs() + except: + traceback.print_exc() + # 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: + pass + + # Something went wrong with decryption. + print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + def KindleMobiDecrypt(self,path_to_ebook): + + # add the alfcrypto directory to sys.path so alfcrypto.py + # will be able to locate the custom lib(s) for CDLL import. + sys.path.insert(0, self.alfdir) + # Had to move this import here so the custom libs can be + # extracted to the appropriate places beforehand these routines + # look for them. + import calibre_plugins.dedrm.config as config + import calibre_plugins.dedrm.k4mobidedrm + + pids = config.dedrmprefs['pids'] + serials = config.dedrmprefs['serials'] + kindleDatabases = config.dedrmprefs['kindlekeys'].items() + + try: + book = k4mobidedrm.GetDecryptedBook(path_to_ebook,kindleDatabases,serials,pids,self.starttime) + except Exception, e: + decoded = False + # perhaps we need to get a new default Kindle for Mac/PC key + if iswindows or isosx: + print u"{0} v{1}: Failed to decrypt with error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION,e.args[0]) + print u"{0} v{1}: Looking for new default Kindle Key".format(PLUGIN_NAME, PLUGIN_VERSION) + import calibre_plugins.dedrm.kindlekey as amazon + + try: + defaultkeys = amazon.kindlekeys() + except: + defaultkeys = [] + newkeys = {} + for i,keyvalue in enumerate(defaultkeys): + keyname = u"default_key_{0:d}".format(i+1) + if keyvalue not in config.dedrmprefs['kindlekeys'].values(): + newkeys[keyname] = keyvalue + if len(newkeys) > 0: + try: + book = k4mobidedrm.GetDecryptedBook(path_to_ebook,newkeys.items(),[],[],self.starttime) + decoded = True + # store the new successful keys in the defaults + for keyvalue in newkeys.values(): + config.addnamedvaluetoprefs('kindlekeys','default_key',keyvalue) + config.writeprefs() + except Exception, e: + 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 Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + traceback.print_exc() + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{4}” after {3:.1f} seconds with error: {2}\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0],time.time()-self.starttime,os.path.basename(path_to_ebook))) + + of = self.temporary_file(book.getBookExtension()) + book.getFile(of.name) + of.close() + book.cleanup() + return of.name + + + def eReaderDecrypt(self,path_to_ebook): + + import calibre_plugins.dedrm.config as config + import calibre_plugins.dedrm.erdr2pml + + # Attempt to decrypt epub with each encryption key (generated or provided). + for keyname, userkey in config.dedrmprefs['ereaderkeys'].items(): + keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname) + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked) + of = self.temporary_file(u".pmlz") + + # Give the userkey, ebook and TemporaryPersistent file to the decryption function. + result = erdr2pml.decryptBook(path_to_ebook, of.name, True, userkey.decode('hex')) + + of.close() + + # Decryption was successful return the modified PersistentTemporary + # file to Calibre's import process. + if result == 0: + return of.name + + 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 Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + + def run(self, path_to_ebook): + + # make sure any unicode output gets converted safely with 'replace' + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + + print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + self.starttime = time.time() + + booktype = os.path.splitext(path_to_ebook)[1].lower()[1:] + if booktype in ['prc','mobi','azw','azw1','azw3','azw4','tpz']: + # Kindle/Mobipocket + decrypted_ebook = self.KindleMobiDecrypt(path_to_ebook) + elif booktype == 'pdb': + # eReader + decrypted_ebook = self.eReaderDecrypt(path_to_ebook) + pass + elif booktype == 'pdf': + # Adobe Adept PDF (hopefully) + decrypted_ebook = self.PDFDecrypt(path_to_ebook) + pass + elif booktype == 'epub': + # Adobe Adept or B&N ePub + decrypted_ebook = self.ePubDecrypt(path_to_ebook) + else: + print u"Unknown booktype {0}. Passing back to calibre unchanged.".format(booktype) + return path_to_ebook + print u"{0} v{1}: Successfully decrypted book after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + return decrypted_ebook + + def is_customizable(self): + # return true to allow customization via the Plugin->Preferences. + return True + + def config_widget(self): + import calibre_plugins.dedrm.config as config + return config.ConfigWidget(self.plugin_path) + + def save_settings(self, config_widget): + config_widget.save_settings() diff --git a/Calibre_Plugins/ineptpdf_plugin/ineptkey.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/adobekey.py similarity index 76% rename from Calibre_Plugins/ineptpdf_plugin/ineptkey.py rename to DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/adobekey.py index a9bc62d..94f7522 100644 --- a/Calibre_Plugins/ineptpdf_plugin/ineptkey.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/adobekey.py @@ -1,25 +1,31 @@ -#! /usr/bin/python +#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import with_statement -# ineptkey.pyw, version 5.6 +# adobekey.pyw, version 5.7 # Copyright © 2009-2010 i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Windows users: Before running this program, you must first install Python 2.6 -# from and PyCrypto from -# (make certain -# to install the version for Python 2.6). Then save this script file as -# ineptkey.pyw and double-click on it to run it. It will create a file named -# adeptkey.der in the same directory. This is your ADEPT user key. +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf + +# Windows users: Before running this program, you must first install Python. +# We recommend ActiveState Python 2.7.X for Windows (x86) from +# http://www.activestate.com/activepython/downloads. +# You must also install PyCrypto from +# http://www.voidspace.org.uk/python/modules.shtml#pycrypto +# (make certain to install the version for Python 2.7). +# Then save this script file as adobekey.pyw and double-click on it to run it. +# It will create a file named adobekey_1.der in in the same directory as the script. +# This is your Adobe Digital Editions user key. # -# Mac OS X users: Save this script file as ineptkey.pyw. You can run this -# program from the command line (pythonw ineptkey.pyw) or by double-clicking +# Mac OS X users: Save this script file as adobekey.pyw. You can run this +# program from the command line (python adobekey.pyw) or by double-clicking # it when it has been associated with PythonLauncher. It will create a file -# named adeptkey.der in the same directory. This is your ADEPT user key. +# named adobekey_1.der in the same directory as the script. +# This is your Adobe Digital Editions user key. # Revision history: # 1 - Initial release, for Adobe Digital Editions 1.7 @@ -30,24 +36,25 @@ from __future__ import with_statement # 4.2 - added old 1.7.1 processing # 4.3 - better key search # 4.4 - Make it working on 64-bit Python -# 5 - Clean up and improve 4.x changes; -# Clean up and merge OS X support by unknown +# 5 - Clean up and improve 4.x changes; +# Clean up and merge OS X support by unknown # 5.1 - add support for using OpenSSL on Windows in place of PyCrypto # 5.2 - added support for output of key to a particular file # 5.3 - On Windows try PyCrypto first, OpenSSL next # 5.4 - Modify interface to allow use of import # 5.5 - Fix for potential problem with PyCrypto # 5.6 - Revised to allow use in Plugins to eliminate need for duplicate code +# 5.7 - Unicode support added, renamed adobekey from ineptkey +# 5.8 - Added getkey interface for Windows DeDRM application """ Retrieve Adobe ADEPT user key. """ __license__ = 'GPL v3' +__version__ = '5.8' -import sys -import os -import struct +import sys, os, struct, getopt # Wrap a stream so that output gets flushed immediately # and also make sure that any unicode strings get @@ -79,8 +86,8 @@ def unicode_argv(): # 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 '?'. - + # characters with '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 from ctypes import POINTER, byref, cdll, c_int, windll from ctypes.wintypes import LPCWSTR, LPWSTR @@ -101,7 +108,9 @@ def unicode_argv(): start = argc.value - len(sys.argv) return [argv[i] for i in xrange(start, argc.value)] - return [u"ineptkey.py"] + # if we don't have any arguments at all, just pass back script name + # this should never happen + return [u"adobekey.py"] else: argvencoding = sys.stdin.encoding if argvencoding == None: @@ -349,7 +358,7 @@ if iswindows: return CryptUnprotectData CryptUnprotectData = CryptUnprotectData() - def retrieve_keys(): + def adeptkeys(): if AES is None: raise ADEPTError("PyCrypto or OpenSSL must be installed") root = GetSystemDirectory().split('\\')[0] + '\\' @@ -406,6 +415,9 @@ elif isosx: 'enc': 'http://www.w3.org/2001/04/xmlenc#'} def findActivationDat(): + import warnings + warnings.filterwarnings('ignore', category=FutureWarning) + home = os.getenv('HOME') cmdline = 'find "' + home + '/Library/Application Support/Adobe/Digital Editions" -name "activation.dat"' cmdline = cmdline.encode(sys.getfilesystemencoding()) @@ -413,6 +425,7 @@ elif isosx: out1, out2 = p2.communicate() reslst = out1.split('\n') cnt = len(reslst) + ActDatPath = "activation.dat" for j in xrange(cnt): resline = reslst[j] pp = resline.find('activation.dat') @@ -423,10 +436,10 @@ elif isosx: return ActDatPath return None - def retrieve_keys(): + def adeptkeys(): actpath = findActivationDat() if actpath is None: - raise ADEPTError("Could not locate ADE activation") + raise ADEPTError("Could not find ADE activation.dat file.") tree = etree.parse(actpath) adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag) expr = '//%s/%s' % (adept('credentials'), adept('privateLicenseKey')) @@ -436,33 +449,93 @@ elif isosx: return [userkey] else: - def retrieve_keys(keypath): + def adeptkeys(): raise ADEPTError("This script only supports Windows and Mac OS X.") return [] -def retrieve_key(keypath): - keys = retrieve_keys() - with open(keypath, 'wb') as f: - f.write(keys[0]) - return True - -def extractKeyfile(keypath): - try: - success = retrieve_key(keypath) - except ADEPTError, e: - print u"Key generation Error: {0}".format(e.args[0]) - return 1 - except Exception, e: - print "General Error: {0}".format(e.args[0]) - return 1 - if not success: - return 1 - return 0 +# interface for Python DeDRM +def getkey(outpath): + keys = adeptkeys() + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'wb') 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"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + print u"Saved a key to {0}".format(outfile) + return True + return False +def usage(progname): + print u"Finds, decrypts and saves the default Adobe Adept encryption key(s)." + print u"Keys are saved to the current directory, or a specified output directory." + print u"If a file name is passed instead of a directory, only the first key is saved, in that file." + print u"Usage:" + print u" {0:s} [-h] []".format(progname) def cli_main(argv=unicode_argv()): - keypath = argv[1] - return extractKeyfile(keypath) + progname = os.path.basename(argv[0]) + print u"{0} v{1}\nCopyright © 2009-2013 i♥cabbages and 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) > 1: + usage(progname) + sys.exit(2) + + if len(args) == 1: + # save to the specified file or directory + outpath = args[0] + if not os.path.isabs(outpath): + outpath = os.path.abspath(outpath) + else: + # save to the same directory as the script + outpath = os.path.dirname(argv[0]) + + # make sure the outpath is the + outpath = os.path.realpath(os.path.normpath(outpath)) + + keys = adeptkeys() + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'wb') 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"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + print u"Saved a key to {0}".format(outfile) + else: + print u"Could not retrieve Adobe Adept key." + return 0 def gui_main(argv=unicode_argv()): @@ -485,23 +558,32 @@ def gui_main(argv=unicode_argv()): root = Tkinter.Tk() root.withdraw() - keypath, progname = os.path.split(argv[0]) - keypath = os.path.join(keypath, u"adeptkey.der") + progpath, progname = os.path.split(argv[0]) success = False try: - success = retrieve_key(keypath) - except ADEPTError, e: - tkMessageBox.showerror(u"ADEPT Key", "Error: {0}".format(e.args[0])) + keys = adeptkeys() + keycount = 0 + for key in keys: + while True: + keycount += 1 + outfile = os.path.join(progpath,u"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + success = True + tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile)) + except DrmException, e: + tkMessageBox.showerror(progname, u"Error: {0}".format(str(e))) except Exception: root.wm_state('normal') - root.title('ADEPT Key') + root.title(progname) text = traceback.format_exc() ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1) root.mainloop() if not success: return 1 - tkMessageBox.showinfo( - u"ADEPT Key", u"Key successfully retrieved to {0}".format(keypath)) return 0 if __name__ == '__main__': diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py index 9521540..04d87c6 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/config.py @@ -1,62 +1,464 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from PyQt4.Qt import QWidget, QVBoxLayout, QLabel, QLineEdit +from __future__ import with_statement -from calibre.utils.config import JSONConfig +__license__ = 'GPL v3' + +# Standard Python modules. +import os, sys, re, hashlib + +# PyQT4 modules (part of calibre). +from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, + QGroupBox, QPushButton, QListWidget, QListWidgetItem, + QAbstractItemView, QIcon, QDialog, QUrl, QString) +from PyQt4 import QtGui + +import zipfile +from zipfile import ZipFile + +# calibre modules and constants. +from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url, + choose_dir, choose_files) +from calibre.utils.config import dynamic, config_dir, JSONConfig +from calibre.constants import iswindows, isosx + +# modules from this plugin's zipfile. +from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION +from calibre_plugins.dedrm.__init__ import RESOURCE_NAME as help_file_name +from calibre_plugins.dedrm.utilities import (uStrCmp, DETAILED_MESSAGE) + +import calibre_plugins.dedrm.dialogs as dialogs +import calibre_plugins.dedrm.ignoblekeygen as bandn +import calibre_plugins.dedrm.erdr2pml as ereader +import calibre_plugins.dedrm.adobekey as adobe +import calibre_plugins.dedrm.kindlekey as amazon + +JSON_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_') +JSON_PATH = os.path.join(u"plugins", JSON_NAME + '.json') + +IGNOBLEPLUGINNAME = "Ignoble Epub DeDRM" +EREADERPLUGINNAME = "eReader PDB 2 PML" +OLDKINDLEPLUGINNAME = "K4PC, K4Mac, Kindle Mobi and Topaz DeDRM" # This is where all preferences for this plugin will be stored # You should always prefix your config file name with plugins/, # so as to ensure you dont accidentally clobber a calibre config file -prefs = JSONConfig('plugins/K4MobiDeDRM') +dedrmprefs = JSONConfig(JSON_PATH) -# Set defaults -prefs.defaults['pids'] = "" -prefs.defaults['serials'] = "" -prefs.defaults['WINEPREFIX'] = None +# get prefs from older tools +kindleprefs = JSONConfig(os.path.join(u"plugins", u"K4MobiDeDRM")) +ignobleprefs = JSONConfig(os.path.join(u"plugins", u"ignoble_epub_dedrm")) + +# Set defaults for the prefs +dedrmprefs.defaults['configured'] = False +dedrmprefs.defaults['bandnkeys'] = {} +dedrmprefs.defaults['adeptkeys'] = {} +dedrmprefs.defaults['ereaderkeys'] = {} +dedrmprefs.defaults['kindlekeys'] = {} +dedrmprefs.defaults['pids'] = [] +dedrmprefs.defaults['serials'] = [] class ConfigWidget(QWidget): - - def __init__(self): + def __init__(self, plugin_path): QWidget.__init__(self) - self.l = QVBoxLayout() - self.setLayout(self.l) - self.serialLabel = QLabel('eInk Kindle Serial numbers (First character B, 16 characters, use commas if more than one)') - self.l.addWidget(self.serialLabel) + self.plugin_path = plugin_path - self.serials = QLineEdit(self) - self.serials.setText(prefs['serials']) - self.l.addWidget(self.serials) - self.serialLabel.setBuddy(self.serials) + # get copy of the prefs from the file + # Otherwise we seem to get a persistent local copy. + self.dedrmprefs = JSONConfig(JSON_PATH) - self.pidLabel = QLabel('Mobipocket PIDs (8 or 10 characters, use commas if more than one)') - self.l.addWidget(self.pidLabel) + self.tempdedrmprefs = {} + self.tempdedrmprefs['bandnkeys'] = self.dedrmprefs['bandnkeys'].copy() + self.tempdedrmprefs['adeptkeys'] = self.dedrmprefs['adeptkeys'].copy() + self.tempdedrmprefs['ereaderkeys'] = self.dedrmprefs['ereaderkeys'].copy() + self.tempdedrmprefs['kindlekeys'] = self.dedrmprefs['kindlekeys'].copy() + self.tempdedrmprefs['pids'] = list(self.dedrmprefs['pids']) + self.tempdedrmprefs['serials'] = list(self.dedrmprefs['serials']) - self.pids = QLineEdit(self) - self.pids.setText(prefs['pids']) - self.l.addWidget(self.pids) - self.pidLabel.setBuddy(self.serials) + # Start Qt Gui dialog layout + layout = QVBoxLayout(self) + self.setLayout(layout) - self.wpLabel = QLabel('For Linux only: WINEPREFIX (enter absolute path)') - self.l.addWidget(self.wpLabel) + help_layout = QHBoxLayout() + layout.addLayout(help_layout) + # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. + help_label = QLabel('Plugin Help', self) + help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) + help_label.setAlignment(Qt.AlignRight) + help_label.linkActivated.connect(self.help_link_activated) + help_layout.addWidget(help_label) - self.wineprefix = QLineEdit(self) - wineprefix = prefs['WINEPREFIX'] - if wineprefix is not None: - self.wineprefix.setText(wineprefix) - else: - self.wineprefix.setText('') + keys_group_box = QGroupBox(_('Configuration:'), self) + layout.addWidget(keys_group_box) + keys_group_box_layout = QHBoxLayout() + keys_group_box.setLayout(keys_group_box_layout) - self.l.addWidget(self.wineprefix) - self.wpLabel.setBuddy(self.wineprefix) + + button_layout = QVBoxLayout() + keys_group_box_layout.addLayout(button_layout) + self.bandn_button = QtGui.QPushButton(self) + self.bandn_button.setToolTip(_(u"Click to manage keys for Barnes and Noble ebooks")) + self.bandn_button.setText(u"Barnes and Noble ebooks") + self.bandn_button.clicked.connect(self.bandn_keys) + self.kindle_serial_button = QtGui.QPushButton(self) + self.kindle_serial_button.setToolTip(_(u"Click to manage eInk Kindle serial numbers for Kindle ebooks")) + self.kindle_serial_button.setText(u"eInk Kindle ebooks") + self.kindle_serial_button.clicked.connect(self.kindle_serials) + self.kindle_key_button = QtGui.QPushButton(self) + self.kindle_key_button.setToolTip(_(u"Click to manage keys for Kindle for Mac/PC ebooks")) + self.kindle_key_button.setText(u"Kindle for Mac/PC ebooks") + self.kindle_key_button.clicked.connect(self.kindle_keys) + self.adept_button = QtGui.QPushButton(self) + self.adept_button.setToolTip(_(u"Click to manage keys for Adobe Digital Editions ebooks")) + self.adept_button.setText(u"Adobe Digital Editions ebooks") + self.adept_button.clicked.connect(self.adept_keys) + self.mobi_button = QtGui.QPushButton(self) + self.mobi_button.setToolTip(_(u"Click to manage PIDs for Mobipocket ebooks")) + self.mobi_button.setText(u"Mobipocket ebooks") + self.mobi_button.clicked.connect(self.mobi_keys) + self.ereader_button = QtGui.QPushButton(self) + self.ereader_button.setToolTip(_(u"Click to manage keys for eReader ebooks")) + self.ereader_button.setText(u"eReader ebooks") + self.ereader_button.clicked.connect(self.ereader_keys) + button_layout.addWidget(self.kindle_serial_button) + button_layout.addWidget(self.bandn_button) + button_layout.addWidget(self.mobi_button) + button_layout.addWidget(self.ereader_button) + button_layout.addWidget(self.adept_button) + button_layout.addWidget(self.kindle_key_button) + + self.resize(self.sizeHint()) + + def kindle_serials(self): + d = dialogs.ManageKeysDialog(self,u"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], dialogs.AddSerialDialog) + d.exec_() + + def kindle_keys(self): + d = dialogs.ManageKeysDialog(self,u"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], dialogs.AddKindleDialog, 'k4i') + d.exec_() + + def adept_keys(self): + d = dialogs.ManageKeysDialog(self,u"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], dialogs.AddAdeptDialog, 'der') + d.exec_() + + def mobi_keys(self): + d = dialogs.ManageKeysDialog(self,u"Mobipocket PID",self.tempdedrmprefs['pids'], dialogs.AddPIDDialog) + d.exec_() + + def bandn_keys(self): + d = dialogs.ManageKeysDialog(self,u"Barnes and Noble Key",self.tempdedrmprefs['bandnkeys'], dialogs.AddBandNKeyDialog, 'b64') + d.exec_() + + def ereader_keys(self): + d = dialogs.ManageKeysDialog(self,u"eReader Key",self.tempdedrmprefs['ereaderkeys'], dialogs.AddEReaderDialog, 'b63') + d.exec_() + + def help_link_activated(self, url): + def get_help_file_resource(): + # Copy the HTML helpfile to the plugin directory each time the + # link is clicked in case the helpfile is updated in newer plugins. + file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name) + with open(file_path,'w') as f: + f.write(self.load_resource(help_file_name)) + return file_path + url = 'file:///' + get_help_file_resource() + open_url(QUrl(url)) def save_settings(self): - prefs['pids'] = str(self.pids.text()).replace(" ","") - prefs['serials'] = str(self.serials.text()).replace(" ","") - winepref=str(self.wineprefix.text()) - if winepref.strip() != '': - prefs['WINEPREFIX'] = winepref - else: - prefs['WINEPREFIX'] = None + self.dedrmprefs['bandnkeys'] = self.tempdedrmprefs['bandnkeys'] + self.dedrmprefs['adeptkeys'] = self.tempdedrmprefs['adeptkeys'] + self.dedrmprefs['ereaderkeys'] = self.tempdedrmprefs['ereaderkeys'] + self.dedrmprefs['kindlekeys'] = self.tempdedrmprefs['kindlekeys'] + self.dedrmprefs['pids'] = self.tempdedrmprefs['pids'] + self.dedrmprefs['serials'] = self.tempdedrmprefs['serials'] + self.dedrmprefs['configured'] = True + + def load_resource(self, name): + with ZipFile(self.plugin_path, 'r') as zf: + if name in zf.namelist(): + return zf.read(name) + return "" + +def writeprefs(value = True): + dedrmprefs['configured'] = value + +def addnamedvaluetoprefs(prefkind, keyname, keyvalue): + try: + if keyvalue not in dedrmprefs[prefkind].values(): + # ensure that the keyname is unique + # by adding a number (starting with 2) to the name if it is not + namecount = 1 + newname = keyname + while newname in dedrmprefs[prefkind]: + namecount += 1 + newname = "{0:s}_{1:d}".format(keyname,namecount) + # add to the preferences + dedrmprefs[prefkind][newname] = keyvalue + return (True, newname) + except: + pass + return (False, keyname) + +def addvaluetoprefs(prefkind, prefsvalue): + # ensure the keyvalue isn't already in the preferences + if prefsvalue not in dedrmprefs[prefkind]: + dedrmprefs[prefkind].append(prefsvalue) + return True + return False + +def convertprefs(always = False): + + def parseIgnobleString(keystuff): + userkeys = {} + ar = keystuff.split(':') + for i, keystring in enumerate(ar): + try: + name, ccn = keystring.split(',') + # Generate Barnes & Noble EPUB user key from name and credit card number. + keyname = u"{0}_{1}_{2:d}".format(name.strip(),ccn.strip()[-4:],i+1) + keyvalue = bandn.generate_key(name, ccn) + if keyvalue not in userkeys.values(): + while keyname in dedrmprefs['bandnkeys']: + keyname = keyname + keyname[-1] + userkeys[keyname] = keyvalue + except Exception, e: + print e.args[0] + pass + return userkeys + + def parseeReaderString(keystuff): + userkeys = {} + ar = keystuff.split(':') + for i, keystring in enumerate(ar): + try: + name, cc = keystring.split(',') + # Generate eReader user key from name and credit card number. + keyname = u"{0}_{1}_{2:d}".format(name.strip(),cc.strip()[-4:],i+1) + keyvalue = ereader.getuser_key(name,cc).encode('hex') + if keyvalue not in userkeys.values(): + while keyname in dedrmprefs['ereaderkeys']: + keyname = keyname + keyname[-1] + userkeys[keyname] = keyvalue + except Exception, e: + print e.args[0] + pass + return userkeys + + def parseKindleString(keystuff): + pids = [] + serials = [] + ar = keystuff.split(',') + for keystring in ar: + keystring = str(keystring).strip().replace(" ","") + if len(keystring) == 10 or len(keystring) == 8 and keystring not in pids: + pids.append(keystring) + elif len(keystring) == 16 and keystring[0] == 'B' and keystring not in serials: + serials.append(keystring) + return (pids,serials) + + def addConfigFiles(extension, prefskey, encoding = ''): + # get any files with extension 'extension' in the config dir + files = [f for f in os.listdir(config_dir) if f.endswith(extension)] + try: + priorkeycount = len(dedrmprefs[prefskey]) + for filename in files: + fpath = os.path.join(config_dir, filename) + key = os.path.splitext(filename)[0] + value = open(fpath, 'rb').read() + if encoding is not '': + value = value.encode(encoding) + if value not in dedrmprefs[prefskey].values(): + while key in dedrmprefs[prefskey]: + key = key+key[-1] + dedrmprefs[prefskey][key] = value + #os.remove(fpath) + return len(dedrmprefs[prefskey])-priorkeycount + except IOError: + return -1 + + if (not always) and dedrmprefs['configured']: + # We've already converted old preferences, + # and we're not being forced to do it again, so just return + return + + # initialise + # we must actually set the prefs that are dictionaries and lists + # to empty dictionaries and lists, otherwise we are unable to add to them + # as then it just adds to the (memory only) dedrmprefs.defaults versions! + if dedrmprefs['bandnkeys'] == {}: + dedrmprefs['bandnkeys'] = {} + if dedrmprefs['adeptkeys'] == {}: + dedrmprefs['adeptkeys'] = {} + if dedrmprefs['ereaderkeys'] == {}: + dedrmprefs['ereaderkeys'] = {} + if dedrmprefs['kindlekeys'] == {}: + dedrmprefs['kindlekeys'] = {} + if dedrmprefs['pids'] == []: + dedrmprefs['pids'] = [] + if dedrmprefs['serials'] == []: + dedrmprefs['serials'] = [] + + # get default adobe adept key(s) + priorkeycount = len(dedrmprefs['adeptkeys']) + try: + defaultkeys = adobe.adeptkeys() + except: + defaultkeys = [] + defaultcount = 1 + for keyvalue in defaultkeys: + keyname = u"default_key_{0:d}".format(defaultcount) + keyvaluehex = keyvalue.encode('hex') + if keyvaluehex not in dedrmprefs['adeptkeys'].values(): + while keyname in dedrmprefs['adeptkeys']: + defaultcount += 1 + keyname = u"default_key_{0:d}".format(defaultcount) + dedrmprefs['adeptkeys'][keyname] = keyvaluehex + addedkeycount = len(dedrmprefs['adeptkeys']) - priorkeycount + if addedkeycount > 0: + print u"{0} v{1}: {2:d} Default Adobe Adept {3} found.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + + # get default kindle key(s) + priorkeycount = len(dedrmprefs['kindlekeys']) + try: + defaultkeys = amazon.kindlekeys() + except: + defaultkeys = [] + defaultcount = 1 + for keyvalue in defaultkeys: + keyname = u"default_key_{0:d}".format(defaultcount) + if keyvalue not in dedrmprefs['kindlekeys'].values(): + while keyname in dedrmprefs['kindlekeys']: + defaultcount += 1 + keyname = u"default_key_{0:d}".format(defaultcount) + dedrmprefs['kindlekeys'][keyname] = keyvalue + addedkeycount = len(dedrmprefs['kindlekeys']) - priorkeycount + if addedkeycount > 0: + print u"{0} v{1}: {2:d} Default Kindle for Mac/PC {3} found.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + print u"{0} v{1}: Importing configuration data from old DeDRM plugins".format(PLUGIN_NAME, PLUGIN_VERSION) + + # Handle the old ignoble plugin's customization string by converting the + # old string to stored keys... get that personal data out of plain sight. + from calibre.customize.ui import config + sc = config['plugin_customization'] + val = sc.pop(IGNOBLEPLUGINNAME, None) + if val is not None: + print u"{0} v{1}: Converting old Ignoble plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION) + priorkeycount = len(dedrmprefs['bandnkeys']) + userkeys = parseIgnobleString(str(val)) + for key in userkeys: + value = userkeys[key] + if value not in dedrmprefs['bandnkeys'].values(): + while key in dedrmprefs['bandnkeys']: + key = key+key[-1] + dedrmprefs['bandnkeys'][key] = value + addedkeycount = len(dedrmprefs['bandnkeys'])-priorkeycount + print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from old Ignoble plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + # Handle the old eReader plugin's customization string by converting the + # old string to stored keys... get that personal data out of plain sight. + val = sc.pop(EREADERPLUGINNAME, None) + if val is not None: + print u"{0} v{1}: Converting old eReader plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION) + priorkeycount = len(dedrmprefs['ereaderkeys']) + userkeys = parseeReaderString(str(val)) + for key in userkeys: + value = userkeys[key] + if value not in dedrmprefs['ereaderkeys'].values(): + while key in dedrmprefs['ereaderkeys']: + key = key+key[-1] + dedrmprefs['ereaderkeys'][key] = value + addedkeycount = len(dedrmprefs['ereaderkeys'])-priorkeycount + print u"{0} v{1}: {2:d} eReader {3} imported from old eReader plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + # get old Kindle plugin configuration string + val = sc.pop(OLDKINDLEPLUGINNAME, None) + if val is not None: + print u"{0} v{1}: Converting old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION) + priorpidcount = len(dedrmprefs['pids']) + priorserialcount = len(dedrmprefs['serials']) + pids, serials = parseKindleString(val) + for pid in pids: + if pid not in dedrmprefs['pids']: + dedrmprefs['pids'].append(pid) + for serial in serials: + if serial not in dedrmprefs['serials']: + dedrmprefs['serials'].append(serial) + addedpidcount = len(dedrmprefs['pids']) - priorpidcount + addedserialcount = len(dedrmprefs['serials']) - priorserialcount + print u"{0} v{1}: {2:d} {3} and {4:d} {5} imported from old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs", addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers") + # Make the json write all the prefs to disk + writeprefs(False) + + # copy the customisations back into calibre preferences, as we've now removed the nasty plaintext + config['plugin_customization'] = sc + + # get any .b64 files in the config dir + ignoblecount = addConfigFiles('.b64', 'bandnkeys') + if ignoblecount > 0: + print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ignoblecount, u"key file" if ignoblecount==1 else u"key files") + elif ignoblecount < 0: + print u"{0} v{1}: Error reading Barnes & Noble keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION) + # Make the json write all the prefs to disk + writeprefs(False) + + # get any .der files in the config dir + ineptcount = addConfigFiles('.der', 'adeptkeys','hex') + if ineptcount > 0: + print u"{0} v{1}: {2:d} Adobe Adept {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ineptcount, u"keyfile" if ineptcount==1 else u"keyfiles") + elif ineptcount < 0: + print u"{0} v{1}: Error reading Adobe Adept keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION) + # Make the json write all the prefs to disk + writeprefs(False) + + # get ignoble json prefs + if 'keys' in ignobleprefs: + priorkeycount = len(dedrmprefs['bandnkeys']) + for key in ignobleprefs['keys']: + value = ignobleprefs['keys'][key] + if value not in dedrmprefs['bandnkeys'].values(): + while key in dedrmprefs['bandnkeys']: + key = key+key[-1] + dedrmprefs['bandnkeys'][key] = value + addedkeycount = len(dedrmprefs['bandnkeys']) - priorkeycount + # no need to delete old prefs, since they contain no recoverable private data + if addedkeycount > 0: + print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from Ignoble plugin preferences.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + # get kindle json prefs + priorpidcount = len(dedrmprefs['pids']) + priorserialcount = len(dedrmprefs['serials']) + if 'pids' in kindleprefs: + pids, serials = parseKindleString(kindleprefs['pids']) + for pid in pids: + if pid not in dedrmprefs['pids']: + dedrmprefs['pids'].append(pid) + if 'serials' in kindleprefs: + pids, serials = parseKindleString(kindleprefs['serials']) + for serial in serials: + if serial not in dedrmprefs['serials']: + dedrmprefs['serials'].append(serial) + addedpidcount = len(dedrmprefs['pids']) - priorpidcount + if addedpidcount > 0: + print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs") + addedserialcount = len(dedrmprefs['serials']) - priorserialcount + if addedserialcount > 0: + print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers") + + # Make the json write all the prefs to disk + writeprefs() + print u"{0} v{1}: Finished setting up configuration data.".format(PLUGIN_NAME, PLUGIN_VERSION) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/convert2xml.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/convert2xml.py index c4e23b7..101c45a 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/convert2xml.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/convert2xml.py @@ -264,6 +264,7 @@ class PageParser(object): 'img.color_src' : (1, 'scalar_number', 0, 0), 'img.gridBeginCenter' : (1, 'scalar_number', 0, 0), 'img.gridEndCenter' : (1, 'scalar_number', 0, 0), + 'img.image_type' : (1, 'scalar_number', 0, 0), 'paragraph' : (1, 'snippets', 1, 0), 'paragraph.class' : (1, 'scalar_text', 0, 0), @@ -272,9 +273,9 @@ class PageParser(object): 'paragraph.lastWord' : (1, 'scalar_number', 0, 0), 'paragraph.gridSize' : (1, 'scalar_number', 0, 0), 'paragraph.gridBottomCenter' : (1, 'scalar_number', 0, 0), - 'paragraph.gridTopCenter' : (1, 'scalar_number', 0, 0), - 'paragraph.gridBeginCenter' : (1, 'scalar_number', 0, 0), - 'paragraph.gridEndCenter' : (1, 'scalar_number', 0, 0), + 'paragraph.gridTopCenter' : (1, 'scalar_number', 0, 0), + 'paragraph.gridBeginCenter' : (1, 'scalar_number', 0, 0), + 'paragraph.gridEndCenter' : (1, 'scalar_number', 0, 0), 'word_semantic' : (1, 'snippets', 1, 1), @@ -282,6 +283,10 @@ class PageParser(object): 'word_semantic.class' : (1, 'scalar_text', 0, 0), 'word_semantic.firstWord' : (1, 'scalar_number', 0, 0), 'word_semantic.lastWord' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridBottomCenter' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridTopCenter' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridBeginCenter' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridEndCenter' : (1, 'scalar_number', 0, 0), 'word' : (1, 'snippets', 1, 0), 'word.type' : (1, 'scalar_text', 0, 0), diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/description.rtfd/TXT.rtf b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/description.rtfd/TXT.rtf index 4ea1054..cbc6490 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/description.rtfd/TXT.rtf +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/description.rtfd/TXT.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360 +{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 {\fonttbl} {\colortbl;\red255\green255\blue255;} } \ No newline at end of file diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/dialogs.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/dialogs.py new file mode 100644 index 0000000..21c1dad --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/dialogs.py @@ -0,0 +1,719 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +from __future__ import with_statement +__license__ = 'GPL v3' + +# Standard Python modules. +import os, sys, re, hashlib +import json + +from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QListWidget, QListWidgetItem, QAbstractItemView, QLineEdit, QPushButton, QIcon, QGroupBox, QDialog, QDialogButtonBox, QUrl, QString) +from PyQt4 import QtGui + +# calibre modules and constants. +from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url, + choose_dir, choose_files) +from calibre.utils.config import dynamic, config_dir, JSONConfig + +from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION +from calibre_plugins.dedrm.utilities import (uStrCmp, DETAILED_MESSAGE, parseCustString) +from calibre_plugins.dedrm.ignoblekeygen import generate_key as generate_bandn_key +from calibre_plugins.dedrm.erdr2pml import getuser_key as generate_ereader_key +from calibre_plugins.dedrm.adobekey import adeptkeys as retrieve_adept_keys +from calibre_plugins.dedrm.kindlekey import kindlekeys as retrieve_kindle_keys + +class ManageKeysDialog(QDialog): + def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = u""): + QDialog.__init__(self,parent) + self.parent = parent + self.key_type_name = key_type_name + self.plugin_keys = plugin_keys + self.create_key = create_key + self.keyfile_ext = keyfile_ext + self.import_key = (keyfile_ext != u"") + self.binary_file = (key_type_name == u"Adobe Digital Editions Key") + self.json_file = (key_type_name == u"Kindle for Mac and PC Key") + + self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) + + # Start Qt Gui dialog layout + layout = QVBoxLayout(self) + self.setLayout(layout) + + help_layout = QHBoxLayout() + layout.addLayout(help_layout) + # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. + help_label = QLabel('Help', self) + help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) + help_label.setAlignment(Qt.AlignRight) + help_label.linkActivated.connect(self.help_link_activated) + help_layout.addWidget(help_label) + + keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self) + layout.addWidget(keys_group_box) + keys_group_box_layout = QHBoxLayout() + keys_group_box.setLayout(keys_group_box_layout) + + self.listy = QListWidget(self) + self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name)) + self.listy.setSelectionMode(QAbstractItemView.SingleSelection) + self.populate_list() + keys_group_box_layout.addWidget(self.listy) + + button_layout = QVBoxLayout() + keys_group_box_layout.addLayout(button_layout) + self._add_key_button = QtGui.QToolButton(self) + self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name)) + self._add_key_button.setIcon(QIcon(I('plus.png'))) + self._add_key_button.clicked.connect(self.add_key) + button_layout.addWidget(self._add_key_button) + + self._delete_key_button = QtGui.QToolButton(self) + self._delete_key_button.setToolTip(_(u"Delete highlighted key")) + self._delete_key_button.setIcon(QIcon(I('list_remove.png'))) + self._delete_key_button.clicked.connect(self.delete_key) + button_layout.addWidget(self._delete_key_button) + + if type(self.plugin_keys) == dict: + self._rename_key_button = QtGui.QToolButton(self) + self._rename_key_button.setToolTip(_(u"Rename highlighted key")) + self._rename_key_button.setIcon(QIcon(I('edit-select-all.png'))) + self._rename_key_button.clicked.connect(self.rename_key) + button_layout.addWidget(self._rename_key_button) + + self.export_key_button = QtGui.QToolButton(self) + self.export_key_button.setToolTip(u"Save highlighted key to a .{0} file".format(self.keyfile_ext)) + self.export_key_button.setIcon(QIcon(I('save.png'))) + self.export_key_button.clicked.connect(self.export_key) + button_layout.addWidget(self.export_key_button) + spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + button_layout.addItem(spacerItem) + + layout.addSpacing(5) + migrate_layout = QHBoxLayout() + layout.addLayout(migrate_layout) + if self.import_key: + migrate_layout.setAlignment(Qt.AlignJustify) + self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self) + self.migrate_btn.setToolTip(u"Import *.{0} files (created using other tools).".format(self.keyfile_ext)) + self.migrate_btn.clicked.connect(self.migrate_wrapper) + migrate_layout.addWidget(self.migrate_btn) + migrate_layout.addStretch() + self.button_box = QDialogButtonBox(QDialogButtonBox.Close) + self.button_box.rejected.connect(self.close) + migrate_layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + def populate_list(self): + if type(self.plugin_keys) == dict: + for key in self.plugin_keys.keys(): + self.listy.addItem(QListWidgetItem(key)) + else: + for key in self.plugin_keys: + self.listy.addItem(QListWidgetItem(key)) + + def add_key(self): + d = self.create_key(self) + d.exec_() + + if d.result() != d.Accepted: + # New key generation cancelled. + return + new_key_value = d.key_value + if type(self.plugin_keys) == dict: + if new_key_value in self.plugin_keys.values(): + old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0] + info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name), + u"The new {1} is the same as the existing {1} named {0} and has not been added.".format(old_key_name,self.key_type_name), show=True) + return + self.plugin_keys[d.key_name] = new_key_value + else: + if new_key_value in self.plugin_keys: + info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name), + u"This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True) + return + + self.plugin_keys.append(d.key_value) + self.listy.clear() + self.populate_list() + + def rename_key(self): + if not self.listy.currentItem(): + errmsg = u"No {0} selected to rename. Highlight a keyfile first.".format(self.key_type_name) + r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + return + + d = RenameKeyDialog(self) + d.exec_() + + if d.result() != d.Accepted: + # rename cancelled or moot. + return + keyname = unicode(self.listy.currentItem().text().toUtf8(),'utf8') + if not question_dialog(self, "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to rename the {2} named {0} to {1}?".format(keyname,d.key_name,self.key_type_name), show_copy_button=False, default_yes=False): + return + self.plugin_keys[d.key_name] = self.plugin_keys[keyname] + del self.plugin_keys[keyname] + + self.listy.clear() + self.populate_list() + + def delete_key(self): + if not self.listy.currentItem(): + return + keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8') + if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to delete the {1} {0}?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False): + return + if type(self.plugin_keys) == dict: + del self.plugin_keys[keyname] + else: + self.plugin_keys.remove(keyname) + + self.listy.clear() + self.populate_list() + + def help_link_activated(self, url): + def get_help_file_resource(): + # Copy the HTML helpfile to the plugin directory each time the + # link is clicked in case the helpfile is updated in newer plugins. + help_file_name = u"{0}_{1}_Help.htm".format(PLUGIN_NAME, self.key_type_name) + file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name) + with open(file_path,'w') as f: + f.write(self.parent.load_resource(help_file_name)) + return file_path + url = 'file:///' + get_help_file_resource() + open_url(QUrl(url)) + + def migrate_files(self): + dynamic[PLUGIN_NAME + u"config_dir"] = config_dir + files = choose_files(self, PLUGIN_NAME + u"config_dir", + u"Select {0} files to import".format(self.key_type_name), [(u"{0} files".format(self.key_type_name), [self.keyfile_ext])], False) + counter = 0 + skipped = 0 + if files: + for filename in files: + fpath = os.path.join(config_dir, filename) + filename = os.path.basename(filename) + new_key_name = os.path.splitext(os.path.basename(filename))[0] + with open(fpath,'rb') as keyfile: + new_key_value = keyfile.read() + if self.binary_file: + new_key_value = new_key_value.encode('hex') + elif self.json_file: + new_key_value = json.loads(new_key_value) + match = False + for key in self.plugin_keys.keys(): + if uStrCmp(new_key_name, key, True): + skipped += 1 + msg = u"A key with the name {0} already exists!\nSkipping key file {1}.\nRename the existing key and import again".format(new_key_name,filename) + inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(msg), show_copy_button=False, show=True) + match = True + break + if not match: + if new_key_value in self.plugin_keys.values(): + old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0] + skipped += 1 + info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + u"The key in file {0} is the same as the existing key {1} and has been skipped.".format(filename,old_key_name), show_copy_button=False, show=True) + else: + counter += 1 + self.plugin_keys[new_key_name] = new_key_value + + msg = u"" + if counter+skipped > 1: + if counter > 0: + msg += u"Imported {0:d} key {1}. ".format(counter, u"file" if counter == 1 else u"files") + if skipped > 0: + msg += u"Skipped {0:d} key {1}.".format(skipped, u"file" if counter == 1 else u"files") + inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(msg), show_copy_button=False, show=True) + return counter > 0 + + def migrate_wrapper(self): + if self.migrate_files(): + self.listy.clear() + self.populate_list() + + def export_key(self): + if not self.listy.currentItem(): + errmsg = u"No keyfile selected to export. Highlight a keyfile first." + r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + return + filter = QString(u"{0} Files (*.{1})".format(self.key_type_name, self.keyfile_ext)) + keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8') + if dynamic.get(PLUGIN_NAME + 'save_dir'): + defaultname = os.path.join(dynamic.get(PLUGIN_NAME + 'save_dir'), u"{0}.{1}".format(keyname , self.keyfile_ext)) + else: + defaultname = os.path.join(os.path.expanduser('~'), u"{0}.{1}".format(keyname , self.keyfile_ext)) + filename = unicode(QtGui.QFileDialog.getSaveFileName(self, u"Save {0} File as...".format(self.key_type_name), defaultname, + u"{0} Files (*.{1})".format(self.key_type_name,self.keyfile_ext), filter)) + if filename: + dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0] + with file(filename, 'w') as fname: + if self.binary_file: + fname.write(self.plugin_keys[keyname].decode('hex')) + elif self.json_file: + fname.write(json.dumps(self.plugin_keys[keyname])) + else: + fname.write(self.plugin_keys[keyname]) + + + + +class RenameKeyDialog(QDialog): + def __init__(self, parent=None,): + print repr(self), repr(parent) + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle("{0} {1}: Rename {0}".format(PLUGIN_NAME, PLUGIN_VERSION, parent.key_type_name)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox('', self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + data_group_box_layout.addWidget(QLabel('New Key Name:', self)) + self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self) + self.key_ledit.setToolTip(u"Enter a new name for this existing {0}.".format(parent.key_type_name)) + data_group_box_layout.addWidget(self.key_ledit) + + layout.addSpacing(20) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + def accept(self): + if self.key_ledit.text().isEmpty() or unicode(self.key_ledit.text()).isspace(): + errmsg = u"Key name field cannot be empty!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + if len(self.key_ledit.text()) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + if uStrCmp(self.key_ledit.text(), self.parent.listy.currentItem().text()): + # Same exact name ... do nothing. + return QDialog.reject(self) + for k in self.parent.plugin_keys.keys(): + if (uStrCmp(self.key_ledit.text(), k, True) and + not uStrCmp(k, self.parent.listy.currentItem().text(), True)): + errmsg = u"The key name {0} is already being used.".format(self.key_ledit.text()) + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + QDialog.accept(self) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + + + + + + + +class AddBandNKeyDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Create New Barnes & Noble Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(_(u"

Enter an identifying name for this new key.

" + + u"

It should be something that will help you remember " + + u"what personal information was used to create it.")) + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + name_group = QHBoxLayout() + data_group_box_layout.addLayout(name_group) + name_group.addWidget(QLabel(u"Your Name:", self)) + self.name_ledit = QLineEdit(u"", self) + self.name_ledit.setToolTip(_(u"

Enter your name as it appears in your B&N " + + u"account or on your credit card.

" + + u"

It will only be used to generate this " + + u"one-time key and won\'t be stored anywhere " + + u"in calibre or on your computer.

" + + u"

(ex: Jonathan Smith)")) + name_group.addWidget(self.name_ledit) + name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self) + name_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(name_disclaimer_label) + + ccn_group = QHBoxLayout() + data_group_box_layout.addLayout(ccn_group) + ccn_group.addWidget(QLabel(u"Credit Card#:", self)) + self.cc_ledit = QLineEdit(u"", self) + self.cc_ledit.setToolTip(_(u"

Enter the full credit card number on record " + + u"in your B&N account.

" + + u"

No spaces or dashes... just the numbers. " + + u"This number will only be used to generate this " + + u"one-time key and won\'t be stored anywhere in " + + u"calibre or on your computer.")) + ccn_group.addWidget(self.cc_ledit) + ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self) + ccn_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(ccn_disclaimer_label) + layout.addSpacing(10) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return generate_bandn_key(self.user_name,self.cc_number) + + @property + def user_name(self): + return unicode(self.name_ledit.text().toUtf8(), 'utf8').strip().lower().replace(' ','') + + @property + def cc_number(self): + return unicode(self.cc_ledit.text().toUtf8(), 'utf8').strip().replace(' ', '').replace('-','') + + + def accept(self): + if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if not self.cc_number.isdigit(): + errmsg = u"Numbers only in the credit card number field!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + +class AddEReaderDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Create New eReader Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"

Enter an identifying name for this new key.\nIt should be something that will help you remember what personal information was used to create it.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + name_group = QHBoxLayout() + data_group_box_layout.addLayout(name_group) + name_group.addWidget(QLabel(u"Your Name:", self)) + self.name_ledit = QLineEdit(u"", self) + self.name_ledit.setToolTip(u"Enter the name for this eReader key, usually the name on your credit card.\nIt will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.\n(ex: Mr Jonathan Q Smith)") + name_group.addWidget(self.name_ledit) + name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self) + name_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(name_disclaimer_label) + + ccn_group = QHBoxLayout() + data_group_box_layout.addLayout(ccn_group) + ccn_group.addWidget(QLabel(u"Credit Card#:", self)) + self.cc_ledit = QLineEdit(u"", self) + self.cc_ledit.setToolTip(u"

Enter the last 8 digits of credit card number for this eReader key.\nThey will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.") + ccn_group.addWidget(self.cc_ledit) + ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self) + ccn_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(ccn_disclaimer_label) + layout.addSpacing(10) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return generate_ereader_key(self.user_name,self.cc_number).encode('hex') + + @property + def user_name(self): + return unicode(self.name_ledit.text().toUtf8(), 'utf8').strip().lower().replace(' ','') + + @property + def cc_number(self): + return unicode(self.cc_ledit.text().toUtf8(), 'utf8').strip().replace(' ', '').replace('-','') + + + def accept(self): + if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if not self.cc_number.isdigit(): + errmsg = u"Numbers only in the credit card number field!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddAdeptDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Getting Default Adobe Digital Editions Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + try: + self.default_key = retrieve_adept_keys()[0] + except: + self.default_key = u"" + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + + if len(self.default_key)>0: + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"

Enter an identifying name for the current default Adobe Digital Editions key.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + self.button_box.accepted.connect(self.accept) + else: + default_key_error = QLabel(u"The default encryption key for Adobe Digital Editions could not be found.", self) + default_key_error.setAlignment(Qt.AlignHCenter) + layout.addWidget(default_key_error) + # if no default, bot buttons do the same + self.button_box.accepted.connect(self.reject) + + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return self.default_key.encode('hex') + + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddKindleDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Getting Default Kindle for Mac/PC Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + try: + self.default_key = retrieve_kindle_keys()[0] + except: + self.default_key = u"" + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + + if len(self.default_key)>0: + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"

Enter an identifying name for the current default Kindle for Mac/PC key.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + self.button_box.accepted.connect(self.accept) + else: + default_key_error = QLabel(u"The default encryption key for Kindle for Mac/PC could not be found.", self) + default_key_error.setAlignment(Qt.AlignHCenter) + layout.addWidget(default_key_error) + # if no default, bot buttons do the same + self.button_box.accepted.connect(self.reject) + + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return self.default_key + + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddSerialDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"EInk Kindle Serial Number:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"Enter an eInk Kindle serial number. EInk Kindle serial numbers are 16 characters long and usually start with a 'B' or a '9'. Kindle Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"Please enter an eInk Kindle Serial Number or click Cancel in the dialog." + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) != 16: + errmsg = u"EInk Kindle Serial Numbers must be 16 characters long. This is {0:d} characters long.".format(len(self.key_name)) + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddPIDDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"PID:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"Please enter a Mobipocket PID or click Cancel in the dialog." + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) != 8 and len(self.key_name) != 10: + errmsg = u"Mobipocket PIDs must be 8 or 10 characters long. This is {0:d} characters long.".format(len(self.key_name)) + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/epubtest.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/epubtest.py index a44308e..d91624f 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/epubtest.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/epubtest.py @@ -7,8 +7,8 @@ # 1.00 - Initial version, with code from various other scripts # 1.01 - Moved authorship announcement to usage section. # -# Changelog drmcheck -# 1.00 - Cut to drmtest.py, testing ePub files only by Apprentice Alf +# Changelog epubtest +# 1.00 - Cut to epubtest.py, testing ePub files only by Apprentice Alf # # Written in 2011 by Paul Durrant # Released with unlicense. See http://unlicense.org/ diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/erdr2pml.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/erdr2pml.py index 239c5ac..d982a44 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/erdr2pml.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/erdr2pml.py @@ -70,7 +70,7 @@ __version__='0.22' import sys, re -import struct, binascii, getopt, zlib, os, os.path, urllib, tempfile +import struct, binascii, getopt, zlib, os, os.path, urllib, tempfile, traceback if 'calibre' in sys.modules: inCalibre = True @@ -139,28 +139,28 @@ Des = None if iswindows: # first try with pycrypto if inCalibre: - from calibre_plugins.erdrpdb2pml import pycrypto_des + from calibre_plugins.dedrm import pycrypto_des else: import pycrypto_des Des = pycrypto_des.load_pycrypto() if Des == None: # they try with openssl if inCalibre: - from calibre_plugins.erdrpdb2pml import openssl_des + from calibre_plugins.dedrm import openssl_des else: import openssl_des Des = openssl_des.load_libcrypto() else: # first try with openssl if inCalibre: - from calibre_plugins.erdrpdb2pml import openssl_des + from calibre_plugins.dedrm import openssl_des else: import openssl_des Des = openssl_des.load_libcrypto() if Des == None: # then try with pycrypto if inCalibre: - from calibre_plugins.erdrpdb2pml import pycrypto_des + from calibre_plugins.dedrm import pycrypto_des else: import pycrypto_des Des = pycrypto_des.load_pycrypto() @@ -169,7 +169,7 @@ else: # of DES and try to speed it up with Psycho if Des == None: if inCalibre: - from calibre_plugins.erdrpdb2pml import python_des + from calibre_plugins.dedrm import python_des else: import python_des Des = python_des.Des @@ -522,7 +522,8 @@ def decryptBook(infile, outpath, make_pmlz, user_key): print u"Output is in {0}".format(outdir) print "done" except ValueError, e: - print u"Error: {0}".format(e.args[0]) + print u"Error: {0}".format(e) + traceback.print_exc() return 1 return 0 diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/genbook.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/genbook.py index 746178f..3ed925d 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/genbook.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/genbook.py @@ -29,10 +29,10 @@ else: inCalibre = False if inCalibre : - from calibre_plugins.k4mobidedrm import convert2xml - from calibre_plugins.k4mobidedrm import flatxml2html - from calibre_plugins.k4mobidedrm import flatxml2svg - from calibre_plugins.k4mobidedrm import stylexml2css + from calibre_plugins.dedrm import convert2xml + from calibre_plugins.dedrm import flatxml2html + from calibre_plugins.dedrm import flatxml2svg + from calibre_plugins.dedrm import stylexml2css else : import convert2xml import flatxml2html diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/getk4pcpids.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/getk4pcpids.py deleted file mode 100644 index 1614a53..0000000 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/getk4pcpids.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/python -# -# This is a python script. You need a Python interpreter to run it. -# For example, ActiveState Python, which exists for windows. -# -# Changelog -# 1.00 - Initial version -# 1.01 - getPidList interface change - -__version__ = '1.01' - -import sys - -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) -sys.stdout=SafeUnbuffered(sys.stdout) -sys.stderr=SafeUnbuffered(sys.stderr) - -import os -import struct -import binascii -import kgenpids -import topazextract -import mobidedrm -from alfcrypto import Pukall_Cipher - -class DrmException(Exception): - pass - -def getK4PCpids(path_to_ebook): - # Return Kindle4PC PIDs. Assumes that the caller checked that we are not on Linux, which will raise an exception - - mobi = True - magic3 = file(path_to_ebook,'rb').read(3) - if magic3 == 'TPZ': - mobi = False - - if mobi: - mb = mobidedrm.MobiBook(path_to_ebook) - else: - mb = topazextract.TopazBook(path_to_ebook) - - md1, md2 = mb.getPIDMetaInfo() - - return kgenpids.getPidList(md1, md2) - - -def main(argv=sys.argv): - print ('getk4pcpids.py v%(__version__)s. ' - 'Copyright 2012 Apprentice Alf' % globals()) - - if len(argv)<2 or len(argv)>3: - print "Gets the possible book-specific PIDs from K4PC for a particular book" - print "Usage:" - print " %s []" % sys.argv[0] - return 1 - else: - infile = argv[1] - try: - pidlist = getK4PCpids(infile) - except DrmException, e: - print "Error: %s" % e - return 1 - pidstring = ','.join(pidlist) - print "Possible PIDs are: ", pidstring - if len(argv) is 3: - outfile = argv[2] - file(outfile, 'w').write(pidstring) - - return 0 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py index b7cbdc5..4cf74ae 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py @@ -3,13 +3,13 @@ from __future__ import with_statement -# ignobleepub.pyw, version 3.7 +# ignobleepub.pyw, version 3.8 # Copyright © 2009-2010 by i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Modified 2010–2012 by some_updates, DiapDealer and Apprentice Alf +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf # Windows users: Before running this program, you must first install Python 2.6 # from and PyCrypto from @@ -32,20 +32,21 @@ from __future__ import with_statement # 3.5 - Fix for potential problem with PyCrypto # 3.6 - Revised to allow use in calibre plugins to eliminate need for duplicate code # 3.7 - Tweaked to match ineptepub more closely +# 3.8 - Fixed to retain zip file metadata (e.g. file modification date) """ Decrypt Barnes & Noble encrypted ePub books. """ __license__ = 'GPL v3' -__version__ = "3.7" +__version__ = "3.8" import sys import os import traceback import zlib import zipfile -from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED +from zipfile import ZipInfo, ZipFile, ZIP_STORED, ZIP_DEFLATED from contextlib import closing import xml.etree.ElementTree as etree @@ -200,13 +201,6 @@ META_NAMES = ('mimetype', 'META-INF/rights.xml', 'META-INF/encryption.xml') NSMAP = {'adept': 'http://ns.adobe.com/adept', 'enc': 'http://www.w3.org/2001/04/xmlenc#'} -class ZipInfo(zipfile.ZipInfo): - def __init__(self, *args, **kwargs): - if 'compress_type' in kwargs: - compress_type = kwargs.pop('compress_type') - super(ZipInfo, self).__init__(*args, **kwargs) - self.compress_type = compress_type - class Decryptor(object): def __init__(self, bookkey, encryption): enc = lambda tag: '{%s}%s' % (NSMAP['enc'], tag) @@ -282,11 +276,40 @@ def decryptBook(keyb64, inpath, outpath): decryptor = Decryptor(bookkey[-16:], encryption) kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: - zi = ZipInfo('mimetype', compress_type=ZIP_STORED) + zi = ZipInfo('mimetype') + zi.compress_type=ZIP_STORED + try: + # if the mimetype is present, get its info, including time-stamp + oldzi = inf.getinfo('mimetype') + # copy across fields to be preserved + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass outf.writestr(zi, inf.read('mimetype')) for path in namelist: data = inf.read(path) - outf.writestr(path, decryptor.decrypt(path, data)) + zi = ZipInfo(path) + zi.compress_type=ZIP_DEFLATED + try: + # get the file info, including time-stamp + oldzi = inf.getinfo(path) + # copy across useful fields + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass + outf.writestr(zi, decryptor.decrypt(path, data)) except: print u"Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc()) return 2 diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py index f25359c..ec78e65 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py @@ -4,21 +4,23 @@ from __future__ import with_statement # ignoblekeygen.pyw, version 2.5 -# Copyright © 2009-2010 by i♥cabbages +# Copyright © 2009-2010 i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Modified 2010–2012 by some_updates, DiapDealer and Apprentice Alf +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf -# Windows users: Before running this program, you must first install Python 2.6 -# from and PyCrypto from -# (make sure to -# install the version for Python 2.6). Save this script file as -# ignoblekeygen.pyw and double-click on it to run it. +# Windows users: Before running this program, you must first install Python. +# We recommend ActiveState Python 2.7.X for Windows (x86) from +# http://www.activestate.com/activepython/downloads. +# You must also install PyCrypto from +# http://www.voidspace.org.uk/python/modules.shtml#pycrypto +# (make certain to install the version for Python 2.7). +# Then save this script file as ignoblekeygen.pyw and double-click on it to run it. # # Mac OS X users: Save this script file as ignoblekeygen.pyw. You can run this -# program from the command line (pythonw ignoblekeygen.pyw) or by double-clicking +# program from the command line (python ignoblekeygen.pyw) or by double-clicking # it when it has been associated with PythonLauncher. # Revision history: @@ -58,8 +60,11 @@ class SafeUnbuffered: def __getattr__(self, attr): return getattr(self.stream, attr) -iswindows = sys.platform.startswith('win') -isosx = sys.platform.startswith('darwin') +try: + from calibre.constants import iswindows, isosx +except: + iswindows = sys.platform.startswith('win') + isosx = sys.platform.startswith('darwin') def unicode_argv(): if iswindows: @@ -68,8 +73,8 @@ def unicode_argv(): # 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 '?'. - + # characters with '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 from ctypes import POINTER, byref, cdll, c_int, windll from ctypes.wintypes import LPCWSTR, LPWSTR diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py index 48b7727..98a134e 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py @@ -3,13 +3,13 @@ from __future__ import with_statement -# ineptepub.pyw, version 5.8 +# ineptepub.pyw, version 5.9 # Copyright © 2009-2010 by i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Modified 2010–2012 by some_updates, DiapDealer and Apprentice Alf +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf # Windows users: Before running this program, you must first install Python 2.6 # from and PyCrypto from @@ -34,20 +34,21 @@ from __future__ import with_statement # 5.6 - Modify interface to allow use with import # 5.7 - Fix for potential problem with PyCrypto # 5.8 - Revised to allow use in calibre plugins to eliminate need for duplicate code +# 5.9 - Fixed to retain zip file metadata (e.g. file modification date) """ Decrypt Adobe Digital Editions encrypted ePub books. """ __license__ = 'GPL v3' -__version__ = "5.8" +__version__ = "5.9" import sys import os import traceback import zlib import zipfile -from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED +from zipfile import ZipInfo, ZipFile, ZIP_STORED, ZIP_DEFLATED from contextlib import closing import xml.etree.ElementTree as etree @@ -340,13 +341,6 @@ META_NAMES = ('mimetype', 'META-INF/rights.xml', 'META-INF/encryption.xml') NSMAP = {'adept': 'http://ns.adobe.com/adept', 'enc': 'http://www.w3.org/2001/04/xmlenc#'} -class ZipInfo(zipfile.ZipInfo): - def __init__(self, *args, **kwargs): - if 'compress_type' in kwargs: - compress_type = kwargs.pop('compress_type') - super(ZipInfo, self).__init__(*args, **kwargs) - self.compress_type = compress_type - class Decryptor(object): def __init__(self, bookkey, encryption): enc = lambda tag: '{%s}%s' % (NSMAP['enc'], tag) @@ -424,11 +418,40 @@ def decryptBook(userkey, inpath, outpath): decryptor = Decryptor(bookkey[-16:], encryption) kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: - zi = ZipInfo('mimetype', compress_type=ZIP_STORED) + zi = ZipInfo('mimetype') + zi.compress_type=ZIP_STORED + try: + # if the mimetype is present, get its info, including time-stamp + oldzi = inf.getinfo('mimetype') + # copy across fields to be preserved + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass outf.writestr(zi, inf.read('mimetype')) for path in namelist: data = inf.read(path) - outf.writestr(path, decryptor.decrypt(path, data)) + zi = ZipInfo(path) + zi.compress_type=ZIP_DEFLATED + try: + # get the file info, including time-stamp + oldzi = inf.getinfo(path) + # copy across useful fields + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass + outf.writestr(zi, decryptor.decrypt(path, data)) except: print u"Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc()) return 2 diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py index 70ed898..1ae5c88 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py @@ -51,8 +51,10 @@ from __future__ import with_statement # 4.8 - Much better unicode handling, matching the updated inept and ignoble scripts # - Moved back into plugin, __init__ in plugin now only contains plugin code. # 4.9 - Missed some invalid characters in cleanup_name +# 5.0 - Extraction of info from Kindle for PC/Mac moved into kindlekey.py +# - tweaked GetDecryptedBook interface to leave passed parameters unchanged -__version__ = '4.9' +__version__ = '5.0' import sys, os, re @@ -62,6 +64,7 @@ import re import traceback import time import htmlentitydefs +import json class DrmException(Exception): pass @@ -72,9 +75,9 @@ else: inCalibre = False if inCalibre: - from calibre_plugins.k4mobidedrm import mobidedrm - from calibre_plugins.k4mobidedrm import topazextract - from calibre_plugins.k4mobidedrm import kgenpids + from calibre_plugins.dedrm import mobidedrm + from calibre_plugins.dedrm import topazextract + from calibre_plugins.dedrm import kgenpids else: import mobidedrm import topazextract @@ -180,13 +183,13 @@ def unescape(text): return text # leave as is return re.sub(u"&#?\w+;", fixup, text) -def GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime = time.time()): +def GetDecryptedBook(infile, kDatabases, serials, pids, starttime = time.time()): # handle the obvious cases at the beginning if not os.path.isfile(infile): raise DRMException (u"Input file does not exist.") mobi = True - magic3 = file(infile,'rb').read(3) + magic3 = open(infile,'rb').read(3) if magic3 == 'TPZ': mobi = False @@ -198,13 +201,15 @@ def GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime = time.time()) bookname = unescape(mb.getBookTitle()) print u"Decrypting {1} ebook: {0}".format(bookname, mb.getBookType()) + # copy list of pids + totalpids = list(pids) # extend PID list with book-specific PIDs md1, md2 = mb.getPIDMetaInfo() - pids.extend(kgenpids.getPidList(md1, md2, serials, kInfoFiles)) - print u"Found {1:d} keys to try after {0:.1f} seconds".format(time.time()-starttime, len(pids)) + totalpids.extend(kgenpids.getPidList(md1, md2, serials, kDatabases)) + print u"Found {1:d} keys to try after {0:.1f} seconds".format(time.time()-starttime, len(totalpids)) try: - mb.processBook(pids) + mb.processBook(totalpids) except: mb.cleanup raise @@ -213,12 +218,24 @@ def GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime = time.time()) return mb -# infile, outdir and kInfoFiles should be unicode strings -def decryptBook(infile, outdir, kInfoFiles, serials, pids): +# kDatabaseFiles is a list of files created by kindlekey +def decryptBook(infile, outdir, kDatabaseFiles, serials, pids): starttime = time.time() - print "Starting decryptBook routine." + kDatabases = [] + for dbfile in kDatabaseFiles: + kindleDatabase = {} + try: + with open(dbfile, 'r') as keyfilein: + kindleDatabase = json.loads(keyfilein.read()) + kDatabases.append([dbfile,kindleDatabase]) + except Exception, e: + print u"Error getting database from file {0:s}: {1:s}".format(dbfile,e) + traceback.print_exc() + + + try: - book = GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime) + book = GetDecryptedBook(infile, kDatabases, serials, pids, starttime) except Exception, e: print u"Error decrypting book after {1:.1f} seconds: {0}".format(e.args[0],time.time()-starttime) traceback.print_exc() @@ -254,14 +271,14 @@ def decryptBook(infile, outdir, kInfoFiles, serials, pids): def usage(progname): print u"Removes DRM protection from Mobipocket, Amazon KF8, Amazon Print Replica and Amazon Topaz ebooks" print u"Usage:" - print u" {0} [-k ] [-p ] [-s ] ".format(progname) + print u" {0} [-k ] [-p ] [-s ] ".format(progname) # # Main # def cli_main(argv=unicode_argv()): progname = os.path.basename(argv[0]) - print u"K4MobiDeDrm v{0}.\nCopyright © 2008-2012 The Dark Reverser et al.".format(__version__) + print u"K4MobiDeDrm v{0}.\nCopyright © 2008-2013 The Dark Reverser et al.".format(__version__) try: opts, args = getopt.getopt(sys.argv[1:], "k:p:s:") @@ -275,7 +292,7 @@ def cli_main(argv=unicode_argv()): infile = args[0] outdir = args[1] - kInfoFiles = [] + kDatabaseFiles = [] serials = [] pids = [] @@ -283,7 +300,7 @@ def cli_main(argv=unicode_argv()): if o == "-k": if a == None : raise DrmException("Invalid parameter for -k") - kInfoFiles.append(a) + kDatabaseFiles.append(a) if o == "-p": if a == None : raise DrmException("Invalid parameter for -p") @@ -296,7 +313,7 @@ def cli_main(argv=unicode_argv()): # try with built in Kindle Info files if not on Linux k4 = not sys.platform.startswith('linux') - return decryptBook(infile, outdir, kInfoFiles, serials, pids) + return decryptBook(infile, outdir, kDatabaseFiles, serials, pids) if __name__ == '__main__': diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mutils.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mutils.py deleted file mode 100644 index bceb3a3..0000000 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mutils.py +++ /dev/null @@ -1,747 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# standlone set of Mac OSX specific routines needed for KindleBooks - -from __future__ import with_statement - -import sys -import os -import os.path -import re -import copy -import subprocess -from struct import pack, unpack, unpack_from - -class DrmException(Exception): - pass - - -# interface to needed routines in openssl's libcrypto -def _load_crypto_libcrypto(): - from ctypes import CDLL, byref, POINTER, c_void_p, c_char_p, c_int, c_long, \ - Structure, c_ulong, create_string_buffer, addressof, string_at, cast - from ctypes.util import find_library - - libcrypto = find_library('crypto') - if libcrypto is None: - raise DrmException(u"libcrypto not found") - libcrypto = CDLL(libcrypto) - - # From OpenSSL's crypto aes header - # - # AES_ENCRYPT 1 - # AES_DECRYPT 0 - # AES_MAXNR 14 (in bytes) - # AES_BLOCK_SIZE 16 (in bytes) - # - # struct aes_key_st { - # unsigned long rd_key[4 *(AES_MAXNR + 1)]; - # int rounds; - # }; - # typedef struct aes_key_st AES_KEY; - # - # int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); - # - # note: the ivec string, and output buffer are both mutable - # void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, - # const unsigned long length, const AES_KEY *key, unsigned char *ivec, const int enc); - - AES_MAXNR = 14 - c_char_pp = POINTER(c_char_p) - c_int_p = POINTER(c_int) - - class AES_KEY(Structure): - _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), ('rounds', c_int)] - AES_KEY_p = POINTER(AES_KEY) - - def F(restype, name, argtypes): - func = getattr(libcrypto, name) - func.restype = restype - func.argtypes = argtypes - return func - - AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',[c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p,c_int]) - - AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',[c_char_p, c_int, AES_KEY_p]) - - # From OpenSSL's Crypto evp/p5_crpt2.c - # - # int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, - # const unsigned char *salt, int saltlen, int iter, - # int keylen, unsigned char *out); - - PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', - [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p]) - - class LibCrypto(object): - def __init__(self): - self._blocksize = 0 - self._keyctx = None - self._iv = 0 - - def set_decrypt_key(self, userkey, iv): - self._blocksize = len(userkey) - if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) : - raise DrmException(u"AES improper key used") - return - keyctx = self._keyctx = AES_KEY() - self._iv = iv - self._userkey = userkey - rv = AES_set_decrypt_key(userkey, len(userkey) * 8, keyctx) - if rv < 0: - raise DrmException(u"Failed to initialize AES key") - - def decrypt(self, data): - out = create_string_buffer(len(data)) - mutable_iv = create_string_buffer(self._iv, len(self._iv)) - keyctx = self._keyctx - rv = AES_cbc_encrypt(data, out, len(data), keyctx, mutable_iv, 0) - if rv == 0: - raise DrmException(u"AES decryption failed") - return out.raw - - def keyivgen(self, passwd, salt, iter, keylen): - saltlen = len(salt) - passlen = len(passwd) - out = create_string_buffer(keylen) - rv = PKCS5_PBKDF2_HMAC_SHA1(passwd, passlen, salt, saltlen, iter, keylen, out) - return out.raw - return LibCrypto - -def _load_crypto(): - LibCrypto = None - try: - LibCrypto = _load_crypto_libcrypto() - except (ImportError, DrmException): - pass - return LibCrypto - -LibCrypto = _load_crypto() - -# -# Utility Routines -# - -# crypto digestroutines -import hashlib - -def MD5(message): - ctx = hashlib.md5() - ctx.update(message) - return ctx.digest() - -def SHA1(message): - ctx = hashlib.sha1() - ctx.update(message) - return ctx.digest() - -def SHA256(message): - ctx = hashlib.sha256() - ctx.update(message) - return ctx.digest() - -# Various character maps used to decrypt books. Probably supposed to act as obfuscation -charMap1 = 'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' -charMap2 = 'ZB0bYyc1xDdW2wEV3Ff7KkPpL8UuGA4gz-Tme9Nn_tHh5SvXCsIiR6rJjQaqlOoM' - -# For kinf approach of K4Mac 1.6.X or later -# On K4PC charMap5 = 'AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE' -# For Mac they seem to re-use charMap2 here -charMap5 = charMap2 - -# new in K4M 1.9.X -testMap8 = 'YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD' - - -def encode(data, map): - result = '' - for char in data: - value = ord(char) - Q = (value ^ 0x80) // len(map) - R = value % len(map) - result += map[Q] - result += map[R] - return result - -# Hash the bytes in data and then encode the digest with the characters in map -def encodeHash(data,map): - return encode(MD5(data),map) - -# Decode the string in data with the characters in map. Returns the decoded bytes -def decode(data,map): - result = '' - for i in range (0,len(data)-1,2): - high = map.find(data[i]) - low = map.find(data[i+1]) - if (high == -1) or (low == -1) : - break - value = (((high * len(map)) ^ 0x80) & 0xFF) + low - result += pack('B',value) - return result - -# For K4M 1.6.X and later -# generate table of prime number less than or equal to int n -def primes(n): - if n==2: return [2] - elif n<2: return [] - s=range(3,n+1,2) - mroot = n ** 0.5 - half=(n+1)/2-1 - i=0 - m=3 - while m <= mroot: - if s[i]: - j=(m*m-3)/2 - s[j]=0 - while j= 0: - sernum = resline[pp+19:-1] - sernum = sernum.strip() - bb = resline.find('\"BSD Name\" = \"') - if bb >= 0: - bsdname = resline[bb+14:-1] - bsdname = bsdname.strip() - if (bsdname == 'disk0') and (sernum != None): - foundIt = True - break - if not foundIt: - sernum = '' - return sernum - -def GetUserHomeAppSupKindleDirParitionName(): - home = os.getenv('HOME') - dpath = home + '/Library' - cmdline = '/sbin/mount' - cmdline = cmdline.encode(sys.getfilesystemencoding()) - p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) - out1, out2 = p.communicate() - reslst = out1.split('\n') - cnt = len(reslst) - disk = '' - foundIt = False - for j in xrange(cnt): - resline = reslst[j] - if resline.startswith('/dev'): - (devpart, mpath) = resline.split(' on ') - dpart = devpart[5:] - pp = mpath.find('(') - if pp >= 0: - mpath = mpath[:pp-1] - if dpath.startswith(mpath): - disk = dpart - return disk - -# uses a sub process to get the UUID of the specified disk partition using ioreg -def GetDiskPartitionUUID(diskpart): - uuidnum = os.getenv('MYUUIDNUMBER') - if uuidnum != None: - return uuidnum - cmdline = '/usr/sbin/ioreg -l -S -w 0 -r -c AppleAHCIDiskDriver' - cmdline = cmdline.encode(sys.getfilesystemencoding()) - p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) - out1, out2 = p.communicate() - reslst = out1.split('\n') - cnt = len(reslst) - bsdname = None - uuidnum = None - foundIt = False - nest = 0 - uuidnest = -1 - partnest = -2 - for j in xrange(cnt): - resline = reslst[j] - if resline.find('{') >= 0: - nest += 1 - if resline.find('}') >= 0: - nest -= 1 - pp = resline.find('\"UUID\" = \"') - if pp >= 0: - uuidnum = resline[pp+10:-1] - uuidnum = uuidnum.strip() - uuidnest = nest - if partnest == uuidnest and uuidnest > 0: - foundIt = True - break - bb = resline.find('\"BSD Name\" = \"') - if bb >= 0: - bsdname = resline[bb+14:-1] - bsdname = bsdname.strip() - if (bsdname == diskpart): - partnest = nest - else : - partnest = -2 - if partnest == uuidnest and partnest > 0: - foundIt = True - break - if nest == 0: - partnest = -2 - uuidnest = -1 - uuidnum = None - bsdname = None - if not foundIt: - uuidnum = '' - return uuidnum - -def GetMACAddressMunged(): - macnum = os.getenv('MYMACNUM') - if macnum != None: - return macnum - cmdline = '/sbin/ifconfig en0' - cmdline = cmdline.encode(sys.getfilesystemencoding()) - p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) - out1, out2 = p.communicate() - reslst = out1.split('\n') - cnt = len(reslst) - macnum = None - foundIt = False - for j in xrange(cnt): - resline = reslst[j] - pp = resline.find('ether ') - if pp >= 0: - macnum = resline[pp+6:-1] - macnum = macnum.strip() - # print 'original mac', macnum - # now munge it up the way Kindle app does - # by xoring it with 0xa5 and swapping elements 3 and 4 - maclst = macnum.split(':') - n = len(maclst) - if n != 6: - fountIt = False - break - for i in range(6): - maclst[i] = int('0x' + maclst[i], 0) - mlst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] - mlst[5] = maclst[5] ^ 0xa5 - mlst[4] = maclst[3] ^ 0xa5 - mlst[3] = maclst[4] ^ 0xa5 - mlst[2] = maclst[2] ^ 0xa5 - mlst[1] = maclst[1] ^ 0xa5 - mlst[0] = maclst[0] ^ 0xa5 - macnum = '%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x' % (mlst[0], mlst[1], mlst[2], mlst[3], mlst[4], mlst[5]) - foundIt = True - break - if not foundIt: - macnum = '' - return macnum - - -# uses unix env to get username instead of using sysctlbyname -def GetUserName(): - username = os.getenv('USER') - return username - -def isNewInstall(): - home = os.getenv('HOME') - # soccer game fan anyone - dpath = home + '/Library/Application Support/Kindle/storage/.pes2011' - # print dpath, os.path.exists(dpath) - if os.path.exists(dpath): - return True - dpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.pes2011' - # print dpath, os.path.exists(dpath) - if os.path.exists(dpath): - return True - return False - - -class Memoize: - """Memoize(fn) - an instance which acts like fn but memoizes its arguments - Will only work on functions with non-mutable arguments - """ - def __init__(self, fn): - self.fn = fn - self.memo = {} - def __call__(self, *args): - if not self.memo.has_key(args): - self.memo[args] = self.fn(*args) - return self.memo[args] - -@Memoize -def GetIDString(): - # K4Mac now has an extensive set of ids strings it uses - # in encoding pids and in creating unique passwords - # for use in its own version of CryptUnprotectDataV2 - - # BUT Amazon has now become nasty enough to detect when its app - # is being run under a debugger and actually changes code paths - # including which one of these strings is chosen, all to try - # to prevent reverse engineering - - # Sad really ... they will only hurt their own sales ... - # true book lovers really want to keep their books forever - # and move them to their devices and DRM prevents that so they - # will just buy from someplace else that they can remove - # the DRM from - - # Amazon should know by now that true book lover's are not like - # penniless kids that pirate music, we do not pirate books - - if isNewInstall(): - mungedmac = GetMACAddressMunged() - if len(mungedmac) > 7: - print('Using Munged MAC Address for ID: '+mungedmac) - return mungedmac - sernum = GetVolumeSerialNumber() - if len(sernum) > 7: - print('Using Volume Serial Number for ID: '+sernum) - return sernum - diskpart = GetUserHomeAppSupKindleDirParitionName() - uuidnum = GetDiskPartitionUUID(diskpart) - if len(uuidnum) > 7: - print('Using Disk Partition UUID for ID: '+uuidnum) - return uuidnum - mungedmac = GetMACAddressMunged() - if len(mungedmac) > 7: - print('Using Munged MAC Address for ID: '+mungedmac) - return mungedmac - print('Using Fixed constant 9999999999 for ID.') - return '9999999999' - - -# implements an Pseudo Mac Version of Windows built-in Crypto routine -# used by Kindle for Mac versions < 1.6.0 -class CryptUnprotectData(object): - def __init__(self): - sernum = GetVolumeSerialNumber() - if sernum == '': - sernum = '9999999999' - sp = sernum + '!@#' + GetUserName() - passwdData = encode(SHA256(sp),charMap1) - salt = '16743' - self.crp = LibCrypto() - iter = 0x3e8 - keylen = 0x80 - key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) - self.key = key_iv[0:32] - self.iv = key_iv[32:48] - self.crp.set_decrypt_key(self.key, self.iv) - - def decrypt(self, encryptedData): - cleartext = self.crp.decrypt(encryptedData) - cleartext = decode(cleartext,charMap1) - return cleartext - - -# implements an Pseudo Mac Version of Windows built-in Crypto routine -# used for Kindle for Mac Versions >= 1.6.0 -class CryptUnprotectDataV2(object): - def __init__(self): - sp = GetUserName() + ':&%:' + GetIDString() - passwdData = encode(SHA256(sp),charMap5) - # salt generation as per the code - salt = 0x0512981d * 2 * 1 * 1 - salt = str(salt) + GetUserName() - salt = encode(salt,charMap5) - self.crp = LibCrypto() - iter = 0x800 - keylen = 0x400 - key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) - self.key = key_iv[0:32] - self.iv = key_iv[32:48] - self.crp.set_decrypt_key(self.key, self.iv) - - def decrypt(self, encryptedData): - cleartext = self.crp.decrypt(encryptedData) - cleartext = decode(cleartext, charMap5) - return cleartext - - -# unprotect the new header blob in .kinf2011 -# used in Kindle for Mac Version >= 1.9.0 -def UnprotectHeaderData(encryptedData): - passwdData = 'header_key_data' - salt = 'HEADER.2011' - iter = 0x80 - keylen = 0x100 - crp = LibCrypto() - key_iv = crp.keyivgen(passwdData, salt, iter, keylen) - key = key_iv[0:32] - iv = key_iv[32:48] - crp.set_decrypt_key(key,iv) - cleartext = crp.decrypt(encryptedData) - return cleartext - - -# implements an Pseudo Mac Version of Windows built-in Crypto routine -# used for Kindle for Mac Versions >= 1.9.0 -class CryptUnprotectDataV3(object): - def __init__(self, entropy): - sp = GetUserName() + '+@#$%+' + GetIDString() - passwdData = encode(SHA256(sp),charMap2) - salt = entropy - self.crp = LibCrypto() - iter = 0x800 - keylen = 0x400 - key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) - self.key = key_iv[0:32] - self.iv = key_iv[32:48] - self.crp.set_decrypt_key(self.key, self.iv) - - def decrypt(self, encryptedData): - cleartext = self.crp.decrypt(encryptedData) - cleartext = decode(cleartext, charMap2) - return cleartext - - -# Locate the .kindle-info files -def getKindleInfoFiles(): - # file searches can take a long time on some systems, so just look in known specific places. - kInfoFiles=[] - found = False - home = os.getenv('HOME') - # check for .kinf2011 file in new location (App Store Kindle for Mac) - testpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.kinf2011' - if os.path.isfile(testpath): - kInfoFiles.append(testpath) - print('Found k4Mac kinf2011 file: ' + testpath) - found = True - # check for .kinf2011 files - testpath = home + '/Library/Application Support/Kindle/storage/.kinf2011' - if os.path.isfile(testpath): - kInfoFiles.append(testpath) - print('Found k4Mac kinf2011 file: ' + testpath) - found = True - # check for .rainier-2.1.1-kinf files - testpath = home + '/Library/Application Support/Kindle/storage/.rainier-2.1.1-kinf' - if os.path.isfile(testpath): - kInfoFiles.append(testpath) - print('Found k4Mac rainier file: ' + testpath) - found = True - # check for .rainier-2.1.1-kinf files - testpath = home + '/Library/Application Support/Kindle/storage/.kindle-info' - if os.path.isfile(testpath): - kInfoFiles.append(testpath) - print('Found k4Mac kindle-info file: ' + testpath) - found = True - if not found: - print('No k4Mac kindle-info/rainier/kinf2011 files have been found.') - return kInfoFiles - -# determine type of kindle info provided and return a -# database of keynames and values -def getDBfromFile(kInfoFile): - - names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] - DB = {} - cnt = 0 - infoReader = open(kInfoFile, 'r') - hdr = infoReader.read(1) - data = infoReader.read() - - if data.find('[') != -1 : - - # older style kindle-info file - cud = CryptUnprotectData() - items = data.split('[') - for item in items: - if item != '': - keyhash, rawdata = item.split(':') - keyname = 'unknown' - for name in names: - if encodeHash(name,charMap2) == keyhash: - keyname = name - break - if keyname == 'unknown': - keyname = keyhash - encryptedValue = decode(rawdata,charMap2) - cleartext = cud.decrypt(encryptedValue) - DB[keyname] = cleartext - cnt = cnt + 1 - if cnt == 0: - DB = None - return DB - - if hdr == '/': - - # else newer style .kinf file used by K4Mac >= 1.6.0 - # the .kinf file uses '/' to separate it into records - # so remove the trailing '/' to make it easy to use split - data = data[:-1] - items = data.split('/') - cud = CryptUnprotectDataV2() - - # loop through the item records until all are processed - while len(items) > 0: - - # get the first item record - item = items.pop(0) - - # the first 32 chars of the first record of a group - # is the MD5 hash of the key name encoded by charMap5 - keyhash = item[0:32] - keyname = 'unknown' - - # the raw keyhash string is also used to create entropy for the actual - # CryptProtectData Blob that represents that keys contents - # 'entropy' not used for K4Mac only K4PC - # entropy = SHA1(keyhash) - - # the remainder of the first record when decoded with charMap5 - # has the ':' split char followed by the string representation - # of the number of records that follow - # and make up the contents - srcnt = decode(item[34:],charMap5) - rcnt = int(srcnt) - - # read and store in rcnt records of data - # that make up the contents value - edlst = [] - for i in xrange(rcnt): - item = items.pop(0) - edlst.append(item) - - keyname = 'unknown' - for name in names: - if encodeHash(name,charMap5) == keyhash: - keyname = name - break - if keyname == 'unknown': - keyname = keyhash - - # the charMap5 encoded contents data has had a length - # of chars (always odd) cut off of the front and moved - # to the end to prevent decoding using charMap5 from - # working properly, and thereby preventing the ensuing - # CryptUnprotectData call from succeeding. - - # The offset into the charMap5 encoded contents seems to be: - # len(contents) - largest prime number less than or equal to int(len(content)/3) - # (in other words split 'about' 2/3rds of the way through) - - # move first offsets chars to end to align for decode by charMap5 - encdata = ''.join(edlst) - contlen = len(encdata) - - # now properly split and recombine - # by moving noffset chars from the start of the - # string to the end of the string - noffset = contlen - primes(int(contlen/3))[-1] - pfx = encdata[0:noffset] - encdata = encdata[noffset:] - encdata = encdata + pfx - - # decode using charMap5 to get the CryptProtect Data - encryptedValue = decode(encdata,charMap5) - cleartext = cud.decrypt(encryptedValue) - DB[keyname] = cleartext - cnt = cnt + 1 - - if cnt == 0: - DB = None - return DB - - # the latest .kinf2011 version for K4M 1.9.1 - # put back the hdr char, it is needed - data = hdr + data - data = data[:-1] - items = data.split('/') - - # the headerblob is the encrypted information needed to build the entropy string - headerblob = items.pop(0) - encryptedValue = decode(headerblob, charMap1) - cleartext = UnprotectHeaderData(encryptedValue) - - # now extract the pieces in the same way - # this version is different from K4PC it scales the build number by multipying by 735 - pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) - for m in re.finditer(pattern, cleartext): - entropy = str(int(m.group(2)) * 0x2df) + m.group(4) - - cud = CryptUnprotectDataV3(entropy) - - # loop through the item records until all are processed - while len(items) > 0: - - # get the first item record - item = items.pop(0) - - # the first 32 chars of the first record of a group - # is the MD5 hash of the key name encoded by charMap5 - keyhash = item[0:32] - keyname = 'unknown' - - # unlike K4PC the keyhash is not used in generating entropy - # entropy = SHA1(keyhash) + added_entropy - # entropy = added_entropy - - # the remainder of the first record when decoded with charMap5 - # has the ':' split char followed by the string representation - # of the number of records that follow - # and make up the contents - srcnt = decode(item[34:],charMap5) - rcnt = int(srcnt) - - # read and store in rcnt records of data - # that make up the contents value - edlst = [] - for i in xrange(rcnt): - item = items.pop(0) - edlst.append(item) - - keyname = 'unknown' - for name in names: - if encodeHash(name,testMap8) == keyhash: - keyname = name - break - if keyname == 'unknown': - keyname = keyhash - - # the testMap8 encoded contents data has had a length - # of chars (always odd) cut off of the front and moved - # to the end to prevent decoding using testMap8 from - # working properly, and thereby preventing the ensuing - # CryptUnprotectData call from succeeding. - - # The offset into the testMap8 encoded contents seems to be: - # len(contents) - largest prime number less than or equal to int(len(content)/3) - # (in other words split 'about' 2/3rds of the way through) - - # move first offsets chars to end to align for decode by testMap8 - encdata = ''.join(edlst) - contlen = len(encdata) - - # now properly split and recombine - # by moving noffset chars from the start of the - # string to the end of the string - noffset = contlen - primes(int(contlen/3))[-1] - pfx = encdata[0:noffset] - encdata = encdata[noffset:] - encdata = encdata + pfx - - # decode using testMap8 to get the CryptProtect Data - encryptedValue = decode(encdata,testMap8) - cleartext = cud.decrypt(encryptedValue) - # print keyname - # print cleartext - DB[keyname] = cleartext - cnt = cnt + 1 - - if cnt == 0: - DB = None - return DB diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4pcutils.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4pcutils.py deleted file mode 100644 index bb9289e..0000000 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4pcutils.py +++ /dev/null @@ -1,457 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# K4PC Windows specific routines - -from __future__ import with_statement - -import sys, os, re -from struct import pack, unpack, unpack_from - -from ctypes import windll, c_char_p, c_wchar_p, c_uint, POINTER, byref, \ - create_unicode_buffer, create_string_buffer, CFUNCTYPE, addressof, \ - string_at, Structure, c_void_p, cast - -import _winreg as winreg -MAX_PATH = 255 -kernel32 = windll.kernel32 -advapi32 = windll.advapi32 -crypt32 = windll.crypt32 - -import traceback - -# crypto digestroutines -import hashlib - -def MD5(message): - ctx = hashlib.md5() - ctx.update(message) - return ctx.digest() - -def SHA1(message): - ctx = hashlib.sha1() - ctx.update(message) - return ctx.digest() - -def SHA256(message): - ctx = hashlib.sha256() - ctx.update(message) - return ctx.digest() - -# For K4PC 1.9.X -# use routines in alfcrypto: -# AES_cbc_encrypt -# AES_set_decrypt_key -# PKCS5_PBKDF2_HMAC_SHA1 - -from alfcrypto import AES_CBC, KeyIVGen - -def UnprotectHeaderData(encryptedData): - passwdData = 'header_key_data' - salt = 'HEADER.2011' - iter = 0x80 - keylen = 0x100 - key_iv = KeyIVGen().pbkdf2(passwdData, salt, iter, keylen) - key = key_iv[0:32] - iv = key_iv[32:48] - aes=AES_CBC() - aes.set_decrypt_key(key, iv) - cleartext = aes.decrypt(encryptedData) - return cleartext - - -# simple primes table (<= n) calculator -def primes(n): - if n==2: return [2] - elif n<2: return [] - s=range(3,n+1,2) - mroot = n ** 0.5 - half=(n+1)/2-1 - i=0 - m=3 - while m <= mroot: - if s[i]: - j=(m*m-3)/2 - s[j]=0 - while j 0: - - # get the first item record - item = items.pop(0) - - # the first 32 chars of the first record of a group - # is the MD5 hash of the key name encoded by charMap5 - keyhash = item[0:32] - - # the raw keyhash string is used to create entropy for the actual - # CryptProtectData Blob that represents that keys contents - entropy = SHA1(keyhash) - - # the remainder of the first record when decoded with charMap5 - # has the ':' split char followed by the string representation - # of the number of records that follow - # and make up the contents - srcnt = decode(item[34:],charMap5) - rcnt = int(srcnt) - - # read and store in rcnt records of data - # that make up the contents value - edlst = [] - for i in xrange(rcnt): - item = items.pop(0) - edlst.append(item) - - keyname = "unknown" - for name in names: - if encodeHash(name,charMap5) == keyhash: - keyname = name - break - if keyname == "unknown": - keyname = keyhash - # the charMap5 encoded contents data has had a length - # of chars (always odd) cut off of the front and moved - # to the end to prevent decoding using charMap5 from - # working properly, and thereby preventing the ensuing - # CryptUnprotectData call from succeeding. - - # The offset into the charMap5 encoded contents seems to be: - # len(contents)-largest prime number <= int(len(content)/3) - # (in other words split "about" 2/3rds of the way through) - - # move first offsets chars to end to align for decode by charMap5 - encdata = "".join(edlst) - contlen = len(encdata) - noffset = contlen - primes(int(contlen/3))[-1] - - # now properly split and recombine - # by moving noffset chars from the start of the - # string to the end of the string - pfx = encdata[0:noffset] - encdata = encdata[noffset:] - encdata = encdata + pfx - - # decode using Map5 to get the CryptProtect Data - encryptedValue = decode(encdata,charMap5) - DB[keyname] = CryptUnprotectData(encryptedValue, entropy, 1) - cnt = cnt + 1 - - if cnt == 0: - DB = None - return DB - - # else newest .kinf2011 style .kinf file - # the .kinf file uses "/" to separate it into records - # so remove the trailing "/" to make it easy to use split - # need to put back the first char read because it it part - # of the added entropy blob - data = hdr + data[:-1] - items = data.split('/') - - # starts with and encoded and encrypted header blob - headerblob = items.pop(0) - encryptedValue = decode(headerblob, testMap1) - cleartext = UnprotectHeaderData(encryptedValue) - # now extract the pieces that form the added entropy - pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) - for m in re.finditer(pattern, cleartext): - added_entropy = m.group(2) + m.group(4) - - - # loop through the item records until all are processed - while len(items) > 0: - - # get the first item record - item = items.pop(0) - - # the first 32 chars of the first record of a group - # is the MD5 hash of the key name encoded by charMap5 - keyhash = item[0:32] - - # the sha1 of raw keyhash string is used to create entropy along - # with the added entropy provided above from the headerblob - entropy = SHA1(keyhash) + added_entropy - - # the remainder of the first record when decoded with charMap5 - # has the ':' split char followed by the string representation - # of the number of records that follow - # and make up the contents - srcnt = decode(item[34:],charMap5) - rcnt = int(srcnt) - - # read and store in rcnt records of data - # that make up the contents value - edlst = [] - for i in xrange(rcnt): - item = items.pop(0) - edlst.append(item) - - # key names now use the new testMap8 encoding - keyname = "unknown" - for name in names: - if encodeHash(name,testMap8) == keyhash: - keyname = name - break - - # the testMap8 encoded contents data has had a length - # of chars (always odd) cut off of the front and moved - # to the end to prevent decoding using testMap8 from - # working properly, and thereby preventing the ensuing - # CryptUnprotectData call from succeeding. - - # The offset into the testMap8 encoded contents seems to be: - # len(contents)-largest prime number <= int(len(content)/3) - # (in other words split "about" 2/3rds of the way through) - - # move first offsets chars to end to align for decode by testMap8 - # by moving noffset chars from the start of the - # string to the end of the string - encdata = "".join(edlst) - contlen = len(encdata) - noffset = contlen - primes(int(contlen/3))[-1] - pfx = encdata[0:noffset] - encdata = encdata[noffset:] - encdata = encdata + pfx - - # decode using new testMap8 to get the original CryptProtect Data - encryptedValue = decode(encdata,testMap8) - cleartext = CryptUnprotectData(encryptedValue, entropy, 1) - DB[keyname] = cleartext - cnt = cnt + 1 - - if cnt == 0: - DB = None - return DB diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kgenpids.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kgenpids.py index c5de9b9..dd88797 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kgenpids.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kgenpids.py @@ -8,6 +8,7 @@ import binascii import zlib import re from struct import pack, unpack, unpack_from +import traceback class DrmException(Exception): pass @@ -16,22 +17,6 @@ global charMap1 global charMap3 global charMap4 -if 'calibre' in sys.modules: - inCalibre = True - from calibre.constants import iswindows, isosx - if iswindows: - from calibre_plugins.k4mobidedrm.k4pcutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString - if isosx: - from calibre_plugins.k4mobidedrm.k4mutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString -else: - inCalibre = False - iswindows = sys.platform.startswith('win') - isosx = sys.platform.startswith('darwin') - if iswindows: - from k4pcutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString - if isosx: - from k4mutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString - charMap1 = 'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' charMap3 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' @@ -178,6 +163,9 @@ def pidFromSerial(s, l): def getKindlePids(rec209, token, serialnum): pids=[] + if isinstance(serialnum,unicode): + serialnum = serialnum.encode('ascii') + # Compute book PID pidHash = SHA1(serialnum+rec209+token) bookPID = encodePID(pidHash) @@ -196,35 +184,32 @@ def getKindlePids(rec209, token, serialnum): keynames = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber'] -def getK4Pids(rec209, token, kInfoFile): +def getK4Pids(rec209, token, kindleDatabase): global charMap1 - kindleDatabase = None pids = [] - try: - kindleDatabase = getDBfromFile(kInfoFile) - except Exception, message: - print(message) - kindleDatabase = None - pass - - if kindleDatabase == None : - return pids try: # Get the Mazama Random number - MazamaRandomNumber = kindleDatabase['MazamaRandomNumber'] + MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex').encode('ascii') # Get the kindle account token - kindleAccountToken = kindleDatabase['kindle.account.tokens'] + kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex').encode('ascii') + + # Get the IDString used to decode the Kindle Info file + IDString = (kindleDatabase[1])['IDString'].decode('hex').encode('ascii') + + # Get the UserName stored when the Kindle Info file was decoded + UserName = (kindleDatabase[1])['UserName'].decode('hex').encode('ascii') + except KeyError: - print u"Keys not found in {0}".format(os.path.basename(kInfoFile)) + print u"Keys not found in the database {0}.".format(kindleDatabase[0]) return pids # Get the ID string used - encodedIDString = encodeHash(GetIDString(),charMap1) + encodedIDString = encodeHash(IDString,charMap1) # Get the current user name - encodedUsername = encodeHash(GetUserName(),charMap1) + encodedUsername = encodeHash(UserName,charMap1) # concat, hash and encode to calculate the DSN DSN = encode(SHA1(MazamaRandomNumber+encodedIDString+encodedUsername),charMap1) @@ -257,22 +242,26 @@ def getK4Pids(rec209, token, kInfoFile): return pids -def getPidList(md1, md2, serials=[], kInfoFiles=[]): +def getPidList(md1, md2, serials=[], kDatabases=[]): pidlst = [] - if kInfoFiles is None: - kInfoFiles = [] + + if kDatabases is None: + kDatabases = [] if serials is None: serials = [] - if iswindows or isosx: - kInfoFiles.extend(getKindleInfoFiles()) - for infoFile in kInfoFiles: + + for kDatabase in kDatabases: try: - pidlst.extend(getK4Pids(md1, md2, infoFile)) + pidlst.extend(getK4Pids(md1, md2, kDatabase)) except Exception, e: - print u"Error getting PIDs from {0}: {1}".format(os.path.basename(infoFile),e.args[0]) + print u"Error getting PIDs from database {0}: {1}".format(kDatabase[0],e.args[0]) + traceback.print_exc() + for serialnum in serials: try: pidlst.extend(getKindlePids(md1, md2, serialnum)) - except Exception, message: + except Exception, e: print u"Error getting PIDs from serial number {0}: {1}".format(serialnum ,e.args[0]) + traceback.print_exc() + return pidlst diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py new file mode 100644 index 0000000..e79622b --- /dev/null +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/kindlekey.py @@ -0,0 +1,1893 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +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 + +# Revision history: +# 1.0 - Kindle info file decryption, extracted from k4mobidedrm, etc. +# 1.1 - Added Tkinter to match adobekey.py +# 1.2 - Fixed testing of successful retrieval on Mac +# 1.3 - Added getkey interface for Windows DeDRM application +# Simplified some of the Kindle for Mac code. +# 1.4 - Remove dependency on alfcrypto + +""" +Retrieve Kindle for PC/Mac user key. +""" + +__license__ = 'GPL v3' +__version__ = '1.4' + +import sys, os, re +from struct import pack, unpack, unpack_from +import json +import getopt + +# Routines common to Mac and PC + +# 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) + +try: + from calibre.constants import iswindows, isosx +except: + 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 '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 + + 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"kindlekey.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] + +class DrmException(Exception): + pass + +# crypto digestroutines +import hashlib + +def MD5(message): + ctx = hashlib.md5() + ctx.update(message) + return ctx.digest() + +def SHA1(message): + ctx = hashlib.sha1() + ctx.update(message) + return ctx.digest() + +def SHA256(message): + ctx = hashlib.sha256() + ctx.update(message) + return ctx.digest() + +# For K4M/PC 1.6.X and later +# generate table of prime number less than or equal to int n +def primes(n): + if n==2: return [2] + elif n<2: return [] + s=range(3,n+1,2) + mroot = n ** 0.5 + half=(n+1)/2-1 + i=0 + m=3 + while m <= mroot: + if s[i]: + j=(m*m-3)/2 + s[j]=0 + while j 0: # save any bytes that are not block aligned + self.bytesToEncrypt = self.bytesToEncrypt[-numExtraBytes:] + else: + self.bytesToEncrypt = '' + + if more == None: # no more data expected from caller + finalBytes = self.padding.addPad(self.bytesToEncrypt,self.blockSize) + if len(finalBytes) > 0: + ctBlock = self.encryptBlock(finalBytes) + self.encryptBlockCount += 1 + cipherText += ctBlock + self.resetEncrypt() + return cipherText + + def decrypt(self, cipherText, more = None): + """ Decrypt a string and return a string """ + self.bytesToDecrypt += cipherText # append to any bytes from prior decrypt + + numBlocks, numExtraBytes = divmod(len(self.bytesToDecrypt), self.blockSize) + if more == None: # no more calls to decrypt, should have all the data + if numExtraBytes != 0: + raise DecryptNotBlockAlignedError, 'Data not block aligned on decrypt' + + # hold back some bytes in case last decrypt has zero len + if (more != None) and (numExtraBytes == 0) and (numBlocks >0) : + numBlocks -= 1 + numExtraBytes = self.blockSize + + plainText = '' + for i in range(numBlocks): + bStart = i*self.blockSize + ptBlock = self.decryptBlock(self.bytesToDecrypt[bStart : bStart+self.blockSize]) + self.decryptBlockCount += 1 + plainText += ptBlock + + if numExtraBytes > 0: # save any bytes that are not block aligned + self.bytesToEncrypt = self.bytesToEncrypt[-numExtraBytes:] + else: + self.bytesToEncrypt = '' + + if more == None: # last decrypt remove padding + plainText = self.padding.removePad(plainText, self.blockSize) + self.resetDecrypt() + return plainText + + + class Pad: + def __init__(self): + pass # eventually could put in calculation of min and max size extension + + class padWithPadLen(Pad): + """ Pad a binary string with the length of the padding """ + + def addPad(self, extraBytes, blockSize): + """ Add padding to a binary string to make it an even multiple + of the block size """ + blocks, numExtraBytes = divmod(len(extraBytes), blockSize) + padLength = blockSize - numExtraBytes + return extraBytes + padLength*chr(padLength) + + def removePad(self, paddedBinaryString, blockSize): + """ Remove padding from a binary string """ + if not(0 6 and i%Nk == 4 : + temp = [ Sbox[byte] for byte in temp ] # SubWord(temp) + w.append( [ w[i-Nk][byte]^temp[byte] for byte in range(4) ] ) + return w + + Rcon = (0,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36, # note extra '0' !!! + 0x6c,0xd8,0xab,0x4d,0x9a,0x2f,0x5e,0xbc,0x63,0xc6, + 0x97,0x35,0x6a,0xd4,0xb3,0x7d,0xfa,0xef,0xc5,0x91) + + #------------------------------------- + def AddRoundKey(algInstance, keyBlock): + """ XOR the algorithm state with a block of key material """ + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] ^= keyBlock[column][row] + #------------------------------------- + + def SubBytes(algInstance): + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] = Sbox[algInstance.state[column][row]] + + def InvSubBytes(algInstance): + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] = InvSbox[algInstance.state[column][row]] + + Sbox = (0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5, + 0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0, + 0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc, + 0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a, + 0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0, + 0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b, + 0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85, + 0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5, + 0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17, + 0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88, + 0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c, + 0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9, + 0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6, + 0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e, + 0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94, + 0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68, + 0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16) + + InvSbox = (0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38, + 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, + 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87, + 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, + 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d, + 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, + 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2, + 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, + 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16, + 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, + 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda, + 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, + 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a, + 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, + 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02, + 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, + 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea, + 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, + 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85, + 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, + 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89, + 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, + 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20, + 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, + 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31, + 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, + 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d, + 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, + 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0, + 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, + 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26, + 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d) + + #------------------------------------- + """ For each block size (Nb), the ShiftRow operation shifts row i + by the amount Ci. Note that row 0 is not shifted. + Nb C1 C2 C3 + ------------------- """ + shiftOffset = { 4 : ( 0, 1, 2, 3), + 5 : ( 0, 1, 2, 3), + 6 : ( 0, 1, 2, 3), + 7 : ( 0, 1, 2, 4), + 8 : ( 0, 1, 3, 4) } + def ShiftRows(algInstance): + tmp = [0]*algInstance.Nb # list of size Nb + for r in range(1,4): # row 0 reamains unchanged and can be skipped + for c in range(algInstance.Nb): + tmp[c] = algInstance.state[(c+shiftOffset[algInstance.Nb][r]) % algInstance.Nb][r] + for c in range(algInstance.Nb): + algInstance.state[c][r] = tmp[c] + def InvShiftRows(algInstance): + tmp = [0]*algInstance.Nb # list of size Nb + for r in range(1,4): # row 0 reamains unchanged and can be skipped + for c in range(algInstance.Nb): + tmp[c] = algInstance.state[(c+algInstance.Nb-shiftOffset[algInstance.Nb][r]) % algInstance.Nb][r] + for c in range(algInstance.Nb): + algInstance.state[c][r] = tmp[c] + #------------------------------------- + def MixColumns(a): + Sprime = [0,0,0,0] + for j in range(a.Nb): # for each column + Sprime[0] = mul(2,a.state[j][0])^mul(3,a.state[j][1])^mul(1,a.state[j][2])^mul(1,a.state[j][3]) + Sprime[1] = mul(1,a.state[j][0])^mul(2,a.state[j][1])^mul(3,a.state[j][2])^mul(1,a.state[j][3]) + Sprime[2] = mul(1,a.state[j][0])^mul(1,a.state[j][1])^mul(2,a.state[j][2])^mul(3,a.state[j][3]) + Sprime[3] = mul(3,a.state[j][0])^mul(1,a.state[j][1])^mul(1,a.state[j][2])^mul(2,a.state[j][3]) + for i in range(4): + a.state[j][i] = Sprime[i] + + def InvMixColumns(a): + """ Mix the four bytes of every column in a linear way + This is the opposite operation of Mixcolumn """ + Sprime = [0,0,0,0] + for j in range(a.Nb): # for each column + Sprime[0] = mul(0x0E,a.state[j][0])^mul(0x0B,a.state[j][1])^mul(0x0D,a.state[j][2])^mul(0x09,a.state[j][3]) + Sprime[1] = mul(0x09,a.state[j][0])^mul(0x0E,a.state[j][1])^mul(0x0B,a.state[j][2])^mul(0x0D,a.state[j][3]) + Sprime[2] = mul(0x0D,a.state[j][0])^mul(0x09,a.state[j][1])^mul(0x0E,a.state[j][2])^mul(0x0B,a.state[j][3]) + Sprime[3] = mul(0x0B,a.state[j][0])^mul(0x0D,a.state[j][1])^mul(0x09,a.state[j][2])^mul(0x0E,a.state[j][3]) + for i in range(4): + a.state[j][i] = Sprime[i] + + #------------------------------------- + def mul(a, b): + """ Multiply two elements of GF(2^m) + needed for MixColumn and InvMixColumn """ + if (a !=0 and b!=0): + return Alogtable[(Logtable[a] + Logtable[b])%255] + else: + return 0 + + Logtable = ( 0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, + 100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, + 125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120, + 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142, + 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56, + 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16, + 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186, + 43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87, + 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, + 44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160, + 127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183, + 204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157, + 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209, + 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, + 68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, + 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7) + + Alogtable= ( 1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, + 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, + 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, + 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, + 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, + 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, + 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, + 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, + 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, + 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, + 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, + 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, + 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, + 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, + 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, + 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1) + + + + + """ + AES Encryption Algorithm + The AES algorithm is just Rijndael algorithm restricted to the default + blockSize of 128 bits. + """ + + class AES(Rijndael): + """ The AES algorithm is the Rijndael block cipher restricted to block + sizes of 128 bits and key sizes of 128, 192 or 256 bits + """ + def __init__(self, key = None, padding = padWithPadLen(), keySize=16): + """ Initialize AES, keySize is in bytes """ + if not (keySize == 16 or keySize == 24 or keySize == 32) : + raise BadKeySizeError, 'Illegal AES key size, must be 16, 24, or 32 bytes' + + Rijndael.__init__( self, key, padding=padding, keySize=keySize, blockSize=16 ) + + self.name = 'AES' + + + """ + CBC mode of encryption for block ciphers. + This algorithm mode wraps any BlockCipher to make a + Cipher Block Chaining mode. + """ + from random import Random # should change to crypto.random!!! + + + class CBC(BlockCipher): + """ The CBC class wraps block ciphers to make cipher block chaining (CBC) mode + algorithms. The initialization (IV) is automatic if set to None. Padding + is also automatic based on the Pad class used to initialize the algorithm + """ + def __init__(self, blockCipherInstance, padding = padWithPadLen()): + """ CBC algorithms are created by initializing with a BlockCipher instance """ + self.baseCipher = blockCipherInstance + self.name = self.baseCipher.name + '_CBC' + self.blockSize = self.baseCipher.blockSize + self.keySize = self.baseCipher.keySize + self.padding = padding + self.baseCipher.padding = noPadding() # baseCipher should NOT pad!! + self.r = Random() # for IV generation, currently uses + # mediocre standard distro version <---------------- + import time + newSeed = time.ctime()+str(self.r) # seed with instance location + self.r.seed(newSeed) # to make unique + self.reset() + + def setKey(self, key): + self.baseCipher.setKey(key) + + # Overload to reset both CBC state and the wrapped baseCipher + def resetEncrypt(self): + BlockCipher.resetEncrypt(self) # reset CBC encrypt state (super class) + self.baseCipher.resetEncrypt() # reset base cipher encrypt state + + def resetDecrypt(self): + BlockCipher.resetDecrypt(self) # reset CBC state (super class) + self.baseCipher.resetDecrypt() # reset base cipher decrypt state + + def encrypt(self, plainText, iv=None, more=None): + """ CBC encryption - overloads baseCipher to allow optional explicit IV + when iv=None, iv is auto generated! + """ + if self.encryptBlockCount == 0: + self.iv = iv + else: + assert(iv==None), 'IV used only on first call to encrypt' + + return BlockCipher.encrypt(self,plainText, more=more) + + def decrypt(self, cipherText, iv=None, more=None): + """ CBC decryption - overloads baseCipher to allow optional explicit IV + when iv=None, iv is auto generated! + """ + if self.decryptBlockCount == 0: + self.iv = iv + else: + assert(iv==None), 'IV used only on first call to decrypt' + + return BlockCipher.decrypt(self, cipherText, more=more) + + def encryptBlock(self, plainTextBlock): + """ CBC block encryption, IV is set with 'encrypt' """ + auto_IV = '' + if self.encryptBlockCount == 0: + if self.iv == None: + # generate IV and use + self.iv = ''.join([chr(self.r.randrange(256)) for i in range(self.blockSize)]) + self.prior_encr_CT_block = self.iv + auto_IV = self.prior_encr_CT_block # prepend IV if it's automatic + else: # application provided IV + assert(len(self.iv) == self.blockSize ),'IV must be same length as block' + self.prior_encr_CT_block = self.iv + """ encrypt the prior CT XORed with the PT """ + ct = self.baseCipher.encryptBlock( xor(self.prior_encr_CT_block, plainTextBlock) ) + self.prior_encr_CT_block = ct + return auto_IV+ct + + def decryptBlock(self, encryptedBlock): + """ Decrypt a single block """ + + if self.decryptBlockCount == 0: # first call, process IV + if self.iv == None: # auto decrypt IV? + self.prior_CT_block = encryptedBlock + return '' + else: + assert(len(self.iv)==self.blockSize),"Bad IV size on CBC decryption" + self.prior_CT_block = self.iv + + dct = self.baseCipher.decryptBlock(encryptedBlock) + """ XOR the prior decrypted CT with the prior CT """ + dct_XOR_priorCT = xor( self.prior_CT_block, dct ) + + self.prior_CT_block = encryptedBlock + + return dct_XOR_priorCT + + + """ + AES_CBC Encryption Algorithm + """ + + class aescbc_AES_CBC(CBC): + """ AES encryption in CBC feedback mode """ + def __init__(self, key=None, padding=padWithPadLen(), keySize=16): + CBC.__init__( self, AES(key, noPadding(), keySize), padding) + self.name = 'AES_CBC' + + class AES_CBC(object): + def __init__(self): + self._key = None + self._iv = None + self.aes = None + + def set_decrypt_key(self, userkey, iv): + self._key = userkey + self._iv = iv + self.aes = aescbc_AES_CBC(userkey, noPadding(), len(userkey)) + + def decrypt(self, data): + iv = self._iv + cleartext = self.aes.decrypt(iv + data) + return cleartext + + import hmac + + class KeyIVGen(object): + # this only exists in openssl so we will use pure python implementation instead + # PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', + # [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p]) + def pbkdf2(self, passwd, salt, iter, keylen): + + def xorstr( a, b ): + if len(a) != len(b): + raise Exception("xorstr(): lengths differ") + return ''.join((chr(ord(x)^ord(y)) for x, y in zip(a, b))) + + def prf( h, data ): + hm = h.copy() + hm.update( data ) + return hm.digest() + + def pbkdf2_F( h, salt, itercount, blocknum ): + U = prf( h, salt + pack('>i',blocknum ) ) + T = U + for i in range(2, itercount+1): + U = prf( h, U ) + T = xorstr( T, U ) + return T + + sha = hashlib.sha1 + digest_size = sha().digest_size + # l - number of output blocks to produce + l = keylen / digest_size + if keylen % digest_size != 0: + l += 1 + h = hmac.new( passwd, None, sha ) + T = "" + for i in range(1, l+1): + T += pbkdf2_F( h, salt, iter, i ) + return T[0: keylen] + + def UnprotectHeaderData(encryptedData): + passwdData = 'header_key_data' + salt = 'HEADER.2011' + iter = 0x80 + keylen = 0x100 + key_iv = KeyIVGen().pbkdf2(passwdData, salt, iter, keylen) + key = key_iv[0:32] + iv = key_iv[32:48] + aes=AES_CBC() + aes.set_decrypt_key(key, iv) + cleartext = aes.decrypt(encryptedData) + return cleartext + + # Various character maps used to decrypt kindle info values. + # Probably supposed to act as obfuscation + charMap2 = "AaZzB0bYyCc1XxDdW2wEeVv3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_" + charMap5 = "AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE" + # New maps in K4PC 1.9.0 + testMap1 = "n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M" + testMap6 = "9YzAb0Cd1Ef2n5Pr6St7Uvh3Jk4M8WxG" + testMap8 = "YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD" + + # interface with Windows OS Routines + class DataBlob(Structure): + _fields_ = [('cbData', c_uint), + ('pbData', c_void_p)] + DataBlob_p = POINTER(DataBlob) + + + def GetSystemDirectory(): + GetSystemDirectoryW = kernel32.GetSystemDirectoryW + GetSystemDirectoryW.argtypes = [c_wchar_p, c_uint] + GetSystemDirectoryW.restype = c_uint + def GetSystemDirectory(): + buffer = create_unicode_buffer(MAX_PATH + 1) + GetSystemDirectoryW(buffer, len(buffer)) + return buffer.value + return GetSystemDirectory + GetSystemDirectory = GetSystemDirectory() + + def GetVolumeSerialNumber(): + GetVolumeInformationW = kernel32.GetVolumeInformationW + GetVolumeInformationW.argtypes = [c_wchar_p, c_wchar_p, c_uint, + POINTER(c_uint), POINTER(c_uint), + POINTER(c_uint), c_wchar_p, c_uint] + GetVolumeInformationW.restype = c_uint + def GetVolumeSerialNumber(path = GetSystemDirectory().split('\\')[0] + '\\'): + vsn = c_uint(0) + GetVolumeInformationW(path, None, 0, byref(vsn), None, None, None, 0) + return str(vsn.value) + return GetVolumeSerialNumber + GetVolumeSerialNumber = GetVolumeSerialNumber() + + def GetIDString(): + vsn = GetVolumeSerialNumber() + #print('Using Volume Serial Number for ID: '+vsn) + return vsn + + def getLastError(): + GetLastError = kernel32.GetLastError + GetLastError.argtypes = None + GetLastError.restype = c_uint + def getLastError(): + return GetLastError() + return getLastError + getLastError = getLastError() + + def GetUserName(): + GetUserNameW = advapi32.GetUserNameW + GetUserNameW.argtypes = [c_wchar_p, POINTER(c_uint)] + GetUserNameW.restype = c_uint + def GetUserName(): + buffer = create_unicode_buffer(2) + size = c_uint(len(buffer)) + while not GetUserNameW(buffer, byref(size)): + errcd = getLastError() + if errcd == 234: + # bad wine implementation up through wine 1.3.21 + return "AlternateUserName" + buffer = create_unicode_buffer(len(buffer) * 2) + size.value = len(buffer) + return buffer.value.encode('utf-16-le')[::2] + return GetUserName + GetUserName = GetUserName() + + def CryptUnprotectData(): + _CryptUnprotectData = crypt32.CryptUnprotectData + _CryptUnprotectData.argtypes = [DataBlob_p, c_wchar_p, DataBlob_p, + c_void_p, c_void_p, c_uint, DataBlob_p] + _CryptUnprotectData.restype = c_uint + def CryptUnprotectData(indata, entropy, flags): + indatab = create_string_buffer(indata) + indata = DataBlob(len(indata), cast(indatab, c_void_p)) + entropyb = create_string_buffer(entropy) + entropy = DataBlob(len(entropy), cast(entropyb, c_void_p)) + outdata = DataBlob() + if not _CryptUnprotectData(byref(indata), None, byref(entropy), + None, None, flags, byref(outdata)): + # raise DrmException("Failed to Unprotect Data") + return 'failed' + return string_at(outdata.pbData, outdata.cbData) + return CryptUnprotectData + CryptUnprotectData = CryptUnprotectData() + + + # Locate all of the kindle-info style files and return as list + def getKindleInfoFiles(): + kInfoFiles = [] + # some 64 bit machines do not have the proper registry key for some reason + # or the pythonn interface to the 32 vs 64 bit registry is broken + path = "" + if 'LOCALAPPDATA' in os.environ.keys(): + path = os.environ['LOCALAPPDATA'] + else: + # User Shell Folders show take precedent over Shell Folders if present + try: + regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\") + path = winreg.QueryValueEx(regkey, 'Local AppData')[0] + if not os.path.isdir(path): + path = "" + try: + regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\") + path = winreg.QueryValueEx(regkey, 'Local AppData')[0] + if not os.path.isdir(path): + path = "" + except RegError: + pass + except RegError: + pass + + found = False + if path == "": + print ('Could not find the folder in which to look for kinfoFiles.') + else: + print('searching for kinfoFiles in ' + path) + + # look for (K4PC 1.9.0 and later) .kinf2011 file + kinfopath = path +'\\Amazon\\Kindle\\storage\\.kinf2011' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.9+ kinf2011 file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for (K4PC 1.6.0 and later) rainier.2.1.1.kinf file + kinfopath = path +'\\Amazon\\Kindle\\storage\\rainier.2.1.1.kinf' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.6-1.8 kinf file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for (K4PC 1.5.0 and later) rainier.2.1.1.kinf file + kinfopath = path +'\\Amazon\\Kindle For PC\\storage\\rainier.2.1.1.kinf' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.5 kinf file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for original (earlier than K4PC 1.5.0) kindle-info files + kinfopath = path +'\\Amazon\\Kindle For PC\\{AMAwzsaPaaZAzmZzZQzgZCAkZ3AjA_AY}\\kindle.info' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC kindle.info file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + if not found: + print('No K4PC kindle.info/kinf/kinf2011 files have been found.') + return kInfoFiles + + + # determine type of kindle info provided and return a + # database of keynames and values + def getDBfromFile(kInfoFile): + names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] + DB = {} + with open(kInfoFile, 'rb') as infoReader: + hdr = infoReader.read(1) + data = infoReader.read() + + if data.find('{') != -1 : + # older style kindle-info file + items = data.split('{') + for item in items: + if item != '': + keyhash, rawdata = item.split(':') + keyname = "unknown" + for name in names: + if encodeHash(name,charMap2) == keyhash: + keyname = name + break + if keyname == "unknown": + keyname = keyhash + encryptedValue = decode(rawdata,charMap2) + DB[keyname] = CryptUnprotectData(encryptedValue, "", 0) + elif hdr == '/': + # else rainier-2-1-1 .kinf file + # the .kinf file uses "/" to separate it into records + # so remove the trailing "/" to make it easy to use split + data = data[:-1] + items = data.split('/') + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + + # the raw keyhash string is used to create entropy for the actual + # CryptProtectData Blob that represents that keys contents + entropy = SHA1(keyhash) + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = "unknown" + for name in names: + if encodeHash(name,charMap5) == keyhash: + keyname = name + break + if keyname == "unknown": + keyname = keyhash + # the charMap5 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using charMap5 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the charMap5 encoded contents seems to be: + # len(contents)-largest prime number <= int(len(content)/3) + # (in other words split "about" 2/3rds of the way through) + + # move first offsets chars to end to align for decode by charMap5 + encdata = "".join(edlst) + contlen = len(encdata) + noffset = contlen - primes(int(contlen/3))[-1] + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using Map5 to get the CryptProtect Data + encryptedValue = decode(encdata,charMap5) + DB[keyname] = CryptUnprotectData(encryptedValue, entropy, 1) + else: + # else newest .kinf2011 style .kinf file + # the .kinf file uses "/" to separate it into records + # so remove the trailing "/" to make it easy to use split + # need to put back the first char read because it it part + # of the added entropy blob + data = hdr + data[:-1] + items = data.split('/') + + # starts with and encoded and encrypted header blob + headerblob = items.pop(0) + encryptedValue = decode(headerblob, testMap1) + cleartext = UnprotectHeaderData(encryptedValue) + # now extract the pieces that form the added entropy + pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) + for m in re.finditer(pattern, cleartext): + added_entropy = m.group(2) + m.group(4) + + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + + # the sha1 of raw keyhash string is used to create entropy along + # with the added entropy provided above from the headerblob + entropy = SHA1(keyhash) + added_entropy + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + # key names now use the new testMap8 encoding + keyname = "unknown" + for name in names: + if encodeHash(name,testMap8) == keyhash: + keyname = name + break + + # the testMap8 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using testMap8 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the testMap8 encoded contents seems to be: + # len(contents)-largest prime number <= int(len(content)/3) + # (in other words split "about" 2/3rds of the way through) + + # move first offsets chars to end to align for decode by testMap8 + # by moving noffset chars from the start of the + # string to the end of the string + encdata = "".join(edlst) + contlen = len(encdata) + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using new testMap8 to get the original CryptProtect Data + encryptedValue = decode(encdata,testMap8) + cleartext = CryptUnprotectData(encryptedValue, entropy, 1) + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName()) + # store values used in decryption + DB['IDString'] = GetIDString() + DB['UserName'] = GetUserName() + else: + DB = {} + return DB +elif isosx: + import copy + import subprocess + + # interface to needed routines in openssl's libcrypto + def _load_crypto_libcrypto(): + from ctypes import CDLL, byref, POINTER, c_void_p, c_char_p, c_int, c_long, \ + Structure, c_ulong, create_string_buffer, addressof, string_at, cast + from ctypes.util import find_library + + libcrypto = find_library('crypto') + if libcrypto is None: + raise DrmException(u"libcrypto not found") + libcrypto = CDLL(libcrypto) + + # From OpenSSL's crypto aes header + # + # AES_ENCRYPT 1 + # AES_DECRYPT 0 + # AES_MAXNR 14 (in bytes) + # AES_BLOCK_SIZE 16 (in bytes) + # + # struct aes_key_st { + # unsigned long rd_key[4 *(AES_MAXNR + 1)]; + # int rounds; + # }; + # typedef struct aes_key_st AES_KEY; + # + # int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); + # + # note: the ivec string, and output buffer are both mutable + # void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + # const unsigned long length, const AES_KEY *key, unsigned char *ivec, const int enc); + + AES_MAXNR = 14 + c_char_pp = POINTER(c_char_p) + c_int_p = POINTER(c_int) + + class AES_KEY(Structure): + _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), ('rounds', c_int)] + AES_KEY_p = POINTER(AES_KEY) + + def F(restype, name, argtypes): + func = getattr(libcrypto, name) + func.restype = restype + func.argtypes = argtypes + return func + + AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',[c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p,c_int]) + + AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',[c_char_p, c_int, AES_KEY_p]) + + # From OpenSSL's Crypto evp/p5_crpt2.c + # + # int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, + # const unsigned char *salt, int saltlen, int iter, + # int keylen, unsigned char *out); + + PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', + [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p]) + + class LibCrypto(object): + def __init__(self): + self._blocksize = 0 + self._keyctx = None + self._iv = 0 + + def set_decrypt_key(self, userkey, iv): + self._blocksize = len(userkey) + if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) : + raise DrmException(u"AES improper key used") + return + keyctx = self._keyctx = AES_KEY() + self._iv = iv + self._userkey = userkey + rv = AES_set_decrypt_key(userkey, len(userkey) * 8, keyctx) + if rv < 0: + raise DrmException(u"Failed to initialize AES key") + + def decrypt(self, data): + out = create_string_buffer(len(data)) + mutable_iv = create_string_buffer(self._iv, len(self._iv)) + keyctx = self._keyctx + rv = AES_cbc_encrypt(data, out, len(data), keyctx, mutable_iv, 0) + if rv == 0: + raise DrmException(u"AES decryption failed") + return out.raw + + def keyivgen(self, passwd, salt, iter, keylen): + saltlen = len(salt) + passlen = len(passwd) + out = create_string_buffer(keylen) + rv = PKCS5_PBKDF2_HMAC_SHA1(passwd, passlen, salt, saltlen, iter, keylen, out) + return out.raw + return LibCrypto + + def _load_crypto(): + LibCrypto = None + try: + LibCrypto = _load_crypto_libcrypto() + except (ImportError, DrmException): + pass + return LibCrypto + + LibCrypto = _load_crypto() + + # Various character maps used to decrypt books. Probably supposed to act as obfuscation + charMap1 = 'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' + charMap2 = 'ZB0bYyc1xDdW2wEV3Ff7KkPpL8UuGA4gz-Tme9Nn_tHh5SvXCsIiR6rJjQaqlOoM' + + # For kinf approach of K4Mac 1.6.X or later + # On K4PC charMap5 = 'AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE' + # For Mac they seem to re-use charMap2 here + charMap5 = charMap2 + + # new in K4M 1.9.X + testMap8 = 'YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD' + + # uses a sub process to get the Hard Drive Serial Number using ioreg + # returns serial numbers of all internal hard drive drives + def GetVolumesSerialNumbers(): + sernum = os.getenv('MYSERIALNUMBER') + if sernum != None: + return [sernum] + sernums = [] + cmdline = '/usr/sbin/ioreg -w 0 -r -c AppleAHCIDiskDriver' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + bsdname = None + sernum = None + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + pp = resline.find('\"Serial Number\" = \"') + if pp >= 0: + sernum = resline[pp+19:-1] + sernums.append(sernum.strip()) + return [sernum] + + def GetUserHomeAppSupKindleDirParitionName(): + home = os.getenv('HOME') + dpath = home + '/Library' + cmdline = '/sbin/mount' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + disk = '' + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + if resline.startswith('/dev'): + (devpart, mpath) = resline.split(' on ') + dpart = devpart[5:] + pp = mpath.find('(') + if pp >= 0: + mpath = mpath[:pp-1] + if dpath.startswith(mpath): + disk = dpart + return disk + + # uses a sub process to get the UUID of the specified disk partition using ioreg + def GetDiskPartitionUUID(diskpart): + uuidnum = os.getenv('MYUUIDNUMBER') + if uuidnum != None: + return uuidnum + cmdline = '/usr/sbin/ioreg -l -S -w 0 -r -c AppleAHCIDiskDriver' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + bsdname = None + uuidnum = None + foundIt = False + nest = 0 + uuidnest = -1 + partnest = -2 + for j in xrange(cnt): + resline = reslst[j] + if resline.find('{') >= 0: + nest += 1 + if resline.find('}') >= 0: + nest -= 1 + pp = resline.find('\"UUID\" = \"') + if pp >= 0: + uuidnum = resline[pp+10:-1] + uuidnum = uuidnum.strip() + uuidnest = nest + if partnest == uuidnest and uuidnest > 0: + foundIt = True + break + bb = resline.find('\"BSD Name\" = \"') + if bb >= 0: + bsdname = resline[bb+14:-1] + bsdname = bsdname.strip() + if (bsdname == diskpart): + partnest = nest + else : + partnest = -2 + if partnest == uuidnest and partnest > 0: + foundIt = True + break + if nest == 0: + partnest = -2 + uuidnest = -1 + uuidnum = None + bsdname = None + if not foundIt: + uuidnum = '' + return uuidnum + + def GetMACAddressMunged(): + macnum = os.getenv('MYMACNUM') + if macnum != None: + return macnum + cmdline = '/sbin/ifconfig en0' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + macnum = None + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + pp = resline.find('ether ') + if pp >= 0: + macnum = resline[pp+6:-1] + macnum = macnum.strip() + # print 'original mac', macnum + # now munge it up the way Kindle app does + # by xoring it with 0xa5 and swapping elements 3 and 4 + maclst = macnum.split(':') + n = len(maclst) + if n != 6: + fountIt = False + break + for i in range(6): + maclst[i] = int('0x' + maclst[i], 0) + mlst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + mlst[5] = maclst[5] ^ 0xa5 + mlst[4] = maclst[3] ^ 0xa5 + mlst[3] = maclst[4] ^ 0xa5 + mlst[2] = maclst[2] ^ 0xa5 + mlst[1] = maclst[1] ^ 0xa5 + mlst[0] = maclst[0] ^ 0xa5 + macnum = '%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x' % (mlst[0], mlst[1], mlst[2], mlst[3], mlst[4], mlst[5]) + foundIt = True + break + if not foundIt: + macnum = '' + return macnum + + + # uses unix env to get username instead of using sysctlbyname + def GetUserName(): + username = os.getenv('USER') + return username + + def GetIDStrings(): + # Return all possible ID Strings + strings = [] + strings.append(GetMACAddressMunged()) + strings.extend(GetVolumesSerialNumbers()) + diskpart = GetUserHomeAppSupKindleDirParitionName() + strings.append(GetDiskPartitionUUID(diskpart)) + strings.append('9999999999') + return strings + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used by Kindle for Mac versions < 1.6.0 + class CryptUnprotectData(object): + def __init__(self, IDString): + sp = IDString + '!@#' + GetUserName() + passwdData = encode(SHA256(sp),charMap1) + salt = '16743' + self.crp = LibCrypto() + iter = 0x3e8 + keylen = 0x80 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext,charMap1) + return cleartext + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used for Kindle for Mac Versions >= 1.6.0 + class CryptUnprotectDataV2(object): + def __init__(self, IDString): + sp = GetUserName() + ':&%:' + IDString + passwdData = encode(SHA256(sp),charMap5) + # salt generation as per the code + salt = 0x0512981d * 2 * 1 * 1 + salt = str(salt) + GetUserName() + salt = encode(salt,charMap5) + self.crp = LibCrypto() + iter = 0x800 + keylen = 0x400 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext, charMap5) + return cleartext + + + # unprotect the new header blob in .kinf2011 + # used in Kindle for Mac Version >= 1.9.0 + def UnprotectHeaderData(encryptedData): + passwdData = 'header_key_data' + salt = 'HEADER.2011' + iter = 0x80 + keylen = 0x100 + crp = LibCrypto() + key_iv = crp.keyivgen(passwdData, salt, iter, keylen) + key = key_iv[0:32] + iv = key_iv[32:48] + crp.set_decrypt_key(key,iv) + cleartext = crp.decrypt(encryptedData) + return cleartext + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used for Kindle for Mac Versions >= 1.9.0 + class CryptUnprotectDataV3(object): + def __init__(self, entropy, IDString): + sp = GetUserName() + '+@#$%+' + IDString + passwdData = encode(SHA256(sp),charMap2) + salt = entropy + self.crp = LibCrypto() + iter = 0x800 + keylen = 0x400 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext, charMap2) + return cleartext + + + # Locate the .kindle-info files + def getKindleInfoFiles(): + # file searches can take a long time on some systems, so just look in known specific places. + kInfoFiles=[] + found = False + home = os.getenv('HOME') + # check for .kinf2011 file in new location (App Store Kindle for Mac) + testpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.kinf2011' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kinf2011 file: ' + testpath) + found = True + # check for .kinf2011 files + testpath = home + '/Library/Application Support/Kindle/storage/.kinf2011' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kinf2011 file: ' + testpath) + found = True + # check for .rainier-2.1.1-kinf files + testpath = home + '/Library/Application Support/Kindle/storage/.rainier-2.1.1-kinf' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac rainier file: ' + testpath) + found = True + # check for .kindle-info files + testpath = home + '/Library/Application Support/Kindle/storage/.kindle-info' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kindle-info file: ' + testpath) + found = True + if not found: + print('No k4Mac kindle-info/rainier/kinf2011 files have been found.') + return kInfoFiles + + # determine type of kindle info provided and return a + # database of keynames and values + def getDBfromFile(kInfoFile): + names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] + with open(kInfoFile, 'rb') as infoReader: + filehdr = infoReader.read(1) + filedata = infoReader.read() + + IDStrings = GetIDStrings() + for IDString in IDStrings: + DB = {} + #print "trying IDString:",IDString + try: + hdr = filehdr + data = filedata + if data.find('[') != -1 : + # older style kindle-info file + cud = CryptUnprotectData(IDString) + items = data.split('[') + for item in items: + if item != '': + keyhash, rawdata = item.split(':') + keyname = 'unknown' + for name in names: + if encodeHash(name,charMap2) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + encryptedValue = decode(rawdata,charMap2) + cleartext = cud.decrypt(encryptedValue) + if len(cleartext) > 0: + DB[keyname] = cleartext + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + elif hdr == '/': + # else newer style .kinf file used by K4Mac >= 1.6.0 + # the .kinf file uses '/' to separate it into records + # so remove the trailing '/' to make it easy to use split + data = data[:-1] + items = data.split('/') + cud = CryptUnprotectDataV2(IDString) + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + keyname = 'unknown' + + # the raw keyhash string is also used to create entropy for the actual + # CryptProtectData Blob that represents that keys contents + # 'entropy' not used for K4Mac only K4PC + # entropy = SHA1(keyhash) + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = 'unknown' + for name in names: + if encodeHash(name,charMap5) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + + # the charMap5 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using charMap5 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the charMap5 encoded contents seems to be: + # len(contents) - largest prime number less than or equal to int(len(content)/3) + # (in other words split 'about' 2/3rds of the way through) + + # move first offsets chars to end to align for decode by charMap5 + encdata = ''.join(edlst) + contlen = len(encdata) + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using charMap5 to get the CryptProtect Data + encryptedValue = decode(encdata,charMap5) + cleartext = cud.decrypt(encryptedValue) + if len(cleartext) > 0: + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + else: + # the latest .kinf2011 version for K4M 1.9.1 + # put back the hdr char, it is needed + data = hdr + data + data = data[:-1] + items = data.split('/') + + # the headerblob is the encrypted information needed to build the entropy string + headerblob = items.pop(0) + encryptedValue = decode(headerblob, charMap1) + cleartext = UnprotectHeaderData(encryptedValue) + + # now extract the pieces in the same way + # this version is different from K4PC it scales the build number by multipying by 735 + pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) + for m in re.finditer(pattern, cleartext): + entropy = str(int(m.group(2)) * 0x2df) + m.group(4) + + cud = CryptUnprotectDataV3(entropy,IDString) + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + keyname = 'unknown' + + # unlike K4PC the keyhash is not used in generating entropy + # entropy = SHA1(keyhash) + added_entropy + # entropy = added_entropy + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = 'unknown' + for name in names: + if encodeHash(name,testMap8) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + + # the testMap8 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using testMap8 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the testMap8 encoded contents seems to be: + # len(contents) - largest prime number less than or equal to int(len(content)/3) + # (in other words split 'about' 2/3rds of the way through) + + # move first offsets chars to end to align for decode by testMap8 + encdata = ''.join(edlst) + contlen = len(encdata) + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using testMap8 to get the CryptProtect Data + encryptedValue = decode(encdata,testMap8) + cleartext = cud.decrypt(encryptedValue) + # print keyname + # print cleartext + if len(cleartext) > 0: + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + except: + pass + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + # store values used in decryption + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(IDString, GetUserName()) + DB['IDString'] = IDString + DB['UserName'] = GetUserName() + else: + print u"Couldn't decrypt file." + DB = {} + return DB +else: + def getDBfromFile(kInfoFile): + raise DrmException(u"This script only runs under Windows or Mac OS X.") + return {} + +def kindlekeys(files = []): + keys = [] + if files == []: + files = getKindleInfoFiles() + for file in files: + key = getDBfromFile(file) + if key: + # convert all values to hex, just in case. + for keyname in key: + key[keyname]=key[keyname].encode('hex') + keys.append(key) + return keys + +# interface for Python DeDRM +# returns single key or multiple keys, depending on path or file passed in +def getkey(outpath, files=[]): + keys = kindlekeys(files) + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(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"kindlekey{0:d}.k4i".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(key)) + print u"Saved a key to {0}".format(outfile) + return True + return False + +def usage(progname): + print u"Finds, decrypts and saves the default Kindle For Mac/PC encryption keys." + print u"Keys are saved to the current directory, or a specified output directory." + print u"If a file name is passed instead of a directory, only the first key is saved, in that file." + print u"Usage:" + print u" {0:s} [-h] [-k ] []".format(progname) + + +def cli_main(argv=unicode_argv()): + progname = os.path.basename(argv[0]) + print u"{0} v{1}\nCopyright © 2010-2013 some_updates and Apprentice Alf".format(progname,__version__) + + try: + opts, args = getopt.getopt(argv[1:], "hk:") + except getopt.GetoptError, err: + print u"Error in options or arguments: {0}".format(err.args[0]) + usage(progname) + sys.exit(2) + + files = [] + for o, a in opts: + if o == "-h": + usage(progname) + sys.exit(0) + if o == "-k": + files = [a] + + if len(args) > 1: + usage(progname) + sys.exit(2) + + if len(args) == 1: + # save to the specified file or directory + outpath = args[0] + if not os.path.isabs(outpath): + outpath = os.path.abspath(outpath) + else: + # save to the same directory as the script + outpath = os.path.dirname(argv[0]) + + # make sure the outpath is the + outpath = os.path.realpath(os.path.normpath(outpath)) + + if not getkey(outpath, files): + print u"Could not retrieve Kindle for Mac/PC key." + return 0 + + +def gui_main(argv=unicode_argv()): + import Tkinter + import Tkconstants + import tkMessageBox + import traceback + + class ExceptionDialog(Tkinter.Frame): + def __init__(self, root, text): + Tkinter.Frame.__init__(self, root, border=5) + label = Tkinter.Label(self, text=u"Unexpected error:", + anchor=Tkconstants.W, justify=Tkconstants.LEFT) + label.pack(fill=Tkconstants.X, expand=0) + self.text = Tkinter.Text(self) + self.text.pack(fill=Tkconstants.BOTH, expand=1) + + self.text.insert(Tkconstants.END, text) + + + root = Tkinter.Tk() + root.withdraw() + progpath, progname = os.path.split(argv[0]) + success = False + try: + keys = kindlekeys() + keycount = 0 + for key in keys: + while True: + keycount += 1 + outfile = os.path.join(progpath,u"kindlekey{0:d}.k4i".format(keycount)) + if not os.path.exists(outfile): + break + + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(key)) + success = True + tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile)) + except DrmException, e: + tkMessageBox.showerror(progname, u"Error: {0}".format(str(e))) + except Exception: + root.wm_state('normal') + root.title(progname) + text = traceback.format_exc() + ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1) + root.mainloop() + if not success: + return 1 + return 0 + +if __name__ == '__main__': + if len(sys.argv) > 1: + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + sys.exit(cli_main()) + sys.exit(gui_main()) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/mobidedrm.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/mobidedrm.py index 264c175..ccbac4e 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/mobidedrm.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/mobidedrm.py @@ -462,7 +462,7 @@ class MobiBook: raise DrmException(u"Encryption not initialised. Must be opened with Mobipocket Reader first.") found_key, pid = self.parseDRM(self.sect[drm_ptr:drm_ptr+drm_size], drm_count, goodpids) if not found_key: - raise DrmException(u"No key found in {0:d} keys tried. Read the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(len(goodpids))) + raise DrmException(u"No key found in {0:d} keys tried.".format(len(goodpids))) # kill the drm keys self.patchSection(0, '\0' * drm_size, drm_ptr) # kill the drm pointers diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/openssl_des.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/openssl_des.py index a4a40ca..9a84e58 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/openssl_des.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/openssl_des.py @@ -65,7 +65,7 @@ def load_libcrypto(): class DES(object): def __init__(self, key): if len(key) != 8 : - raise Error('DES improper key used') + raise Exception('DES improper key used') return self.key = key self.keyschedule = DES_KEY_SCHEDULE() diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/plugin-import-name-k4mobidedrm.txt b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/plugin-import-name-dedrm.txt similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/plugin-import-name-k4mobidedrm.txt rename to DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/plugin-import-name-dedrm.txt diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/scrolltextwidget.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/scrolltextwidget.py deleted file mode 100644 index 98b4147..0000000 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/scrolltextwidget.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab - -import Tkinter -import Tkconstants - -# basic scrolled text widget -class ScrolledText(Tkinter.Text): - def __init__(self, master=None, **kw): - self.frame = Tkinter.Frame(master) - self.vbar = Tkinter.Scrollbar(self.frame) - self.vbar.pack(side=Tkconstants.RIGHT, fill=Tkconstants.Y) - kw.update({'yscrollcommand': self.vbar.set}) - Tkinter.Text.__init__(self, self.frame, **kw) - self.pack(side=Tkconstants.LEFT, fill=Tkconstants.BOTH, expand=True) - self.vbar['command'] = self.yview - # Copy geometry methods of self.frame without overriding Text - # methods = hack! - text_meths = vars(Tkinter.Text).keys() - methods = vars(Tkinter.Pack).keys() + vars(Tkinter.Grid).keys() + vars(Tkinter.Place).keys() - methods = set(methods).difference(text_meths) - for m in methods: - if m[0] != '_' and m != 'config' and m != 'configure': - setattr(self, m, getattr(self.frame, m)) - - def __str__(self): - return str(self.frame) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/subasyncio.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/subasyncio.py deleted file mode 100644 index de084d3..0000000 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/subasyncio.py +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env python -# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab - -import os, sys -import signal -import threading -import subprocess -from subprocess import Popen, PIPE, STDOUT - -# **heavily** chopped up and modfied version of asyncproc.py -# to make it actually work on Windows as well as Mac/Linux -# For the original see: -# "http://www.lysator.liu.se/~bellman/download/" -# author is "Thomas Bellman " -# available under GPL version 3 or Later - -# create an asynchronous subprocess whose output can be collected in -# a non-blocking manner - -# What a mess! Have to use threads just to get non-blocking io -# in a cross-platform manner - -# luckily all thread use is hidden within this class - -class Process(object): - def __init__(self, *params, **kwparams): - if len(params) <= 3: - kwparams.setdefault('stdin', subprocess.PIPE) - if len(params) <= 4: - kwparams.setdefault('stdout', subprocess.PIPE) - if len(params) <= 5: - kwparams.setdefault('stderr', subprocess.PIPE) - self.__pending_input = [] - self.__collected_outdata = [] - self.__collected_errdata = [] - self.__exitstatus = None - self.__lock = threading.Lock() - self.__inputsem = threading.Semaphore(0) - self.__quit = False - - self.__process = subprocess.Popen(*params, **kwparams) - - if self.__process.stdin: - self.__stdin_thread = threading.Thread( - name="stdin-thread", - target=self.__feeder, args=(self.__pending_input, - self.__process.stdin)) - self.__stdin_thread.setDaemon(True) - self.__stdin_thread.start() - - if self.__process.stdout: - self.__stdout_thread = threading.Thread( - name="stdout-thread", - target=self.__reader, args=(self.__collected_outdata, - self.__process.stdout)) - self.__stdout_thread.setDaemon(True) - self.__stdout_thread.start() - - if self.__process.stderr: - self.__stderr_thread = threading.Thread( - name="stderr-thread", - target=self.__reader, args=(self.__collected_errdata, - self.__process.stderr)) - self.__stderr_thread.setDaemon(True) - self.__stderr_thread.start() - - def pid(self): - return self.__process.pid - - def kill(self, signal): - self.__process.send_signal(signal) - - # check on subprocess (pass in 'nowait') to act like poll - def wait(self, flag): - if flag.lower() == 'nowait': - rc = self.__process.poll() - else: - rc = self.__process.wait() - if rc != None: - if self.__process.stdin: - self.closeinput() - if self.__process.stdout: - self.__stdout_thread.join() - if self.__process.stderr: - self.__stderr_thread.join() - return self.__process.returncode - - def terminate(self): - if self.__process.stdin: - self.closeinput() - self.__process.terminate() - - # thread gets data from subprocess stdout - def __reader(self, collector, source): - while True: - data = os.read(source.fileno(), 65536) - self.__lock.acquire() - collector.append(data) - self.__lock.release() - if data == "": - source.close() - break - return - - # thread feeds data to subprocess stdin - def __feeder(self, pending, drain): - while True: - self.__inputsem.acquire() - self.__lock.acquire() - if not pending and self.__quit: - drain.close() - self.__lock.release() - break - data = pending.pop(0) - self.__lock.release() - drain.write(data) - - # non-blocking read of data from subprocess stdout - def read(self): - self.__lock.acquire() - outdata = "".join(self.__collected_outdata) - del self.__collected_outdata[:] - self.__lock.release() - return outdata - - # non-blocking read of data from subprocess stderr - def readerr(self): - self.__lock.acquire() - errdata = "".join(self.__collected_errdata) - del self.__collected_errdata[:] - self.__lock.release() - return errdata - - # non-blocking write to stdin of subprocess - def write(self, data): - if self.__process.stdin is None: - raise ValueError("Writing to process with stdin not a pipe") - self.__lock.acquire() - self.__pending_input.append(data) - self.__inputsem.release() - self.__lock.release() - - # close stdinput of subprocess - def closeinput(self): - self.__lock.acquire() - self.__quit = True - self.__inputsem.release() - self.__lock.release() diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py index 3e4db39..71fe8ab 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/topazextract.py @@ -74,7 +74,7 @@ debug = False if 'calibre' in sys.modules: inCalibre = True - from calibre_plugins.k4mobidedrm import kgenpids + from calibre_plugins.dedrm import kgenpids else: inCalibre = False import kgenpids @@ -321,7 +321,7 @@ class TopazBook: self.extractFiles() print u"Successfully Extracted Topaz contents" if inCalibre: - from calibre_plugins.k4mobidedrm import genbook + from calibre_plugins.dedrm import genbook else: import genbook @@ -355,7 +355,7 @@ class TopazBook: self.extractFiles() print u"Successfully Extracted Topaz contents" if inCalibre: - from calibre_plugins.k4mobidedrm import genbook + from calibre_plugins.dedrm import genbook else: import genbook @@ -439,7 +439,7 @@ class TopazBook: def usage(progname): print u"Removes DRM protection from Topaz ebooks and extracts the contents" print u"Usage:" - print u" {0} [-k ] [-p ] [-s ] ".format(progname) + print u" {0} [-k ] [-p ] [-s ] ".format(progname) # Main def cli_main(argv=unicode_argv()): @@ -466,7 +466,7 @@ def cli_main(argv=unicode_argv()): print u"Output Directory {0} Does Not Exist.".format(outdir) return 1 - kInfoFiles = [] + kDatabaseFiles = [] serials = [] pids = [] @@ -474,7 +474,7 @@ def cli_main(argv=unicode_argv()): if o == '-k': if a == None : raise DrmException("Invalid parameter for -k") - kInfoFiles.append(a) + kDatabaseFiles.append(a) if o == '-p': if a == None : raise DrmException("Invalid parameter for -p") @@ -490,7 +490,7 @@ def cli_main(argv=unicode_argv()): title = tb.getBookTitle() print u"Processing Book: {0}".format(title) md1, md2 = tb.getPIDMetaInfo() - pids.extend(kgenpids.getPidList(md1, md2, serials, kInfoFiles)) + pids.extend(kgenpids.getPidList(md1, md2, serials, kDatabaseFiles)) try: print u"Decrypting Book" diff --git a/Calibre_Plugins/ignobleepub_plugin/zipfix.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/utilities.py similarity index 100% rename from Calibre_Plugins/ignobleepub_plugin/zipfix.py rename to DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/utilities.py diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/zipfilerugged.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/zipfilerugged.py index adf3c53..4a55a69 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/zipfilerugged.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/zipfilerugged.py @@ -354,7 +354,7 @@ class ZipInfo (object): def _decodeFilename(self): if self.flag_bits & 0x800: try: - print "decoding filename",self.filename + #print "decoding filename",self.filename return self.filename.decode('utf-8') except: return self.filename diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/zipfix.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/zipfix.py index eaee20d..8ddfae3 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/zipfix.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/zipfix.py @@ -1,6 +1,23 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# zipfix.py, version 1.1 +# Copyright © 2010-2013 by some_updates, DiapDealer and Apprentice Alf + +# Released under the terms of the GNU General Public Licence, version 3 +# + +# Revision history: +# 1.0 - Initial release +# 1.1 - Updated to handle zip file metadata correctly + +""" +Re-write zip (or ePub) fixing problems with file names (and mimetype entry). +""" + +__license__ = 'GPL v3' +__version__ = "1.1" + import sys import zlib import zipfilerugged @@ -96,25 +113,41 @@ class fixZip: # if epub write mimetype file first, with no compression if self.ztype == 'epub': - nzinfo = ZipInfo('mimetype', compress_type=zipfilerugged.ZIP_STORED) - self.outzip.writestr(nzinfo, _MIMETYPE) + # first get a ZipInfo with current time and no compression + mimeinfo = ZipInfo('mimetype',compress_type=zipfilerugged.ZIP_STORED) + mimeinfo.internal_attr = 1 # text file + try: + # if the mimetype is present, get its info, including time-stamp + oldmimeinfo = self.inzip.getinfo('mimetype') + # copy across useful fields + mimeinfo.date_time = oldmimeinfo.date_time + mimeinfo.comment = oldmimeinfo.comment + mimeinfo.extra = oldmimeinfo.extra + mimeinfo.internal_attr = oldmimeinfo.internal_attr + mimeinfo.external_attr = oldmimeinfo.external_attr + mimeinfo.create_system = oldmimeinfo.create_system + except: + pass + self.outzip.writestr(mimeinfo, _MIMETYPE) # write the rest of the files for zinfo in self.inzip.infolist(): - if zinfo.filename != "mimetype" or self.ztype == '.zip': + if zinfo.filename != "mimetype" or self.ztype != 'epub': data = None - nzinfo = zinfo try: data = self.inzip.read(zinfo.filename) except zipfilerugged.BadZipfile or zipfilerugged.error: local_name = self.getlocalname(zinfo) data = self.getfiledata(zinfo) - nzinfo.filename = local_name + zinfo.filename = local_name - nzinfo.date_time = zinfo.date_time - nzinfo.compress_type = zinfo.compress_type - nzinfo.flag_bits = 0 - nzinfo.internal_attr = 0 + # create new ZipInfo with only the useful attributes from the old info + nzinfo = ZipInfo(zinfo.filename, zinfo.date_time, compress_type=zinfo.compress_type) + nzinfo.comment=zinfo.comment + nzinfo.extra=zinfo.extra + nzinfo.internal_attr=zinfo.internal_attr + nzinfo.external_attr=zinfo.external_attr + nzinfo.create_system=zinfo.create_system self.outzip.writestr(nzinfo,data) self.bzf.close() 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 2b7bbed..40781bb 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/DeDRM_app.pyw @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# DeDRM.pyw, version 5.6.2 +# DeDRM.pyw, version 6.0.0 # By some_updates and Apprentice Alf import sys @@ -22,8 +22,11 @@ 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 @@ -46,7 +49,7 @@ class QueuedUTF8Stream: def __getattr__(self, attr): return getattr(self.stream, attr) -__version__ = '5.6.2' +__version__ = '6.0.0' class DrmException(Exception): pass @@ -78,13 +81,21 @@ class MainApp(Tk): def getPreferences(self): prefs = self.po.getPreferences() prefdir = prefs['dir'] - keyfile = os.path.join(prefdir,'adeptkey.der') - if not os.path.exists(keyfile): - import ineptkey + adeptkeyfile = os.path.join(prefdir,'adeptkey.der') + if not os.path.exists(adeptkeyfile): + import adobekey try: - ineptkey.extractKeyfile(keyfile) + 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 return prefs def setPreferences(self, newprefs): @@ -131,7 +142,7 @@ class PrefsDialog(Toplevel): sticky = Tkconstants.E + Tkconstants.W body.grid_columnconfigure(1, weight=2) - Tkinter.Label(body, text='Adept Key file (adeptkey.der)').grid(row=0, sticky=Tkconstants.E) + 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'] @@ -142,30 +153,26 @@ class PrefsDialog(Toplevel): button = Tkinter.Button(body, text="...", command=self.get_adkpath) button.grid(row=0, column=2) - Tkinter.Label(body, text='Barnes and Noble Key file (bnepubkey.b64)').grid(row=1, sticky=Tkconstants.E) + 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=1, column=1, sticky=sticky) + 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(0, path) + self.bnkpath.insert(2, path) button = Tkinter.Button(body, text="...", command=self.get_bnkpath) - button.grid(row=1, column=2) - - Tkinter.Label(body, text='Additional kindle.info or .kinf file').grid(row=2, sticky=Tkconstants.E) - self.altinfopath = Tkinter.Entry(body, width=50) - self.altinfopath.grid(row=2, column=1, sticky=sticky) - prefdir = self.prefs_array['dir'] - path = '' - infofile = os.path.join(prefdir,'kindle.info') - ainfofile = os.path.join(prefdir,'.kinf') - if os.path.isfile(infofile): - path = infofile - elif os.path.isfile(ainfofile): - path = ainfofile - self.altinfopath.insert(0, path) - button = Tkinter.Button(body, text="...", command=self.get_altinfopath) 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) @@ -244,9 +251,16 @@ class PrefsDialog(Toplevel): def get_outpath(self): cpath = self.outpath.get() - outpath = tkFileDialog.askdirectory( - parent=None, title='Folder to Store Unencrypted file(s) into', - initialdir=cpath, initialfile=None) + 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) @@ -263,6 +277,16 @@ class PrefsDialog(Toplevel): 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', @@ -273,17 +297,6 @@ class PrefsDialog(Toplevel): self.bnkpath.insert(0, bnkpath) return - def get_altinfopath(self): - cpath = self.altinfopath.get() - altinfopath = tkFileDialog.askopenfilename(parent=None, title='Select Alternative kindle.info or .kinf File', - defaultextension='.info', filetypes=[('Kindle Info', '.info'),('Kindle KInf','.kinf'),('All Files', '.*')], - initialdir=cpath) - if altinfopath: - altinfopath = os.path.normpath(altinfopath) - self.altinfopath.delete(0, Tkconstants.END) - self.altinfopath.insert(0, altinfopath) - return - def get_bookpath(self): cpath = self.bookpath.get() bookpath = tkFileDialog.askopenfilename(parent=None, title='Select eBook for DRM Removal', @@ -323,10 +336,15 @@ class PrefsDialog(Toplevel): bnkpath = self.bnkpath.get() if os.path.dirname(bnkpath) != prefdir: new_prefs['bnkfile'] = bnkpath - altinfopath = self.altinfopath.get() - if os.path.dirname(altinfopath) != prefdir: - new_prefs['kinfofile'] = altinfopath + 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() @@ -458,37 +476,26 @@ class ConvDialog(Toplevel): # nothing to wait for so just return return poll = self.p2.exitcode + print "processing", poll if poll != None: self.bar.stop() + done = False + text = '' + while not done: + try: + data = self.q.get_nowait() + text += data + except Empty: + done = True + self.log += text if poll == 0: msg = 'Success\n' self.numgood += 1 - done = False - text = '' - while not done: - try: - data = self.q.get_nowait() - text += data - except Empty: - done = True - pass - self.log += text self.log += msg - if poll != 0: + else: msg = 'Failed\n' - done = False - text = '' - while not done: - try: - data = self.q.get_nowait() - text += data - except Empty: - done = True - pass - msg += '\n' - self.log += text - self.log += msg self.numbad += 1 + self.log += msg self.p2.join() self.showCmdOutput(msg) self.p2 = None diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Adobe Digital Editions Key_Help.htm b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Adobe Digital Editions Key_Help.htm new file mode 100644 index 0000000..ee9edb2 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Adobe Digital Editions Key_Help.htm @@ -0,0 +1,55 @@ + + + + + + +Managing Adobe Digital Editions Keys + +

+ + + +

Managing Adobe Digital Editions Keys

+ + +

If you have upgraded from an earlier version of the plugin, any existing Adobe Digital Editions keys will have been automatically imported, so you might not need to do any more configuration. In addition, on Windows and Mac, the default Adobe Digital Editions key is added the first time the plugin is run. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog prompting you to enter a key name for the default Adobe Digital Editions key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys.
  • +
+ +

Click the OK button to create and store the Adobe Digital Editions key for the current installation of Adobe Digital Editions. Or Cancel if you don’t want to create the key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.der’ key files. Key files might come from being exported from this or older plugins, or may have been generated using the adobekey.pyw script running under Wine on Linux systems.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Barnes and Noble Key_Help.htm b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Barnes and Noble Key_Help.htm new file mode 100644 index 0000000..ac1b693 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Barnes and Noble Key_Help.htm @@ -0,0 +1,57 @@ + + + + + + +Managing Barnes and Noble Keys + + + + + +

Managing Barnes and Noble Keys

+ + +

If you have upgraded from an earlier version of the plugin, any existing Barnes and Noble keys will have been automatically imported, so you might not need to do any more configuration. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys. Choose something that will help you remember the data (name, cc#) it was created with.
  • +
  • Your Name: This is the name used by Barnes and Noble to generate your encryption key. Seemingly at random, Barnes and Noble choose one of three places from which to take this name. Most commonly, it’s your name as set in your Barnes & Noble account, My Account page, directly under PERSONAL INFORMATION. Sometimes it is the the name used in the default shipping address, and sometimes it’s the name listed for the active credit card. If these names are different in your Barnes and Noble account preferences, I suggest creating one key for each version of your name. This name will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • +
  • Credit Card#: this is the default credit card number that was on file with Barnes and Noble at the time of download of the ebook to be de-DRMed. Just enter the 16 (15 for American Express) digits. As with the name, this number will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • +
+ +

Click the OK button to create and store the generated key. Or Cancel if you don’t want to create a key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.b64’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.b64’ key files. Key files might come from being exported from this or older plugins, or may have been generated using the original i♥cabbages script.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_EInk Kindle Serial Number_Help.htm b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_EInk Kindle Serial Number_Help.htm new file mode 100644 index 0000000..e79abd7 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_EInk Kindle Serial Number_Help.htm @@ -0,0 +1,43 @@ + + + + + + +Managing eInk Kindle serial numbers + + + + + +

Managing eInk Kindle serial numbers

+ +

If you have upgraded from an earlier version of the plugin, any existing eInk Kindle serial numbers will have been automatically imported, so you might not need to do any more configuration.

+ +

Please note that Kindle serial numbers are only valid keys for eInk Kindles like the Kindle Touch and PaperWhite. The Kindle Fire and Fire HD do not use their serial number for DRM and it is useless to enter those serial numbers.

+ +

Creating New Kindle serial numbers:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle serial number.

+
    +
  • Eink Kindle Serial Number: this is the unique serial number of your device. It usually starts with a ‘B’ or a ‘9’ and is sixteen characters long. For a reference of where to find serial numbers and their ranges, please refere to this mobileread wiki page.
  • +
+ +

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

+ +

Deleting Kindle serial numbers:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Kindle serial number from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Once done creating/deleting serial numbers, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + 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 new file mode 100644 index 0000000..69edade --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Help.htm @@ -0,0 +1,73 @@ + + + + + + +DeDRM Plugin Configuration + + + + + +

DeDRM Plugin (v6.0.0)

+ +

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.

+ +

Installation

+

You have obviously managed to install the plugin, as otherwise you wouldn’t be reading this help file. However, you should also delete any older DeDRM plugins, as this DeDRM plugin replaces the five older plugins: Kindle and Mobipocket DeDRM (K4MobiDeDRM), Ignoble Epub DeDRM (ignobleepub), Inept Epub DeDRM (ineptepub), Inept PDF DeDRM (ineptepub) and eReader PDB 2 PML (eReaderPDB2PML).

+ +

Configuration

+

On Windows and Mac, the keys for ebooks downloaded for Kindle for Mac/PC and Adobe Digital Editions are automatically generated. If all your DRMed ebooks can be opened and read in Kindle for Mac/PC and/or Adobe Digital Editions on the same computer on which you are running calibre, you do not need to do any configuration of this plugin. On Linux, keys for Kindle for PC and Adobe Digital Editions need to be generated separately (see the Linux section below)

+ +

If you have other DRMed ebooks, you will need to enter extra configuration information. The buttons in this dialog will open individual configuration dialogs that will allow you to enter the needed information, depending on the type and source of your DRMed eBooks. Additional help on the information required is available in each of the the dialogs.

+ +

If you have used previous versions of the various DeDRM plugins on this machine, you may find that some of the configuration dialogs already contain the information you entered through those previous plugins.

+ +

When you have finished entering your configuration information, you must click the OK button to save it. If you click the Cancel button, all your changes in all the configuration dialogs will be lost.

+ +

Troubleshooting:

+ +

If you find that it’s not working for you , you can save a lot of time by trying to add the ebook to Calibre in debug mode. This will print out a lot of helpful info that can be copied into any online help requests.

+ +

Open a command prompt (terminal window) and type "calibre-debug -g" (without the quotes). Calibre will launch, and you can can add the problem ebook the usual way. The debug info will be output to the original command prompt (terminal window). Copy the resulting output and paste it into the comment you make at my blog.

+

Note: The Mac version of Calibre doesn’t install the command line tools by default. If you go to the ‘Preferences’ page and click on the miscellaneous button, you’ll find the option to install the command line tools.

+ +

Credits:

+
    +
  • The Dark Reverser for the Mobipocket and eReader scripts
  • +
  • i♥cabbages for the Adobe Digital Editions scripts
  • +
  • Skindle aka Bart Simpson for the Amazon Kindle for PC script
  • +
  • CMBDTC for Amazon Topaz DRM removal script
  • +
  • some_updates, clarknova and Bart Simpson for Amazon Topaz conversion scripts
  • +
  • DiapDealer for the first calibre plugin versions of the tools
  • +
  • some_updates, DiapDealer, Apprentice Alf and mdlnx for Amazon Kindle/Mobipocket tools
  • +
  • some_updates for the DeDRM all-in-one Python tool
  • +
  • Apprentice Alf for the DeDRM all-in-one AppleScript tool
  • +
  • Apprentice Alf for the DeDRM all-in-one calibre plugin
  • +
  • And probably many more.
  • +
+ +

For additional help read the FAQs at Apprentice Alf’s Blog and ask questions in the comments section of the first post.

+ +

Linux Systems Only

+

Generating decryption keys for Adobe Digital Editions and Kindle for PC

+

If you install Kindle for PC and/or Adobe Digital Editions in Wine, you will be able to download DRMed ebooks to them under Wine. To be able to remove the DRM, you will need to generate key files and add them in the plugin's customisation dialogs.

+ +

To generate the key files you will need to install Python and PyCrypto under the same Wine setup as your Kindle for PC and/or Adobe Digital Editions installations. (Kindle for PC, Python and Pycrypto installation instructions in the ReadMe.)

+ +

Once everything's installed under Wine, you'll need to run the adobekey.pyw script (for Adobe Digital Editions) and kindlekey.pyw (For Kindle for PC) using the python installation in your Wine system. The scripts can be found in Other_Tools/Key_Retrieval_Scripts.

+ +

Each script will create a key file in the same folder as the script. Copy the key files to your Linux system and then load the key files using the Adobe Digital Editions ebooks dialog and the Kindle for Mac/PC ebooks dialog.

+ + + + + diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Kindle for Mac and PC Key_Help.htm b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Kindle for Mac and PC Key_Help.htm new file mode 100644 index 0000000..c714581 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Kindle for Mac and PC Key_Help.htm @@ -0,0 +1,55 @@ + + + + + + +Managing Kindle for Mac/PC Keys + + + + + +

Managing Kindle for Mac/PC Keys

+ + +

If you have upgraded from an earlier version of the plugin, any existing Kindle for Mac/PC keys will have been automatically imported, so you might not need to do any more configuration. In addition, on Windows and Mac, the default Kindle for Mac/PC key is added the first time the plugin is run. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog prompting you to enter a key name for the default Kindle for Mac/PC key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys.
  • +
+ +

Click the OK button to create and store the Kindle for Mac/PC key for the current installation of Kindle for Mac/PC. Or Cancel if you don’t want to create the key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.k4i’ key files. Key files might come from being exported from this plugin, or may have been generated using the kindlekey.pyw script running under Wine on Linux systems.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Mobipocket PID_Help.htm b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Mobipocket PID_Help.htm new file mode 100644 index 0000000..00aeeca --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_Mobipocket PID_Help.htm @@ -0,0 +1,42 @@ + + + + + + +Managing Mobipocket PIDs + + + + + +

Managing Mobipocket PIDs

+ +

If you have upgraded from an earlier version of the plugin, any existing Mobipocket PIDs will have been automatically imported, so you might not need to do any more configuration.

+ + +

Creating New Mobipocket PIDs:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Mobipocket PID.

+
    +
  • PID: this is a PID used to decrypt your Mobipocket ebooks. It is eight or ten characters long. Mobipocket PIDs are usualy displayed in the About screen of your Mobipocket device.
  • +
+ +

Click the OK button to save the PID. Or Cancel if you didn’t want to enter a PID.

+ +

Deleting Mobipocket PIDs:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Mobipocket PID from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Once done creating/deleting PIDs, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_eReader Key_Help.htm b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_eReader Key_Help.htm new file mode 100644 index 0000000..c1c78ad --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/DeDRM_eReader Key_Help.htm @@ -0,0 +1,56 @@ + + + + + + +Managing eReader Keys + + + + + +

Managing eReader Keys

+ +

If you have upgraded from an earlier version of the plugin, any existing eReader (Fictionwise ‘.pdb’) keys will have been automatically imported, so you might not need to do any more configuration. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys. Choose something that will help you remember the data (name, cc#) it was created with.
  • +
  • Your Name: This is the name used by Fictionwise to generate your encryption key. Since Fictionwise has now closed down, you might not have easy access to this. It was often the name on the Credit Card used at Fictionwise.
  • +
  • Credit Card#: this is the default credit card number that was on file with Fictionwise at the time of download of the ebook to be de-DRMed. Just enter the last 8 digits of the number. As with the name, this number will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • +
+ +

Click the OK button to create and store the generated key. Or Cancel if you don’t want to create a key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.b63’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.b63’ key files that have previously been exported.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py new file mode 100644 index 0000000..a9ac2fd --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/__init__.py @@ -0,0 +1,450 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement +__license__ = 'GPL v3' +__docformat__ = 'restructuredtext en' + + +# Released under the terms of the GNU General Public Licence, version 3 +# +# +# Requires Calibre version 0.7.55 or higher. +# +# All credit given to i♥cabbages and The Dark Reverser for the original standalone scripts. +# We had the much easier job of converting them to a calibre plugin. +# +# This plugin is meant to decrypt eReader PDBs, Adobe Adept ePubs, Barnes & Noble ePubs, +# Adobe Adept PDFs, Amazon Kindle and Mobipocket files without having to +# install any dependencies... other than having calibre installed, of course. +# +# Configuration: +# Check out the plugin's configuration settings by clicking the "Customize plugin" +# button when you have the "DeDRM" plugin highlighted (under Preferences-> +# Plugins->File type plugins). Once you have the configuration dialog open, you'll +# see a Help link on the top right-hand side. +# +# Revision history: +# 6.0.0 - Initial release + +""" +Decrypt DRMed ebooks. +""" + +PLUGIN_NAME = u"DeDRM" +PLUGIN_VERSION_TUPLE = (6, 0, 0) +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' + +import sys, os, re +import time +import zipfile +import traceback +from zipfile import ZipFile + +class DeDRMError(Exception): + pass + +from calibre.customize import FileTypePlugin +from calibre.constants import iswindows, isosx +from calibre.gui2 import is_ok_to_use_qt +from calibre.utils.config import config_dir + + +# Wrap a stream so that output gets flushed immediately +# and also make sure that any unicode strings get safely +# 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) + +class DeDRM(FileTypePlugin): + name = PLUGIN_NAME + description = u"Removes DRM from Amazon Kindle, Adobe Adept (including Kobo), Barnes & Noble, Mobipocket and eReader ebooks. Credit given to i♥cabbages and The Dark Reverser for the original stand-alone scripts." + supported_platforms = ['linux', 'osx', 'windows'] + 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']) + on_import = True + priority = 600 + + def initialize(self): + # convert old preferences, if necessary. + import calibre_plugins.dedrm.config + + config.convertprefs() + + """ + Dynamic modules can't be imported/loaded from a zipfile... so this routine + runs whenever the plugin gets initialized. This will extract the appropriate + library for the target OS and copy it to the 'alfcrypto' subdirectory of + calibre's configuration directory. That 'alfcrypto' directory is then + inserted into the syspath (as the very first entry) in the run function + so the CDLL stuff will work in the alfcrypto.py script. + """ + try: + if iswindows: + names = [u"alfcrypto.dll",u"alfcrypto64.dll"] + elif isosx: + names = [u"libalfcrypto.dylib"] + else: + names = [u"libalfcrypto32.so",u"libalfcrypto64.so"] + lib_dict = self.load_resources(names) + self.pluginsdir = os.path.join(config_dir,u"plugins") + if not os.path.exists(self.pluginsdir): + os.mkdir(self.pluginsdir) + self.maindir = os.path.join(self.pluginsdir,u"DeDRM") + if not os.path.exists(self.maindir): + os.mkdir(self.maindir) + self.helpdir = os.path.join(self.maindir,u"help") + if not os.path.exists(self.helpdir): + os.mkdir(self.helpdir) + self.alfdir = os.path.join(self.maindir,u"alfcrypto") + if not os.path.exists(self.alfdir): + os.mkdir(self.alfdir) + for entry, data in lib_dict.items(): + file_path = os.path.join(self.alfdir, entry) + open(file_path,'wb').write(data) + except Exception, e: + traceback.print_exc() + raise + + def ePubDecrypt(self,path_to_ebook): + # Create a TemporaryPersistent file to work with. + # Check original epub archive for zip errors. + import calibre_plugins.dedrm.zipfix + + inf = self.temporary_file(u".epub") + try: + print u"{0} v{1}: Verifying zip archive integrity.".format(PLUGIN_NAME, PLUGIN_VERSION) + fr = zipfix.fixZip(path_to_ebook, inf.name) + fr.fix() + except Exception, e: + print u"{0} v{1}: Error \'{2}\' when checking zip archive.".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) + raise Exception(e) + + # import the decryption keys + import calibre_plugins.dedrm.config as config + + # import the Barnes & Noble ePub handler + import calibre_plugins.dedrm.ignobleepub as ignobleepub + + #check the book + if ignobleepub.ignobleBook(inf.name): + print u"{0} v{1}: “{2}” is a secure Barnes & Noble ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + + # Attempt to decrypt epub with each encryption key (generated or provided). + for keyname, userkey in config.dedrmprefs['bandnkeys'].items(): + keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname) + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked) + of = self.temporary_file(u".epub") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + result = ignobleepub.decryptBook(userkey, inf.name, of.name) + + of.close() + + if result == 0: + # Decryption was successful. + # Return the modified PersistentTemporary file to calibre. + return of.name + + 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 Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + # import the Adobe Adept ePub handler + import calibre_plugins.dedrm.ineptepub as ineptepub + + if ineptepub.adeptBook(inf.name): + print u"{0} v{1}: {2} is a secure Adobe Adept ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + + # Attempt to decrypt epub with each encryption key (generated or provided). + for keyname, userkeyhex in config.dedrmprefs['adeptkeys'].items(): + userkey = userkeyhex.decode('hex') + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) + of = self.temporary_file(u".epub") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptepub.decryptBook(userkey, inf.name, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was successful. + # Return the modified PersistentTemporary file to calibre. + return of.name + + print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime) + + # perhaps we need to get a new default ADE key + if iswindows or isosx: + print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys".format(PLUGIN_NAME, PLUGIN_VERSION) + + # get the default Adobe keys + import calibre_plugins.dedrm.adobekey as adobe + + try: + defaultkeys = adobe.adeptkeys() + except: + defaultkeys = [] + + newkeys = [] + for keyvalue in defaultkeys: + if keyvalue.encode('hex') not in config.dedrmprefs['adeptkeys'].values(): + newkeys.append(keyvalue) + + if len(newkeys) > 0: + try: + for i,userkey in enumerate(newkeys): + print u"{0} v{1}: Trying a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + of = self.temporary_file(u".epub") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptepub.decryptBook(userkey, inf.name, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was a success + # Store the new successful key in the defaults + print u"{0} v{1}: Saving a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + try: + config.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex')) + config.writeprefs() + except: + traceback.print_exc() + # 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: + pass + + # Something went wrong with decryption. + print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + # Not a Barnes & Noble nor an Adobe Adept + # Import the fixed epub. + print u"{0} v{1}: “{2}” is neither an Adobe Adept nor a Barnes & Noble encrypted ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + return inf.name + + def PDFDecrypt(self,path_to_ebook): + import calibre_plugins.dedrm.config as config + import calibre_plugins.dedrm.ineptpdf + + # Attempt to decrypt epub with each encryption key (generated or provided). + print u"{0} v{1}: {2} is a PDF ebook.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + for keyname, userkeyhex in config.dedrmprefs['adeptkeys'].items(): + userkey = userkeyhex.decode('hex') + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) + of = self.temporary_file(u".pdf") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptpdf.decryptBook(userkey, path_to_ebook, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was successful. + # Return the modified PersistentTemporary file to calibre. + return of.name + + # perhaps we need to get a new default ADE key + if iswindows or isosx: + print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys".format(PLUGIN_NAME, PLUGIN_VERSION) + + # get the default Adobe keys + import calibre_plugins.dedrm.adobekey as adobe + + try: + defaultkeys = adobe.adeptkeys() + except: + defaultkeys = [] + + newkeys = [] + for keyvalue in defaultkeys: + if keyvalue.encode('hex') not in config.dedrmprefs['adeptkeys'].values(): + newkeys.append(keyvalue) + + if len(newkeys) > 0: + try: + for i,userkey in enumerate(newkeys): + print u"{0} v{1}: Trying a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + of = self.temporary_file(u".pdf") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptepdf.decryptBook(userkey, inf.name, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was a success + # Store the new successful key in the defaults + print u"{0} v{1}: Saving a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + try: + config.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex')) + config.writeprefs() + except: + traceback.print_exc() + # 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: + pass + + # Something went wrong with decryption. + print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + def KindleMobiDecrypt(self,path_to_ebook): + + # add the alfcrypto directory to sys.path so alfcrypto.py + # will be able to locate the custom lib(s) for CDLL import. + sys.path.insert(0, self.alfdir) + # Had to move this import here so the custom libs can be + # extracted to the appropriate places beforehand these routines + # look for them. + import calibre_plugins.dedrm.config as config + import calibre_plugins.dedrm.k4mobidedrm + + pids = config.dedrmprefs['pids'] + serials = config.dedrmprefs['serials'] + kindleDatabases = config.dedrmprefs['kindlekeys'].items() + + try: + book = k4mobidedrm.GetDecryptedBook(path_to_ebook,kindleDatabases,serials,pids,self.starttime) + except Exception, e: + decoded = False + # perhaps we need to get a new default Kindle for Mac/PC key + if iswindows or isosx: + print u"{0} v{1}: Failed to decrypt with error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION,e.args[0]) + print u"{0} v{1}: Looking for new default Kindle Key".format(PLUGIN_NAME, PLUGIN_VERSION) + import calibre_plugins.dedrm.kindlekey as amazon + + try: + defaultkeys = amazon.kindlekeys() + except: + defaultkeys = [] + newkeys = {} + for i,keyvalue in enumerate(defaultkeys): + keyname = u"default_key_{0:d}".format(i+1) + if keyvalue not in config.dedrmprefs['kindlekeys'].values(): + newkeys[keyname] = keyvalue + if len(newkeys) > 0: + try: + book = k4mobidedrm.GetDecryptedBook(path_to_ebook,newkeys.items(),[],[],self.starttime) + decoded = True + # store the new successful keys in the defaults + for keyvalue in newkeys.values(): + config.addnamedvaluetoprefs('kindlekeys','default_key',keyvalue) + config.writeprefs() + except Exception, e: + 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 Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + traceback.print_exc() + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{4}” after {3:.1f} seconds with error: {2}\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0],time.time()-self.starttime,os.path.basename(path_to_ebook))) + + of = self.temporary_file(book.getBookExtension()) + book.getFile(of.name) + of.close() + book.cleanup() + return of.name + + + def eReaderDecrypt(self,path_to_ebook): + + import calibre_plugins.dedrm.config as config + import calibre_plugins.dedrm.erdr2pml + + # Attempt to decrypt epub with each encryption key (generated or provided). + for keyname, userkey in config.dedrmprefs['ereaderkeys'].items(): + keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname) + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked) + of = self.temporary_file(u".pmlz") + + # Give the userkey, ebook and TemporaryPersistent file to the decryption function. + result = erdr2pml.decryptBook(path_to_ebook, of.name, True, userkey.decode('hex')) + + of.close() + + # Decryption was successful return the modified PersistentTemporary + # file to Calibre's import process. + if result == 0: + return of.name + + 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 Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + + def run(self, path_to_ebook): + + # make sure any unicode output gets converted safely with 'replace' + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + + print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + self.starttime = time.time() + + booktype = os.path.splitext(path_to_ebook)[1].lower()[1:] + if booktype in ['prc','mobi','azw','azw1','azw3','azw4','tpz']: + # Kindle/Mobipocket + decrypted_ebook = self.KindleMobiDecrypt(path_to_ebook) + elif booktype == 'pdb': + # eReader + decrypted_ebook = self.eReaderDecrypt(path_to_ebook) + pass + elif booktype == 'pdf': + # Adobe Adept PDF (hopefully) + decrypted_ebook = self.PDFDecrypt(path_to_ebook) + pass + elif booktype == 'epub': + # Adobe Adept or B&N ePub + decrypted_ebook = self.ePubDecrypt(path_to_ebook) + else: + print u"Unknown booktype {0}. Passing back to calibre unchanged.".format(booktype) + return path_to_ebook + print u"{0} v{1}: Successfully decrypted book after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + return decrypted_ebook + + def is_customizable(self): + # return true to allow customization via the Plugin->Preferences. + return True + + def config_widget(self): + import calibre_plugins.dedrm.config as config + return config.ConfigWidget(self.plugin_path) + + def save_settings(self, config_widget): + config_widget.save_settings() diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/adobekey.py similarity index 76% rename from DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.py rename to DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/adobekey.py index a9bc62d..94f7522 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/adobekey.py @@ -1,25 +1,31 @@ -#! /usr/bin/python +#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import with_statement -# ineptkey.pyw, version 5.6 +# adobekey.pyw, version 5.7 # Copyright © 2009-2010 i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Windows users: Before running this program, you must first install Python 2.6 -# from and PyCrypto from -# (make certain -# to install the version for Python 2.6). Then save this script file as -# ineptkey.pyw and double-click on it to run it. It will create a file named -# adeptkey.der in the same directory. This is your ADEPT user key. +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf + +# Windows users: Before running this program, you must first install Python. +# We recommend ActiveState Python 2.7.X for Windows (x86) from +# http://www.activestate.com/activepython/downloads. +# You must also install PyCrypto from +# http://www.voidspace.org.uk/python/modules.shtml#pycrypto +# (make certain to install the version for Python 2.7). +# Then save this script file as adobekey.pyw and double-click on it to run it. +# It will create a file named adobekey_1.der in in the same directory as the script. +# This is your Adobe Digital Editions user key. # -# Mac OS X users: Save this script file as ineptkey.pyw. You can run this -# program from the command line (pythonw ineptkey.pyw) or by double-clicking +# Mac OS X users: Save this script file as adobekey.pyw. You can run this +# program from the command line (python adobekey.pyw) or by double-clicking # it when it has been associated with PythonLauncher. It will create a file -# named adeptkey.der in the same directory. This is your ADEPT user key. +# named adobekey_1.der in the same directory as the script. +# This is your Adobe Digital Editions user key. # Revision history: # 1 - Initial release, for Adobe Digital Editions 1.7 @@ -30,24 +36,25 @@ from __future__ import with_statement # 4.2 - added old 1.7.1 processing # 4.3 - better key search # 4.4 - Make it working on 64-bit Python -# 5 - Clean up and improve 4.x changes; -# Clean up and merge OS X support by unknown +# 5 - Clean up and improve 4.x changes; +# Clean up and merge OS X support by unknown # 5.1 - add support for using OpenSSL on Windows in place of PyCrypto # 5.2 - added support for output of key to a particular file # 5.3 - On Windows try PyCrypto first, OpenSSL next # 5.4 - Modify interface to allow use of import # 5.5 - Fix for potential problem with PyCrypto # 5.6 - Revised to allow use in Plugins to eliminate need for duplicate code +# 5.7 - Unicode support added, renamed adobekey from ineptkey +# 5.8 - Added getkey interface for Windows DeDRM application """ Retrieve Adobe ADEPT user key. """ __license__ = 'GPL v3' +__version__ = '5.8' -import sys -import os -import struct +import sys, os, struct, getopt # Wrap a stream so that output gets flushed immediately # and also make sure that any unicode strings get @@ -79,8 +86,8 @@ def unicode_argv(): # 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 '?'. - + # characters with '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 from ctypes import POINTER, byref, cdll, c_int, windll from ctypes.wintypes import LPCWSTR, LPWSTR @@ -101,7 +108,9 @@ def unicode_argv(): start = argc.value - len(sys.argv) return [argv[i] for i in xrange(start, argc.value)] - return [u"ineptkey.py"] + # if we don't have any arguments at all, just pass back script name + # this should never happen + return [u"adobekey.py"] else: argvencoding = sys.stdin.encoding if argvencoding == None: @@ -349,7 +358,7 @@ if iswindows: return CryptUnprotectData CryptUnprotectData = CryptUnprotectData() - def retrieve_keys(): + def adeptkeys(): if AES is None: raise ADEPTError("PyCrypto or OpenSSL must be installed") root = GetSystemDirectory().split('\\')[0] + '\\' @@ -406,6 +415,9 @@ elif isosx: 'enc': 'http://www.w3.org/2001/04/xmlenc#'} def findActivationDat(): + import warnings + warnings.filterwarnings('ignore', category=FutureWarning) + home = os.getenv('HOME') cmdline = 'find "' + home + '/Library/Application Support/Adobe/Digital Editions" -name "activation.dat"' cmdline = cmdline.encode(sys.getfilesystemencoding()) @@ -413,6 +425,7 @@ elif isosx: out1, out2 = p2.communicate() reslst = out1.split('\n') cnt = len(reslst) + ActDatPath = "activation.dat" for j in xrange(cnt): resline = reslst[j] pp = resline.find('activation.dat') @@ -423,10 +436,10 @@ elif isosx: return ActDatPath return None - def retrieve_keys(): + def adeptkeys(): actpath = findActivationDat() if actpath is None: - raise ADEPTError("Could not locate ADE activation") + raise ADEPTError("Could not find ADE activation.dat file.") tree = etree.parse(actpath) adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag) expr = '//%s/%s' % (adept('credentials'), adept('privateLicenseKey')) @@ -436,33 +449,93 @@ elif isosx: return [userkey] else: - def retrieve_keys(keypath): + def adeptkeys(): raise ADEPTError("This script only supports Windows and Mac OS X.") return [] -def retrieve_key(keypath): - keys = retrieve_keys() - with open(keypath, 'wb') as f: - f.write(keys[0]) - return True - -def extractKeyfile(keypath): - try: - success = retrieve_key(keypath) - except ADEPTError, e: - print u"Key generation Error: {0}".format(e.args[0]) - return 1 - except Exception, e: - print "General Error: {0}".format(e.args[0]) - return 1 - if not success: - return 1 - return 0 +# interface for Python DeDRM +def getkey(outpath): + keys = adeptkeys() + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'wb') 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"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + print u"Saved a key to {0}".format(outfile) + return True + return False +def usage(progname): + print u"Finds, decrypts and saves the default Adobe Adept encryption key(s)." + print u"Keys are saved to the current directory, or a specified output directory." + print u"If a file name is passed instead of a directory, only the first key is saved, in that file." + print u"Usage:" + print u" {0:s} [-h] []".format(progname) def cli_main(argv=unicode_argv()): - keypath = argv[1] - return extractKeyfile(keypath) + progname = os.path.basename(argv[0]) + print u"{0} v{1}\nCopyright © 2009-2013 i♥cabbages and 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) > 1: + usage(progname) + sys.exit(2) + + if len(args) == 1: + # save to the specified file or directory + outpath = args[0] + if not os.path.isabs(outpath): + outpath = os.path.abspath(outpath) + else: + # save to the same directory as the script + outpath = os.path.dirname(argv[0]) + + # make sure the outpath is the + outpath = os.path.realpath(os.path.normpath(outpath)) + + keys = adeptkeys() + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'wb') 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"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + print u"Saved a key to {0}".format(outfile) + else: + print u"Could not retrieve Adobe Adept key." + return 0 def gui_main(argv=unicode_argv()): @@ -485,23 +558,32 @@ def gui_main(argv=unicode_argv()): root = Tkinter.Tk() root.withdraw() - keypath, progname = os.path.split(argv[0]) - keypath = os.path.join(keypath, u"adeptkey.der") + progpath, progname = os.path.split(argv[0]) success = False try: - success = retrieve_key(keypath) - except ADEPTError, e: - tkMessageBox.showerror(u"ADEPT Key", "Error: {0}".format(e.args[0])) + keys = adeptkeys() + keycount = 0 + for key in keys: + while True: + keycount += 1 + outfile = os.path.join(progpath,u"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + success = True + tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile)) + except DrmException, e: + tkMessageBox.showerror(progname, u"Error: {0}".format(str(e))) except Exception: root.wm_state('normal') - root.title('ADEPT Key') + root.title(progname) text = traceback.format_exc() ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1) root.mainloop() if not success: return 1 - tkMessageBox.showinfo( - u"ADEPT Key", u"Key successfully retrieved to {0}".format(keypath)) return 0 if __name__ == '__main__': diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/askfolder_ed.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/askfolder_ed.py new file mode 100644 index 0000000..a4a2ae0 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/askfolder_ed.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab + +# to work around tk_chooseDirectory not properly returning unicode paths on Windows +# need to use a dialog that can be hacked up to actually return full unicode paths +# originally based on AskFolder from EasyDialogs for Windows but modified to fix it +# to actually use unicode for path + +# The original license for EasyDialogs is as follows +# +# Copyright (c) 2003-2005 Jimmy Retzlaff +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +""" +AskFolder(...) -- Ask the user to select a folder Windows specific +""" + +import os + +import ctypes +from ctypes import POINTER, byref, cdll, c_int, windll +from ctypes.wintypes import LPCWSTR, LPWSTR +import ctypes.wintypes as wintypes + + +__all__ = ['AskFolder'] + +# Load required Windows DLLs +ole32 = ctypes.windll.ole32 +shell32 = ctypes.windll.shell32 +user32 = ctypes.windll.user32 + + +# Windows Constants +BFFM_INITIALIZED = 1 +BFFM_SETOKTEXT = 1129 +BFFM_SETSELECTIONA = 1126 +BFFM_SETSELECTIONW = 1127 +BIF_EDITBOX = 16 +BS_DEFPUSHBUTTON = 1 +CB_ADDSTRING = 323 +CB_GETCURSEL = 327 +CB_SETCURSEL = 334 +CDM_SETCONTROLTEXT = 1128 +EM_GETLINECOUNT = 186 +EM_GETMARGINS = 212 +EM_POSFROMCHAR = 214 +EM_SETSEL = 177 +GWL_STYLE = -16 +IDC_STATIC = -1 +IDCANCEL = 2 +IDNO = 7 +IDOK = 1 +IDYES = 6 +MAX_PATH = 260 +OFN_ALLOWMULTISELECT = 512 +OFN_ENABLEHOOK = 32 +OFN_ENABLESIZING = 8388608 +OFN_ENABLETEMPLATEHANDLE = 128 +OFN_EXPLORER = 524288 +OFN_OVERWRITEPROMPT = 2 +OPENFILENAME_SIZE_VERSION_400 = 76 +PBM_GETPOS = 1032 +PBM_SETMARQUEE = 1034 +PBM_SETPOS = 1026 +PBM_SETRANGE = 1025 +PBM_SETRANGE32 = 1030 +PBS_MARQUEE = 8 +PM_REMOVE = 1 +SW_HIDE = 0 +SW_SHOW = 5 +SW_SHOWNORMAL = 1 +SWP_NOACTIVATE = 16 +SWP_NOMOVE = 2 +SWP_NOSIZE = 1 +SWP_NOZORDER = 4 +VER_PLATFORM_WIN32_NT = 2 +WM_COMMAND = 273 +WM_GETTEXT = 13 +WM_GETTEXTLENGTH = 14 +WM_INITDIALOG = 272 +WM_NOTIFY = 78 + +# Windows function prototypes +BrowseCallbackProc = ctypes.WINFUNCTYPE(ctypes.c_int, wintypes.HWND, ctypes.c_uint, wintypes.LPARAM, wintypes.LPARAM) + +# Windows types +LPCTSTR = ctypes.c_char_p +LPTSTR = ctypes.c_char_p +LPVOID = ctypes.c_voidp +TCHAR = ctypes.c_char + +class BROWSEINFO(ctypes.Structure): + _fields_ = [ + ("hwndOwner", wintypes.HWND), + ("pidlRoot", LPVOID), + ("pszDisplayName", LPTSTR), + ("lpszTitle", LPCTSTR), + ("ulFlags", ctypes.c_uint), + ("lpfn", BrowseCallbackProc), + ("lParam", wintypes.LPARAM), + ("iImage", ctypes.c_int) + ] + + +# Utilities +def CenterWindow(hwnd): + desktopRect = GetWindowRect(user32.GetDesktopWindow()) + myRect = GetWindowRect(hwnd) + x = width(desktopRect) // 2 - width(myRect) // 2 + y = height(desktopRect) // 2 - height(myRect) // 2 + user32.SetWindowPos(hwnd, 0, + desktopRect.left + x, + desktopRect.top + y, + 0, 0, + SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER + ) + + +def GetWindowRect(hwnd): + rect = wintypes.RECT() + user32.GetWindowRect(hwnd, ctypes.byref(rect)) + return rect + +def width(rect): + return rect.right-rect.left + +def height(rect): + return rect.bottom-rect.top + + +def AskFolder( + message=None, + version=None, + defaultLocation=None, + location=None, + windowTitle=None, + actionButtonLabel=None, + cancelButtonLabel=None, + multiple=None): + """Display a dialog asking the user for select a folder. + modified to use unicode strings as much as possible + returns unicode path + """ + + def BrowseCallback(hwnd, uMsg, lParam, lpData): + if uMsg == BFFM_INITIALIZED: + if actionButtonLabel: + label = unicode(actionButtonLabel, errors='replace') + user32.SendMessageW(hwnd, BFFM_SETOKTEXT, 0, label) + if cancelButtonLabel: + label = unicode(cancelButtonLabel, errors='replace') + cancelButton = user32.GetDlgItem(hwnd, IDCANCEL) + if cancelButton: + user32.SetWindowTextW(cancelButton, label) + if windowTitle: + title = unicode(windowTitle, erros='replace') + user32.SetWindowTextW(hwnd, title) + if defaultLocation: + user32.SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, defaultLocation.replace('/', '\\')) + if location: + x, y = location + desktopRect = wintypes.RECT() + user32.GetWindowRect(0, ctypes.byref(desktopRect)) + user32.SetWindowPos(hwnd, 0, + desktopRect.left + x, + desktopRect.top + y, 0, 0, + SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER) + else: + CenterWindow(hwnd) + return 0 + + # This next line is needed to prevent gc of the callback + callback = BrowseCallbackProc(BrowseCallback) + + browseInfo = BROWSEINFO() + browseInfo.pszDisplayName = ctypes.c_char_p('\0' * (MAX_PATH+1)) + browseInfo.lpszTitle = message + browseInfo.lpfn = callback + + pidl = shell32.SHBrowseForFolder(ctypes.byref(browseInfo)) + if not pidl: + result = None + else: + path = LPCWSTR(u" " * (MAX_PATH+1)) + shell32.SHGetPathFromIDListW(pidl, path) + ole32.CoTaskMemFree(pidl) + result = path.value + return result + + + + 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 9521540..04d87c6 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/config.py @@ -1,62 +1,464 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from PyQt4.Qt import QWidget, QVBoxLayout, QLabel, QLineEdit +from __future__ import with_statement -from calibre.utils.config import JSONConfig +__license__ = 'GPL v3' + +# Standard Python modules. +import os, sys, re, hashlib + +# PyQT4 modules (part of calibre). +from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, + QGroupBox, QPushButton, QListWidget, QListWidgetItem, + QAbstractItemView, QIcon, QDialog, QUrl, QString) +from PyQt4 import QtGui + +import zipfile +from zipfile import ZipFile + +# calibre modules and constants. +from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url, + choose_dir, choose_files) +from calibre.utils.config import dynamic, config_dir, JSONConfig +from calibre.constants import iswindows, isosx + +# modules from this plugin's zipfile. +from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION +from calibre_plugins.dedrm.__init__ import RESOURCE_NAME as help_file_name +from calibre_plugins.dedrm.utilities import (uStrCmp, DETAILED_MESSAGE) + +import calibre_plugins.dedrm.dialogs as dialogs +import calibre_plugins.dedrm.ignoblekeygen as bandn +import calibre_plugins.dedrm.erdr2pml as ereader +import calibre_plugins.dedrm.adobekey as adobe +import calibre_plugins.dedrm.kindlekey as amazon + +JSON_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_') +JSON_PATH = os.path.join(u"plugins", JSON_NAME + '.json') + +IGNOBLEPLUGINNAME = "Ignoble Epub DeDRM" +EREADERPLUGINNAME = "eReader PDB 2 PML" +OLDKINDLEPLUGINNAME = "K4PC, K4Mac, Kindle Mobi and Topaz DeDRM" # This is where all preferences for this plugin will be stored # You should always prefix your config file name with plugins/, # so as to ensure you dont accidentally clobber a calibre config file -prefs = JSONConfig('plugins/K4MobiDeDRM') +dedrmprefs = JSONConfig(JSON_PATH) -# Set defaults -prefs.defaults['pids'] = "" -prefs.defaults['serials'] = "" -prefs.defaults['WINEPREFIX'] = None +# get prefs from older tools +kindleprefs = JSONConfig(os.path.join(u"plugins", u"K4MobiDeDRM")) +ignobleprefs = JSONConfig(os.path.join(u"plugins", u"ignoble_epub_dedrm")) + +# Set defaults for the prefs +dedrmprefs.defaults['configured'] = False +dedrmprefs.defaults['bandnkeys'] = {} +dedrmprefs.defaults['adeptkeys'] = {} +dedrmprefs.defaults['ereaderkeys'] = {} +dedrmprefs.defaults['kindlekeys'] = {} +dedrmprefs.defaults['pids'] = [] +dedrmprefs.defaults['serials'] = [] class ConfigWidget(QWidget): - - def __init__(self): + def __init__(self, plugin_path): QWidget.__init__(self) - self.l = QVBoxLayout() - self.setLayout(self.l) - self.serialLabel = QLabel('eInk Kindle Serial numbers (First character B, 16 characters, use commas if more than one)') - self.l.addWidget(self.serialLabel) + self.plugin_path = plugin_path - self.serials = QLineEdit(self) - self.serials.setText(prefs['serials']) - self.l.addWidget(self.serials) - self.serialLabel.setBuddy(self.serials) + # get copy of the prefs from the file + # Otherwise we seem to get a persistent local copy. + self.dedrmprefs = JSONConfig(JSON_PATH) - self.pidLabel = QLabel('Mobipocket PIDs (8 or 10 characters, use commas if more than one)') - self.l.addWidget(self.pidLabel) + self.tempdedrmprefs = {} + self.tempdedrmprefs['bandnkeys'] = self.dedrmprefs['bandnkeys'].copy() + self.tempdedrmprefs['adeptkeys'] = self.dedrmprefs['adeptkeys'].copy() + self.tempdedrmprefs['ereaderkeys'] = self.dedrmprefs['ereaderkeys'].copy() + self.tempdedrmprefs['kindlekeys'] = self.dedrmprefs['kindlekeys'].copy() + self.tempdedrmprefs['pids'] = list(self.dedrmprefs['pids']) + self.tempdedrmprefs['serials'] = list(self.dedrmprefs['serials']) - self.pids = QLineEdit(self) - self.pids.setText(prefs['pids']) - self.l.addWidget(self.pids) - self.pidLabel.setBuddy(self.serials) + # Start Qt Gui dialog layout + layout = QVBoxLayout(self) + self.setLayout(layout) - self.wpLabel = QLabel('For Linux only: WINEPREFIX (enter absolute path)') - self.l.addWidget(self.wpLabel) + help_layout = QHBoxLayout() + layout.addLayout(help_layout) + # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. + help_label = QLabel('Plugin Help', self) + help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) + help_label.setAlignment(Qt.AlignRight) + help_label.linkActivated.connect(self.help_link_activated) + help_layout.addWidget(help_label) - self.wineprefix = QLineEdit(self) - wineprefix = prefs['WINEPREFIX'] - if wineprefix is not None: - self.wineprefix.setText(wineprefix) - else: - self.wineprefix.setText('') + keys_group_box = QGroupBox(_('Configuration:'), self) + layout.addWidget(keys_group_box) + keys_group_box_layout = QHBoxLayout() + keys_group_box.setLayout(keys_group_box_layout) - self.l.addWidget(self.wineprefix) - self.wpLabel.setBuddy(self.wineprefix) + + button_layout = QVBoxLayout() + keys_group_box_layout.addLayout(button_layout) + self.bandn_button = QtGui.QPushButton(self) + self.bandn_button.setToolTip(_(u"Click to manage keys for Barnes and Noble ebooks")) + self.bandn_button.setText(u"Barnes and Noble ebooks") + self.bandn_button.clicked.connect(self.bandn_keys) + self.kindle_serial_button = QtGui.QPushButton(self) + self.kindle_serial_button.setToolTip(_(u"Click to manage eInk Kindle serial numbers for Kindle ebooks")) + self.kindle_serial_button.setText(u"eInk Kindle ebooks") + self.kindle_serial_button.clicked.connect(self.kindle_serials) + self.kindle_key_button = QtGui.QPushButton(self) + self.kindle_key_button.setToolTip(_(u"Click to manage keys for Kindle for Mac/PC ebooks")) + self.kindle_key_button.setText(u"Kindle for Mac/PC ebooks") + self.kindle_key_button.clicked.connect(self.kindle_keys) + self.adept_button = QtGui.QPushButton(self) + self.adept_button.setToolTip(_(u"Click to manage keys for Adobe Digital Editions ebooks")) + self.adept_button.setText(u"Adobe Digital Editions ebooks") + self.adept_button.clicked.connect(self.adept_keys) + self.mobi_button = QtGui.QPushButton(self) + self.mobi_button.setToolTip(_(u"Click to manage PIDs for Mobipocket ebooks")) + self.mobi_button.setText(u"Mobipocket ebooks") + self.mobi_button.clicked.connect(self.mobi_keys) + self.ereader_button = QtGui.QPushButton(self) + self.ereader_button.setToolTip(_(u"Click to manage keys for eReader ebooks")) + self.ereader_button.setText(u"eReader ebooks") + self.ereader_button.clicked.connect(self.ereader_keys) + button_layout.addWidget(self.kindle_serial_button) + button_layout.addWidget(self.bandn_button) + button_layout.addWidget(self.mobi_button) + button_layout.addWidget(self.ereader_button) + button_layout.addWidget(self.adept_button) + button_layout.addWidget(self.kindle_key_button) + + self.resize(self.sizeHint()) + + def kindle_serials(self): + d = dialogs.ManageKeysDialog(self,u"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], dialogs.AddSerialDialog) + d.exec_() + + def kindle_keys(self): + d = dialogs.ManageKeysDialog(self,u"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], dialogs.AddKindleDialog, 'k4i') + d.exec_() + + def adept_keys(self): + d = dialogs.ManageKeysDialog(self,u"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], dialogs.AddAdeptDialog, 'der') + d.exec_() + + def mobi_keys(self): + d = dialogs.ManageKeysDialog(self,u"Mobipocket PID",self.tempdedrmprefs['pids'], dialogs.AddPIDDialog) + d.exec_() + + def bandn_keys(self): + d = dialogs.ManageKeysDialog(self,u"Barnes and Noble Key",self.tempdedrmprefs['bandnkeys'], dialogs.AddBandNKeyDialog, 'b64') + d.exec_() + + def ereader_keys(self): + d = dialogs.ManageKeysDialog(self,u"eReader Key",self.tempdedrmprefs['ereaderkeys'], dialogs.AddEReaderDialog, 'b63') + d.exec_() + + def help_link_activated(self, url): + def get_help_file_resource(): + # Copy the HTML helpfile to the plugin directory each time the + # link is clicked in case the helpfile is updated in newer plugins. + file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name) + with open(file_path,'w') as f: + f.write(self.load_resource(help_file_name)) + return file_path + url = 'file:///' + get_help_file_resource() + open_url(QUrl(url)) def save_settings(self): - prefs['pids'] = str(self.pids.text()).replace(" ","") - prefs['serials'] = str(self.serials.text()).replace(" ","") - winepref=str(self.wineprefix.text()) - if winepref.strip() != '': - prefs['WINEPREFIX'] = winepref - else: - prefs['WINEPREFIX'] = None + self.dedrmprefs['bandnkeys'] = self.tempdedrmprefs['bandnkeys'] + self.dedrmprefs['adeptkeys'] = self.tempdedrmprefs['adeptkeys'] + self.dedrmprefs['ereaderkeys'] = self.tempdedrmprefs['ereaderkeys'] + self.dedrmprefs['kindlekeys'] = self.tempdedrmprefs['kindlekeys'] + self.dedrmprefs['pids'] = self.tempdedrmprefs['pids'] + self.dedrmprefs['serials'] = self.tempdedrmprefs['serials'] + self.dedrmprefs['configured'] = True + + def load_resource(self, name): + with ZipFile(self.plugin_path, 'r') as zf: + if name in zf.namelist(): + return zf.read(name) + return "" + +def writeprefs(value = True): + dedrmprefs['configured'] = value + +def addnamedvaluetoprefs(prefkind, keyname, keyvalue): + try: + if keyvalue not in dedrmprefs[prefkind].values(): + # ensure that the keyname is unique + # by adding a number (starting with 2) to the name if it is not + namecount = 1 + newname = keyname + while newname in dedrmprefs[prefkind]: + namecount += 1 + newname = "{0:s}_{1:d}".format(keyname,namecount) + # add to the preferences + dedrmprefs[prefkind][newname] = keyvalue + return (True, newname) + except: + pass + return (False, keyname) + +def addvaluetoprefs(prefkind, prefsvalue): + # ensure the keyvalue isn't already in the preferences + if prefsvalue not in dedrmprefs[prefkind]: + dedrmprefs[prefkind].append(prefsvalue) + return True + return False + +def convertprefs(always = False): + + def parseIgnobleString(keystuff): + userkeys = {} + ar = keystuff.split(':') + for i, keystring in enumerate(ar): + try: + name, ccn = keystring.split(',') + # Generate Barnes & Noble EPUB user key from name and credit card number. + keyname = u"{0}_{1}_{2:d}".format(name.strip(),ccn.strip()[-4:],i+1) + keyvalue = bandn.generate_key(name, ccn) + if keyvalue not in userkeys.values(): + while keyname in dedrmprefs['bandnkeys']: + keyname = keyname + keyname[-1] + userkeys[keyname] = keyvalue + except Exception, e: + print e.args[0] + pass + return userkeys + + def parseeReaderString(keystuff): + userkeys = {} + ar = keystuff.split(':') + for i, keystring in enumerate(ar): + try: + name, cc = keystring.split(',') + # Generate eReader user key from name and credit card number. + keyname = u"{0}_{1}_{2:d}".format(name.strip(),cc.strip()[-4:],i+1) + keyvalue = ereader.getuser_key(name,cc).encode('hex') + if keyvalue not in userkeys.values(): + while keyname in dedrmprefs['ereaderkeys']: + keyname = keyname + keyname[-1] + userkeys[keyname] = keyvalue + except Exception, e: + print e.args[0] + pass + return userkeys + + def parseKindleString(keystuff): + pids = [] + serials = [] + ar = keystuff.split(',') + for keystring in ar: + keystring = str(keystring).strip().replace(" ","") + if len(keystring) == 10 or len(keystring) == 8 and keystring not in pids: + pids.append(keystring) + elif len(keystring) == 16 and keystring[0] == 'B' and keystring not in serials: + serials.append(keystring) + return (pids,serials) + + def addConfigFiles(extension, prefskey, encoding = ''): + # get any files with extension 'extension' in the config dir + files = [f for f in os.listdir(config_dir) if f.endswith(extension)] + try: + priorkeycount = len(dedrmprefs[prefskey]) + for filename in files: + fpath = os.path.join(config_dir, filename) + key = os.path.splitext(filename)[0] + value = open(fpath, 'rb').read() + if encoding is not '': + value = value.encode(encoding) + if value not in dedrmprefs[prefskey].values(): + while key in dedrmprefs[prefskey]: + key = key+key[-1] + dedrmprefs[prefskey][key] = value + #os.remove(fpath) + return len(dedrmprefs[prefskey])-priorkeycount + except IOError: + return -1 + + if (not always) and dedrmprefs['configured']: + # We've already converted old preferences, + # and we're not being forced to do it again, so just return + return + + # initialise + # we must actually set the prefs that are dictionaries and lists + # to empty dictionaries and lists, otherwise we are unable to add to them + # as then it just adds to the (memory only) dedrmprefs.defaults versions! + if dedrmprefs['bandnkeys'] == {}: + dedrmprefs['bandnkeys'] = {} + if dedrmprefs['adeptkeys'] == {}: + dedrmprefs['adeptkeys'] = {} + if dedrmprefs['ereaderkeys'] == {}: + dedrmprefs['ereaderkeys'] = {} + if dedrmprefs['kindlekeys'] == {}: + dedrmprefs['kindlekeys'] = {} + if dedrmprefs['pids'] == []: + dedrmprefs['pids'] = [] + if dedrmprefs['serials'] == []: + dedrmprefs['serials'] = [] + + # get default adobe adept key(s) + priorkeycount = len(dedrmprefs['adeptkeys']) + try: + defaultkeys = adobe.adeptkeys() + except: + defaultkeys = [] + defaultcount = 1 + for keyvalue in defaultkeys: + keyname = u"default_key_{0:d}".format(defaultcount) + keyvaluehex = keyvalue.encode('hex') + if keyvaluehex not in dedrmprefs['adeptkeys'].values(): + while keyname in dedrmprefs['adeptkeys']: + defaultcount += 1 + keyname = u"default_key_{0:d}".format(defaultcount) + dedrmprefs['adeptkeys'][keyname] = keyvaluehex + addedkeycount = len(dedrmprefs['adeptkeys']) - priorkeycount + if addedkeycount > 0: + print u"{0} v{1}: {2:d} Default Adobe Adept {3} found.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + + # get default kindle key(s) + priorkeycount = len(dedrmprefs['kindlekeys']) + try: + defaultkeys = amazon.kindlekeys() + except: + defaultkeys = [] + defaultcount = 1 + for keyvalue in defaultkeys: + keyname = u"default_key_{0:d}".format(defaultcount) + if keyvalue not in dedrmprefs['kindlekeys'].values(): + while keyname in dedrmprefs['kindlekeys']: + defaultcount += 1 + keyname = u"default_key_{0:d}".format(defaultcount) + dedrmprefs['kindlekeys'][keyname] = keyvalue + addedkeycount = len(dedrmprefs['kindlekeys']) - priorkeycount + if addedkeycount > 0: + print u"{0} v{1}: {2:d} Default Kindle for Mac/PC {3} found.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + print u"{0} v{1}: Importing configuration data from old DeDRM plugins".format(PLUGIN_NAME, PLUGIN_VERSION) + + # Handle the old ignoble plugin's customization string by converting the + # old string to stored keys... get that personal data out of plain sight. + from calibre.customize.ui import config + sc = config['plugin_customization'] + val = sc.pop(IGNOBLEPLUGINNAME, None) + if val is not None: + print u"{0} v{1}: Converting old Ignoble plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION) + priorkeycount = len(dedrmprefs['bandnkeys']) + userkeys = parseIgnobleString(str(val)) + for key in userkeys: + value = userkeys[key] + if value not in dedrmprefs['bandnkeys'].values(): + while key in dedrmprefs['bandnkeys']: + key = key+key[-1] + dedrmprefs['bandnkeys'][key] = value + addedkeycount = len(dedrmprefs['bandnkeys'])-priorkeycount + print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from old Ignoble plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + # Handle the old eReader plugin's customization string by converting the + # old string to stored keys... get that personal data out of plain sight. + val = sc.pop(EREADERPLUGINNAME, None) + if val is not None: + print u"{0} v{1}: Converting old eReader plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION) + priorkeycount = len(dedrmprefs['ereaderkeys']) + userkeys = parseeReaderString(str(val)) + for key in userkeys: + value = userkeys[key] + if value not in dedrmprefs['ereaderkeys'].values(): + while key in dedrmprefs['ereaderkeys']: + key = key+key[-1] + dedrmprefs['ereaderkeys'][key] = value + addedkeycount = len(dedrmprefs['ereaderkeys'])-priorkeycount + print u"{0} v{1}: {2:d} eReader {3} imported from old eReader plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + # get old Kindle plugin configuration string + val = sc.pop(OLDKINDLEPLUGINNAME, None) + if val is not None: + print u"{0} v{1}: Converting old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION) + priorpidcount = len(dedrmprefs['pids']) + priorserialcount = len(dedrmprefs['serials']) + pids, serials = parseKindleString(val) + for pid in pids: + if pid not in dedrmprefs['pids']: + dedrmprefs['pids'].append(pid) + for serial in serials: + if serial not in dedrmprefs['serials']: + dedrmprefs['serials'].append(serial) + addedpidcount = len(dedrmprefs['pids']) - priorpidcount + addedserialcount = len(dedrmprefs['serials']) - priorserialcount + print u"{0} v{1}: {2:d} {3} and {4:d} {5} imported from old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs", addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers") + # Make the json write all the prefs to disk + writeprefs(False) + + # copy the customisations back into calibre preferences, as we've now removed the nasty plaintext + config['plugin_customization'] = sc + + # get any .b64 files in the config dir + ignoblecount = addConfigFiles('.b64', 'bandnkeys') + if ignoblecount > 0: + print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ignoblecount, u"key file" if ignoblecount==1 else u"key files") + elif ignoblecount < 0: + print u"{0} v{1}: Error reading Barnes & Noble keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION) + # Make the json write all the prefs to disk + writeprefs(False) + + # get any .der files in the config dir + ineptcount = addConfigFiles('.der', 'adeptkeys','hex') + if ineptcount > 0: + print u"{0} v{1}: {2:d} Adobe Adept {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ineptcount, u"keyfile" if ineptcount==1 else u"keyfiles") + elif ineptcount < 0: + print u"{0} v{1}: Error reading Adobe Adept keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION) + # Make the json write all the prefs to disk + writeprefs(False) + + # get ignoble json prefs + if 'keys' in ignobleprefs: + priorkeycount = len(dedrmprefs['bandnkeys']) + for key in ignobleprefs['keys']: + value = ignobleprefs['keys'][key] + if value not in dedrmprefs['bandnkeys'].values(): + while key in dedrmprefs['bandnkeys']: + key = key+key[-1] + dedrmprefs['bandnkeys'][key] = value + addedkeycount = len(dedrmprefs['bandnkeys']) - priorkeycount + # no need to delete old prefs, since they contain no recoverable private data + if addedkeycount > 0: + print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from Ignoble plugin preferences.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + # get kindle json prefs + priorpidcount = len(dedrmprefs['pids']) + priorserialcount = len(dedrmprefs['serials']) + if 'pids' in kindleprefs: + pids, serials = parseKindleString(kindleprefs['pids']) + for pid in pids: + if pid not in dedrmprefs['pids']: + dedrmprefs['pids'].append(pid) + if 'serials' in kindleprefs: + pids, serials = parseKindleString(kindleprefs['serials']) + for serial in serials: + if serial not in dedrmprefs['serials']: + dedrmprefs['serials'].append(serial) + addedpidcount = len(dedrmprefs['pids']) - priorpidcount + if addedpidcount > 0: + print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs") + addedserialcount = len(dedrmprefs['serials']) - priorserialcount + if addedserialcount > 0: + print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers") + + # Make the json write all the prefs to disk + writeprefs() + print u"{0} v{1}: Finished setting up configuration data.".format(PLUGIN_NAME, PLUGIN_VERSION) diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/convert2xml.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/convert2xml.py index c4e23b7..101c45a 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/convert2xml.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/convert2xml.py @@ -264,6 +264,7 @@ class PageParser(object): 'img.color_src' : (1, 'scalar_number', 0, 0), 'img.gridBeginCenter' : (1, 'scalar_number', 0, 0), 'img.gridEndCenter' : (1, 'scalar_number', 0, 0), + 'img.image_type' : (1, 'scalar_number', 0, 0), 'paragraph' : (1, 'snippets', 1, 0), 'paragraph.class' : (1, 'scalar_text', 0, 0), @@ -272,9 +273,9 @@ class PageParser(object): 'paragraph.lastWord' : (1, 'scalar_number', 0, 0), 'paragraph.gridSize' : (1, 'scalar_number', 0, 0), 'paragraph.gridBottomCenter' : (1, 'scalar_number', 0, 0), - 'paragraph.gridTopCenter' : (1, 'scalar_number', 0, 0), - 'paragraph.gridBeginCenter' : (1, 'scalar_number', 0, 0), - 'paragraph.gridEndCenter' : (1, 'scalar_number', 0, 0), + 'paragraph.gridTopCenter' : (1, 'scalar_number', 0, 0), + 'paragraph.gridBeginCenter' : (1, 'scalar_number', 0, 0), + 'paragraph.gridEndCenter' : (1, 'scalar_number', 0, 0), 'word_semantic' : (1, 'snippets', 1, 1), @@ -282,6 +283,10 @@ class PageParser(object): 'word_semantic.class' : (1, 'scalar_text', 0, 0), 'word_semantic.firstWord' : (1, 'scalar_number', 0, 0), 'word_semantic.lastWord' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridBottomCenter' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridTopCenter' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridBeginCenter' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridEndCenter' : (1, 'scalar_number', 0, 0), 'word' : (1, 'snippets', 1, 0), 'word.type' : (1, 'scalar_text', 0, 0), diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/dialogs.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/dialogs.py new file mode 100644 index 0000000..21c1dad --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/dialogs.py @@ -0,0 +1,719 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +from __future__ import with_statement +__license__ = 'GPL v3' + +# Standard Python modules. +import os, sys, re, hashlib +import json + +from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QListWidget, QListWidgetItem, QAbstractItemView, QLineEdit, QPushButton, QIcon, QGroupBox, QDialog, QDialogButtonBox, QUrl, QString) +from PyQt4 import QtGui + +# calibre modules and constants. +from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url, + choose_dir, choose_files) +from calibre.utils.config import dynamic, config_dir, JSONConfig + +from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION +from calibre_plugins.dedrm.utilities import (uStrCmp, DETAILED_MESSAGE, parseCustString) +from calibre_plugins.dedrm.ignoblekeygen import generate_key as generate_bandn_key +from calibre_plugins.dedrm.erdr2pml import getuser_key as generate_ereader_key +from calibre_plugins.dedrm.adobekey import adeptkeys as retrieve_adept_keys +from calibre_plugins.dedrm.kindlekey import kindlekeys as retrieve_kindle_keys + +class ManageKeysDialog(QDialog): + def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = u""): + QDialog.__init__(self,parent) + self.parent = parent + self.key_type_name = key_type_name + self.plugin_keys = plugin_keys + self.create_key = create_key + self.keyfile_ext = keyfile_ext + self.import_key = (keyfile_ext != u"") + self.binary_file = (key_type_name == u"Adobe Digital Editions Key") + self.json_file = (key_type_name == u"Kindle for Mac and PC Key") + + self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) + + # Start Qt Gui dialog layout + layout = QVBoxLayout(self) + self.setLayout(layout) + + help_layout = QHBoxLayout() + layout.addLayout(help_layout) + # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. + help_label = QLabel('Help', self) + help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) + help_label.setAlignment(Qt.AlignRight) + help_label.linkActivated.connect(self.help_link_activated) + help_layout.addWidget(help_label) + + keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self) + layout.addWidget(keys_group_box) + keys_group_box_layout = QHBoxLayout() + keys_group_box.setLayout(keys_group_box_layout) + + self.listy = QListWidget(self) + self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name)) + self.listy.setSelectionMode(QAbstractItemView.SingleSelection) + self.populate_list() + keys_group_box_layout.addWidget(self.listy) + + button_layout = QVBoxLayout() + keys_group_box_layout.addLayout(button_layout) + self._add_key_button = QtGui.QToolButton(self) + self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name)) + self._add_key_button.setIcon(QIcon(I('plus.png'))) + self._add_key_button.clicked.connect(self.add_key) + button_layout.addWidget(self._add_key_button) + + self._delete_key_button = QtGui.QToolButton(self) + self._delete_key_button.setToolTip(_(u"Delete highlighted key")) + self._delete_key_button.setIcon(QIcon(I('list_remove.png'))) + self._delete_key_button.clicked.connect(self.delete_key) + button_layout.addWidget(self._delete_key_button) + + if type(self.plugin_keys) == dict: + self._rename_key_button = QtGui.QToolButton(self) + self._rename_key_button.setToolTip(_(u"Rename highlighted key")) + self._rename_key_button.setIcon(QIcon(I('edit-select-all.png'))) + self._rename_key_button.clicked.connect(self.rename_key) + button_layout.addWidget(self._rename_key_button) + + self.export_key_button = QtGui.QToolButton(self) + self.export_key_button.setToolTip(u"Save highlighted key to a .{0} file".format(self.keyfile_ext)) + self.export_key_button.setIcon(QIcon(I('save.png'))) + self.export_key_button.clicked.connect(self.export_key) + button_layout.addWidget(self.export_key_button) + spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + button_layout.addItem(spacerItem) + + layout.addSpacing(5) + migrate_layout = QHBoxLayout() + layout.addLayout(migrate_layout) + if self.import_key: + migrate_layout.setAlignment(Qt.AlignJustify) + self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self) + self.migrate_btn.setToolTip(u"Import *.{0} files (created using other tools).".format(self.keyfile_ext)) + self.migrate_btn.clicked.connect(self.migrate_wrapper) + migrate_layout.addWidget(self.migrate_btn) + migrate_layout.addStretch() + self.button_box = QDialogButtonBox(QDialogButtonBox.Close) + self.button_box.rejected.connect(self.close) + migrate_layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + def populate_list(self): + if type(self.plugin_keys) == dict: + for key in self.plugin_keys.keys(): + self.listy.addItem(QListWidgetItem(key)) + else: + for key in self.plugin_keys: + self.listy.addItem(QListWidgetItem(key)) + + def add_key(self): + d = self.create_key(self) + d.exec_() + + if d.result() != d.Accepted: + # New key generation cancelled. + return + new_key_value = d.key_value + if type(self.plugin_keys) == dict: + if new_key_value in self.plugin_keys.values(): + old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0] + info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name), + u"The new {1} is the same as the existing {1} named {0} and has not been added.".format(old_key_name,self.key_type_name), show=True) + return + self.plugin_keys[d.key_name] = new_key_value + else: + if new_key_value in self.plugin_keys: + info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name), + u"This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True) + return + + self.plugin_keys.append(d.key_value) + self.listy.clear() + self.populate_list() + + def rename_key(self): + if not self.listy.currentItem(): + errmsg = u"No {0} selected to rename. Highlight a keyfile first.".format(self.key_type_name) + r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + return + + d = RenameKeyDialog(self) + d.exec_() + + if d.result() != d.Accepted: + # rename cancelled or moot. + return + keyname = unicode(self.listy.currentItem().text().toUtf8(),'utf8') + if not question_dialog(self, "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to rename the {2} named {0} to {1}?".format(keyname,d.key_name,self.key_type_name), show_copy_button=False, default_yes=False): + return + self.plugin_keys[d.key_name] = self.plugin_keys[keyname] + del self.plugin_keys[keyname] + + self.listy.clear() + self.populate_list() + + def delete_key(self): + if not self.listy.currentItem(): + return + keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8') + if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to delete the {1} {0}?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False): + return + if type(self.plugin_keys) == dict: + del self.plugin_keys[keyname] + else: + self.plugin_keys.remove(keyname) + + self.listy.clear() + self.populate_list() + + def help_link_activated(self, url): + def get_help_file_resource(): + # Copy the HTML helpfile to the plugin directory each time the + # link is clicked in case the helpfile is updated in newer plugins. + help_file_name = u"{0}_{1}_Help.htm".format(PLUGIN_NAME, self.key_type_name) + file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name) + with open(file_path,'w') as f: + f.write(self.parent.load_resource(help_file_name)) + return file_path + url = 'file:///' + get_help_file_resource() + open_url(QUrl(url)) + + def migrate_files(self): + dynamic[PLUGIN_NAME + u"config_dir"] = config_dir + files = choose_files(self, PLUGIN_NAME + u"config_dir", + u"Select {0} files to import".format(self.key_type_name), [(u"{0} files".format(self.key_type_name), [self.keyfile_ext])], False) + counter = 0 + skipped = 0 + if files: + for filename in files: + fpath = os.path.join(config_dir, filename) + filename = os.path.basename(filename) + new_key_name = os.path.splitext(os.path.basename(filename))[0] + with open(fpath,'rb') as keyfile: + new_key_value = keyfile.read() + if self.binary_file: + new_key_value = new_key_value.encode('hex') + elif self.json_file: + new_key_value = json.loads(new_key_value) + match = False + for key in self.plugin_keys.keys(): + if uStrCmp(new_key_name, key, True): + skipped += 1 + msg = u"A key with the name {0} already exists!\nSkipping key file {1}.\nRename the existing key and import again".format(new_key_name,filename) + inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(msg), show_copy_button=False, show=True) + match = True + break + if not match: + if new_key_value in self.plugin_keys.values(): + old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0] + skipped += 1 + info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + u"The key in file {0} is the same as the existing key {1} and has been skipped.".format(filename,old_key_name), show_copy_button=False, show=True) + else: + counter += 1 + self.plugin_keys[new_key_name] = new_key_value + + msg = u"" + if counter+skipped > 1: + if counter > 0: + msg += u"Imported {0:d} key {1}. ".format(counter, u"file" if counter == 1 else u"files") + if skipped > 0: + msg += u"Skipped {0:d} key {1}.".format(skipped, u"file" if counter == 1 else u"files") + inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(msg), show_copy_button=False, show=True) + return counter > 0 + + def migrate_wrapper(self): + if self.migrate_files(): + self.listy.clear() + self.populate_list() + + def export_key(self): + if not self.listy.currentItem(): + errmsg = u"No keyfile selected to export. Highlight a keyfile first." + r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + return + filter = QString(u"{0} Files (*.{1})".format(self.key_type_name, self.keyfile_ext)) + keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8') + if dynamic.get(PLUGIN_NAME + 'save_dir'): + defaultname = os.path.join(dynamic.get(PLUGIN_NAME + 'save_dir'), u"{0}.{1}".format(keyname , self.keyfile_ext)) + else: + defaultname = os.path.join(os.path.expanduser('~'), u"{0}.{1}".format(keyname , self.keyfile_ext)) + filename = unicode(QtGui.QFileDialog.getSaveFileName(self, u"Save {0} File as...".format(self.key_type_name), defaultname, + u"{0} Files (*.{1})".format(self.key_type_name,self.keyfile_ext), filter)) + if filename: + dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0] + with file(filename, 'w') as fname: + if self.binary_file: + fname.write(self.plugin_keys[keyname].decode('hex')) + elif self.json_file: + fname.write(json.dumps(self.plugin_keys[keyname])) + else: + fname.write(self.plugin_keys[keyname]) + + + + +class RenameKeyDialog(QDialog): + def __init__(self, parent=None,): + print repr(self), repr(parent) + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle("{0} {1}: Rename {0}".format(PLUGIN_NAME, PLUGIN_VERSION, parent.key_type_name)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox('', self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + data_group_box_layout.addWidget(QLabel('New Key Name:', self)) + self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self) + self.key_ledit.setToolTip(u"Enter a new name for this existing {0}.".format(parent.key_type_name)) + data_group_box_layout.addWidget(self.key_ledit) + + layout.addSpacing(20) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + def accept(self): + if self.key_ledit.text().isEmpty() or unicode(self.key_ledit.text()).isspace(): + errmsg = u"Key name field cannot be empty!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + if len(self.key_ledit.text()) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + if uStrCmp(self.key_ledit.text(), self.parent.listy.currentItem().text()): + # Same exact name ... do nothing. + return QDialog.reject(self) + for k in self.parent.plugin_keys.keys(): + if (uStrCmp(self.key_ledit.text(), k, True) and + not uStrCmp(k, self.parent.listy.currentItem().text(), True)): + errmsg = u"The key name {0} is already being used.".format(self.key_ledit.text()) + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + QDialog.accept(self) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + + + + + + + +class AddBandNKeyDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Create New Barnes & Noble Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(_(u"

Enter an identifying name for this new key.

" + + u"

It should be something that will help you remember " + + u"what personal information was used to create it.")) + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + name_group = QHBoxLayout() + data_group_box_layout.addLayout(name_group) + name_group.addWidget(QLabel(u"Your Name:", self)) + self.name_ledit = QLineEdit(u"", self) + self.name_ledit.setToolTip(_(u"

Enter your name as it appears in your B&N " + + u"account or on your credit card.

" + + u"

It will only be used to generate this " + + u"one-time key and won\'t be stored anywhere " + + u"in calibre or on your computer.

" + + u"

(ex: Jonathan Smith)")) + name_group.addWidget(self.name_ledit) + name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self) + name_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(name_disclaimer_label) + + ccn_group = QHBoxLayout() + data_group_box_layout.addLayout(ccn_group) + ccn_group.addWidget(QLabel(u"Credit Card#:", self)) + self.cc_ledit = QLineEdit(u"", self) + self.cc_ledit.setToolTip(_(u"

Enter the full credit card number on record " + + u"in your B&N account.

" + + u"

No spaces or dashes... just the numbers. " + + u"This number will only be used to generate this " + + u"one-time key and won\'t be stored anywhere in " + + u"calibre or on your computer.")) + ccn_group.addWidget(self.cc_ledit) + ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self) + ccn_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(ccn_disclaimer_label) + layout.addSpacing(10) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return generate_bandn_key(self.user_name,self.cc_number) + + @property + def user_name(self): + return unicode(self.name_ledit.text().toUtf8(), 'utf8').strip().lower().replace(' ','') + + @property + def cc_number(self): + return unicode(self.cc_ledit.text().toUtf8(), 'utf8').strip().replace(' ', '').replace('-','') + + + def accept(self): + if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if not self.cc_number.isdigit(): + errmsg = u"Numbers only in the credit card number field!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + +class AddEReaderDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Create New eReader Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"

Enter an identifying name for this new key.\nIt should be something that will help you remember what personal information was used to create it.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + name_group = QHBoxLayout() + data_group_box_layout.addLayout(name_group) + name_group.addWidget(QLabel(u"Your Name:", self)) + self.name_ledit = QLineEdit(u"", self) + self.name_ledit.setToolTip(u"Enter the name for this eReader key, usually the name on your credit card.\nIt will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.\n(ex: Mr Jonathan Q Smith)") + name_group.addWidget(self.name_ledit) + name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self) + name_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(name_disclaimer_label) + + ccn_group = QHBoxLayout() + data_group_box_layout.addLayout(ccn_group) + ccn_group.addWidget(QLabel(u"Credit Card#:", self)) + self.cc_ledit = QLineEdit(u"", self) + self.cc_ledit.setToolTip(u"

Enter the last 8 digits of credit card number for this eReader key.\nThey will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.") + ccn_group.addWidget(self.cc_ledit) + ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self) + ccn_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(ccn_disclaimer_label) + layout.addSpacing(10) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return generate_ereader_key(self.user_name,self.cc_number).encode('hex') + + @property + def user_name(self): + return unicode(self.name_ledit.text().toUtf8(), 'utf8').strip().lower().replace(' ','') + + @property + def cc_number(self): + return unicode(self.cc_ledit.text().toUtf8(), 'utf8').strip().replace(' ', '').replace('-','') + + + def accept(self): + if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if not self.cc_number.isdigit(): + errmsg = u"Numbers only in the credit card number field!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddAdeptDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Getting Default Adobe Digital Editions Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + try: + self.default_key = retrieve_adept_keys()[0] + except: + self.default_key = u"" + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + + if len(self.default_key)>0: + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"

Enter an identifying name for the current default Adobe Digital Editions key.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + self.button_box.accepted.connect(self.accept) + else: + default_key_error = QLabel(u"The default encryption key for Adobe Digital Editions could not be found.", self) + default_key_error.setAlignment(Qt.AlignHCenter) + layout.addWidget(default_key_error) + # if no default, bot buttons do the same + self.button_box.accepted.connect(self.reject) + + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return self.default_key.encode('hex') + + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddKindleDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Getting Default Kindle for Mac/PC Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + try: + self.default_key = retrieve_kindle_keys()[0] + except: + self.default_key = u"" + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + + if len(self.default_key)>0: + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"

Enter an identifying name for the current default Kindle for Mac/PC key.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + self.button_box.accepted.connect(self.accept) + else: + default_key_error = QLabel(u"The default encryption key for Kindle for Mac/PC could not be found.", self) + default_key_error.setAlignment(Qt.AlignHCenter) + layout.addWidget(default_key_error) + # if no default, bot buttons do the same + self.button_box.accepted.connect(self.reject) + + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return self.default_key + + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddSerialDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"EInk Kindle Serial Number:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"Enter an eInk Kindle serial number. EInk Kindle serial numbers are 16 characters long and usually start with a 'B' or a '9'. Kindle Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"Please enter an eInk Kindle Serial Number or click Cancel in the dialog." + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) != 16: + errmsg = u"EInk Kindle Serial Numbers must be 16 characters long. This is {0:d} characters long.".format(len(self.key_name)) + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddPIDDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"PID:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"Please enter a Mobipocket PID or click Cancel in the dialog." + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) != 8 and len(self.key_name) != 10: + errmsg = u"Mobipocket PIDs must be 8 or 10 characters long. This is {0:d} characters long.".format(len(self.key_name)) + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/epubtest.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/epubtest.py index a44308e..d91624f 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/epubtest.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/epubtest.py @@ -7,8 +7,8 @@ # 1.00 - Initial version, with code from various other scripts # 1.01 - Moved authorship announcement to usage section. # -# Changelog drmcheck -# 1.00 - Cut to drmtest.py, testing ePub files only by Apprentice Alf +# Changelog epubtest +# 1.00 - Cut to epubtest.py, testing ePub files only by Apprentice Alf # # Written in 2011 by Paul Durrant # Released with unlicense. See http://unlicense.org/ diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/erdr2pml.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/erdr2pml.py index 239c5ac..d982a44 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/erdr2pml.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/erdr2pml.py @@ -70,7 +70,7 @@ __version__='0.22' import sys, re -import struct, binascii, getopt, zlib, os, os.path, urllib, tempfile +import struct, binascii, getopt, zlib, os, os.path, urllib, tempfile, traceback if 'calibre' in sys.modules: inCalibre = True @@ -139,28 +139,28 @@ Des = None if iswindows: # first try with pycrypto if inCalibre: - from calibre_plugins.erdrpdb2pml import pycrypto_des + from calibre_plugins.dedrm import pycrypto_des else: import pycrypto_des Des = pycrypto_des.load_pycrypto() if Des == None: # they try with openssl if inCalibre: - from calibre_plugins.erdrpdb2pml import openssl_des + from calibre_plugins.dedrm import openssl_des else: import openssl_des Des = openssl_des.load_libcrypto() else: # first try with openssl if inCalibre: - from calibre_plugins.erdrpdb2pml import openssl_des + from calibre_plugins.dedrm import openssl_des else: import openssl_des Des = openssl_des.load_libcrypto() if Des == None: # then try with pycrypto if inCalibre: - from calibre_plugins.erdrpdb2pml import pycrypto_des + from calibre_plugins.dedrm import pycrypto_des else: import pycrypto_des Des = pycrypto_des.load_pycrypto() @@ -169,7 +169,7 @@ else: # of DES and try to speed it up with Psycho if Des == None: if inCalibre: - from calibre_plugins.erdrpdb2pml import python_des + from calibre_plugins.dedrm import python_des else: import python_des Des = python_des.Des @@ -522,7 +522,8 @@ def decryptBook(infile, outpath, make_pmlz, user_key): print u"Output is in {0}".format(outdir) print "done" except ValueError, e: - print u"Error: {0}".format(e.args[0]) + print u"Error: {0}".format(e) + traceback.print_exc() return 1 return 0 diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/genbook.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/genbook.py index 746178f..3ed925d 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/genbook.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/genbook.py @@ -29,10 +29,10 @@ else: inCalibre = False if inCalibre : - from calibre_plugins.k4mobidedrm import convert2xml - from calibre_plugins.k4mobidedrm import flatxml2html - from calibre_plugins.k4mobidedrm import flatxml2svg - from calibre_plugins.k4mobidedrm import stylexml2css + from calibre_plugins.dedrm import convert2xml + from calibre_plugins.dedrm import flatxml2html + from calibre_plugins.dedrm import flatxml2svg + from calibre_plugins.dedrm import stylexml2css else : import convert2xml import flatxml2html diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ignobleepub.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ignobleepub.py index b7cbdc5..4cf74ae 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ignobleepub.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ignobleepub.py @@ -3,13 +3,13 @@ from __future__ import with_statement -# ignobleepub.pyw, version 3.7 +# ignobleepub.pyw, version 3.8 # Copyright © 2009-2010 by i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Modified 2010–2012 by some_updates, DiapDealer and Apprentice Alf +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf # Windows users: Before running this program, you must first install Python 2.6 # from and PyCrypto from @@ -32,20 +32,21 @@ from __future__ import with_statement # 3.5 - Fix for potential problem with PyCrypto # 3.6 - Revised to allow use in calibre plugins to eliminate need for duplicate code # 3.7 - Tweaked to match ineptepub more closely +# 3.8 - Fixed to retain zip file metadata (e.g. file modification date) """ Decrypt Barnes & Noble encrypted ePub books. """ __license__ = 'GPL v3' -__version__ = "3.7" +__version__ = "3.8" import sys import os import traceback import zlib import zipfile -from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED +from zipfile import ZipInfo, ZipFile, ZIP_STORED, ZIP_DEFLATED from contextlib import closing import xml.etree.ElementTree as etree @@ -200,13 +201,6 @@ META_NAMES = ('mimetype', 'META-INF/rights.xml', 'META-INF/encryption.xml') NSMAP = {'adept': 'http://ns.adobe.com/adept', 'enc': 'http://www.w3.org/2001/04/xmlenc#'} -class ZipInfo(zipfile.ZipInfo): - def __init__(self, *args, **kwargs): - if 'compress_type' in kwargs: - compress_type = kwargs.pop('compress_type') - super(ZipInfo, self).__init__(*args, **kwargs) - self.compress_type = compress_type - class Decryptor(object): def __init__(self, bookkey, encryption): enc = lambda tag: '{%s}%s' % (NSMAP['enc'], tag) @@ -282,11 +276,40 @@ def decryptBook(keyb64, inpath, outpath): decryptor = Decryptor(bookkey[-16:], encryption) kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: - zi = ZipInfo('mimetype', compress_type=ZIP_STORED) + zi = ZipInfo('mimetype') + zi.compress_type=ZIP_STORED + try: + # if the mimetype is present, get its info, including time-stamp + oldzi = inf.getinfo('mimetype') + # copy across fields to be preserved + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass outf.writestr(zi, inf.read('mimetype')) for path in namelist: data = inf.read(path) - outf.writestr(path, decryptor.decrypt(path, data)) + zi = ZipInfo(path) + zi.compress_type=ZIP_DEFLATED + try: + # get the file info, including time-stamp + oldzi = inf.getinfo(path) + # copy across useful fields + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass + outf.writestr(zi, decryptor.decrypt(path, data)) except: print u"Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc()) return 2 diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ignoblekeygen.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ignoblekeygen.py index f25359c..ec78e65 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ignoblekeygen.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ignoblekeygen.py @@ -4,21 +4,23 @@ from __future__ import with_statement # ignoblekeygen.pyw, version 2.5 -# Copyright © 2009-2010 by i♥cabbages +# Copyright © 2009-2010 i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Modified 2010–2012 by some_updates, DiapDealer and Apprentice Alf +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf -# Windows users: Before running this program, you must first install Python 2.6 -# from and PyCrypto from -# (make sure to -# install the version for Python 2.6). Save this script file as -# ignoblekeygen.pyw and double-click on it to run it. +# Windows users: Before running this program, you must first install Python. +# We recommend ActiveState Python 2.7.X for Windows (x86) from +# http://www.activestate.com/activepython/downloads. +# You must also install PyCrypto from +# http://www.voidspace.org.uk/python/modules.shtml#pycrypto +# (make certain to install the version for Python 2.7). +# Then save this script file as ignoblekeygen.pyw and double-click on it to run it. # # Mac OS X users: Save this script file as ignoblekeygen.pyw. You can run this -# program from the command line (pythonw ignoblekeygen.pyw) or by double-clicking +# program from the command line (python ignoblekeygen.pyw) or by double-clicking # it when it has been associated with PythonLauncher. # Revision history: @@ -58,8 +60,11 @@ class SafeUnbuffered: def __getattr__(self, attr): return getattr(self.stream, attr) -iswindows = sys.platform.startswith('win') -isosx = sys.platform.startswith('darwin') +try: + from calibre.constants import iswindows, isosx +except: + iswindows = sys.platform.startswith('win') + isosx = sys.platform.startswith('darwin') def unicode_argv(): if iswindows: @@ -68,8 +73,8 @@ def unicode_argv(): # 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 '?'. - + # characters with '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 from ctypes import POINTER, byref, cdll, c_int, windll from ctypes.wintypes import LPCWSTR, LPWSTR diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ineptepub.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ineptepub.py index 48b7727..98a134e 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ineptepub.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/ineptepub.py @@ -3,13 +3,13 @@ from __future__ import with_statement -# ineptepub.pyw, version 5.8 +# ineptepub.pyw, version 5.9 # Copyright © 2009-2010 by i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Modified 2010–2012 by some_updates, DiapDealer and Apprentice Alf +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf # Windows users: Before running this program, you must first install Python 2.6 # from and PyCrypto from @@ -34,20 +34,21 @@ from __future__ import with_statement # 5.6 - Modify interface to allow use with import # 5.7 - Fix for potential problem with PyCrypto # 5.8 - Revised to allow use in calibre plugins to eliminate need for duplicate code +# 5.9 - Fixed to retain zip file metadata (e.g. file modification date) """ Decrypt Adobe Digital Editions encrypted ePub books. """ __license__ = 'GPL v3' -__version__ = "5.8" +__version__ = "5.9" import sys import os import traceback import zlib import zipfile -from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED +from zipfile import ZipInfo, ZipFile, ZIP_STORED, ZIP_DEFLATED from contextlib import closing import xml.etree.ElementTree as etree @@ -340,13 +341,6 @@ META_NAMES = ('mimetype', 'META-INF/rights.xml', 'META-INF/encryption.xml') NSMAP = {'adept': 'http://ns.adobe.com/adept', 'enc': 'http://www.w3.org/2001/04/xmlenc#'} -class ZipInfo(zipfile.ZipInfo): - def __init__(self, *args, **kwargs): - if 'compress_type' in kwargs: - compress_type = kwargs.pop('compress_type') - super(ZipInfo, self).__init__(*args, **kwargs) - self.compress_type = compress_type - class Decryptor(object): def __init__(self, bookkey, encryption): enc = lambda tag: '{%s}%s' % (NSMAP['enc'], tag) @@ -424,11 +418,40 @@ def decryptBook(userkey, inpath, outpath): decryptor = Decryptor(bookkey[-16:], encryption) kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: - zi = ZipInfo('mimetype', compress_type=ZIP_STORED) + zi = ZipInfo('mimetype') + zi.compress_type=ZIP_STORED + try: + # if the mimetype is present, get its info, including time-stamp + oldzi = inf.getinfo('mimetype') + # copy across fields to be preserved + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass outf.writestr(zi, inf.read('mimetype')) for path in namelist: data = inf.read(path) - outf.writestr(path, decryptor.decrypt(path, data)) + zi = ZipInfo(path) + zi.compress_type=ZIP_DEFLATED + try: + # get the file info, including time-stamp + oldzi = inf.getinfo(path) + # copy across useful fields + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass + outf.writestr(zi, decryptor.decrypt(path, data)) except: print u"Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc()) return 2 diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/k4mobidedrm.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/k4mobidedrm.py index 70ed898..1ae5c88 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/k4mobidedrm.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/k4mobidedrm.py @@ -51,8 +51,10 @@ from __future__ import with_statement # 4.8 - Much better unicode handling, matching the updated inept and ignoble scripts # - Moved back into plugin, __init__ in plugin now only contains plugin code. # 4.9 - Missed some invalid characters in cleanup_name +# 5.0 - Extraction of info from Kindle for PC/Mac moved into kindlekey.py +# - tweaked GetDecryptedBook interface to leave passed parameters unchanged -__version__ = '4.9' +__version__ = '5.0' import sys, os, re @@ -62,6 +64,7 @@ import re import traceback import time import htmlentitydefs +import json class DrmException(Exception): pass @@ -72,9 +75,9 @@ else: inCalibre = False if inCalibre: - from calibre_plugins.k4mobidedrm import mobidedrm - from calibre_plugins.k4mobidedrm import topazextract - from calibre_plugins.k4mobidedrm import kgenpids + from calibre_plugins.dedrm import mobidedrm + from calibre_plugins.dedrm import topazextract + from calibre_plugins.dedrm import kgenpids else: import mobidedrm import topazextract @@ -180,13 +183,13 @@ def unescape(text): return text # leave as is return re.sub(u"&#?\w+;", fixup, text) -def GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime = time.time()): +def GetDecryptedBook(infile, kDatabases, serials, pids, starttime = time.time()): # handle the obvious cases at the beginning if not os.path.isfile(infile): raise DRMException (u"Input file does not exist.") mobi = True - magic3 = file(infile,'rb').read(3) + magic3 = open(infile,'rb').read(3) if magic3 == 'TPZ': mobi = False @@ -198,13 +201,15 @@ def GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime = time.time()) bookname = unescape(mb.getBookTitle()) print u"Decrypting {1} ebook: {0}".format(bookname, mb.getBookType()) + # copy list of pids + totalpids = list(pids) # extend PID list with book-specific PIDs md1, md2 = mb.getPIDMetaInfo() - pids.extend(kgenpids.getPidList(md1, md2, serials, kInfoFiles)) - print u"Found {1:d} keys to try after {0:.1f} seconds".format(time.time()-starttime, len(pids)) + totalpids.extend(kgenpids.getPidList(md1, md2, serials, kDatabases)) + print u"Found {1:d} keys to try after {0:.1f} seconds".format(time.time()-starttime, len(totalpids)) try: - mb.processBook(pids) + mb.processBook(totalpids) except: mb.cleanup raise @@ -213,12 +218,24 @@ def GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime = time.time()) return mb -# infile, outdir and kInfoFiles should be unicode strings -def decryptBook(infile, outdir, kInfoFiles, serials, pids): +# kDatabaseFiles is a list of files created by kindlekey +def decryptBook(infile, outdir, kDatabaseFiles, serials, pids): starttime = time.time() - print "Starting decryptBook routine." + kDatabases = [] + for dbfile in kDatabaseFiles: + kindleDatabase = {} + try: + with open(dbfile, 'r') as keyfilein: + kindleDatabase = json.loads(keyfilein.read()) + kDatabases.append([dbfile,kindleDatabase]) + except Exception, e: + print u"Error getting database from file {0:s}: {1:s}".format(dbfile,e) + traceback.print_exc() + + + try: - book = GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime) + book = GetDecryptedBook(infile, kDatabases, serials, pids, starttime) except Exception, e: print u"Error decrypting book after {1:.1f} seconds: {0}".format(e.args[0],time.time()-starttime) traceback.print_exc() @@ -254,14 +271,14 @@ def decryptBook(infile, outdir, kInfoFiles, serials, pids): def usage(progname): print u"Removes DRM protection from Mobipocket, Amazon KF8, Amazon Print Replica and Amazon Topaz ebooks" print u"Usage:" - print u" {0} [-k ] [-p ] [-s ] ".format(progname) + print u" {0} [-k ] [-p ] [-s ] ".format(progname) # # Main # def cli_main(argv=unicode_argv()): progname = os.path.basename(argv[0]) - print u"K4MobiDeDrm v{0}.\nCopyright © 2008-2012 The Dark Reverser et al.".format(__version__) + print u"K4MobiDeDrm v{0}.\nCopyright © 2008-2013 The Dark Reverser et al.".format(__version__) try: opts, args = getopt.getopt(sys.argv[1:], "k:p:s:") @@ -275,7 +292,7 @@ def cli_main(argv=unicode_argv()): infile = args[0] outdir = args[1] - kInfoFiles = [] + kDatabaseFiles = [] serials = [] pids = [] @@ -283,7 +300,7 @@ def cli_main(argv=unicode_argv()): if o == "-k": if a == None : raise DrmException("Invalid parameter for -k") - kInfoFiles.append(a) + kDatabaseFiles.append(a) if o == "-p": if a == None : raise DrmException("Invalid parameter for -p") @@ -296,7 +313,7 @@ def cli_main(argv=unicode_argv()): # try with built in Kindle Info files if not on Linux k4 = not sys.platform.startswith('linux') - return decryptBook(infile, outdir, kInfoFiles, serials, pids) + return decryptBook(infile, outdir, kDatabaseFiles, serials, pids) if __name__ == '__main__': 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 c5de9b9..dd88797 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kgenpids.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kgenpids.py @@ -8,6 +8,7 @@ import binascii import zlib import re from struct import pack, unpack, unpack_from +import traceback class DrmException(Exception): pass @@ -16,22 +17,6 @@ global charMap1 global charMap3 global charMap4 -if 'calibre' in sys.modules: - inCalibre = True - from calibre.constants import iswindows, isosx - if iswindows: - from calibre_plugins.k4mobidedrm.k4pcutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString - if isosx: - from calibre_plugins.k4mobidedrm.k4mutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString -else: - inCalibre = False - iswindows = sys.platform.startswith('win') - isosx = sys.platform.startswith('darwin') - if iswindows: - from k4pcutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString - if isosx: - from k4mutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString - charMap1 = 'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' charMap3 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' @@ -178,6 +163,9 @@ def pidFromSerial(s, l): def getKindlePids(rec209, token, serialnum): pids=[] + if isinstance(serialnum,unicode): + serialnum = serialnum.encode('ascii') + # Compute book PID pidHash = SHA1(serialnum+rec209+token) bookPID = encodePID(pidHash) @@ -196,35 +184,32 @@ def getKindlePids(rec209, token, serialnum): keynames = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber'] -def getK4Pids(rec209, token, kInfoFile): +def getK4Pids(rec209, token, kindleDatabase): global charMap1 - kindleDatabase = None pids = [] - try: - kindleDatabase = getDBfromFile(kInfoFile) - except Exception, message: - print(message) - kindleDatabase = None - pass - - if kindleDatabase == None : - return pids try: # Get the Mazama Random number - MazamaRandomNumber = kindleDatabase['MazamaRandomNumber'] + MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex').encode('ascii') # Get the kindle account token - kindleAccountToken = kindleDatabase['kindle.account.tokens'] + kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex').encode('ascii') + + # Get the IDString used to decode the Kindle Info file + IDString = (kindleDatabase[1])['IDString'].decode('hex').encode('ascii') + + # Get the UserName stored when the Kindle Info file was decoded + UserName = (kindleDatabase[1])['UserName'].decode('hex').encode('ascii') + except KeyError: - print u"Keys not found in {0}".format(os.path.basename(kInfoFile)) + print u"Keys not found in the database {0}.".format(kindleDatabase[0]) return pids # Get the ID string used - encodedIDString = encodeHash(GetIDString(),charMap1) + encodedIDString = encodeHash(IDString,charMap1) # Get the current user name - encodedUsername = encodeHash(GetUserName(),charMap1) + encodedUsername = encodeHash(UserName,charMap1) # concat, hash and encode to calculate the DSN DSN = encode(SHA1(MazamaRandomNumber+encodedIDString+encodedUsername),charMap1) @@ -257,22 +242,26 @@ def getK4Pids(rec209, token, kInfoFile): return pids -def getPidList(md1, md2, serials=[], kInfoFiles=[]): +def getPidList(md1, md2, serials=[], kDatabases=[]): pidlst = [] - if kInfoFiles is None: - kInfoFiles = [] + + if kDatabases is None: + kDatabases = [] if serials is None: serials = [] - if iswindows or isosx: - kInfoFiles.extend(getKindleInfoFiles()) - for infoFile in kInfoFiles: + + for kDatabase in kDatabases: try: - pidlst.extend(getK4Pids(md1, md2, infoFile)) + pidlst.extend(getK4Pids(md1, md2, kDatabase)) except Exception, e: - print u"Error getting PIDs from {0}: {1}".format(os.path.basename(infoFile),e.args[0]) + print u"Error getting PIDs from database {0}: {1}".format(kDatabase[0],e.args[0]) + traceback.print_exc() + for serialnum in serials: try: pidlst.extend(getKindlePids(md1, md2, serialnum)) - except Exception, message: + except Exception, e: print u"Error getting PIDs from serial number {0}: {1}".format(serialnum ,e.args[0]) + traceback.print_exc() + return pidlst diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py new file mode 100644 index 0000000..e79622b --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/kindlekey.py @@ -0,0 +1,1893 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +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 + +# Revision history: +# 1.0 - Kindle info file decryption, extracted from k4mobidedrm, etc. +# 1.1 - Added Tkinter to match adobekey.py +# 1.2 - Fixed testing of successful retrieval on Mac +# 1.3 - Added getkey interface for Windows DeDRM application +# Simplified some of the Kindle for Mac code. +# 1.4 - Remove dependency on alfcrypto + +""" +Retrieve Kindle for PC/Mac user key. +""" + +__license__ = 'GPL v3' +__version__ = '1.4' + +import sys, os, re +from struct import pack, unpack, unpack_from +import json +import getopt + +# Routines common to Mac and PC + +# 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) + +try: + from calibre.constants import iswindows, isosx +except: + 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 '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 + + 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"kindlekey.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] + +class DrmException(Exception): + pass + +# crypto digestroutines +import hashlib + +def MD5(message): + ctx = hashlib.md5() + ctx.update(message) + return ctx.digest() + +def SHA1(message): + ctx = hashlib.sha1() + ctx.update(message) + return ctx.digest() + +def SHA256(message): + ctx = hashlib.sha256() + ctx.update(message) + return ctx.digest() + +# For K4M/PC 1.6.X and later +# generate table of prime number less than or equal to int n +def primes(n): + if n==2: return [2] + elif n<2: return [] + s=range(3,n+1,2) + mroot = n ** 0.5 + half=(n+1)/2-1 + i=0 + m=3 + while m <= mroot: + if s[i]: + j=(m*m-3)/2 + s[j]=0 + while j 0: # save any bytes that are not block aligned + self.bytesToEncrypt = self.bytesToEncrypt[-numExtraBytes:] + else: + self.bytesToEncrypt = '' + + if more == None: # no more data expected from caller + finalBytes = self.padding.addPad(self.bytesToEncrypt,self.blockSize) + if len(finalBytes) > 0: + ctBlock = self.encryptBlock(finalBytes) + self.encryptBlockCount += 1 + cipherText += ctBlock + self.resetEncrypt() + return cipherText + + def decrypt(self, cipherText, more = None): + """ Decrypt a string and return a string """ + self.bytesToDecrypt += cipherText # append to any bytes from prior decrypt + + numBlocks, numExtraBytes = divmod(len(self.bytesToDecrypt), self.blockSize) + if more == None: # no more calls to decrypt, should have all the data + if numExtraBytes != 0: + raise DecryptNotBlockAlignedError, 'Data not block aligned on decrypt' + + # hold back some bytes in case last decrypt has zero len + if (more != None) and (numExtraBytes == 0) and (numBlocks >0) : + numBlocks -= 1 + numExtraBytes = self.blockSize + + plainText = '' + for i in range(numBlocks): + bStart = i*self.blockSize + ptBlock = self.decryptBlock(self.bytesToDecrypt[bStart : bStart+self.blockSize]) + self.decryptBlockCount += 1 + plainText += ptBlock + + if numExtraBytes > 0: # save any bytes that are not block aligned + self.bytesToEncrypt = self.bytesToEncrypt[-numExtraBytes:] + else: + self.bytesToEncrypt = '' + + if more == None: # last decrypt remove padding + plainText = self.padding.removePad(plainText, self.blockSize) + self.resetDecrypt() + return plainText + + + class Pad: + def __init__(self): + pass # eventually could put in calculation of min and max size extension + + class padWithPadLen(Pad): + """ Pad a binary string with the length of the padding """ + + def addPad(self, extraBytes, blockSize): + """ Add padding to a binary string to make it an even multiple + of the block size """ + blocks, numExtraBytes = divmod(len(extraBytes), blockSize) + padLength = blockSize - numExtraBytes + return extraBytes + padLength*chr(padLength) + + def removePad(self, paddedBinaryString, blockSize): + """ Remove padding from a binary string """ + if not(0 6 and i%Nk == 4 : + temp = [ Sbox[byte] for byte in temp ] # SubWord(temp) + w.append( [ w[i-Nk][byte]^temp[byte] for byte in range(4) ] ) + return w + + Rcon = (0,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36, # note extra '0' !!! + 0x6c,0xd8,0xab,0x4d,0x9a,0x2f,0x5e,0xbc,0x63,0xc6, + 0x97,0x35,0x6a,0xd4,0xb3,0x7d,0xfa,0xef,0xc5,0x91) + + #------------------------------------- + def AddRoundKey(algInstance, keyBlock): + """ XOR the algorithm state with a block of key material """ + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] ^= keyBlock[column][row] + #------------------------------------- + + def SubBytes(algInstance): + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] = Sbox[algInstance.state[column][row]] + + def InvSubBytes(algInstance): + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] = InvSbox[algInstance.state[column][row]] + + Sbox = (0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5, + 0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0, + 0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc, + 0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a, + 0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0, + 0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b, + 0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85, + 0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5, + 0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17, + 0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88, + 0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c, + 0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9, + 0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6, + 0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e, + 0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94, + 0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68, + 0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16) + + InvSbox = (0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38, + 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, + 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87, + 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, + 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d, + 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, + 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2, + 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, + 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16, + 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, + 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda, + 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, + 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a, + 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, + 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02, + 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, + 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea, + 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, + 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85, + 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, + 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89, + 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, + 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20, + 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, + 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31, + 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, + 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d, + 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, + 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0, + 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, + 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26, + 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d) + + #------------------------------------- + """ For each block size (Nb), the ShiftRow operation shifts row i + by the amount Ci. Note that row 0 is not shifted. + Nb C1 C2 C3 + ------------------- """ + shiftOffset = { 4 : ( 0, 1, 2, 3), + 5 : ( 0, 1, 2, 3), + 6 : ( 0, 1, 2, 3), + 7 : ( 0, 1, 2, 4), + 8 : ( 0, 1, 3, 4) } + def ShiftRows(algInstance): + tmp = [0]*algInstance.Nb # list of size Nb + for r in range(1,4): # row 0 reamains unchanged and can be skipped + for c in range(algInstance.Nb): + tmp[c] = algInstance.state[(c+shiftOffset[algInstance.Nb][r]) % algInstance.Nb][r] + for c in range(algInstance.Nb): + algInstance.state[c][r] = tmp[c] + def InvShiftRows(algInstance): + tmp = [0]*algInstance.Nb # list of size Nb + for r in range(1,4): # row 0 reamains unchanged and can be skipped + for c in range(algInstance.Nb): + tmp[c] = algInstance.state[(c+algInstance.Nb-shiftOffset[algInstance.Nb][r]) % algInstance.Nb][r] + for c in range(algInstance.Nb): + algInstance.state[c][r] = tmp[c] + #------------------------------------- + def MixColumns(a): + Sprime = [0,0,0,0] + for j in range(a.Nb): # for each column + Sprime[0] = mul(2,a.state[j][0])^mul(3,a.state[j][1])^mul(1,a.state[j][2])^mul(1,a.state[j][3]) + Sprime[1] = mul(1,a.state[j][0])^mul(2,a.state[j][1])^mul(3,a.state[j][2])^mul(1,a.state[j][3]) + Sprime[2] = mul(1,a.state[j][0])^mul(1,a.state[j][1])^mul(2,a.state[j][2])^mul(3,a.state[j][3]) + Sprime[3] = mul(3,a.state[j][0])^mul(1,a.state[j][1])^mul(1,a.state[j][2])^mul(2,a.state[j][3]) + for i in range(4): + a.state[j][i] = Sprime[i] + + def InvMixColumns(a): + """ Mix the four bytes of every column in a linear way + This is the opposite operation of Mixcolumn """ + Sprime = [0,0,0,0] + for j in range(a.Nb): # for each column + Sprime[0] = mul(0x0E,a.state[j][0])^mul(0x0B,a.state[j][1])^mul(0x0D,a.state[j][2])^mul(0x09,a.state[j][3]) + Sprime[1] = mul(0x09,a.state[j][0])^mul(0x0E,a.state[j][1])^mul(0x0B,a.state[j][2])^mul(0x0D,a.state[j][3]) + Sprime[2] = mul(0x0D,a.state[j][0])^mul(0x09,a.state[j][1])^mul(0x0E,a.state[j][2])^mul(0x0B,a.state[j][3]) + Sprime[3] = mul(0x0B,a.state[j][0])^mul(0x0D,a.state[j][1])^mul(0x09,a.state[j][2])^mul(0x0E,a.state[j][3]) + for i in range(4): + a.state[j][i] = Sprime[i] + + #------------------------------------- + def mul(a, b): + """ Multiply two elements of GF(2^m) + needed for MixColumn and InvMixColumn """ + if (a !=0 and b!=0): + return Alogtable[(Logtable[a] + Logtable[b])%255] + else: + return 0 + + Logtable = ( 0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, + 100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, + 125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120, + 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142, + 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56, + 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16, + 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186, + 43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87, + 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, + 44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160, + 127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183, + 204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157, + 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209, + 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, + 68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, + 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7) + + Alogtable= ( 1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, + 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, + 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, + 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, + 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, + 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, + 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, + 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, + 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, + 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, + 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, + 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, + 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, + 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, + 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, + 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1) + + + + + """ + AES Encryption Algorithm + The AES algorithm is just Rijndael algorithm restricted to the default + blockSize of 128 bits. + """ + + class AES(Rijndael): + """ The AES algorithm is the Rijndael block cipher restricted to block + sizes of 128 bits and key sizes of 128, 192 or 256 bits + """ + def __init__(self, key = None, padding = padWithPadLen(), keySize=16): + """ Initialize AES, keySize is in bytes """ + if not (keySize == 16 or keySize == 24 or keySize == 32) : + raise BadKeySizeError, 'Illegal AES key size, must be 16, 24, or 32 bytes' + + Rijndael.__init__( self, key, padding=padding, keySize=keySize, blockSize=16 ) + + self.name = 'AES' + + + """ + CBC mode of encryption for block ciphers. + This algorithm mode wraps any BlockCipher to make a + Cipher Block Chaining mode. + """ + from random import Random # should change to crypto.random!!! + + + class CBC(BlockCipher): + """ The CBC class wraps block ciphers to make cipher block chaining (CBC) mode + algorithms. The initialization (IV) is automatic if set to None. Padding + is also automatic based on the Pad class used to initialize the algorithm + """ + def __init__(self, blockCipherInstance, padding = padWithPadLen()): + """ CBC algorithms are created by initializing with a BlockCipher instance """ + self.baseCipher = blockCipherInstance + self.name = self.baseCipher.name + '_CBC' + self.blockSize = self.baseCipher.blockSize + self.keySize = self.baseCipher.keySize + self.padding = padding + self.baseCipher.padding = noPadding() # baseCipher should NOT pad!! + self.r = Random() # for IV generation, currently uses + # mediocre standard distro version <---------------- + import time + newSeed = time.ctime()+str(self.r) # seed with instance location + self.r.seed(newSeed) # to make unique + self.reset() + + def setKey(self, key): + self.baseCipher.setKey(key) + + # Overload to reset both CBC state and the wrapped baseCipher + def resetEncrypt(self): + BlockCipher.resetEncrypt(self) # reset CBC encrypt state (super class) + self.baseCipher.resetEncrypt() # reset base cipher encrypt state + + def resetDecrypt(self): + BlockCipher.resetDecrypt(self) # reset CBC state (super class) + self.baseCipher.resetDecrypt() # reset base cipher decrypt state + + def encrypt(self, plainText, iv=None, more=None): + """ CBC encryption - overloads baseCipher to allow optional explicit IV + when iv=None, iv is auto generated! + """ + if self.encryptBlockCount == 0: + self.iv = iv + else: + assert(iv==None), 'IV used only on first call to encrypt' + + return BlockCipher.encrypt(self,plainText, more=more) + + def decrypt(self, cipherText, iv=None, more=None): + """ CBC decryption - overloads baseCipher to allow optional explicit IV + when iv=None, iv is auto generated! + """ + if self.decryptBlockCount == 0: + self.iv = iv + else: + assert(iv==None), 'IV used only on first call to decrypt' + + return BlockCipher.decrypt(self, cipherText, more=more) + + def encryptBlock(self, plainTextBlock): + """ CBC block encryption, IV is set with 'encrypt' """ + auto_IV = '' + if self.encryptBlockCount == 0: + if self.iv == None: + # generate IV and use + self.iv = ''.join([chr(self.r.randrange(256)) for i in range(self.blockSize)]) + self.prior_encr_CT_block = self.iv + auto_IV = self.prior_encr_CT_block # prepend IV if it's automatic + else: # application provided IV + assert(len(self.iv) == self.blockSize ),'IV must be same length as block' + self.prior_encr_CT_block = self.iv + """ encrypt the prior CT XORed with the PT """ + ct = self.baseCipher.encryptBlock( xor(self.prior_encr_CT_block, plainTextBlock) ) + self.prior_encr_CT_block = ct + return auto_IV+ct + + def decryptBlock(self, encryptedBlock): + """ Decrypt a single block """ + + if self.decryptBlockCount == 0: # first call, process IV + if self.iv == None: # auto decrypt IV? + self.prior_CT_block = encryptedBlock + return '' + else: + assert(len(self.iv)==self.blockSize),"Bad IV size on CBC decryption" + self.prior_CT_block = self.iv + + dct = self.baseCipher.decryptBlock(encryptedBlock) + """ XOR the prior decrypted CT with the prior CT """ + dct_XOR_priorCT = xor( self.prior_CT_block, dct ) + + self.prior_CT_block = encryptedBlock + + return dct_XOR_priorCT + + + """ + AES_CBC Encryption Algorithm + """ + + class aescbc_AES_CBC(CBC): + """ AES encryption in CBC feedback mode """ + def __init__(self, key=None, padding=padWithPadLen(), keySize=16): + CBC.__init__( self, AES(key, noPadding(), keySize), padding) + self.name = 'AES_CBC' + + class AES_CBC(object): + def __init__(self): + self._key = None + self._iv = None + self.aes = None + + def set_decrypt_key(self, userkey, iv): + self._key = userkey + self._iv = iv + self.aes = aescbc_AES_CBC(userkey, noPadding(), len(userkey)) + + def decrypt(self, data): + iv = self._iv + cleartext = self.aes.decrypt(iv + data) + return cleartext + + import hmac + + class KeyIVGen(object): + # this only exists in openssl so we will use pure python implementation instead + # PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', + # [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p]) + def pbkdf2(self, passwd, salt, iter, keylen): + + def xorstr( a, b ): + if len(a) != len(b): + raise Exception("xorstr(): lengths differ") + return ''.join((chr(ord(x)^ord(y)) for x, y in zip(a, b))) + + def prf( h, data ): + hm = h.copy() + hm.update( data ) + return hm.digest() + + def pbkdf2_F( h, salt, itercount, blocknum ): + U = prf( h, salt + pack('>i',blocknum ) ) + T = U + for i in range(2, itercount+1): + U = prf( h, U ) + T = xorstr( T, U ) + return T + + sha = hashlib.sha1 + digest_size = sha().digest_size + # l - number of output blocks to produce + l = keylen / digest_size + if keylen % digest_size != 0: + l += 1 + h = hmac.new( passwd, None, sha ) + T = "" + for i in range(1, l+1): + T += pbkdf2_F( h, salt, iter, i ) + return T[0: keylen] + + def UnprotectHeaderData(encryptedData): + passwdData = 'header_key_data' + salt = 'HEADER.2011' + iter = 0x80 + keylen = 0x100 + key_iv = KeyIVGen().pbkdf2(passwdData, salt, iter, keylen) + key = key_iv[0:32] + iv = key_iv[32:48] + aes=AES_CBC() + aes.set_decrypt_key(key, iv) + cleartext = aes.decrypt(encryptedData) + return cleartext + + # Various character maps used to decrypt kindle info values. + # Probably supposed to act as obfuscation + charMap2 = "AaZzB0bYyCc1XxDdW2wEeVv3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_" + charMap5 = "AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE" + # New maps in K4PC 1.9.0 + testMap1 = "n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M" + testMap6 = "9YzAb0Cd1Ef2n5Pr6St7Uvh3Jk4M8WxG" + testMap8 = "YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD" + + # interface with Windows OS Routines + class DataBlob(Structure): + _fields_ = [('cbData', c_uint), + ('pbData', c_void_p)] + DataBlob_p = POINTER(DataBlob) + + + def GetSystemDirectory(): + GetSystemDirectoryW = kernel32.GetSystemDirectoryW + GetSystemDirectoryW.argtypes = [c_wchar_p, c_uint] + GetSystemDirectoryW.restype = c_uint + def GetSystemDirectory(): + buffer = create_unicode_buffer(MAX_PATH + 1) + GetSystemDirectoryW(buffer, len(buffer)) + return buffer.value + return GetSystemDirectory + GetSystemDirectory = GetSystemDirectory() + + def GetVolumeSerialNumber(): + GetVolumeInformationW = kernel32.GetVolumeInformationW + GetVolumeInformationW.argtypes = [c_wchar_p, c_wchar_p, c_uint, + POINTER(c_uint), POINTER(c_uint), + POINTER(c_uint), c_wchar_p, c_uint] + GetVolumeInformationW.restype = c_uint + def GetVolumeSerialNumber(path = GetSystemDirectory().split('\\')[0] + '\\'): + vsn = c_uint(0) + GetVolumeInformationW(path, None, 0, byref(vsn), None, None, None, 0) + return str(vsn.value) + return GetVolumeSerialNumber + GetVolumeSerialNumber = GetVolumeSerialNumber() + + def GetIDString(): + vsn = GetVolumeSerialNumber() + #print('Using Volume Serial Number for ID: '+vsn) + return vsn + + def getLastError(): + GetLastError = kernel32.GetLastError + GetLastError.argtypes = None + GetLastError.restype = c_uint + def getLastError(): + return GetLastError() + return getLastError + getLastError = getLastError() + + def GetUserName(): + GetUserNameW = advapi32.GetUserNameW + GetUserNameW.argtypes = [c_wchar_p, POINTER(c_uint)] + GetUserNameW.restype = c_uint + def GetUserName(): + buffer = create_unicode_buffer(2) + size = c_uint(len(buffer)) + while not GetUserNameW(buffer, byref(size)): + errcd = getLastError() + if errcd == 234: + # bad wine implementation up through wine 1.3.21 + return "AlternateUserName" + buffer = create_unicode_buffer(len(buffer) * 2) + size.value = len(buffer) + return buffer.value.encode('utf-16-le')[::2] + return GetUserName + GetUserName = GetUserName() + + def CryptUnprotectData(): + _CryptUnprotectData = crypt32.CryptUnprotectData + _CryptUnprotectData.argtypes = [DataBlob_p, c_wchar_p, DataBlob_p, + c_void_p, c_void_p, c_uint, DataBlob_p] + _CryptUnprotectData.restype = c_uint + def CryptUnprotectData(indata, entropy, flags): + indatab = create_string_buffer(indata) + indata = DataBlob(len(indata), cast(indatab, c_void_p)) + entropyb = create_string_buffer(entropy) + entropy = DataBlob(len(entropy), cast(entropyb, c_void_p)) + outdata = DataBlob() + if not _CryptUnprotectData(byref(indata), None, byref(entropy), + None, None, flags, byref(outdata)): + # raise DrmException("Failed to Unprotect Data") + return 'failed' + return string_at(outdata.pbData, outdata.cbData) + return CryptUnprotectData + CryptUnprotectData = CryptUnprotectData() + + + # Locate all of the kindle-info style files and return as list + def getKindleInfoFiles(): + kInfoFiles = [] + # some 64 bit machines do not have the proper registry key for some reason + # or the pythonn interface to the 32 vs 64 bit registry is broken + path = "" + if 'LOCALAPPDATA' in os.environ.keys(): + path = os.environ['LOCALAPPDATA'] + else: + # User Shell Folders show take precedent over Shell Folders if present + try: + regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\") + path = winreg.QueryValueEx(regkey, 'Local AppData')[0] + if not os.path.isdir(path): + path = "" + try: + regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\") + path = winreg.QueryValueEx(regkey, 'Local AppData')[0] + if not os.path.isdir(path): + path = "" + except RegError: + pass + except RegError: + pass + + found = False + if path == "": + print ('Could not find the folder in which to look for kinfoFiles.') + else: + print('searching for kinfoFiles in ' + path) + + # look for (K4PC 1.9.0 and later) .kinf2011 file + kinfopath = path +'\\Amazon\\Kindle\\storage\\.kinf2011' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.9+ kinf2011 file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for (K4PC 1.6.0 and later) rainier.2.1.1.kinf file + kinfopath = path +'\\Amazon\\Kindle\\storage\\rainier.2.1.1.kinf' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.6-1.8 kinf file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for (K4PC 1.5.0 and later) rainier.2.1.1.kinf file + kinfopath = path +'\\Amazon\\Kindle For PC\\storage\\rainier.2.1.1.kinf' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.5 kinf file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for original (earlier than K4PC 1.5.0) kindle-info files + kinfopath = path +'\\Amazon\\Kindle For PC\\{AMAwzsaPaaZAzmZzZQzgZCAkZ3AjA_AY}\\kindle.info' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC kindle.info file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + if not found: + print('No K4PC kindle.info/kinf/kinf2011 files have been found.') + return kInfoFiles + + + # determine type of kindle info provided and return a + # database of keynames and values + def getDBfromFile(kInfoFile): + names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] + DB = {} + with open(kInfoFile, 'rb') as infoReader: + hdr = infoReader.read(1) + data = infoReader.read() + + if data.find('{') != -1 : + # older style kindle-info file + items = data.split('{') + for item in items: + if item != '': + keyhash, rawdata = item.split(':') + keyname = "unknown" + for name in names: + if encodeHash(name,charMap2) == keyhash: + keyname = name + break + if keyname == "unknown": + keyname = keyhash + encryptedValue = decode(rawdata,charMap2) + DB[keyname] = CryptUnprotectData(encryptedValue, "", 0) + elif hdr == '/': + # else rainier-2-1-1 .kinf file + # the .kinf file uses "/" to separate it into records + # so remove the trailing "/" to make it easy to use split + data = data[:-1] + items = data.split('/') + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + + # the raw keyhash string is used to create entropy for the actual + # CryptProtectData Blob that represents that keys contents + entropy = SHA1(keyhash) + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = "unknown" + for name in names: + if encodeHash(name,charMap5) == keyhash: + keyname = name + break + if keyname == "unknown": + keyname = keyhash + # the charMap5 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using charMap5 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the charMap5 encoded contents seems to be: + # len(contents)-largest prime number <= int(len(content)/3) + # (in other words split "about" 2/3rds of the way through) + + # move first offsets chars to end to align for decode by charMap5 + encdata = "".join(edlst) + contlen = len(encdata) + noffset = contlen - primes(int(contlen/3))[-1] + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using Map5 to get the CryptProtect Data + encryptedValue = decode(encdata,charMap5) + DB[keyname] = CryptUnprotectData(encryptedValue, entropy, 1) + else: + # else newest .kinf2011 style .kinf file + # the .kinf file uses "/" to separate it into records + # so remove the trailing "/" to make it easy to use split + # need to put back the first char read because it it part + # of the added entropy blob + data = hdr + data[:-1] + items = data.split('/') + + # starts with and encoded and encrypted header blob + headerblob = items.pop(0) + encryptedValue = decode(headerblob, testMap1) + cleartext = UnprotectHeaderData(encryptedValue) + # now extract the pieces that form the added entropy + pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) + for m in re.finditer(pattern, cleartext): + added_entropy = m.group(2) + m.group(4) + + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + + # the sha1 of raw keyhash string is used to create entropy along + # with the added entropy provided above from the headerblob + entropy = SHA1(keyhash) + added_entropy + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + # key names now use the new testMap8 encoding + keyname = "unknown" + for name in names: + if encodeHash(name,testMap8) == keyhash: + keyname = name + break + + # the testMap8 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using testMap8 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the testMap8 encoded contents seems to be: + # len(contents)-largest prime number <= int(len(content)/3) + # (in other words split "about" 2/3rds of the way through) + + # move first offsets chars to end to align for decode by testMap8 + # by moving noffset chars from the start of the + # string to the end of the string + encdata = "".join(edlst) + contlen = len(encdata) + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using new testMap8 to get the original CryptProtect Data + encryptedValue = decode(encdata,testMap8) + cleartext = CryptUnprotectData(encryptedValue, entropy, 1) + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName()) + # store values used in decryption + DB['IDString'] = GetIDString() + DB['UserName'] = GetUserName() + else: + DB = {} + return DB +elif isosx: + import copy + import subprocess + + # interface to needed routines in openssl's libcrypto + def _load_crypto_libcrypto(): + from ctypes import CDLL, byref, POINTER, c_void_p, c_char_p, c_int, c_long, \ + Structure, c_ulong, create_string_buffer, addressof, string_at, cast + from ctypes.util import find_library + + libcrypto = find_library('crypto') + if libcrypto is None: + raise DrmException(u"libcrypto not found") + libcrypto = CDLL(libcrypto) + + # From OpenSSL's crypto aes header + # + # AES_ENCRYPT 1 + # AES_DECRYPT 0 + # AES_MAXNR 14 (in bytes) + # AES_BLOCK_SIZE 16 (in bytes) + # + # struct aes_key_st { + # unsigned long rd_key[4 *(AES_MAXNR + 1)]; + # int rounds; + # }; + # typedef struct aes_key_st AES_KEY; + # + # int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); + # + # note: the ivec string, and output buffer are both mutable + # void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + # const unsigned long length, const AES_KEY *key, unsigned char *ivec, const int enc); + + AES_MAXNR = 14 + c_char_pp = POINTER(c_char_p) + c_int_p = POINTER(c_int) + + class AES_KEY(Structure): + _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), ('rounds', c_int)] + AES_KEY_p = POINTER(AES_KEY) + + def F(restype, name, argtypes): + func = getattr(libcrypto, name) + func.restype = restype + func.argtypes = argtypes + return func + + AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',[c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p,c_int]) + + AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',[c_char_p, c_int, AES_KEY_p]) + + # From OpenSSL's Crypto evp/p5_crpt2.c + # + # int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, + # const unsigned char *salt, int saltlen, int iter, + # int keylen, unsigned char *out); + + PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', + [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p]) + + class LibCrypto(object): + def __init__(self): + self._blocksize = 0 + self._keyctx = None + self._iv = 0 + + def set_decrypt_key(self, userkey, iv): + self._blocksize = len(userkey) + if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) : + raise DrmException(u"AES improper key used") + return + keyctx = self._keyctx = AES_KEY() + self._iv = iv + self._userkey = userkey + rv = AES_set_decrypt_key(userkey, len(userkey) * 8, keyctx) + if rv < 0: + raise DrmException(u"Failed to initialize AES key") + + def decrypt(self, data): + out = create_string_buffer(len(data)) + mutable_iv = create_string_buffer(self._iv, len(self._iv)) + keyctx = self._keyctx + rv = AES_cbc_encrypt(data, out, len(data), keyctx, mutable_iv, 0) + if rv == 0: + raise DrmException(u"AES decryption failed") + return out.raw + + def keyivgen(self, passwd, salt, iter, keylen): + saltlen = len(salt) + passlen = len(passwd) + out = create_string_buffer(keylen) + rv = PKCS5_PBKDF2_HMAC_SHA1(passwd, passlen, salt, saltlen, iter, keylen, out) + return out.raw + return LibCrypto + + def _load_crypto(): + LibCrypto = None + try: + LibCrypto = _load_crypto_libcrypto() + except (ImportError, DrmException): + pass + return LibCrypto + + LibCrypto = _load_crypto() + + # Various character maps used to decrypt books. Probably supposed to act as obfuscation + charMap1 = 'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' + charMap2 = 'ZB0bYyc1xDdW2wEV3Ff7KkPpL8UuGA4gz-Tme9Nn_tHh5SvXCsIiR6rJjQaqlOoM' + + # For kinf approach of K4Mac 1.6.X or later + # On K4PC charMap5 = 'AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE' + # For Mac they seem to re-use charMap2 here + charMap5 = charMap2 + + # new in K4M 1.9.X + testMap8 = 'YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD' + + # uses a sub process to get the Hard Drive Serial Number using ioreg + # returns serial numbers of all internal hard drive drives + def GetVolumesSerialNumbers(): + sernum = os.getenv('MYSERIALNUMBER') + if sernum != None: + return [sernum] + sernums = [] + cmdline = '/usr/sbin/ioreg -w 0 -r -c AppleAHCIDiskDriver' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + bsdname = None + sernum = None + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + pp = resline.find('\"Serial Number\" = \"') + if pp >= 0: + sernum = resline[pp+19:-1] + sernums.append(sernum.strip()) + return [sernum] + + def GetUserHomeAppSupKindleDirParitionName(): + home = os.getenv('HOME') + dpath = home + '/Library' + cmdline = '/sbin/mount' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + disk = '' + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + if resline.startswith('/dev'): + (devpart, mpath) = resline.split(' on ') + dpart = devpart[5:] + pp = mpath.find('(') + if pp >= 0: + mpath = mpath[:pp-1] + if dpath.startswith(mpath): + disk = dpart + return disk + + # uses a sub process to get the UUID of the specified disk partition using ioreg + def GetDiskPartitionUUID(diskpart): + uuidnum = os.getenv('MYUUIDNUMBER') + if uuidnum != None: + return uuidnum + cmdline = '/usr/sbin/ioreg -l -S -w 0 -r -c AppleAHCIDiskDriver' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + bsdname = None + uuidnum = None + foundIt = False + nest = 0 + uuidnest = -1 + partnest = -2 + for j in xrange(cnt): + resline = reslst[j] + if resline.find('{') >= 0: + nest += 1 + if resline.find('}') >= 0: + nest -= 1 + pp = resline.find('\"UUID\" = \"') + if pp >= 0: + uuidnum = resline[pp+10:-1] + uuidnum = uuidnum.strip() + uuidnest = nest + if partnest == uuidnest and uuidnest > 0: + foundIt = True + break + bb = resline.find('\"BSD Name\" = \"') + if bb >= 0: + bsdname = resline[bb+14:-1] + bsdname = bsdname.strip() + if (bsdname == diskpart): + partnest = nest + else : + partnest = -2 + if partnest == uuidnest and partnest > 0: + foundIt = True + break + if nest == 0: + partnest = -2 + uuidnest = -1 + uuidnum = None + bsdname = None + if not foundIt: + uuidnum = '' + return uuidnum + + def GetMACAddressMunged(): + macnum = os.getenv('MYMACNUM') + if macnum != None: + return macnum + cmdline = '/sbin/ifconfig en0' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + macnum = None + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + pp = resline.find('ether ') + if pp >= 0: + macnum = resline[pp+6:-1] + macnum = macnum.strip() + # print 'original mac', macnum + # now munge it up the way Kindle app does + # by xoring it with 0xa5 and swapping elements 3 and 4 + maclst = macnum.split(':') + n = len(maclst) + if n != 6: + fountIt = False + break + for i in range(6): + maclst[i] = int('0x' + maclst[i], 0) + mlst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + mlst[5] = maclst[5] ^ 0xa5 + mlst[4] = maclst[3] ^ 0xa5 + mlst[3] = maclst[4] ^ 0xa5 + mlst[2] = maclst[2] ^ 0xa5 + mlst[1] = maclst[1] ^ 0xa5 + mlst[0] = maclst[0] ^ 0xa5 + macnum = '%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x' % (mlst[0], mlst[1], mlst[2], mlst[3], mlst[4], mlst[5]) + foundIt = True + break + if not foundIt: + macnum = '' + return macnum + + + # uses unix env to get username instead of using sysctlbyname + def GetUserName(): + username = os.getenv('USER') + return username + + def GetIDStrings(): + # Return all possible ID Strings + strings = [] + strings.append(GetMACAddressMunged()) + strings.extend(GetVolumesSerialNumbers()) + diskpart = GetUserHomeAppSupKindleDirParitionName() + strings.append(GetDiskPartitionUUID(diskpart)) + strings.append('9999999999') + return strings + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used by Kindle for Mac versions < 1.6.0 + class CryptUnprotectData(object): + def __init__(self, IDString): + sp = IDString + '!@#' + GetUserName() + passwdData = encode(SHA256(sp),charMap1) + salt = '16743' + self.crp = LibCrypto() + iter = 0x3e8 + keylen = 0x80 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext,charMap1) + return cleartext + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used for Kindle for Mac Versions >= 1.6.0 + class CryptUnprotectDataV2(object): + def __init__(self, IDString): + sp = GetUserName() + ':&%:' + IDString + passwdData = encode(SHA256(sp),charMap5) + # salt generation as per the code + salt = 0x0512981d * 2 * 1 * 1 + salt = str(salt) + GetUserName() + salt = encode(salt,charMap5) + self.crp = LibCrypto() + iter = 0x800 + keylen = 0x400 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext, charMap5) + return cleartext + + + # unprotect the new header blob in .kinf2011 + # used in Kindle for Mac Version >= 1.9.0 + def UnprotectHeaderData(encryptedData): + passwdData = 'header_key_data' + salt = 'HEADER.2011' + iter = 0x80 + keylen = 0x100 + crp = LibCrypto() + key_iv = crp.keyivgen(passwdData, salt, iter, keylen) + key = key_iv[0:32] + iv = key_iv[32:48] + crp.set_decrypt_key(key,iv) + cleartext = crp.decrypt(encryptedData) + return cleartext + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used for Kindle for Mac Versions >= 1.9.0 + class CryptUnprotectDataV3(object): + def __init__(self, entropy, IDString): + sp = GetUserName() + '+@#$%+' + IDString + passwdData = encode(SHA256(sp),charMap2) + salt = entropy + self.crp = LibCrypto() + iter = 0x800 + keylen = 0x400 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext, charMap2) + return cleartext + + + # Locate the .kindle-info files + def getKindleInfoFiles(): + # file searches can take a long time on some systems, so just look in known specific places. + kInfoFiles=[] + found = False + home = os.getenv('HOME') + # check for .kinf2011 file in new location (App Store Kindle for Mac) + testpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.kinf2011' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kinf2011 file: ' + testpath) + found = True + # check for .kinf2011 files + testpath = home + '/Library/Application Support/Kindle/storage/.kinf2011' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kinf2011 file: ' + testpath) + found = True + # check for .rainier-2.1.1-kinf files + testpath = home + '/Library/Application Support/Kindle/storage/.rainier-2.1.1-kinf' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac rainier file: ' + testpath) + found = True + # check for .kindle-info files + testpath = home + '/Library/Application Support/Kindle/storage/.kindle-info' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kindle-info file: ' + testpath) + found = True + if not found: + print('No k4Mac kindle-info/rainier/kinf2011 files have been found.') + return kInfoFiles + + # determine type of kindle info provided and return a + # database of keynames and values + def getDBfromFile(kInfoFile): + names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] + with open(kInfoFile, 'rb') as infoReader: + filehdr = infoReader.read(1) + filedata = infoReader.read() + + IDStrings = GetIDStrings() + for IDString in IDStrings: + DB = {} + #print "trying IDString:",IDString + try: + hdr = filehdr + data = filedata + if data.find('[') != -1 : + # older style kindle-info file + cud = CryptUnprotectData(IDString) + items = data.split('[') + for item in items: + if item != '': + keyhash, rawdata = item.split(':') + keyname = 'unknown' + for name in names: + if encodeHash(name,charMap2) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + encryptedValue = decode(rawdata,charMap2) + cleartext = cud.decrypt(encryptedValue) + if len(cleartext) > 0: + DB[keyname] = cleartext + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + elif hdr == '/': + # else newer style .kinf file used by K4Mac >= 1.6.0 + # the .kinf file uses '/' to separate it into records + # so remove the trailing '/' to make it easy to use split + data = data[:-1] + items = data.split('/') + cud = CryptUnprotectDataV2(IDString) + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + keyname = 'unknown' + + # the raw keyhash string is also used to create entropy for the actual + # CryptProtectData Blob that represents that keys contents + # 'entropy' not used for K4Mac only K4PC + # entropy = SHA1(keyhash) + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = 'unknown' + for name in names: + if encodeHash(name,charMap5) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + + # the charMap5 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using charMap5 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the charMap5 encoded contents seems to be: + # len(contents) - largest prime number less than or equal to int(len(content)/3) + # (in other words split 'about' 2/3rds of the way through) + + # move first offsets chars to end to align for decode by charMap5 + encdata = ''.join(edlst) + contlen = len(encdata) + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using charMap5 to get the CryptProtect Data + encryptedValue = decode(encdata,charMap5) + cleartext = cud.decrypt(encryptedValue) + if len(cleartext) > 0: + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + else: + # the latest .kinf2011 version for K4M 1.9.1 + # put back the hdr char, it is needed + data = hdr + data + data = data[:-1] + items = data.split('/') + + # the headerblob is the encrypted information needed to build the entropy string + headerblob = items.pop(0) + encryptedValue = decode(headerblob, charMap1) + cleartext = UnprotectHeaderData(encryptedValue) + + # now extract the pieces in the same way + # this version is different from K4PC it scales the build number by multipying by 735 + pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) + for m in re.finditer(pattern, cleartext): + entropy = str(int(m.group(2)) * 0x2df) + m.group(4) + + cud = CryptUnprotectDataV3(entropy,IDString) + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + keyname = 'unknown' + + # unlike K4PC the keyhash is not used in generating entropy + # entropy = SHA1(keyhash) + added_entropy + # entropy = added_entropy + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = 'unknown' + for name in names: + if encodeHash(name,testMap8) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + + # the testMap8 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using testMap8 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the testMap8 encoded contents seems to be: + # len(contents) - largest prime number less than or equal to int(len(content)/3) + # (in other words split 'about' 2/3rds of the way through) + + # move first offsets chars to end to align for decode by testMap8 + encdata = ''.join(edlst) + contlen = len(encdata) + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using testMap8 to get the CryptProtect Data + encryptedValue = decode(encdata,testMap8) + cleartext = cud.decrypt(encryptedValue) + # print keyname + # print cleartext + if len(cleartext) > 0: + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + except: + pass + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + # store values used in decryption + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(IDString, GetUserName()) + DB['IDString'] = IDString + DB['UserName'] = GetUserName() + else: + print u"Couldn't decrypt file." + DB = {} + return DB +else: + def getDBfromFile(kInfoFile): + raise DrmException(u"This script only runs under Windows or Mac OS X.") + return {} + +def kindlekeys(files = []): + keys = [] + if files == []: + files = getKindleInfoFiles() + for file in files: + key = getDBfromFile(file) + if key: + # convert all values to hex, just in case. + for keyname in key: + key[keyname]=key[keyname].encode('hex') + keys.append(key) + return keys + +# interface for Python DeDRM +# returns single key or multiple keys, depending on path or file passed in +def getkey(outpath, files=[]): + keys = kindlekeys(files) + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(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"kindlekey{0:d}.k4i".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(key)) + print u"Saved a key to {0}".format(outfile) + return True + return False + +def usage(progname): + print u"Finds, decrypts and saves the default Kindle For Mac/PC encryption keys." + print u"Keys are saved to the current directory, or a specified output directory." + print u"If a file name is passed instead of a directory, only the first key is saved, in that file." + print u"Usage:" + print u" {0:s} [-h] [-k ] []".format(progname) + + +def cli_main(argv=unicode_argv()): + progname = os.path.basename(argv[0]) + print u"{0} v{1}\nCopyright © 2010-2013 some_updates and Apprentice Alf".format(progname,__version__) + + try: + opts, args = getopt.getopt(argv[1:], "hk:") + except getopt.GetoptError, err: + print u"Error in options or arguments: {0}".format(err.args[0]) + usage(progname) + sys.exit(2) + + files = [] + for o, a in opts: + if o == "-h": + usage(progname) + sys.exit(0) + if o == "-k": + files = [a] + + if len(args) > 1: + usage(progname) + sys.exit(2) + + if len(args) == 1: + # save to the specified file or directory + outpath = args[0] + if not os.path.isabs(outpath): + outpath = os.path.abspath(outpath) + else: + # save to the same directory as the script + outpath = os.path.dirname(argv[0]) + + # make sure the outpath is the + outpath = os.path.realpath(os.path.normpath(outpath)) + + if not getkey(outpath, files): + print u"Could not retrieve Kindle for Mac/PC key." + return 0 + + +def gui_main(argv=unicode_argv()): + import Tkinter + import Tkconstants + import tkMessageBox + import traceback + + class ExceptionDialog(Tkinter.Frame): + def __init__(self, root, text): + Tkinter.Frame.__init__(self, root, border=5) + label = Tkinter.Label(self, text=u"Unexpected error:", + anchor=Tkconstants.W, justify=Tkconstants.LEFT) + label.pack(fill=Tkconstants.X, expand=0) + self.text = Tkinter.Text(self) + self.text.pack(fill=Tkconstants.BOTH, expand=1) + + self.text.insert(Tkconstants.END, text) + + + root = Tkinter.Tk() + root.withdraw() + progpath, progname = os.path.split(argv[0]) + success = False + try: + keys = kindlekeys() + keycount = 0 + for key in keys: + while True: + keycount += 1 + outfile = os.path.join(progpath,u"kindlekey{0:d}.k4i".format(keycount)) + if not os.path.exists(outfile): + break + + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(key)) + success = True + tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile)) + except DrmException, e: + tkMessageBox.showerror(progname, u"Error: {0}".format(str(e))) + except Exception: + root.wm_state('normal') + root.title(progname) + text = traceback.format_exc() + ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1) + root.mainloop() + if not success: + return 1 + return 0 + +if __name__ == '__main__': + if len(sys.argv) > 1: + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + sys.exit(cli_main()) + sys.exit(gui_main()) diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/mobidedrm.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/mobidedrm.py index 264c175..ccbac4e 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/mobidedrm.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/mobidedrm.py @@ -462,7 +462,7 @@ class MobiBook: raise DrmException(u"Encryption not initialised. Must be opened with Mobipocket Reader first.") found_key, pid = self.parseDRM(self.sect[drm_ptr:drm_ptr+drm_size], drm_count, goodpids) if not found_key: - raise DrmException(u"No key found in {0:d} keys tried. Read the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(len(goodpids))) + raise DrmException(u"No key found in {0:d} keys tried.".format(len(goodpids))) # kill the drm keys self.patchSection(0, '\0' * drm_size, drm_ptr) # kill the drm pointers diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/openssl_des.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/openssl_des.py index a4a40ca..9a84e58 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/openssl_des.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/openssl_des.py @@ -65,7 +65,7 @@ def load_libcrypto(): class DES(object): def __init__(self, key): if len(key) != 8 : - raise Error('DES improper key used') + raise Exception('DES improper key used') return self.key = key self.keyschedule = DES_KEY_SCHEDULE() diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/scriptinterface.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/scriptinterface.py index b8f1cff..391b683 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/scriptinterface.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/scriptinterface.py @@ -11,6 +11,7 @@ import zipfix import ineptpdf import erdr2pml import k4mobidedrm +import traceback def decryptepub(infile, outdir, rscpath): errlog = '' @@ -29,44 +30,48 @@ def decryptepub(infile, outdir, rscpath): rv = 1 # first try with the Adobe adept epub - # try with any keyfiles (*.der) in the rscpath - files = os.listdir(rscpath) - filefilter = re.compile("\.der$", re.IGNORECASE) - files = filter(filefilter.search, files) - if files: - for filename in files: - keypath = os.path.join(rscpath, filename) - userkey = open(keypath,'rb').read() - try: - rv = ineptepub.decryptBook(userkey, zippath, outfile) - if rv == 0: - break - except Exception, e: - errlog += str(e) - rv = 1 - pass - if rv == 0: - os.remove(zippath) - return 0 + if ineptepub.adeptBook(zippath): + # try with any keyfiles (*.der) in the rscpath + files = os.listdir(rscpath) + filefilter = re.compile("\.der$", re.IGNORECASE) + files = filter(filefilter.search, files) + if files: + for filename in files: + keypath = os.path.join(rscpath, filename) + userkey = open(keypath,'rb').read() + try: + rv = ineptepub.decryptBook(userkey, zippath, outfile) + if rv == 0: + break + except Exception, e: + errlog += traceback.format_exc() + errlog += str(e) + rv = 1 + + if rv == 0: + os.remove(zippath) + return 0 - # still no luck # now try with ignoble epub - # try with any keyfiles (*.b64) in the rscpath - files = os.listdir(rscpath) - filefilter = re.compile("\.b64$", re.IGNORECASE) - files = filter(filefilter.search, files) - if files: - for filename in files: - keypath = os.path.join(rscpath, filename) - userkey = open(keypath,'rb').read() - try: - rv = ignobleepub.decryptBook(userkey, zippath, outfile) - if rv == 0: - break - except Exception, e: - errlog += str(e) - rv = 1 - pass + if ignobleepub.ignobleBook(zippath): + # try with any keyfiles (*.b64) in the rscpath + files = os.listdir(rscpath) + filefilter = re.compile("\.b64$", re.IGNORECASE) + files = filter(filefilter.search, files) + if files: + for filename in files: + keypath = os.path.join(rscpath, filename) + userkey = open(keypath,'r').read() + print userkey + try: + rv = ignobleepub.decryptBook(userkey, zippath, outfile) + if rv == 0: + break + except Exception, e: + errlog += traceback.format_exc() + errlog += str(e) + rv = 1 + os.remove(zippath) if rv != 0: print errlog @@ -94,9 +99,10 @@ def decryptpdf(infile, outdir, rscpath): if rv == 0: break except Exception, e: + errlog += traceback.format_exc() errlog += str(e) rv = 1 - pass + if rv != 0: print errlog return rv @@ -117,7 +123,13 @@ def decryptpdb(infile, outdir, rscpath): except ValueError: print ' Error parsing user supplied social drm data.' return 1 - rv = erdr2pml.decryptBook(infile, outpath, True, erdr2pml.getuser_key(name, cc8)) + try: + rv = erdr2pml.decryptBook(infile, outpath, True, erdr2pml.getuser_key(name, cc8)) + except Exception, e: + errlog += traceback.format_exc() + errlog += str(e) + rv = 1 + if rv == 0: break return rv @@ -141,13 +153,19 @@ def decryptk4mobi(infile, outdir, rscpath): serialstr = serialstr.strip() if serialstr != '': serialnums = serialstr.split(',') - kInfoFiles = [] + kDatabaseFiles = [] files = os.listdir(rscpath) - filefilter = re.compile("\.info$|\.kinf$", re.IGNORECASE) + filefilter = re.compile("\.k4i$", re.IGNORECASE) files = filter(filefilter.search, files) if files: for filename in files: dpath = os.path.join(rscpath,filename) - kInfoFiles.append(dpath) - rv = k4mobidedrm.decryptBook(infile, outdir, kInfoFiles, serialnums, pidnums) + kDatabaseFiles.append(dpath) + try: + rv = k4mobidedrm.decryptBook(infile, outdir, kDatabaseFiles, serialnums, pidnums) + except Exception, e: + errlog += traceback.format_exc() + errlog += str(e) + rv = 1 + return rv diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/topazextract.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/topazextract.py index 3e4db39..71fe8ab 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/topazextract.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/topazextract.py @@ -74,7 +74,7 @@ debug = False if 'calibre' in sys.modules: inCalibre = True - from calibre_plugins.k4mobidedrm import kgenpids + from calibre_plugins.dedrm import kgenpids else: inCalibre = False import kgenpids @@ -321,7 +321,7 @@ class TopazBook: self.extractFiles() print u"Successfully Extracted Topaz contents" if inCalibre: - from calibre_plugins.k4mobidedrm import genbook + from calibre_plugins.dedrm import genbook else: import genbook @@ -355,7 +355,7 @@ class TopazBook: self.extractFiles() print u"Successfully Extracted Topaz contents" if inCalibre: - from calibre_plugins.k4mobidedrm import genbook + from calibre_plugins.dedrm import genbook else: import genbook @@ -439,7 +439,7 @@ class TopazBook: def usage(progname): print u"Removes DRM protection from Topaz ebooks and extracts the contents" print u"Usage:" - print u" {0} [-k ] [-p ] [-s ] ".format(progname) + print u" {0} [-k ] [-p ] [-s ] ".format(progname) # Main def cli_main(argv=unicode_argv()): @@ -466,7 +466,7 @@ def cli_main(argv=unicode_argv()): print u"Output Directory {0} Does Not Exist.".format(outdir) return 1 - kInfoFiles = [] + kDatabaseFiles = [] serials = [] pids = [] @@ -474,7 +474,7 @@ def cli_main(argv=unicode_argv()): if o == '-k': if a == None : raise DrmException("Invalid parameter for -k") - kInfoFiles.append(a) + kDatabaseFiles.append(a) if o == '-p': if a == None : raise DrmException("Invalid parameter for -p") @@ -490,7 +490,7 @@ def cli_main(argv=unicode_argv()): title = tb.getBookTitle() print u"Processing Book: {0}".format(title) md1, md2 = tb.getPIDMetaInfo() - pids.extend(kgenpids.getPidList(md1, md2, serials, kInfoFiles)) + pids.extend(kgenpids.getPidList(md1, md2, serials, kDatabaseFiles)) try: print u"Decrypting Book" diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/utilities.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/utilities.py new file mode 100644 index 0000000..c730607 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/utilities.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +__license__ = 'GPL v3' + +DETAILED_MESSAGE = \ +'You have personal information stored in this plugin\'s customization '+ \ +'string from a previous version of this plugin.\n\n'+ \ +'This new version of the plugin can convert that info '+ \ +'into key data that the new plugin can then use (which doesn\'t '+ \ +'require personal information to be stored/displayed in an insecure '+ \ +'manner like the old plugin did).\n\nIf you choose NOT to migrate this data at this time '+ \ +'you will be prompted to save that personal data to a file elsewhere; and you\'ll have '+ \ +'to manually re-configure this plugin with your information.\n\nEither way... ' + \ +'this new version of the plugin will not be responsible for storing that personal '+ \ +'info in plain sight any longer.' + +def uStrCmp (s1, s2, caseless=False): + import unicodedata as ud + str1 = s1 if isinstance(s1, unicode) else unicode(s1) + str2 = s2 if isinstance(s2, unicode) else unicode(s2) + if caseless: + return ud.normalize('NFC', str1.lower()) == ud.normalize('NFC', str2.lower()) + else: + return ud.normalize('NFC', str1) == ud.normalize('NFC', str2) + +def parseCustString(keystuff): + userkeys = [] + ar = keystuff.split(':') + for i in ar: + try: + name, ccn = i.split(',') + # Generate Barnes & Noble EPUB user key from name and credit card number. + userkeys.append(generate_key(name, ccn)) + except: + pass + return userkeys diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/zipfilerugged.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/zipfilerugged.py index adf3c53..4a55a69 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/zipfilerugged.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/zipfilerugged.py @@ -354,7 +354,7 @@ class ZipInfo (object): def _decodeFilename(self): if self.flag_bits & 0x800: try: - print "decoding filename",self.filename + #print "decoding filename",self.filename return self.filename.decode('utf-8') except: return self.filename diff --git a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/zipfix.py b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/zipfix.py index eaee20d..8ddfae3 100644 --- a/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/zipfix.py +++ b/DeDRM_Windows_Application/DeDRM_App/DeDRM_lib/lib/zipfix.py @@ -1,6 +1,23 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# zipfix.py, version 1.1 +# Copyright © 2010-2013 by some_updates, DiapDealer and Apprentice Alf + +# Released under the terms of the GNU General Public Licence, version 3 +# + +# Revision history: +# 1.0 - Initial release +# 1.1 - Updated to handle zip file metadata correctly + +""" +Re-write zip (or ePub) fixing problems with file names (and mimetype entry). +""" + +__license__ = 'GPL v3' +__version__ = "1.1" + import sys import zlib import zipfilerugged @@ -96,25 +113,41 @@ class fixZip: # if epub write mimetype file first, with no compression if self.ztype == 'epub': - nzinfo = ZipInfo('mimetype', compress_type=zipfilerugged.ZIP_STORED) - self.outzip.writestr(nzinfo, _MIMETYPE) + # first get a ZipInfo with current time and no compression + mimeinfo = ZipInfo('mimetype',compress_type=zipfilerugged.ZIP_STORED) + mimeinfo.internal_attr = 1 # text file + try: + # if the mimetype is present, get its info, including time-stamp + oldmimeinfo = self.inzip.getinfo('mimetype') + # copy across useful fields + mimeinfo.date_time = oldmimeinfo.date_time + mimeinfo.comment = oldmimeinfo.comment + mimeinfo.extra = oldmimeinfo.extra + mimeinfo.internal_attr = oldmimeinfo.internal_attr + mimeinfo.external_attr = oldmimeinfo.external_attr + mimeinfo.create_system = oldmimeinfo.create_system + except: + pass + self.outzip.writestr(mimeinfo, _MIMETYPE) # write the rest of the files for zinfo in self.inzip.infolist(): - if zinfo.filename != "mimetype" or self.ztype == '.zip': + if zinfo.filename != "mimetype" or self.ztype != 'epub': data = None - nzinfo = zinfo try: data = self.inzip.read(zinfo.filename) except zipfilerugged.BadZipfile or zipfilerugged.error: local_name = self.getlocalname(zinfo) data = self.getfiledata(zinfo) - nzinfo.filename = local_name + zinfo.filename = local_name - nzinfo.date_time = zinfo.date_time - nzinfo.compress_type = zinfo.compress_type - nzinfo.flag_bits = 0 - nzinfo.internal_attr = 0 + # create new ZipInfo with only the useful attributes from the old info + nzinfo = ZipInfo(zinfo.filename, zinfo.date_time, compress_type=zinfo.compress_type) + nzinfo.comment=zinfo.comment + nzinfo.extra=zinfo.extra + nzinfo.internal_attr=zinfo.internal_attr + nzinfo.external_attr=zinfo.external_attr + nzinfo.create_system=zinfo.create_system self.outzip.writestr(nzinfo,data) self.bzf.close() diff --git a/DeDRM_Windows_Application/DeDRM_App_ReadMe.txt b/DeDRM_Windows_Application/DeDRM_App_ReadMe.txt new file mode 100644 index 0000000..4cb51d5 --- /dev/null +++ b/DeDRM_Windows_Application/DeDRM_App_ReadMe.txt @@ -0,0 +1,66 @@ +DeDRM_App - DeDRM_App.pyw and DeDRM_Drop_Target.bat +=========================================================== + +DeDRM_App.pyw is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target.bat to have the DRM removed. It repackages all the "tools" python software in one easy to use program that remembers preferences and settings. + +It will work without manual configuration for Kindle for PC ebooks and Adobe Digital Edition epub and pdf ebooks, when Kindle for PC and/or Adobe Digital Editions are installed on the same computer. + +To remove the DRM from eInk Kindle ebooks, Barnes and Noble epubs, Mobipocket ebooks and Fictionwise eReader ebooks requires the user to double-click the DeDRM_Drop_Target.bat file and set some additional Preferences including: + +eInk Kindle: 16 digit Serial Number +Barnes & Noble: key file (bnepubkey.b64) generate using ignoblekeygen.pyw +eReader Social DRM: Name:Last 8 digits of CC number +MobiPocket: 10 digit PID + +Once these preferences have been set, the user can simply drag and drop ebooks onto the DeDRM_Drop_Target to remove the DRM. Note that after setting preferences it is necessary to click on "Set Prefs" button and then quit the application for the change in preferences to fully take effect. + +This program requires that a 32 bit version of Python 2.x (tested with Python 2.5 through Python 2.7) and PyCrypto be installed on your computer before it will work. See below for where to get theese programs for Windows. + + +Installation +------------ +0. If you don't already have a correct version of Python and PyCrypto installed, follow the "Installing Python on Windows" and "Installing PyCrypto on Windows" sections below before continuing. + +1. Drag the DeDRM_App folder from tools_v6.0.0/DeDRM_Application_Windows to your "My Documents" folder. + +2. Open the DeDRM_App folder you've just dragged, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop. + +3. To set the preferences simply double-click on the short-cut you've just created. + + +Credits +------- +The mobidedrm and erdr2pml scripts were created by The Dark Reverser +The ignobleepub, ignoblekeygen, ineptepub and adobe key scripts were created by i♥cabbages +The k4mobidedrm script and supporting scripts were written by some_updates with help from DiapDealer and Apprentice Alf, based on code by Bart Simpson (aka Skindle), CMBDTC and clarknova +The alfcrypto library was created by some_updates +The ePub encryption detection script was adapted by Apprentice Alf from a script by Paul Durrant +The DeDRM all-in-one AppleScript was created by Apprentice Alf +The DeDRM all-in-one python script was created by some_updates and Apprentice Alf + + +Installing Python on Windows +---------------------------- +I strongly recommend fully installing ActiveState’s Active Python, free Community Edition for Windows (x86) 32 bits. This is a free, full version of the Python. It comes with some important additional modules that are not included in the bare-bones version from www.python.org unless you choose to install everything. + +1. Download ActivePython 2.7.X for Windows (x86) (or later 2.7 version for Windows (x86) ) from http://www.activestate.com/activepython/downloads. Do not download the ActivePython 2.7.X for Windows (64-bit, x64) verson, even if you are running 64-bit Windows. + +2. When it has finished downloading, run the installer. Accept the default options. + + +Installing PyCrypto on Windows +------------------------------ +PyCrypto is a set of encryption/decryption routines that work with Python. The sources are freely available, and compiled versions are available from several sources. You must install a version that is for 32-bit Windows and Python 2.7. I recommend the installer linked from Michael Foord’s blog. + +1. Download PyCrypto 2.1 for 32bit Windows and Python 2.7 from http://www.voidspace.org.uk/python/modules.shtml#pycrypto + +2. When it has finished downloading, unzip it. This will produce a file “pycrypto-2.1.0.win32-py2.7.exe”. + +3. Double-click “pycrypto-2.1.0.win32-py2.7.exe” to run it. Accept the default options. + + + + +Linux Users +=========== +The DeDRM_app.pyw script, although not the bat shortcut, should work under Linux. Drag & drop functionality is not available. diff --git a/DeDRM_Windows_Application/DeDRM_ReadMe.txt b/DeDRM_Windows_Application/DeDRM_ReadMe.txt deleted file mode 100644 index 4e8c447..0000000 --- a/DeDRM_Windows_Application/DeDRM_ReadMe.txt +++ /dev/null @@ -1,52 +0,0 @@ -ReadMe_DeDRM_v5.6.2_WinApp -======================== - -DeDRM_v5.6.2_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target to have the DRM removed. It repackages all the "tools" python software in one easy to use program that remembers preferences and settings. - -It will work without manual configuration for Kindle for PC ebooks and Adobe Adept epub and pdf ebooks. - -To remove the DRM from standalone Kindle ebooks, eReader pdb ebooks, Barnes and Noble epubs, and Mobipocket ebooks requires the user to double-click the DeDRM_Drop_Target and set some additional Preferences including: - -eInk Kindle: 16 digit Serial Number -Barnes & Noble: key file (bnepubkey.b64) -eReader Social DRM: Name:Last 8 digits of CC number -MobiPocket: 10 digit PID - -Once these preferences have been set, the user can simply drag and drop ebooks onto the DeDRM_Drop_Target to remove the DRM. - -This program requires that a 32 bit version of Python 2.X (tested with Python 2.5 through Python 2.7) and PyCrypto be installed on your computer before it will work. See below for where to get theese programs for Windows. - -As from version 5.6.2, the DeDRM application should work correctly with file names containing non-ASCII characters. - -Installation ------------- - -0. If you don't already have a correct version of Python and PyCrypto installed, follow the "Installing Python on Windows" and "Installing PyCrypto on Windows" sections below before continuing. - -1. Drag the DeDRM_5.6.2 folder from tools_v5.6.2/DeDRM_Applications/Windows to your "My Documents" folder. - -2. Open the DeDRM_5.6.2 folder you've just dragged, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop. - -3. To set the preferences simply double-click on your just created short-cut. - - - -Installing Python on Windows ----------------------------- -I strongly recommend fully installing ActiveState’s Active Python, free Community Edition for Windows (x86) 32 bits. This is a free, full version of the Python. It comes with some important additional modules that are not included in the bare-bones version from www.python.org unless you choose to install everything. - -1. Download ActivePython 2.7.X for Windows (x86) (or later 2.7 version for Windows (x86) ) from http://www.activestate.com/activepython/downloads. Do not download the ActivePython 2.7.X for Windows (64-bit, x64) verson, even if you are running 64-bit Windows. - -2. When it has finished downloading, run the installer. Accept the default options. - - -Installing PyCrypto on Windows ------------------------------- -PyCrypto is a set of encryption/decryption routines that work with Python. The sources are freely available, and compiled versions are available from several sources. You must install a version that is for 32-bit Windows and Python 2.7. I recommend the installer linked from Michael Foord’s blog. - -1. Download PyCrypto 2.1 for 32bit Windows and Python 2.7 from http://www.voidspace.org.uk/python/modules.shtml#pycrypto - -2. When it has finished downloading, unzip it. This will produce a file “pycrypto-2.1.0.win32-py2.7.exe”. - -3. Double-click “pycrypto-2.1.0.win32-py2.7.exe” to run it. Accept the default options. - diff --git a/DeDRM_calibre_plugin/DeDRM_plugin.zip b/DeDRM_calibre_plugin/DeDRM_plugin.zip new file mode 100644 index 0000000000000000000000000000000000000000..545288cab0a46846bf642467f6dd9b6b4491d665 GIT binary patch literal 319654 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 rt&Bk(zT4ft38}|*%m4c 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 #4S4NS97K0mK>t1@7R?>Qz+es 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 literal 0 HcmV?d00001 diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Adobe Digital Editions Key_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Adobe Digital Editions Key_Help.htm new file mode 100644 index 0000000..ee9edb2 --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Adobe Digital Editions Key_Help.htm @@ -0,0 +1,55 @@ + + + + + + +Managing Adobe Digital Editions Keys + +

+ + + +

Managing Adobe Digital Editions Keys

+ + +

If you have upgraded from an earlier version of the plugin, any existing Adobe Digital Editions keys will have been automatically imported, so you might not need to do any more configuration. In addition, on Windows and Mac, the default Adobe Digital Editions key is added the first time the plugin is run. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog prompting you to enter a key name for the default Adobe Digital Editions key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys.
  • +
+ +

Click the OK button to create and store the Adobe Digital Editions key for the current installation of Adobe Digital Editions. Or Cancel if you don’t want to create the key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.der’ key files. Key files might come from being exported from this or older plugins, or may have been generated using the adobekey.pyw script running under Wine on Linux systems.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Barnes and Noble Key_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Barnes and Noble Key_Help.htm new file mode 100644 index 0000000..ac1b693 --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Barnes and Noble Key_Help.htm @@ -0,0 +1,57 @@ + + + + + + +Managing Barnes and Noble Keys + + + + + +

Managing Barnes and Noble Keys

+ + +

If you have upgraded from an earlier version of the plugin, any existing Barnes and Noble keys will have been automatically imported, so you might not need to do any more configuration. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys. Choose something that will help you remember the data (name, cc#) it was created with.
  • +
  • Your Name: This is the name used by Barnes and Noble to generate your encryption key. Seemingly at random, Barnes and Noble choose one of three places from which to take this name. Most commonly, it’s your name as set in your Barnes & Noble account, My Account page, directly under PERSONAL INFORMATION. Sometimes it is the the name used in the default shipping address, and sometimes it’s the name listed for the active credit card. If these names are different in your Barnes and Noble account preferences, I suggest creating one key for each version of your name. This name will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • +
  • Credit Card#: this is the default credit card number that was on file with Barnes and Noble at the time of download of the ebook to be de-DRMed. Just enter the 16 (15 for American Express) digits. As with the name, this number will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • +
+ +

Click the OK button to create and store the generated key. Or Cancel if you don’t want to create a key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.b64’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.b64’ key files. Key files might come from being exported from this or older plugins, or may have been generated using the original i♥cabbages script.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_EInk Kindle Serial Number_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_EInk Kindle Serial Number_Help.htm new file mode 100644 index 0000000..e79abd7 --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_EInk Kindle Serial Number_Help.htm @@ -0,0 +1,43 @@ + + + + + + +Managing eInk Kindle serial numbers + + + + + +

Managing eInk Kindle serial numbers

+ +

If you have upgraded from an earlier version of the plugin, any existing eInk Kindle serial numbers will have been automatically imported, so you might not need to do any more configuration.

+ +

Please note that Kindle serial numbers are only valid keys for eInk Kindles like the Kindle Touch and PaperWhite. The Kindle Fire and Fire HD do not use their serial number for DRM and it is useless to enter those serial numbers.

+ +

Creating New Kindle serial numbers:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Kindle serial number.

+
+ +

Click the OK button to save the serial number. Or Cancel if you didn’t want to enter a serial number.

+ +

Deleting Kindle serial numbers:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Kindle serial number from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Once done creating/deleting serial numbers, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Help.htm new file mode 100644 index 0000000..69edade --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Help.htm @@ -0,0 +1,73 @@ + + + + + + +DeDRM Plugin Configuration + + + + + +

DeDRM Plugin (v6.0.0)

+ +

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.

+ +

Installation

+

You have obviously managed to install the plugin, as otherwise you wouldn’t be reading this help file. However, you should also delete any older DeDRM plugins, as this DeDRM plugin replaces the five older plugins: Kindle and Mobipocket DeDRM (K4MobiDeDRM), Ignoble Epub DeDRM (ignobleepub), Inept Epub DeDRM (ineptepub), Inept PDF DeDRM (ineptepub) and eReader PDB 2 PML (eReaderPDB2PML).

+ +

Configuration

+

On Windows and Mac, the keys for ebooks downloaded for Kindle for Mac/PC and Adobe Digital Editions are automatically generated. If all your DRMed ebooks can be opened and read in Kindle for Mac/PC and/or Adobe Digital Editions on the same computer on which you are running calibre, you do not need to do any configuration of this plugin. On Linux, keys for Kindle for PC and Adobe Digital Editions need to be generated separately (see the Linux section below)

+ +

If you have other DRMed ebooks, you will need to enter extra configuration information. The buttons in this dialog will open individual configuration dialogs that will allow you to enter the needed information, depending on the type and source of your DRMed eBooks. Additional help on the information required is available in each of the the dialogs.

+ +

If you have used previous versions of the various DeDRM plugins on this machine, you may find that some of the configuration dialogs already contain the information you entered through those previous plugins.

+ +

When you have finished entering your configuration information, you must click the OK button to save it. If you click the Cancel button, all your changes in all the configuration dialogs will be lost.

+ +

Troubleshooting:

+ +

If you find that it’s not working for you , you can save a lot of time by trying to add the ebook to Calibre in debug mode. This will print out a lot of helpful info that can be copied into any online help requests.

+ +

Open a command prompt (terminal window) and type "calibre-debug -g" (without the quotes). Calibre will launch, and you can can add the problem ebook the usual way. The debug info will be output to the original command prompt (terminal window). Copy the resulting output and paste it into the comment you make at my blog.

+

Note: The Mac version of Calibre doesn’t install the command line tools by default. If you go to the ‘Preferences’ page and click on the miscellaneous button, you’ll find the option to install the command line tools.

+ +

Credits:

+
    +
  • The Dark Reverser for the Mobipocket and eReader scripts
  • +
  • i♥cabbages for the Adobe Digital Editions scripts
  • +
  • Skindle aka Bart Simpson for the Amazon Kindle for PC script
  • +
  • CMBDTC for Amazon Topaz DRM removal script
  • +
  • some_updates, clarknova and Bart Simpson for Amazon Topaz conversion scripts
  • +
  • DiapDealer for the first calibre plugin versions of the tools
  • +
  • some_updates, DiapDealer, Apprentice Alf and mdlnx for Amazon Kindle/Mobipocket tools
  • +
  • some_updates for the DeDRM all-in-one Python tool
  • +
  • Apprentice Alf for the DeDRM all-in-one AppleScript tool
  • +
  • Apprentice Alf for the DeDRM all-in-one calibre plugin
  • +
  • And probably many more.
  • +
+ +

For additional help read the FAQs at Apprentice Alf’s Blog and ask questions in the comments section of the first post.

+ +

Linux Systems Only

+

Generating decryption keys for Adobe Digital Editions and Kindle for PC

+

If you install Kindle for PC and/or Adobe Digital Editions in Wine, you will be able to download DRMed ebooks to them under Wine. To be able to remove the DRM, you will need to generate key files and add them in the plugin's customisation dialogs.

+ +

To generate the key files you will need to install Python and PyCrypto under the same Wine setup as your Kindle for PC and/or Adobe Digital Editions installations. (Kindle for PC, Python and Pycrypto installation instructions in the ReadMe.)

+ +

Once everything's installed under Wine, you'll need to run the adobekey.pyw script (for Adobe Digital Editions) and kindlekey.pyw (For Kindle for PC) using the python installation in your Wine system. The scripts can be found in Other_Tools/Key_Retrieval_Scripts.

+ +

Each script will create a key file in the same folder as the script. Copy the key files to your Linux system and then load the key files using the Adobe Digital Editions ebooks dialog and the Kindle for Mac/PC ebooks dialog.

+ + + + + diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Kindle for Mac and PC Key_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Kindle for Mac and PC Key_Help.htm new file mode 100644 index 0000000..c714581 --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Kindle for Mac and PC Key_Help.htm @@ -0,0 +1,55 @@ + + + + + + +Managing Kindle for Mac/PC Keys + + + + + +

Managing Kindle for Mac/PC Keys

+ + +

If you have upgraded from an earlier version of the plugin, any existing Kindle for Mac/PC keys will have been automatically imported, so you might not need to do any more configuration. In addition, on Windows and Mac, the default Kindle for Mac/PC key is added the first time the plugin is run. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog prompting you to enter a key name for the default Kindle for Mac/PC key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys.
  • +
+ +

Click the OK button to create and store the Kindle for Mac/PC key for the current installation of Kindle for Mac/PC. Or Cancel if you don’t want to create the key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.der’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.k4i’ key files. Key files might come from being exported from this plugin, or may have been generated using the kindlekey.pyw script running under Wine on Linux systems.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Mobipocket PID_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Mobipocket PID_Help.htm new file mode 100644 index 0000000..00aeeca --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_Mobipocket PID_Help.htm @@ -0,0 +1,42 @@ + + + + + + +Managing Mobipocket PIDs + + + + + +

Managing Mobipocket PIDs

+ +

If you have upgraded from an earlier version of the plugin, any existing Mobipocket PIDs will have been automatically imported, so you might not need to do any more configuration.

+ + +

Creating New Mobipocket PIDs:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering a new Mobipocket PID.

+
    +
  • PID: this is a PID used to decrypt your Mobipocket ebooks. It is eight or ten characters long. Mobipocket PIDs are usualy displayed in the About screen of your Mobipocket device.
  • +
+ +

Click the OK button to save the PID. Or Cancel if you didn’t want to enter a PID.

+ +

Deleting Mobipocket PIDs:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted Mobipocket PID from the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Once done creating/deleting PIDs, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_eReader Key_Help.htm b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_eReader Key_Help.htm new file mode 100644 index 0000000..c1c78ad --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/DeDRM_eReader Key_Help.htm @@ -0,0 +1,56 @@ + + + + + + +Managing eReader Keys + + + + + +

Managing eReader Keys

+ +

If you have upgraded from an earlier version of the plugin, any existing eReader (Fictionwise ‘.pdb’) keys will have been automatically imported, so you might not need to do any more configuration. Continue reading for key generation and management instructions.

+ +

Creating New Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a green plus sign (+). Clicking this button will open a new dialog for entering the necessary data to generate a new key.

+
    +
  • Unique Key Name: this is a unique name you choose to help you identify the key. This name will show in the list of configured keys. Choose something that will help you remember the data (name, cc#) it was created with.
  • +
  • Your Name: This is the name used by Fictionwise to generate your encryption key. Since Fictionwise has now closed down, you might not have easy access to this. It was often the name on the Credit Card used at Fictionwise.
  • +
  • Credit Card#: this is the default credit card number that was on file with Fictionwise at the time of download of the ebook to be de-DRMed. Just enter the last 8 digits of the number. As with the name, this number will not be stored anywhere on your computer or in calibre. It will only be used in the creation of the one-way hash/key that’s stored in the preferences.
  • +
+ +

Click the OK button to create and store the generated key. Or Cancel if you don’t want to create a key.

+

New keys are checked against the current list of keys before being added, and duplicates are discarded.

+ +

Deleting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a red "X". Clicking this button will delete the highlighted key in the list. You will be prompted once to be sure that’s what you truly mean to do. Once gone, it’s permanently gone.

+ +

Renaming Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a sheet of paper. Clicking this button will promt you to enter a new name for the highlighted key in the list. Enter the new name for the encryption key and click the OK button to use the new name, or Cancel to revert to the old name..

+ +

Exporting Keys:

+ +

On the right-hand side of the plugin’s customization dialog, you will see a button with an icon that looks like a computer’s hard-drive. Use this button to export the highlighted key to a file (with a ‘.b63’ file name extension). Used for backup purposes or to migrate key data to other computers/calibre installations. The dialog will prompt you for a place to save the file.

+ +

Importing Existing Keyfiles:

+ +

At the bottom-left of the plugin’s customization dialog, you will see a button labeled "Import Existing Keyfiles". Use this button to import existing ‘.b63’ key files that have previously been exported.

+ +

Once done creating/deleting/renaming/importing decryption keys, click Close to exit the customization dialogue. Your changes wil only be saved permanently when you click OK in the main configuration dialog.

+ + + + diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py b/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py new file mode 100644 index 0000000..a9ac2fd --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/__init__.py @@ -0,0 +1,450 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement +__license__ = 'GPL v3' +__docformat__ = 'restructuredtext en' + + +# Released under the terms of the GNU General Public Licence, version 3 +# +# +# Requires Calibre version 0.7.55 or higher. +# +# All credit given to i♥cabbages and The Dark Reverser for the original standalone scripts. +# We had the much easier job of converting them to a calibre plugin. +# +# This plugin is meant to decrypt eReader PDBs, Adobe Adept ePubs, Barnes & Noble ePubs, +# Adobe Adept PDFs, Amazon Kindle and Mobipocket files without having to +# install any dependencies... other than having calibre installed, of course. +# +# Configuration: +# Check out the plugin's configuration settings by clicking the "Customize plugin" +# button when you have the "DeDRM" plugin highlighted (under Preferences-> +# Plugins->File type plugins). Once you have the configuration dialog open, you'll +# see a Help link on the top right-hand side. +# +# Revision history: +# 6.0.0 - Initial release + +""" +Decrypt DRMed ebooks. +""" + +PLUGIN_NAME = u"DeDRM" +PLUGIN_VERSION_TUPLE = (6, 0, 0) +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' + +import sys, os, re +import time +import zipfile +import traceback +from zipfile import ZipFile + +class DeDRMError(Exception): + pass + +from calibre.customize import FileTypePlugin +from calibre.constants import iswindows, isosx +from calibre.gui2 import is_ok_to_use_qt +from calibre.utils.config import config_dir + + +# Wrap a stream so that output gets flushed immediately +# and also make sure that any unicode strings get safely +# 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) + +class DeDRM(FileTypePlugin): + name = PLUGIN_NAME + description = u"Removes DRM from Amazon Kindle, Adobe Adept (including Kobo), Barnes & Noble, Mobipocket and eReader ebooks. Credit given to i♥cabbages and The Dark Reverser for the original stand-alone scripts." + supported_platforms = ['linux', 'osx', 'windows'] + 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']) + on_import = True + priority = 600 + + def initialize(self): + # convert old preferences, if necessary. + import calibre_plugins.dedrm.config + + config.convertprefs() + + """ + Dynamic modules can't be imported/loaded from a zipfile... so this routine + runs whenever the plugin gets initialized. This will extract the appropriate + library for the target OS and copy it to the 'alfcrypto' subdirectory of + calibre's configuration directory. That 'alfcrypto' directory is then + inserted into the syspath (as the very first entry) in the run function + so the CDLL stuff will work in the alfcrypto.py script. + """ + try: + if iswindows: + names = [u"alfcrypto.dll",u"alfcrypto64.dll"] + elif isosx: + names = [u"libalfcrypto.dylib"] + else: + names = [u"libalfcrypto32.so",u"libalfcrypto64.so"] + lib_dict = self.load_resources(names) + self.pluginsdir = os.path.join(config_dir,u"plugins") + if not os.path.exists(self.pluginsdir): + os.mkdir(self.pluginsdir) + self.maindir = os.path.join(self.pluginsdir,u"DeDRM") + if not os.path.exists(self.maindir): + os.mkdir(self.maindir) + self.helpdir = os.path.join(self.maindir,u"help") + if not os.path.exists(self.helpdir): + os.mkdir(self.helpdir) + self.alfdir = os.path.join(self.maindir,u"alfcrypto") + if not os.path.exists(self.alfdir): + os.mkdir(self.alfdir) + for entry, data in lib_dict.items(): + file_path = os.path.join(self.alfdir, entry) + open(file_path,'wb').write(data) + except Exception, e: + traceback.print_exc() + raise + + def ePubDecrypt(self,path_to_ebook): + # Create a TemporaryPersistent file to work with. + # Check original epub archive for zip errors. + import calibre_plugins.dedrm.zipfix + + inf = self.temporary_file(u".epub") + try: + print u"{0} v{1}: Verifying zip archive integrity.".format(PLUGIN_NAME, PLUGIN_VERSION) + fr = zipfix.fixZip(path_to_ebook, inf.name) + fr.fix() + except Exception, e: + print u"{0} v{1}: Error \'{2}\' when checking zip archive.".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0]) + raise Exception(e) + + # import the decryption keys + import calibre_plugins.dedrm.config as config + + # import the Barnes & Noble ePub handler + import calibre_plugins.dedrm.ignobleepub as ignobleepub + + #check the book + if ignobleepub.ignobleBook(inf.name): + print u"{0} v{1}: “{2}” is a secure Barnes & Noble ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + + # Attempt to decrypt epub with each encryption key (generated or provided). + for keyname, userkey in config.dedrmprefs['bandnkeys'].items(): + keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname) + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked) + of = self.temporary_file(u".epub") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + result = ignobleepub.decryptBook(userkey, inf.name, of.name) + + of.close() + + if result == 0: + # Decryption was successful. + # Return the modified PersistentTemporary file to calibre. + return of.name + + 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 Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + # import the Adobe Adept ePub handler + import calibre_plugins.dedrm.ineptepub as ineptepub + + if ineptepub.adeptBook(inf.name): + print u"{0} v{1}: {2} is a secure Adobe Adept ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + + # Attempt to decrypt epub with each encryption key (generated or provided). + for keyname, userkeyhex in config.dedrmprefs['adeptkeys'].items(): + userkey = userkeyhex.decode('hex') + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) + of = self.temporary_file(u".epub") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptepub.decryptBook(userkey, inf.name, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was successful. + # Return the modified PersistentTemporary file to calibre. + return of.name + + print u"{0} v{1}: Failed to decrypt with key {2:s} after {3:.1f} seconds.".format(PLUGIN_NAME, PLUGIN_VERSION,keyname,time.time()-self.starttime) + + # perhaps we need to get a new default ADE key + if iswindows or isosx: + print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys".format(PLUGIN_NAME, PLUGIN_VERSION) + + # get the default Adobe keys + import calibre_plugins.dedrm.adobekey as adobe + + try: + defaultkeys = adobe.adeptkeys() + except: + defaultkeys = [] + + newkeys = [] + for keyvalue in defaultkeys: + if keyvalue.encode('hex') not in config.dedrmprefs['adeptkeys'].values(): + newkeys.append(keyvalue) + + if len(newkeys) > 0: + try: + for i,userkey in enumerate(newkeys): + print u"{0} v{1}: Trying a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + of = self.temporary_file(u".epub") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptepub.decryptBook(userkey, inf.name, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was a success + # Store the new successful key in the defaults + print u"{0} v{1}: Saving a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + try: + config.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex')) + config.writeprefs() + except: + traceback.print_exc() + # 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: + pass + + # Something went wrong with decryption. + print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + # Not a Barnes & Noble nor an Adobe Adept + # Import the fixed epub. + print u"{0} v{1}: “{2}” is neither an Adobe Adept nor a Barnes & Noble encrypted ePub.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + return inf.name + + def PDFDecrypt(self,path_to_ebook): + import calibre_plugins.dedrm.config as config + import calibre_plugins.dedrm.ineptpdf + + # Attempt to decrypt epub with each encryption key (generated or provided). + print u"{0} v{1}: {2} is a PDF ebook.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + for keyname, userkeyhex in config.dedrmprefs['adeptkeys'].items(): + userkey = userkeyhex.decode('hex') + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname) + of = self.temporary_file(u".pdf") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptpdf.decryptBook(userkey, path_to_ebook, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was successful. + # Return the modified PersistentTemporary file to calibre. + return of.name + + # perhaps we need to get a new default ADE key + if iswindows or isosx: + print u"{0} v{1}: Looking for new default Adobe Digital Editions Keys".format(PLUGIN_NAME, PLUGIN_VERSION) + + # get the default Adobe keys + import calibre_plugins.dedrm.adobekey as adobe + + try: + defaultkeys = adobe.adeptkeys() + except: + defaultkeys = [] + + newkeys = [] + for keyvalue in defaultkeys: + if keyvalue.encode('hex') not in config.dedrmprefs['adeptkeys'].values(): + newkeys.append(keyvalue) + + if len(newkeys) > 0: + try: + for i,userkey in enumerate(newkeys): + print u"{0} v{1}: Trying a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + of = self.temporary_file(u".pdf") + + # Give the user key, ebook and TemporaryPersistent file to the decryption function. + try: + result = ineptepdf.decryptBook(userkey, inf.name, of.name) + except: + result = 1 + + of.close() + + if result == 0: + # Decryption was a success + # Store the new successful key in the defaults + print u"{0} v{1}: Saving a new default key.".format(PLUGIN_NAME, PLUGIN_VERSION) + try: + config.addnamedvaluetoprefs('adeptkeys','default_key',keyvalue.encode('hex')) + config.writeprefs() + except: + traceback.print_exc() + # 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: + pass + + # Something went wrong with decryption. + print u"{0} v{1}: Ultimately failed to decrypt after {2:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + def KindleMobiDecrypt(self,path_to_ebook): + + # add the alfcrypto directory to sys.path so alfcrypto.py + # will be able to locate the custom lib(s) for CDLL import. + sys.path.insert(0, self.alfdir) + # Had to move this import here so the custom libs can be + # extracted to the appropriate places beforehand these routines + # look for them. + import calibre_plugins.dedrm.config as config + import calibre_plugins.dedrm.k4mobidedrm + + pids = config.dedrmprefs['pids'] + serials = config.dedrmprefs['serials'] + kindleDatabases = config.dedrmprefs['kindlekeys'].items() + + try: + book = k4mobidedrm.GetDecryptedBook(path_to_ebook,kindleDatabases,serials,pids,self.starttime) + except Exception, e: + decoded = False + # perhaps we need to get a new default Kindle for Mac/PC key + if iswindows or isosx: + print u"{0} v{1}: Failed to decrypt with error: {2}".format(PLUGIN_NAME, PLUGIN_VERSION,e.args[0]) + print u"{0} v{1}: Looking for new default Kindle Key".format(PLUGIN_NAME, PLUGIN_VERSION) + import calibre_plugins.dedrm.kindlekey as amazon + + try: + defaultkeys = amazon.kindlekeys() + except: + defaultkeys = [] + newkeys = {} + for i,keyvalue in enumerate(defaultkeys): + keyname = u"default_key_{0:d}".format(i+1) + if keyvalue not in config.dedrmprefs['kindlekeys'].values(): + newkeys[keyname] = keyvalue + if len(newkeys) > 0: + try: + book = k4mobidedrm.GetDecryptedBook(path_to_ebook,newkeys.items(),[],[],self.starttime) + decoded = True + # store the new successful keys in the defaults + for keyvalue in newkeys.values(): + config.addnamedvaluetoprefs('kindlekeys','default_key',keyvalue) + config.writeprefs() + except Exception, e: + 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 Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + traceback.print_exc() + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{4}” after {3:.1f} seconds with error: {2}\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, e.args[0],time.time()-self.starttime,os.path.basename(path_to_ebook))) + + of = self.temporary_file(book.getBookExtension()) + book.getFile(of.name) + of.close() + book.cleanup() + return of.name + + + def eReaderDecrypt(self,path_to_ebook): + + import calibre_plugins.dedrm.config as config + import calibre_plugins.dedrm.erdr2pml + + # Attempt to decrypt epub with each encryption key (generated or provided). + for keyname, userkey in config.dedrmprefs['ereaderkeys'].items(): + keyname_masked = u"".join((u'X' if (x.isdigit()) else x) for x in keyname) + print u"{0} v{1}: Trying Encryption key {2:s}".format(PLUGIN_NAME, PLUGIN_VERSION, keyname_masked) + of = self.temporary_file(u".pmlz") + + # Give the userkey, ebook and TemporaryPersistent file to the decryption function. + result = erdr2pml.decryptBook(path_to_ebook, of.name, True, userkey.decode('hex')) + + of.close() + + # Decryption was successful return the modified PersistentTemporary + # file to Calibre's import process. + if result == 0: + return of.name + + 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 Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + raise DeDRMError(u"{0} v{1}: Ultimately failed to decrypt “{2}” after {3:.1f} seconds.\nRead the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook),time.time()-self.starttime)) + + + def run(self, path_to_ebook): + + # make sure any unicode output gets converted safely with 'replace' + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + + print u"{0} v{1}: Trying to decrypt {2}.".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)) + self.starttime = time.time() + + booktype = os.path.splitext(path_to_ebook)[1].lower()[1:] + if booktype in ['prc','mobi','azw','azw1','azw3','azw4','tpz']: + # Kindle/Mobipocket + decrypted_ebook = self.KindleMobiDecrypt(path_to_ebook) + elif booktype == 'pdb': + # eReader + decrypted_ebook = self.eReaderDecrypt(path_to_ebook) + pass + elif booktype == 'pdf': + # Adobe Adept PDF (hopefully) + decrypted_ebook = self.PDFDecrypt(path_to_ebook) + pass + elif booktype == 'epub': + # Adobe Adept or B&N ePub + decrypted_ebook = self.ePubDecrypt(path_to_ebook) + else: + print u"Unknown booktype {0}. Passing back to calibre unchanged.".format(booktype) + return path_to_ebook + print u"{0} v{1}: Successfully decrypted book after {2:.1f} seconds".format(PLUGIN_NAME, PLUGIN_VERSION,time.time()-self.starttime) + return decrypted_ebook + + def is_customizable(self): + # return true to allow customization via the Plugin->Preferences. + return True + + def config_widget(self): + import calibre_plugins.dedrm.config as config + return config.ConfigWidget(self.plugin_path) + + def save_settings(self, config_widget): + config_widget.save_settings() diff --git a/Calibre_Plugins/ineptepub_plugin/ineptkey.py b/DeDRM_calibre_plugin/DeDRM_plugin/adobekey.py similarity index 76% rename from Calibre_Plugins/ineptepub_plugin/ineptkey.py rename to DeDRM_calibre_plugin/DeDRM_plugin/adobekey.py index a9bc62d..94f7522 100644 --- a/Calibre_Plugins/ineptepub_plugin/ineptkey.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/adobekey.py @@ -1,25 +1,31 @@ -#! /usr/bin/python +#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import with_statement -# ineptkey.pyw, version 5.6 +# adobekey.pyw, version 5.7 # Copyright © 2009-2010 i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Windows users: Before running this program, you must first install Python 2.6 -# from and PyCrypto from -# (make certain -# to install the version for Python 2.6). Then save this script file as -# ineptkey.pyw and double-click on it to run it. It will create a file named -# adeptkey.der in the same directory. This is your ADEPT user key. +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf + +# Windows users: Before running this program, you must first install Python. +# We recommend ActiveState Python 2.7.X for Windows (x86) from +# http://www.activestate.com/activepython/downloads. +# You must also install PyCrypto from +# http://www.voidspace.org.uk/python/modules.shtml#pycrypto +# (make certain to install the version for Python 2.7). +# Then save this script file as adobekey.pyw and double-click on it to run it. +# It will create a file named adobekey_1.der in in the same directory as the script. +# This is your Adobe Digital Editions user key. # -# Mac OS X users: Save this script file as ineptkey.pyw. You can run this -# program from the command line (pythonw ineptkey.pyw) or by double-clicking +# Mac OS X users: Save this script file as adobekey.pyw. You can run this +# program from the command line (python adobekey.pyw) or by double-clicking # it when it has been associated with PythonLauncher. It will create a file -# named adeptkey.der in the same directory. This is your ADEPT user key. +# named adobekey_1.der in the same directory as the script. +# This is your Adobe Digital Editions user key. # Revision history: # 1 - Initial release, for Adobe Digital Editions 1.7 @@ -30,24 +36,25 @@ from __future__ import with_statement # 4.2 - added old 1.7.1 processing # 4.3 - better key search # 4.4 - Make it working on 64-bit Python -# 5 - Clean up and improve 4.x changes; -# Clean up and merge OS X support by unknown +# 5 - Clean up and improve 4.x changes; +# Clean up and merge OS X support by unknown # 5.1 - add support for using OpenSSL on Windows in place of PyCrypto # 5.2 - added support for output of key to a particular file # 5.3 - On Windows try PyCrypto first, OpenSSL next # 5.4 - Modify interface to allow use of import # 5.5 - Fix for potential problem with PyCrypto # 5.6 - Revised to allow use in Plugins to eliminate need for duplicate code +# 5.7 - Unicode support added, renamed adobekey from ineptkey +# 5.8 - Added getkey interface for Windows DeDRM application """ Retrieve Adobe ADEPT user key. """ __license__ = 'GPL v3' +__version__ = '5.8' -import sys -import os -import struct +import sys, os, struct, getopt # Wrap a stream so that output gets flushed immediately # and also make sure that any unicode strings get @@ -79,8 +86,8 @@ def unicode_argv(): # 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 '?'. - + # characters with '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 from ctypes import POINTER, byref, cdll, c_int, windll from ctypes.wintypes import LPCWSTR, LPWSTR @@ -101,7 +108,9 @@ def unicode_argv(): start = argc.value - len(sys.argv) return [argv[i] for i in xrange(start, argc.value)] - return [u"ineptkey.py"] + # if we don't have any arguments at all, just pass back script name + # this should never happen + return [u"adobekey.py"] else: argvencoding = sys.stdin.encoding if argvencoding == None: @@ -349,7 +358,7 @@ if iswindows: return CryptUnprotectData CryptUnprotectData = CryptUnprotectData() - def retrieve_keys(): + def adeptkeys(): if AES is None: raise ADEPTError("PyCrypto or OpenSSL must be installed") root = GetSystemDirectory().split('\\')[0] + '\\' @@ -406,6 +415,9 @@ elif isosx: 'enc': 'http://www.w3.org/2001/04/xmlenc#'} def findActivationDat(): + import warnings + warnings.filterwarnings('ignore', category=FutureWarning) + home = os.getenv('HOME') cmdline = 'find "' + home + '/Library/Application Support/Adobe/Digital Editions" -name "activation.dat"' cmdline = cmdline.encode(sys.getfilesystemencoding()) @@ -413,6 +425,7 @@ elif isosx: out1, out2 = p2.communicate() reslst = out1.split('\n') cnt = len(reslst) + ActDatPath = "activation.dat" for j in xrange(cnt): resline = reslst[j] pp = resline.find('activation.dat') @@ -423,10 +436,10 @@ elif isosx: return ActDatPath return None - def retrieve_keys(): + def adeptkeys(): actpath = findActivationDat() if actpath is None: - raise ADEPTError("Could not locate ADE activation") + raise ADEPTError("Could not find ADE activation.dat file.") tree = etree.parse(actpath) adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag) expr = '//%s/%s' % (adept('credentials'), adept('privateLicenseKey')) @@ -436,33 +449,93 @@ elif isosx: return [userkey] else: - def retrieve_keys(keypath): + def adeptkeys(): raise ADEPTError("This script only supports Windows and Mac OS X.") return [] -def retrieve_key(keypath): - keys = retrieve_keys() - with open(keypath, 'wb') as f: - f.write(keys[0]) - return True - -def extractKeyfile(keypath): - try: - success = retrieve_key(keypath) - except ADEPTError, e: - print u"Key generation Error: {0}".format(e.args[0]) - return 1 - except Exception, e: - print "General Error: {0}".format(e.args[0]) - return 1 - if not success: - return 1 - return 0 +# interface for Python DeDRM +def getkey(outpath): + keys = adeptkeys() + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'wb') 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"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + print u"Saved a key to {0}".format(outfile) + return True + return False +def usage(progname): + print u"Finds, decrypts and saves the default Adobe Adept encryption key(s)." + print u"Keys are saved to the current directory, or a specified output directory." + print u"If a file name is passed instead of a directory, only the first key is saved, in that file." + print u"Usage:" + print u" {0:s} [-h] []".format(progname) def cli_main(argv=unicode_argv()): - keypath = argv[1] - return extractKeyfile(keypath) + progname = os.path.basename(argv[0]) + print u"{0} v{1}\nCopyright © 2009-2013 i♥cabbages and 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) > 1: + usage(progname) + sys.exit(2) + + if len(args) == 1: + # save to the specified file or directory + outpath = args[0] + if not os.path.isabs(outpath): + outpath = os.path.abspath(outpath) + else: + # save to the same directory as the script + outpath = os.path.dirname(argv[0]) + + # make sure the outpath is the + outpath = os.path.realpath(os.path.normpath(outpath)) + + keys = adeptkeys() + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'wb') 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"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + print u"Saved a key to {0}".format(outfile) + else: + print u"Could not retrieve Adobe Adept key." + return 0 def gui_main(argv=unicode_argv()): @@ -485,23 +558,32 @@ def gui_main(argv=unicode_argv()): root = Tkinter.Tk() root.withdraw() - keypath, progname = os.path.split(argv[0]) - keypath = os.path.join(keypath, u"adeptkey.der") + progpath, progname = os.path.split(argv[0]) success = False try: - success = retrieve_key(keypath) - except ADEPTError, e: - tkMessageBox.showerror(u"ADEPT Key", "Error: {0}".format(e.args[0])) + keys = adeptkeys() + keycount = 0 + for key in keys: + while True: + keycount += 1 + outfile = os.path.join(progpath,u"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + success = True + tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile)) + except DrmException, e: + tkMessageBox.showerror(progname, u"Error: {0}".format(str(e))) except Exception: root.wm_state('normal') - root.title('ADEPT Key') + root.title(progname) text = traceback.format_exc() ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1) root.mainloop() if not success: return 1 - tkMessageBox.showinfo( - u"ADEPT Key", u"Key successfully retrieved to {0}".format(keypath)) return 0 if __name__ == '__main__': diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/aescbc.py b/DeDRM_calibre_plugin/DeDRM_plugin/aescbc.py similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/aescbc.py rename to DeDRM_calibre_plugin/DeDRM_plugin/aescbc.py diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/alfcrypto.dll b/DeDRM_calibre_plugin/DeDRM_plugin/alfcrypto.dll similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/alfcrypto.dll rename to DeDRM_calibre_plugin/DeDRM_plugin/alfcrypto.dll diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/alfcrypto.py b/DeDRM_calibre_plugin/DeDRM_plugin/alfcrypto.py similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/alfcrypto.py rename to DeDRM_calibre_plugin/DeDRM_plugin/alfcrypto.py diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/alfcrypto64.dll b/DeDRM_calibre_plugin/DeDRM_plugin/alfcrypto64.dll similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/alfcrypto64.dll rename to DeDRM_calibre_plugin/DeDRM_plugin/alfcrypto64.dll diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/alfcrypto_src.zip b/DeDRM_calibre_plugin/DeDRM_plugin/alfcrypto_src.zip similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/alfcrypto_src.zip rename to DeDRM_calibre_plugin/DeDRM_plugin/alfcrypto_src.zip diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/config.py b/DeDRM_calibre_plugin/DeDRM_plugin/config.py new file mode 100644 index 0000000..04d87c6 --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/config.py @@ -0,0 +1,464 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +__license__ = 'GPL v3' + +# Standard Python modules. +import os, sys, re, hashlib + +# PyQT4 modules (part of calibre). +from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, + QGroupBox, QPushButton, QListWidget, QListWidgetItem, + QAbstractItemView, QIcon, QDialog, QUrl, QString) +from PyQt4 import QtGui + +import zipfile +from zipfile import ZipFile + +# calibre modules and constants. +from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url, + choose_dir, choose_files) +from calibre.utils.config import dynamic, config_dir, JSONConfig +from calibre.constants import iswindows, isosx + +# modules from this plugin's zipfile. +from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION +from calibre_plugins.dedrm.__init__ import RESOURCE_NAME as help_file_name +from calibre_plugins.dedrm.utilities import (uStrCmp, DETAILED_MESSAGE) + +import calibre_plugins.dedrm.dialogs as dialogs +import calibre_plugins.dedrm.ignoblekeygen as bandn +import calibre_plugins.dedrm.erdr2pml as ereader +import calibre_plugins.dedrm.adobekey as adobe +import calibre_plugins.dedrm.kindlekey as amazon + +JSON_NAME = PLUGIN_NAME.strip().lower().replace(' ', '_') +JSON_PATH = os.path.join(u"plugins", JSON_NAME + '.json') + +IGNOBLEPLUGINNAME = "Ignoble Epub DeDRM" +EREADERPLUGINNAME = "eReader PDB 2 PML" +OLDKINDLEPLUGINNAME = "K4PC, K4Mac, Kindle Mobi and Topaz DeDRM" + +# This is where all preferences for this plugin will be stored +# You should always prefix your config file name with plugins/, +# so as to ensure you dont accidentally clobber a calibre config file +dedrmprefs = JSONConfig(JSON_PATH) + +# get prefs from older tools +kindleprefs = JSONConfig(os.path.join(u"plugins", u"K4MobiDeDRM")) +ignobleprefs = JSONConfig(os.path.join(u"plugins", u"ignoble_epub_dedrm")) + +# Set defaults for the prefs +dedrmprefs.defaults['configured'] = False +dedrmprefs.defaults['bandnkeys'] = {} +dedrmprefs.defaults['adeptkeys'] = {} +dedrmprefs.defaults['ereaderkeys'] = {} +dedrmprefs.defaults['kindlekeys'] = {} +dedrmprefs.defaults['pids'] = [] +dedrmprefs.defaults['serials'] = [] + + +class ConfigWidget(QWidget): + def __init__(self, plugin_path): + QWidget.__init__(self) + + self.plugin_path = plugin_path + + # get copy of the prefs from the file + # Otherwise we seem to get a persistent local copy. + self.dedrmprefs = JSONConfig(JSON_PATH) + + self.tempdedrmprefs = {} + self.tempdedrmprefs['bandnkeys'] = self.dedrmprefs['bandnkeys'].copy() + self.tempdedrmprefs['adeptkeys'] = self.dedrmprefs['adeptkeys'].copy() + self.tempdedrmprefs['ereaderkeys'] = self.dedrmprefs['ereaderkeys'].copy() + self.tempdedrmprefs['kindlekeys'] = self.dedrmprefs['kindlekeys'].copy() + self.tempdedrmprefs['pids'] = list(self.dedrmprefs['pids']) + self.tempdedrmprefs['serials'] = list(self.dedrmprefs['serials']) + + # Start Qt Gui dialog layout + layout = QVBoxLayout(self) + self.setLayout(layout) + + help_layout = QHBoxLayout() + layout.addLayout(help_layout) + # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. + help_label = QLabel('Plugin Help', self) + help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) + help_label.setAlignment(Qt.AlignRight) + help_label.linkActivated.connect(self.help_link_activated) + help_layout.addWidget(help_label) + + keys_group_box = QGroupBox(_('Configuration:'), self) + layout.addWidget(keys_group_box) + keys_group_box_layout = QHBoxLayout() + keys_group_box.setLayout(keys_group_box_layout) + + + button_layout = QVBoxLayout() + keys_group_box_layout.addLayout(button_layout) + self.bandn_button = QtGui.QPushButton(self) + self.bandn_button.setToolTip(_(u"Click to manage keys for Barnes and Noble ebooks")) + self.bandn_button.setText(u"Barnes and Noble ebooks") + self.bandn_button.clicked.connect(self.bandn_keys) + self.kindle_serial_button = QtGui.QPushButton(self) + self.kindle_serial_button.setToolTip(_(u"Click to manage eInk Kindle serial numbers for Kindle ebooks")) + self.kindle_serial_button.setText(u"eInk Kindle ebooks") + self.kindle_serial_button.clicked.connect(self.kindle_serials) + self.kindle_key_button = QtGui.QPushButton(self) + self.kindle_key_button.setToolTip(_(u"Click to manage keys for Kindle for Mac/PC ebooks")) + self.kindle_key_button.setText(u"Kindle for Mac/PC ebooks") + self.kindle_key_button.clicked.connect(self.kindle_keys) + self.adept_button = QtGui.QPushButton(self) + self.adept_button.setToolTip(_(u"Click to manage keys for Adobe Digital Editions ebooks")) + self.adept_button.setText(u"Adobe Digital Editions ebooks") + self.adept_button.clicked.connect(self.adept_keys) + self.mobi_button = QtGui.QPushButton(self) + self.mobi_button.setToolTip(_(u"Click to manage PIDs for Mobipocket ebooks")) + self.mobi_button.setText(u"Mobipocket ebooks") + self.mobi_button.clicked.connect(self.mobi_keys) + self.ereader_button = QtGui.QPushButton(self) + self.ereader_button.setToolTip(_(u"Click to manage keys for eReader ebooks")) + self.ereader_button.setText(u"eReader ebooks") + self.ereader_button.clicked.connect(self.ereader_keys) + button_layout.addWidget(self.kindle_serial_button) + button_layout.addWidget(self.bandn_button) + button_layout.addWidget(self.mobi_button) + button_layout.addWidget(self.ereader_button) + button_layout.addWidget(self.adept_button) + button_layout.addWidget(self.kindle_key_button) + + self.resize(self.sizeHint()) + + def kindle_serials(self): + d = dialogs.ManageKeysDialog(self,u"EInk Kindle Serial Number",self.tempdedrmprefs['serials'], dialogs.AddSerialDialog) + d.exec_() + + def kindle_keys(self): + d = dialogs.ManageKeysDialog(self,u"Kindle for Mac and PC Key",self.tempdedrmprefs['kindlekeys'], dialogs.AddKindleDialog, 'k4i') + d.exec_() + + def adept_keys(self): + d = dialogs.ManageKeysDialog(self,u"Adobe Digital Editions Key",self.tempdedrmprefs['adeptkeys'], dialogs.AddAdeptDialog, 'der') + d.exec_() + + def mobi_keys(self): + d = dialogs.ManageKeysDialog(self,u"Mobipocket PID",self.tempdedrmprefs['pids'], dialogs.AddPIDDialog) + d.exec_() + + def bandn_keys(self): + d = dialogs.ManageKeysDialog(self,u"Barnes and Noble Key",self.tempdedrmprefs['bandnkeys'], dialogs.AddBandNKeyDialog, 'b64') + d.exec_() + + def ereader_keys(self): + d = dialogs.ManageKeysDialog(self,u"eReader Key",self.tempdedrmprefs['ereaderkeys'], dialogs.AddEReaderDialog, 'b63') + d.exec_() + + def help_link_activated(self, url): + def get_help_file_resource(): + # Copy the HTML helpfile to the plugin directory each time the + # link is clicked in case the helpfile is updated in newer plugins. + file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name) + with open(file_path,'w') as f: + f.write(self.load_resource(help_file_name)) + return file_path + url = 'file:///' + get_help_file_resource() + open_url(QUrl(url)) + + def save_settings(self): + self.dedrmprefs['bandnkeys'] = self.tempdedrmprefs['bandnkeys'] + self.dedrmprefs['adeptkeys'] = self.tempdedrmprefs['adeptkeys'] + self.dedrmprefs['ereaderkeys'] = self.tempdedrmprefs['ereaderkeys'] + self.dedrmprefs['kindlekeys'] = self.tempdedrmprefs['kindlekeys'] + self.dedrmprefs['pids'] = self.tempdedrmprefs['pids'] + self.dedrmprefs['serials'] = self.tempdedrmprefs['serials'] + self.dedrmprefs['configured'] = True + + def load_resource(self, name): + with ZipFile(self.plugin_path, 'r') as zf: + if name in zf.namelist(): + return zf.read(name) + return "" + +def writeprefs(value = True): + dedrmprefs['configured'] = value + +def addnamedvaluetoprefs(prefkind, keyname, keyvalue): + try: + if keyvalue not in dedrmprefs[prefkind].values(): + # ensure that the keyname is unique + # by adding a number (starting with 2) to the name if it is not + namecount = 1 + newname = keyname + while newname in dedrmprefs[prefkind]: + namecount += 1 + newname = "{0:s}_{1:d}".format(keyname,namecount) + # add to the preferences + dedrmprefs[prefkind][newname] = keyvalue + return (True, newname) + except: + pass + return (False, keyname) + +def addvaluetoprefs(prefkind, prefsvalue): + # ensure the keyvalue isn't already in the preferences + if prefsvalue not in dedrmprefs[prefkind]: + dedrmprefs[prefkind].append(prefsvalue) + return True + return False + +def convertprefs(always = False): + + def parseIgnobleString(keystuff): + userkeys = {} + ar = keystuff.split(':') + for i, keystring in enumerate(ar): + try: + name, ccn = keystring.split(',') + # Generate Barnes & Noble EPUB user key from name and credit card number. + keyname = u"{0}_{1}_{2:d}".format(name.strip(),ccn.strip()[-4:],i+1) + keyvalue = bandn.generate_key(name, ccn) + if keyvalue not in userkeys.values(): + while keyname in dedrmprefs['bandnkeys']: + keyname = keyname + keyname[-1] + userkeys[keyname] = keyvalue + except Exception, e: + print e.args[0] + pass + return userkeys + + def parseeReaderString(keystuff): + userkeys = {} + ar = keystuff.split(':') + for i, keystring in enumerate(ar): + try: + name, cc = keystring.split(',') + # Generate eReader user key from name and credit card number. + keyname = u"{0}_{1}_{2:d}".format(name.strip(),cc.strip()[-4:],i+1) + keyvalue = ereader.getuser_key(name,cc).encode('hex') + if keyvalue not in userkeys.values(): + while keyname in dedrmprefs['ereaderkeys']: + keyname = keyname + keyname[-1] + userkeys[keyname] = keyvalue + except Exception, e: + print e.args[0] + pass + return userkeys + + def parseKindleString(keystuff): + pids = [] + serials = [] + ar = keystuff.split(',') + for keystring in ar: + keystring = str(keystring).strip().replace(" ","") + if len(keystring) == 10 or len(keystring) == 8 and keystring not in pids: + pids.append(keystring) + elif len(keystring) == 16 and keystring[0] == 'B' and keystring not in serials: + serials.append(keystring) + return (pids,serials) + + def addConfigFiles(extension, prefskey, encoding = ''): + # get any files with extension 'extension' in the config dir + files = [f for f in os.listdir(config_dir) if f.endswith(extension)] + try: + priorkeycount = len(dedrmprefs[prefskey]) + for filename in files: + fpath = os.path.join(config_dir, filename) + key = os.path.splitext(filename)[0] + value = open(fpath, 'rb').read() + if encoding is not '': + value = value.encode(encoding) + if value not in dedrmprefs[prefskey].values(): + while key in dedrmprefs[prefskey]: + key = key+key[-1] + dedrmprefs[prefskey][key] = value + #os.remove(fpath) + return len(dedrmprefs[prefskey])-priorkeycount + except IOError: + return -1 + + if (not always) and dedrmprefs['configured']: + # We've already converted old preferences, + # and we're not being forced to do it again, so just return + return + + # initialise + # we must actually set the prefs that are dictionaries and lists + # to empty dictionaries and lists, otherwise we are unable to add to them + # as then it just adds to the (memory only) dedrmprefs.defaults versions! + if dedrmprefs['bandnkeys'] == {}: + dedrmprefs['bandnkeys'] = {} + if dedrmprefs['adeptkeys'] == {}: + dedrmprefs['adeptkeys'] = {} + if dedrmprefs['ereaderkeys'] == {}: + dedrmprefs['ereaderkeys'] = {} + if dedrmprefs['kindlekeys'] == {}: + dedrmprefs['kindlekeys'] = {} + if dedrmprefs['pids'] == []: + dedrmprefs['pids'] = [] + if dedrmprefs['serials'] == []: + dedrmprefs['serials'] = [] + + # get default adobe adept key(s) + priorkeycount = len(dedrmprefs['adeptkeys']) + try: + defaultkeys = adobe.adeptkeys() + except: + defaultkeys = [] + defaultcount = 1 + for keyvalue in defaultkeys: + keyname = u"default_key_{0:d}".format(defaultcount) + keyvaluehex = keyvalue.encode('hex') + if keyvaluehex not in dedrmprefs['adeptkeys'].values(): + while keyname in dedrmprefs['adeptkeys']: + defaultcount += 1 + keyname = u"default_key_{0:d}".format(defaultcount) + dedrmprefs['adeptkeys'][keyname] = keyvaluehex + addedkeycount = len(dedrmprefs['adeptkeys']) - priorkeycount + if addedkeycount > 0: + print u"{0} v{1}: {2:d} Default Adobe Adept {3} found.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + + # get default kindle key(s) + priorkeycount = len(dedrmprefs['kindlekeys']) + try: + defaultkeys = amazon.kindlekeys() + except: + defaultkeys = [] + defaultcount = 1 + for keyvalue in defaultkeys: + keyname = u"default_key_{0:d}".format(defaultcount) + if keyvalue not in dedrmprefs['kindlekeys'].values(): + while keyname in dedrmprefs['kindlekeys']: + defaultcount += 1 + keyname = u"default_key_{0:d}".format(defaultcount) + dedrmprefs['kindlekeys'][keyname] = keyvalue + addedkeycount = len(dedrmprefs['kindlekeys']) - priorkeycount + if addedkeycount > 0: + print u"{0} v{1}: {2:d} Default Kindle for Mac/PC {3} found.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + print u"{0} v{1}: Importing configuration data from old DeDRM plugins".format(PLUGIN_NAME, PLUGIN_VERSION) + + # Handle the old ignoble plugin's customization string by converting the + # old string to stored keys... get that personal data out of plain sight. + from calibre.customize.ui import config + sc = config['plugin_customization'] + val = sc.pop(IGNOBLEPLUGINNAME, None) + if val is not None: + print u"{0} v{1}: Converting old Ignoble plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION) + priorkeycount = len(dedrmprefs['bandnkeys']) + userkeys = parseIgnobleString(str(val)) + for key in userkeys: + value = userkeys[key] + if value not in dedrmprefs['bandnkeys'].values(): + while key in dedrmprefs['bandnkeys']: + key = key+key[-1] + dedrmprefs['bandnkeys'][key] = value + addedkeycount = len(dedrmprefs['bandnkeys'])-priorkeycount + print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from old Ignoble plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + # Handle the old eReader plugin's customization string by converting the + # old string to stored keys... get that personal data out of plain sight. + val = sc.pop(EREADERPLUGINNAME, None) + if val is not None: + print u"{0} v{1}: Converting old eReader plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION) + priorkeycount = len(dedrmprefs['ereaderkeys']) + userkeys = parseeReaderString(str(val)) + for key in userkeys: + value = userkeys[key] + if value not in dedrmprefs['ereaderkeys'].values(): + while key in dedrmprefs['ereaderkeys']: + key = key+key[-1] + dedrmprefs['ereaderkeys'][key] = value + addedkeycount = len(dedrmprefs['ereaderkeys'])-priorkeycount + print u"{0} v{1}: {2:d} eReader {3} imported from old eReader plugin configuration string".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + # get old Kindle plugin configuration string + val = sc.pop(OLDKINDLEPLUGINNAME, None) + if val is not None: + print u"{0} v{1}: Converting old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION) + priorpidcount = len(dedrmprefs['pids']) + priorserialcount = len(dedrmprefs['serials']) + pids, serials = parseKindleString(val) + for pid in pids: + if pid not in dedrmprefs['pids']: + dedrmprefs['pids'].append(pid) + for serial in serials: + if serial not in dedrmprefs['serials']: + dedrmprefs['serials'].append(serial) + addedpidcount = len(dedrmprefs['pids']) - priorpidcount + addedserialcount = len(dedrmprefs['serials']) - priorserialcount + print u"{0} v{1}: {2:d} {3} and {4:d} {5} imported from old Kindle plugin configuration string.".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs", addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers") + # Make the json write all the prefs to disk + writeprefs(False) + + # copy the customisations back into calibre preferences, as we've now removed the nasty plaintext + config['plugin_customization'] = sc + + # get any .b64 files in the config dir + ignoblecount = addConfigFiles('.b64', 'bandnkeys') + if ignoblecount > 0: + print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ignoblecount, u"key file" if ignoblecount==1 else u"key files") + elif ignoblecount < 0: + print u"{0} v{1}: Error reading Barnes & Noble keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION) + # Make the json write all the prefs to disk + writeprefs(False) + + # get any .der files in the config dir + ineptcount = addConfigFiles('.der', 'adeptkeys','hex') + if ineptcount > 0: + print u"{0} v{1}: {2:d} Adobe Adept {3} imported from config folder.".format(PLUGIN_NAME, PLUGIN_VERSION, ineptcount, u"keyfile" if ineptcount==1 else u"keyfiles") + elif ineptcount < 0: + print u"{0} v{1}: Error reading Adobe Adept keyfiles from config directory.".format(PLUGIN_NAME, PLUGIN_VERSION) + # Make the json write all the prefs to disk + writeprefs(False) + + # get ignoble json prefs + if 'keys' in ignobleprefs: + priorkeycount = len(dedrmprefs['bandnkeys']) + for key in ignobleprefs['keys']: + value = ignobleprefs['keys'][key] + if value not in dedrmprefs['bandnkeys'].values(): + while key in dedrmprefs['bandnkeys']: + key = key+key[-1] + dedrmprefs['bandnkeys'][key] = value + addedkeycount = len(dedrmprefs['bandnkeys']) - priorkeycount + # no need to delete old prefs, since they contain no recoverable private data + if addedkeycount > 0: + print u"{0} v{1}: {2:d} Barnes and Noble {3} imported from Ignoble plugin preferences.".format(PLUGIN_NAME, PLUGIN_VERSION, addedkeycount, u"key" if addedkeycount==1 else u"keys") + # Make the json write all the prefs to disk + writeprefs(False) + + # get kindle json prefs + priorpidcount = len(dedrmprefs['pids']) + priorserialcount = len(dedrmprefs['serials']) + if 'pids' in kindleprefs: + pids, serials = parseKindleString(kindleprefs['pids']) + for pid in pids: + if pid not in dedrmprefs['pids']: + dedrmprefs['pids'].append(pid) + if 'serials' in kindleprefs: + pids, serials = parseKindleString(kindleprefs['serials']) + for serial in serials: + if serial not in dedrmprefs['serials']: + dedrmprefs['serials'].append(serial) + addedpidcount = len(dedrmprefs['pids']) - priorpidcount + if addedpidcount > 0: + print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedpidcount, u"PID" if addedpidcount==1 else u"PIDs") + addedserialcount = len(dedrmprefs['serials']) - priorserialcount + if addedserialcount > 0: + print u"{0} v{1}: {2:d} {3} imported from Kindle plugin preferences".format(PLUGIN_NAME, PLUGIN_VERSION, addedserialcount, u"serial number" if addedserialcount==1 else u"serial numbers") + + # Make the json write all the prefs to disk + writeprefs() + print u"{0} v{1}: Finished setting up configuration data.".format(PLUGIN_NAME, PLUGIN_VERSION) diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/convert2xml.py b/DeDRM_calibre_plugin/DeDRM_plugin/convert2xml.py similarity index 98% rename from Calibre_Plugins/K4MobiDeDRM_plugin/convert2xml.py rename to DeDRM_calibre_plugin/DeDRM_plugin/convert2xml.py index c4e23b7..101c45a 100644 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/convert2xml.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/convert2xml.py @@ -264,6 +264,7 @@ class PageParser(object): 'img.color_src' : (1, 'scalar_number', 0, 0), 'img.gridBeginCenter' : (1, 'scalar_number', 0, 0), 'img.gridEndCenter' : (1, 'scalar_number', 0, 0), + 'img.image_type' : (1, 'scalar_number', 0, 0), 'paragraph' : (1, 'snippets', 1, 0), 'paragraph.class' : (1, 'scalar_text', 0, 0), @@ -272,9 +273,9 @@ class PageParser(object): 'paragraph.lastWord' : (1, 'scalar_number', 0, 0), 'paragraph.gridSize' : (1, 'scalar_number', 0, 0), 'paragraph.gridBottomCenter' : (1, 'scalar_number', 0, 0), - 'paragraph.gridTopCenter' : (1, 'scalar_number', 0, 0), - 'paragraph.gridBeginCenter' : (1, 'scalar_number', 0, 0), - 'paragraph.gridEndCenter' : (1, 'scalar_number', 0, 0), + 'paragraph.gridTopCenter' : (1, 'scalar_number', 0, 0), + 'paragraph.gridBeginCenter' : (1, 'scalar_number', 0, 0), + 'paragraph.gridEndCenter' : (1, 'scalar_number', 0, 0), 'word_semantic' : (1, 'snippets', 1, 1), @@ -282,6 +283,10 @@ class PageParser(object): 'word_semantic.class' : (1, 'scalar_text', 0, 0), 'word_semantic.firstWord' : (1, 'scalar_number', 0, 0), 'word_semantic.lastWord' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridBottomCenter' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridTopCenter' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridBeginCenter' : (1, 'scalar_number', 0, 0), + 'word_semantic.gridEndCenter' : (1, 'scalar_number', 0, 0), 'word' : (1, 'snippets', 1, 0), 'word.type' : (1, 'scalar_text', 0, 0), diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/dialogs.py b/DeDRM_calibre_plugin/DeDRM_plugin/dialogs.py new file mode 100644 index 0000000..21c1dad --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/dialogs.py @@ -0,0 +1,719 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +from __future__ import with_statement +__license__ = 'GPL v3' + +# Standard Python modules. +import os, sys, re, hashlib +import json + +from PyQt4.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QListWidget, QListWidgetItem, QAbstractItemView, QLineEdit, QPushButton, QIcon, QGroupBox, QDialog, QDialogButtonBox, QUrl, QString) +from PyQt4 import QtGui + +# calibre modules and constants. +from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url, + choose_dir, choose_files) +from calibre.utils.config import dynamic, config_dir, JSONConfig + +from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION +from calibre_plugins.dedrm.utilities import (uStrCmp, DETAILED_MESSAGE, parseCustString) +from calibre_plugins.dedrm.ignoblekeygen import generate_key as generate_bandn_key +from calibre_plugins.dedrm.erdr2pml import getuser_key as generate_ereader_key +from calibre_plugins.dedrm.adobekey import adeptkeys as retrieve_adept_keys +from calibre_plugins.dedrm.kindlekey import kindlekeys as retrieve_kindle_keys + +class ManageKeysDialog(QDialog): + def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = u""): + QDialog.__init__(self,parent) + self.parent = parent + self.key_type_name = key_type_name + self.plugin_keys = plugin_keys + self.create_key = create_key + self.keyfile_ext = keyfile_ext + self.import_key = (keyfile_ext != u"") + self.binary_file = (key_type_name == u"Adobe Digital Editions Key") + self.json_file = (key_type_name == u"Kindle for Mac and PC Key") + + self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name)) + + # Start Qt Gui dialog layout + layout = QVBoxLayout(self) + self.setLayout(layout) + + help_layout = QHBoxLayout() + layout.addLayout(help_layout) + # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked. + help_label = QLabel('Help', self) + help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) + help_label.setAlignment(Qt.AlignRight) + help_label.linkActivated.connect(self.help_link_activated) + help_layout.addWidget(help_label) + + keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self) + layout.addWidget(keys_group_box) + keys_group_box_layout = QHBoxLayout() + keys_group_box.setLayout(keys_group_box_layout) + + self.listy = QListWidget(self) + self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name)) + self.listy.setSelectionMode(QAbstractItemView.SingleSelection) + self.populate_list() + keys_group_box_layout.addWidget(self.listy) + + button_layout = QVBoxLayout() + keys_group_box_layout.addLayout(button_layout) + self._add_key_button = QtGui.QToolButton(self) + self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name)) + self._add_key_button.setIcon(QIcon(I('plus.png'))) + self._add_key_button.clicked.connect(self.add_key) + button_layout.addWidget(self._add_key_button) + + self._delete_key_button = QtGui.QToolButton(self) + self._delete_key_button.setToolTip(_(u"Delete highlighted key")) + self._delete_key_button.setIcon(QIcon(I('list_remove.png'))) + self._delete_key_button.clicked.connect(self.delete_key) + button_layout.addWidget(self._delete_key_button) + + if type(self.plugin_keys) == dict: + self._rename_key_button = QtGui.QToolButton(self) + self._rename_key_button.setToolTip(_(u"Rename highlighted key")) + self._rename_key_button.setIcon(QIcon(I('edit-select-all.png'))) + self._rename_key_button.clicked.connect(self.rename_key) + button_layout.addWidget(self._rename_key_button) + + self.export_key_button = QtGui.QToolButton(self) + self.export_key_button.setToolTip(u"Save highlighted key to a .{0} file".format(self.keyfile_ext)) + self.export_key_button.setIcon(QIcon(I('save.png'))) + self.export_key_button.clicked.connect(self.export_key) + button_layout.addWidget(self.export_key_button) + spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + button_layout.addItem(spacerItem) + + layout.addSpacing(5) + migrate_layout = QHBoxLayout() + layout.addLayout(migrate_layout) + if self.import_key: + migrate_layout.setAlignment(Qt.AlignJustify) + self.migrate_btn = QPushButton(u"Import Existing Keyfiles", self) + self.migrate_btn.setToolTip(u"Import *.{0} files (created using other tools).".format(self.keyfile_ext)) + self.migrate_btn.clicked.connect(self.migrate_wrapper) + migrate_layout.addWidget(self.migrate_btn) + migrate_layout.addStretch() + self.button_box = QDialogButtonBox(QDialogButtonBox.Close) + self.button_box.rejected.connect(self.close) + migrate_layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + def populate_list(self): + if type(self.plugin_keys) == dict: + for key in self.plugin_keys.keys(): + self.listy.addItem(QListWidgetItem(key)) + else: + for key in self.plugin_keys: + self.listy.addItem(QListWidgetItem(key)) + + def add_key(self): + d = self.create_key(self) + d.exec_() + + if d.result() != d.Accepted: + # New key generation cancelled. + return + new_key_value = d.key_value + if type(self.plugin_keys) == dict: + if new_key_value in self.plugin_keys.values(): + old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0] + info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name), + u"The new {1} is the same as the existing {1} named {0} and has not been added.".format(old_key_name,self.key_type_name), show=True) + return + self.plugin_keys[d.key_name] = new_key_value + else: + if new_key_value in self.plugin_keys: + info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name), + u"This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True) + return + + self.plugin_keys.append(d.key_value) + self.listy.clear() + self.populate_list() + + def rename_key(self): + if not self.listy.currentItem(): + errmsg = u"No {0} selected to rename. Highlight a keyfile first.".format(self.key_type_name) + r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + return + + d = RenameKeyDialog(self) + d.exec_() + + if d.result() != d.Accepted: + # rename cancelled or moot. + return + keyname = unicode(self.listy.currentItem().text().toUtf8(),'utf8') + if not question_dialog(self, "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to rename the {2} named {0} to {1}?".format(keyname,d.key_name,self.key_type_name), show_copy_button=False, default_yes=False): + return + self.plugin_keys[d.key_name] = self.plugin_keys[keyname] + del self.plugin_keys[keyname] + + self.listy.clear() + self.populate_list() + + def delete_key(self): + if not self.listy.currentItem(): + return + keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8') + if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to delete the {1} {0}?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False): + return + if type(self.plugin_keys) == dict: + del self.plugin_keys[keyname] + else: + self.plugin_keys.remove(keyname) + + self.listy.clear() + self.populate_list() + + def help_link_activated(self, url): + def get_help_file_resource(): + # Copy the HTML helpfile to the plugin directory each time the + # link is clicked in case the helpfile is updated in newer plugins. + help_file_name = u"{0}_{1}_Help.htm".format(PLUGIN_NAME, self.key_type_name) + file_path = os.path.join(config_dir, u"plugins", u"DeDRM", u"help", help_file_name) + with open(file_path,'w') as f: + f.write(self.parent.load_resource(help_file_name)) + return file_path + url = 'file:///' + get_help_file_resource() + open_url(QUrl(url)) + + def migrate_files(self): + dynamic[PLUGIN_NAME + u"config_dir"] = config_dir + files = choose_files(self, PLUGIN_NAME + u"config_dir", + u"Select {0} files to import".format(self.key_type_name), [(u"{0} files".format(self.key_type_name), [self.keyfile_ext])], False) + counter = 0 + skipped = 0 + if files: + for filename in files: + fpath = os.path.join(config_dir, filename) + filename = os.path.basename(filename) + new_key_name = os.path.splitext(os.path.basename(filename))[0] + with open(fpath,'rb') as keyfile: + new_key_value = keyfile.read() + if self.binary_file: + new_key_value = new_key_value.encode('hex') + elif self.json_file: + new_key_value = json.loads(new_key_value) + match = False + for key in self.plugin_keys.keys(): + if uStrCmp(new_key_name, key, True): + skipped += 1 + msg = u"A key with the name {0} already exists!\nSkipping key file {1}.\nRename the existing key and import again".format(new_key_name,filename) + inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(msg), show_copy_button=False, show=True) + match = True + break + if not match: + if new_key_value in self.plugin_keys.values(): + old_key_name = [name for name, value in self.plugin_keys.iteritems() if value == new_key_value][0] + skipped += 1 + info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + u"The key in file {0} is the same as the existing key {1} and has been skipped.".format(filename,old_key_name), show_copy_button=False, show=True) + else: + counter += 1 + self.plugin_keys[new_key_name] = new_key_value + + msg = u"" + if counter+skipped > 1: + if counter > 0: + msg += u"Imported {0:d} key {1}. ".format(counter, u"file" if counter == 1 else u"files") + if skipped > 0: + msg += u"Skipped {0:d} key {1}.".format(skipped, u"file" if counter == 1 else u"files") + inf = info_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(msg), show_copy_button=False, show=True) + return counter > 0 + + def migrate_wrapper(self): + if self.migrate_files(): + self.listy.clear() + self.populate_list() + + def export_key(self): + if not self.listy.currentItem(): + errmsg = u"No keyfile selected to export. Highlight a keyfile first." + r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + return + filter = QString(u"{0} Files (*.{1})".format(self.key_type_name, self.keyfile_ext)) + keyname = unicode(self.listy.currentItem().text().toUtf8(), 'utf8') + if dynamic.get(PLUGIN_NAME + 'save_dir'): + defaultname = os.path.join(dynamic.get(PLUGIN_NAME + 'save_dir'), u"{0}.{1}".format(keyname , self.keyfile_ext)) + else: + defaultname = os.path.join(os.path.expanduser('~'), u"{0}.{1}".format(keyname , self.keyfile_ext)) + filename = unicode(QtGui.QFileDialog.getSaveFileName(self, u"Save {0} File as...".format(self.key_type_name), defaultname, + u"{0} Files (*.{1})".format(self.key_type_name,self.keyfile_ext), filter)) + if filename: + dynamic[PLUGIN_NAME + 'save_dir'] = os.path.split(filename)[0] + with file(filename, 'w') as fname: + if self.binary_file: + fname.write(self.plugin_keys[keyname].decode('hex')) + elif self.json_file: + fname.write(json.dumps(self.plugin_keys[keyname])) + else: + fname.write(self.plugin_keys[keyname]) + + + + +class RenameKeyDialog(QDialog): + def __init__(self, parent=None,): + print repr(self), repr(parent) + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle("{0} {1}: Rename {0}".format(PLUGIN_NAME, PLUGIN_VERSION, parent.key_type_name)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox('', self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + data_group_box_layout.addWidget(QLabel('New Key Name:', self)) + self.key_ledit = QLineEdit(self.parent.listy.currentItem().text(), self) + self.key_ledit.setToolTip(u"Enter a new name for this existing {0}.".format(parent.key_type_name)) + data_group_box_layout.addWidget(self.key_ledit) + + layout.addSpacing(20) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + def accept(self): + if self.key_ledit.text().isEmpty() or unicode(self.key_ledit.text()).isspace(): + errmsg = u"Key name field cannot be empty!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + if len(self.key_ledit.text()) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + if uStrCmp(self.key_ledit.text(), self.parent.listy.currentItem().text()): + # Same exact name ... do nothing. + return QDialog.reject(self) + for k in self.parent.plugin_keys.keys(): + if (uStrCmp(self.key_ledit.text(), k, True) and + not uStrCmp(k, self.parent.listy.currentItem().text(), True)): + errmsg = u"The key name {0} is already being used.".format(self.key_ledit.text()) + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), + _(errmsg), show=True, show_copy_button=False) + QDialog.accept(self) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + + + + + + + +class AddBandNKeyDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Create New Barnes & Noble Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(_(u"

Enter an identifying name for this new key.

" + + u"

It should be something that will help you remember " + + u"what personal information was used to create it.")) + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + name_group = QHBoxLayout() + data_group_box_layout.addLayout(name_group) + name_group.addWidget(QLabel(u"Your Name:", self)) + self.name_ledit = QLineEdit(u"", self) + self.name_ledit.setToolTip(_(u"

Enter your name as it appears in your B&N " + + u"account or on your credit card.

" + + u"

It will only be used to generate this " + + u"one-time key and won\'t be stored anywhere " + + u"in calibre or on your computer.

" + + u"

(ex: Jonathan Smith)")) + name_group.addWidget(self.name_ledit) + name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self) + name_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(name_disclaimer_label) + + ccn_group = QHBoxLayout() + data_group_box_layout.addLayout(ccn_group) + ccn_group.addWidget(QLabel(u"Credit Card#:", self)) + self.cc_ledit = QLineEdit(u"", self) + self.cc_ledit.setToolTip(_(u"

Enter the full credit card number on record " + + u"in your B&N account.

" + + u"

No spaces or dashes... just the numbers. " + + u"This number will only be used to generate this " + + u"one-time key and won\'t be stored anywhere in " + + u"calibre or on your computer.")) + ccn_group.addWidget(self.cc_ledit) + ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self) + ccn_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(ccn_disclaimer_label) + layout.addSpacing(10) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return generate_bandn_key(self.user_name,self.cc_number) + + @property + def user_name(self): + return unicode(self.name_ledit.text().toUtf8(), 'utf8').strip().lower().replace(' ','') + + @property + def cc_number(self): + return unicode(self.cc_ledit.text().toUtf8(), 'utf8').strip().replace(' ', '').replace('-','') + + + def accept(self): + if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if not self.cc_number.isdigit(): + errmsg = u"Numbers only in the credit card number field!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + +class AddEReaderDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Create New eReader Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"

Enter an identifying name for this new key.\nIt should be something that will help you remember what personal information was used to create it.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + name_group = QHBoxLayout() + data_group_box_layout.addLayout(name_group) + name_group.addWidget(QLabel(u"Your Name:", self)) + self.name_ledit = QLineEdit(u"", self) + self.name_ledit.setToolTip(u"Enter the name for this eReader key, usually the name on your credit card.\nIt will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.\n(ex: Mr Jonathan Q Smith)") + name_group.addWidget(self.name_ledit) + name_disclaimer_label = QLabel(_(u"(Will not be saved in configuration data)"), self) + name_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(name_disclaimer_label) + + ccn_group = QHBoxLayout() + data_group_box_layout.addLayout(ccn_group) + ccn_group.addWidget(QLabel(u"Credit Card#:", self)) + self.cc_ledit = QLineEdit(u"", self) + self.cc_ledit.setToolTip(u"

Enter the last 8 digits of credit card number for this eReader key.\nThey will only be used to generate this one-time key and won\'t be stored anywhere in calibre or on your computer.") + ccn_group.addWidget(self.cc_ledit) + ccn_disclaimer_label = QLabel(_('(Will not be saved in configuration data)'), self) + ccn_disclaimer_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(ccn_disclaimer_label) + layout.addSpacing(10) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return generate_ereader_key(self.user_name,self.cc_number).encode('hex') + + @property + def user_name(self): + return unicode(self.name_ledit.text().toUtf8(), 'utf8').strip().lower().replace(' ','') + + @property + def cc_number(self): + return unicode(self.cc_ledit.text().toUtf8(), 'utf8').strip().replace(' ', '').replace('-','') + + + def accept(self): + if len(self.key_name) == 0 or len(self.user_name) == 0 or len(self.cc_number) == 0 or self.key_name.isspace() or self.user_name.isspace() or self.cc_number.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if not self.cc_number.isdigit(): + errmsg = u"Numbers only in the credit card number field!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddAdeptDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Getting Default Adobe Digital Editions Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + try: + self.default_key = retrieve_adept_keys()[0] + except: + self.default_key = u"" + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + + if len(self.default_key)>0: + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"

Enter an identifying name for the current default Adobe Digital Editions key.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + self.button_box.accepted.connect(self.accept) + else: + default_key_error = QLabel(u"The default encryption key for Adobe Digital Editions could not be found.", self) + default_key_error.setAlignment(Qt.AlignHCenter) + layout.addWidget(default_key_error) + # if no default, bot buttons do the same + self.button_box.accepted.connect(self.reject) + + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return self.default_key.encode('hex') + + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddKindleDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Getting Default Kindle for Mac/PC Key".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + try: + self.default_key = retrieve_kindle_keys()[0] + except: + self.default_key = u"" + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + + if len(self.default_key)>0: + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"Unique Key Name:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"

Enter an identifying name for the current default Kindle for Mac/PC key.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + self.button_box.accepted.connect(self.accept) + else: + default_key_error = QLabel(u"The default encryption key for Kindle for Mac/PC could not be found.", self) + default_key_error.setAlignment(Qt.AlignHCenter) + layout.addWidget(default_key_error) + # if no default, bot buttons do the same + self.button_box.accepted.connect(self.reject) + + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return self.default_key + + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"All fields are required!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) < 4: + errmsg = u"Key name must be at least 4 characters long!" + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddSerialDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Add New EInk Kindle Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"EInk Kindle Serial Number:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"Enter an eInk Kindle serial number. EInk Kindle serial numbers are 16 characters long and usually start with a 'B' or a '9'. Kindle Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"Please enter an eInk Kindle Serial Number or click Cancel in the dialog." + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) != 16: + errmsg = u"EInk Kindle Serial Numbers must be 16 characters long. This is {0:d} characters long.".format(len(self.key_name)) + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + +class AddPIDDialog(QDialog): + def __init__(self, parent=None,): + QDialog.__init__(self, parent) + self.parent = parent + self.setWindowTitle(u"{0} {1}: Add New Mobipocket PID".format(PLUGIN_NAME, PLUGIN_VERSION)) + layout = QVBoxLayout(self) + self.setLayout(layout) + + data_group_box = QGroupBox(u"", self) + layout.addWidget(data_group_box) + data_group_box_layout = QVBoxLayout() + data_group_box.setLayout(data_group_box_layout) + + key_group = QHBoxLayout() + data_group_box_layout.addLayout(key_group) + key_group.addWidget(QLabel(u"PID:", self)) + self.key_ledit = QLineEdit("", self) + self.key_ledit.setToolTip(u"Enter a Mobipocket PID. Mobipocket PIDs are 8 or 10 characters long. Mobipocket PIDs are case-sensitive, so be sure to enter the upper and lower case letters unchanged.") + key_group.addWidget(self.key_ledit) + key_label = QLabel(_(''), self) + key_label.setAlignment(Qt.AlignHCenter) + data_group_box_layout.addWidget(key_label) + + self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.button_box.accepted.connect(self.accept) + self.button_box.rejected.connect(self.reject) + layout.addWidget(self.button_box) + + self.resize(self.sizeHint()) + + @property + def key_name(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + @property + def key_value(self): + return unicode(self.key_ledit.text().toUtf8(), 'utf8').strip() + + def accept(self): + if len(self.key_name) == 0 or self.key_name.isspace(): + errmsg = u"Please enter a Mobipocket PID or click Cancel in the dialog." + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + if len(self.key_name) != 8 and len(self.key_name) != 10: + errmsg = u"Mobipocket PIDs must be 8 or 10 characters long. This is {0:d} characters long.".format(len(self.key_name)) + return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False) + QDialog.accept(self) + + diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/encodebase64.py b/DeDRM_calibre_plugin/DeDRM_plugin/encodebase64.py new file mode 100644 index 0000000..6bb8c37 --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/encodebase64.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# base64.py, version 1.0 +# Copyright © 2010 Apprentice Alf + +# Released under the terms of the GNU General Public Licence, version 3 or +# later. + +# Revision history: +# 1 - Initial release. To allow Applescript to do base64 encoding + +""" +Provide base64 encoding. +""" + +from __future__ import with_statement + +__license__ = 'GPL v3' + +import sys +import os +import base64 + +def usage(progname): + print "Applies base64 encoding to the supplied file, sending to standard output" + print "Usage:" + print " %s " % progname + +def cli_main(argv=sys.argv): + progname = os.path.basename(argv[0]) + + if len(argv)<2: + usage(progname) + sys.exit(2) + + keypath = argv[1] + with open(keypath, 'rb') as f: + keyder = f.read() + print keyder.encode('base64') + return 0 + + +if __name__ == '__main__': + sys.exit(cli_main()) diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/epubtest.py b/DeDRM_calibre_plugin/DeDRM_plugin/epubtest.py new file mode 100644 index 0000000..d91624f --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/epubtest.py @@ -0,0 +1,169 @@ +#!/usr/bin/python +# +# This is a python script. You need a Python interpreter to run it. +# For example, ActiveState Python, which exists for windows. +# +# Changelog drmcheck +# 1.00 - Initial version, with code from various other scripts +# 1.01 - Moved authorship announcement to usage section. +# +# Changelog epubtest +# 1.00 - Cut to epubtest.py, testing ePub files only by Apprentice Alf +# +# Written in 2011 by Paul Durrant +# Released with unlicense. See http://unlicense.org/ +# +############################################################################# +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +############################################################################# +# +# It's still polite to give attribution if you do reuse this code. +# + +from __future__ import with_statement + +__version__ = '1.00' + +import sys, struct, os +import zlib +import zipfile +import xml.etree.ElementTree as etree + +NSMAP = {'adept': 'http://ns.adobe.com/adept', + 'enc': 'http://www.w3.org/2001/04/xmlenc#'} + +# 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) + +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] + +_FILENAME_LEN_OFFSET = 26 +_EXTRA_LEN_OFFSET = 28 +_FILENAME_OFFSET = 30 +_MAX_SIZE = 64 * 1024 + + +def uncompress(cmpdata): + dc = zlib.decompressobj(-15) + data = '' + while len(cmpdata) > 0: + if len(cmpdata) > _MAX_SIZE : + newdata = cmpdata[0:_MAX_SIZE] + cmpdata = cmpdata[_MAX_SIZE:] + else: + newdata = cmpdata + cmpdata = '' + newdata = dc.decompress(newdata) + unprocessed = dc.unconsumed_tail + if len(unprocessed) == 0: + newdata += dc.flush() + data += newdata + cmpdata += unprocessed + unprocessed = '' + return data + +def getfiledata(file, zi): + # get file name length and exta data length to find start of file data + local_header_offset = zi.header_offset + + file.seek(local_header_offset + _FILENAME_LEN_OFFSET) + leninfo = file.read(2) + local_name_length, = struct.unpack(' -# Modified 2010–2012 by some_updates, DiapDealer and Apprentice Alf +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf # Windows users: Before running this program, you must first install Python 2.6 # from and PyCrypto from @@ -32,20 +32,21 @@ from __future__ import with_statement # 3.5 - Fix for potential problem with PyCrypto # 3.6 - Revised to allow use in calibre plugins to eliminate need for duplicate code # 3.7 - Tweaked to match ineptepub more closely +# 3.8 - Fixed to retain zip file metadata (e.g. file modification date) """ Decrypt Barnes & Noble encrypted ePub books. """ __license__ = 'GPL v3' -__version__ = "3.7" +__version__ = "3.8" import sys import os import traceback import zlib import zipfile -from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED +from zipfile import ZipInfo, ZipFile, ZIP_STORED, ZIP_DEFLATED from contextlib import closing import xml.etree.ElementTree as etree @@ -200,13 +201,6 @@ META_NAMES = ('mimetype', 'META-INF/rights.xml', 'META-INF/encryption.xml') NSMAP = {'adept': 'http://ns.adobe.com/adept', 'enc': 'http://www.w3.org/2001/04/xmlenc#'} -class ZipInfo(zipfile.ZipInfo): - def __init__(self, *args, **kwargs): - if 'compress_type' in kwargs: - compress_type = kwargs.pop('compress_type') - super(ZipInfo, self).__init__(*args, **kwargs) - self.compress_type = compress_type - class Decryptor(object): def __init__(self, bookkey, encryption): enc = lambda tag: '{%s}%s' % (NSMAP['enc'], tag) @@ -282,11 +276,40 @@ def decryptBook(keyb64, inpath, outpath): decryptor = Decryptor(bookkey[-16:], encryption) kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: - zi = ZipInfo('mimetype', compress_type=ZIP_STORED) + zi = ZipInfo('mimetype') + zi.compress_type=ZIP_STORED + try: + # if the mimetype is present, get its info, including time-stamp + oldzi = inf.getinfo('mimetype') + # copy across fields to be preserved + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass outf.writestr(zi, inf.read('mimetype')) for path in namelist: data = inf.read(path) - outf.writestr(path, decryptor.decrypt(path, data)) + zi = ZipInfo(path) + zi.compress_type=ZIP_DEFLATED + try: + # get the file info, including time-stamp + oldzi = inf.getinfo(path) + # copy across useful fields + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass + outf.writestr(zi, decryptor.decrypt(path, data)) except: print u"Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc()) return 2 diff --git a/Calibre_Plugins/ignobleepub_plugin/plugin-import-name-ignobleepub.txt b/DeDRM_calibre_plugin/DeDRM_plugin/ignoblekeygen.py similarity index 92% rename from Calibre_Plugins/ignobleepub_plugin/plugin-import-name-ignobleepub.txt rename to DeDRM_calibre_plugin/DeDRM_plugin/ignoblekeygen.py index f25359c..ec78e65 100644 --- a/Calibre_Plugins/ignobleepub_plugin/plugin-import-name-ignobleepub.txt +++ b/DeDRM_calibre_plugin/DeDRM_plugin/ignoblekeygen.py @@ -4,21 +4,23 @@ from __future__ import with_statement # ignoblekeygen.pyw, version 2.5 -# Copyright © 2009-2010 by i♥cabbages +# Copyright © 2009-2010 i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Modified 2010–2012 by some_updates, DiapDealer and Apprentice Alf +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf -# Windows users: Before running this program, you must first install Python 2.6 -# from and PyCrypto from -# (make sure to -# install the version for Python 2.6). Save this script file as -# ignoblekeygen.pyw and double-click on it to run it. +# Windows users: Before running this program, you must first install Python. +# We recommend ActiveState Python 2.7.X for Windows (x86) from +# http://www.activestate.com/activepython/downloads. +# You must also install PyCrypto from +# http://www.voidspace.org.uk/python/modules.shtml#pycrypto +# (make certain to install the version for Python 2.7). +# Then save this script file as ignoblekeygen.pyw and double-click on it to run it. # # Mac OS X users: Save this script file as ignoblekeygen.pyw. You can run this -# program from the command line (pythonw ignoblekeygen.pyw) or by double-clicking +# program from the command line (python ignoblekeygen.pyw) or by double-clicking # it when it has been associated with PythonLauncher. # Revision history: @@ -58,8 +60,11 @@ class SafeUnbuffered: def __getattr__(self, attr): return getattr(self.stream, attr) -iswindows = sys.platform.startswith('win') -isosx = sys.platform.startswith('darwin') +try: + from calibre.constants import iswindows, isosx +except: + iswindows = sys.platform.startswith('win') + isosx = sys.platform.startswith('darwin') def unicode_argv(): if iswindows: @@ -68,8 +73,8 @@ def unicode_argv(): # 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 '?'. - + # characters with '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 from ctypes import POINTER, byref, cdll, c_int, windll from ctypes.wintypes import LPCWSTR, LPWSTR diff --git a/Calibre_Plugins/ineptepub_plugin/ineptepub.py b/DeDRM_calibre_plugin/DeDRM_plugin/ineptepub.py similarity index 91% rename from Calibre_Plugins/ineptepub_plugin/ineptepub.py rename to DeDRM_calibre_plugin/DeDRM_plugin/ineptepub.py index 48b7727..98a134e 100644 --- a/Calibre_Plugins/ineptepub_plugin/ineptepub.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/ineptepub.py @@ -3,13 +3,13 @@ from __future__ import with_statement -# ineptepub.pyw, version 5.8 +# ineptepub.pyw, version 5.9 # Copyright © 2009-2010 by i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 # -# Modified 2010–2012 by some_updates, DiapDealer and Apprentice Alf +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf # Windows users: Before running this program, you must first install Python 2.6 # from and PyCrypto from @@ -34,20 +34,21 @@ from __future__ import with_statement # 5.6 - Modify interface to allow use with import # 5.7 - Fix for potential problem with PyCrypto # 5.8 - Revised to allow use in calibre plugins to eliminate need for duplicate code +# 5.9 - Fixed to retain zip file metadata (e.g. file modification date) """ Decrypt Adobe Digital Editions encrypted ePub books. """ __license__ = 'GPL v3' -__version__ = "5.8" +__version__ = "5.9" import sys import os import traceback import zlib import zipfile -from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED +from zipfile import ZipInfo, ZipFile, ZIP_STORED, ZIP_DEFLATED from contextlib import closing import xml.etree.ElementTree as etree @@ -340,13 +341,6 @@ META_NAMES = ('mimetype', 'META-INF/rights.xml', 'META-INF/encryption.xml') NSMAP = {'adept': 'http://ns.adobe.com/adept', 'enc': 'http://www.w3.org/2001/04/xmlenc#'} -class ZipInfo(zipfile.ZipInfo): - def __init__(self, *args, **kwargs): - if 'compress_type' in kwargs: - compress_type = kwargs.pop('compress_type') - super(ZipInfo, self).__init__(*args, **kwargs) - self.compress_type = compress_type - class Decryptor(object): def __init__(self, bookkey, encryption): enc = lambda tag: '{%s}%s' % (NSMAP['enc'], tag) @@ -424,11 +418,40 @@ def decryptBook(userkey, inpath, outpath): decryptor = Decryptor(bookkey[-16:], encryption) kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: - zi = ZipInfo('mimetype', compress_type=ZIP_STORED) + zi = ZipInfo('mimetype') + zi.compress_type=ZIP_STORED + try: + # if the mimetype is present, get its info, including time-stamp + oldzi = inf.getinfo('mimetype') + # copy across fields to be preserved + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass outf.writestr(zi, inf.read('mimetype')) for path in namelist: data = inf.read(path) - outf.writestr(path, decryptor.decrypt(path, data)) + zi = ZipInfo(path) + zi.compress_type=ZIP_DEFLATED + try: + # get the file info, including time-stamp + oldzi = inf.getinfo(path) + # copy across useful fields + zi.date_time = oldzi.date_time + zi.comment = oldzi.comment + zi.extra = oldzi.extra + zi.internal_attr = oldzi.internal_attr + # external attributes are dependent on the create system, so copy both. + zi.external_attr = oldzi.external_attr + zi.create_system = oldzi.create_system + except: + pass + outf.writestr(zi, decryptor.decrypt(path, data)) except: print u"Could not decrypt {0:s} because of an exception:\n{1:s}".format(os.path.basename(inpath), traceback.format_exc()) return 2 diff --git a/Calibre_Plugins/ineptpdf_plugin/ineptpdf.py b/DeDRM_calibre_plugin/DeDRM_plugin/ineptpdf.py similarity index 100% rename from Calibre_Plugins/ineptpdf_plugin/ineptpdf.py rename to DeDRM_calibre_plugin/DeDRM_plugin/ineptpdf.py diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/k4mobidedrm.py b/DeDRM_calibre_plugin/DeDRM_plugin/k4mobidedrm.py similarity index 86% rename from Calibre_Plugins/K4MobiDeDRM_plugin/k4mobidedrm.py rename to DeDRM_calibre_plugin/DeDRM_plugin/k4mobidedrm.py index 70ed898..1ae5c88 100644 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/k4mobidedrm.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/k4mobidedrm.py @@ -51,8 +51,10 @@ from __future__ import with_statement # 4.8 - Much better unicode handling, matching the updated inept and ignoble scripts # - Moved back into plugin, __init__ in plugin now only contains plugin code. # 4.9 - Missed some invalid characters in cleanup_name +# 5.0 - Extraction of info from Kindle for PC/Mac moved into kindlekey.py +# - tweaked GetDecryptedBook interface to leave passed parameters unchanged -__version__ = '4.9' +__version__ = '5.0' import sys, os, re @@ -62,6 +64,7 @@ import re import traceback import time import htmlentitydefs +import json class DrmException(Exception): pass @@ -72,9 +75,9 @@ else: inCalibre = False if inCalibre: - from calibre_plugins.k4mobidedrm import mobidedrm - from calibre_plugins.k4mobidedrm import topazextract - from calibre_plugins.k4mobidedrm import kgenpids + from calibre_plugins.dedrm import mobidedrm + from calibre_plugins.dedrm import topazextract + from calibre_plugins.dedrm import kgenpids else: import mobidedrm import topazextract @@ -180,13 +183,13 @@ def unescape(text): return text # leave as is return re.sub(u"&#?\w+;", fixup, text) -def GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime = time.time()): +def GetDecryptedBook(infile, kDatabases, serials, pids, starttime = time.time()): # handle the obvious cases at the beginning if not os.path.isfile(infile): raise DRMException (u"Input file does not exist.") mobi = True - magic3 = file(infile,'rb').read(3) + magic3 = open(infile,'rb').read(3) if magic3 == 'TPZ': mobi = False @@ -198,13 +201,15 @@ def GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime = time.time()) bookname = unescape(mb.getBookTitle()) print u"Decrypting {1} ebook: {0}".format(bookname, mb.getBookType()) + # copy list of pids + totalpids = list(pids) # extend PID list with book-specific PIDs md1, md2 = mb.getPIDMetaInfo() - pids.extend(kgenpids.getPidList(md1, md2, serials, kInfoFiles)) - print u"Found {1:d} keys to try after {0:.1f} seconds".format(time.time()-starttime, len(pids)) + totalpids.extend(kgenpids.getPidList(md1, md2, serials, kDatabases)) + print u"Found {1:d} keys to try after {0:.1f} seconds".format(time.time()-starttime, len(totalpids)) try: - mb.processBook(pids) + mb.processBook(totalpids) except: mb.cleanup raise @@ -213,12 +218,24 @@ def GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime = time.time()) return mb -# infile, outdir and kInfoFiles should be unicode strings -def decryptBook(infile, outdir, kInfoFiles, serials, pids): +# kDatabaseFiles is a list of files created by kindlekey +def decryptBook(infile, outdir, kDatabaseFiles, serials, pids): starttime = time.time() - print "Starting decryptBook routine." + kDatabases = [] + for dbfile in kDatabaseFiles: + kindleDatabase = {} + try: + with open(dbfile, 'r') as keyfilein: + kindleDatabase = json.loads(keyfilein.read()) + kDatabases.append([dbfile,kindleDatabase]) + except Exception, e: + print u"Error getting database from file {0:s}: {1:s}".format(dbfile,e) + traceback.print_exc() + + + try: - book = GetDecryptedBook(infile, kInfoFiles, serials, pids, starttime) + book = GetDecryptedBook(infile, kDatabases, serials, pids, starttime) except Exception, e: print u"Error decrypting book after {1:.1f} seconds: {0}".format(e.args[0],time.time()-starttime) traceback.print_exc() @@ -254,14 +271,14 @@ def decryptBook(infile, outdir, kInfoFiles, serials, pids): def usage(progname): print u"Removes DRM protection from Mobipocket, Amazon KF8, Amazon Print Replica and Amazon Topaz ebooks" print u"Usage:" - print u" {0} [-k ] [-p ] [-s ] ".format(progname) + print u" {0} [-k ] [-p ] [-s ] ".format(progname) # # Main # def cli_main(argv=unicode_argv()): progname = os.path.basename(argv[0]) - print u"K4MobiDeDrm v{0}.\nCopyright © 2008-2012 The Dark Reverser et al.".format(__version__) + print u"K4MobiDeDrm v{0}.\nCopyright © 2008-2013 The Dark Reverser et al.".format(__version__) try: opts, args = getopt.getopt(sys.argv[1:], "k:p:s:") @@ -275,7 +292,7 @@ def cli_main(argv=unicode_argv()): infile = args[0] outdir = args[1] - kInfoFiles = [] + kDatabaseFiles = [] serials = [] pids = [] @@ -283,7 +300,7 @@ def cli_main(argv=unicode_argv()): if o == "-k": if a == None : raise DrmException("Invalid parameter for -k") - kInfoFiles.append(a) + kDatabaseFiles.append(a) if o == "-p": if a == None : raise DrmException("Invalid parameter for -p") @@ -296,7 +313,7 @@ def cli_main(argv=unicode_argv()): # try with built in Kindle Info files if not on Linux k4 = not sys.platform.startswith('linux') - return decryptBook(infile, outdir, kInfoFiles, serials, pids) + return decryptBook(infile, outdir, kDatabaseFiles, serials, pids) if __name__ == '__main__': diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/kgenpids.py b/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py similarity index 79% rename from Calibre_Plugins/K4MobiDeDRM_plugin/kgenpids.py rename to DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py index c5de9b9..dd88797 100644 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/kgenpids.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/kgenpids.py @@ -8,6 +8,7 @@ import binascii import zlib import re from struct import pack, unpack, unpack_from +import traceback class DrmException(Exception): pass @@ -16,22 +17,6 @@ global charMap1 global charMap3 global charMap4 -if 'calibre' in sys.modules: - inCalibre = True - from calibre.constants import iswindows, isosx - if iswindows: - from calibre_plugins.k4mobidedrm.k4pcutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString - if isosx: - from calibre_plugins.k4mobidedrm.k4mutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString -else: - inCalibre = False - iswindows = sys.platform.startswith('win') - isosx = sys.platform.startswith('darwin') - if iswindows: - from k4pcutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString - if isosx: - from k4mutils import getKindleInfoFiles, getDBfromFile, GetUserName, GetIDString - charMap1 = 'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' charMap3 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' @@ -178,6 +163,9 @@ def pidFromSerial(s, l): def getKindlePids(rec209, token, serialnum): pids=[] + if isinstance(serialnum,unicode): + serialnum = serialnum.encode('ascii') + # Compute book PID pidHash = SHA1(serialnum+rec209+token) bookPID = encodePID(pidHash) @@ -196,35 +184,32 @@ def getKindlePids(rec209, token, serialnum): keynames = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber'] -def getK4Pids(rec209, token, kInfoFile): +def getK4Pids(rec209, token, kindleDatabase): global charMap1 - kindleDatabase = None pids = [] - try: - kindleDatabase = getDBfromFile(kInfoFile) - except Exception, message: - print(message) - kindleDatabase = None - pass - - if kindleDatabase == None : - return pids try: # Get the Mazama Random number - MazamaRandomNumber = kindleDatabase['MazamaRandomNumber'] + MazamaRandomNumber = (kindleDatabase[1])['MazamaRandomNumber'].decode('hex').encode('ascii') # Get the kindle account token - kindleAccountToken = kindleDatabase['kindle.account.tokens'] + kindleAccountToken = (kindleDatabase[1])['kindle.account.tokens'].decode('hex').encode('ascii') + + # Get the IDString used to decode the Kindle Info file + IDString = (kindleDatabase[1])['IDString'].decode('hex').encode('ascii') + + # Get the UserName stored when the Kindle Info file was decoded + UserName = (kindleDatabase[1])['UserName'].decode('hex').encode('ascii') + except KeyError: - print u"Keys not found in {0}".format(os.path.basename(kInfoFile)) + print u"Keys not found in the database {0}.".format(kindleDatabase[0]) return pids # Get the ID string used - encodedIDString = encodeHash(GetIDString(),charMap1) + encodedIDString = encodeHash(IDString,charMap1) # Get the current user name - encodedUsername = encodeHash(GetUserName(),charMap1) + encodedUsername = encodeHash(UserName,charMap1) # concat, hash and encode to calculate the DSN DSN = encode(SHA1(MazamaRandomNumber+encodedIDString+encodedUsername),charMap1) @@ -257,22 +242,26 @@ def getK4Pids(rec209, token, kInfoFile): return pids -def getPidList(md1, md2, serials=[], kInfoFiles=[]): +def getPidList(md1, md2, serials=[], kDatabases=[]): pidlst = [] - if kInfoFiles is None: - kInfoFiles = [] + + if kDatabases is None: + kDatabases = [] if serials is None: serials = [] - if iswindows or isosx: - kInfoFiles.extend(getKindleInfoFiles()) - for infoFile in kInfoFiles: + + for kDatabase in kDatabases: try: - pidlst.extend(getK4Pids(md1, md2, infoFile)) + pidlst.extend(getK4Pids(md1, md2, kDatabase)) except Exception, e: - print u"Error getting PIDs from {0}: {1}".format(os.path.basename(infoFile),e.args[0]) + print u"Error getting PIDs from database {0}: {1}".format(kDatabase[0],e.args[0]) + traceback.print_exc() + for serialnum in serials: try: pidlst.extend(getKindlePids(md1, md2, serialnum)) - except Exception, message: + except Exception, e: print u"Error getting PIDs from serial number {0}: {1}".format(serialnum ,e.args[0]) + traceback.print_exc() + return pidlst diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py b/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py new file mode 100644 index 0000000..e79622b --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/kindlekey.py @@ -0,0 +1,1893 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +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 + +# Revision history: +# 1.0 - Kindle info file decryption, extracted from k4mobidedrm, etc. +# 1.1 - Added Tkinter to match adobekey.py +# 1.2 - Fixed testing of successful retrieval on Mac +# 1.3 - Added getkey interface for Windows DeDRM application +# Simplified some of the Kindle for Mac code. +# 1.4 - Remove dependency on alfcrypto + +""" +Retrieve Kindle for PC/Mac user key. +""" + +__license__ = 'GPL v3' +__version__ = '1.4' + +import sys, os, re +from struct import pack, unpack, unpack_from +import json +import getopt + +# Routines common to Mac and PC + +# 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) + +try: + from calibre.constants import iswindows, isosx +except: + 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 '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 + + 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"kindlekey.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] + +class DrmException(Exception): + pass + +# crypto digestroutines +import hashlib + +def MD5(message): + ctx = hashlib.md5() + ctx.update(message) + return ctx.digest() + +def SHA1(message): + ctx = hashlib.sha1() + ctx.update(message) + return ctx.digest() + +def SHA256(message): + ctx = hashlib.sha256() + ctx.update(message) + return ctx.digest() + +# For K4M/PC 1.6.X and later +# generate table of prime number less than or equal to int n +def primes(n): + if n==2: return [2] + elif n<2: return [] + s=range(3,n+1,2) + mroot = n ** 0.5 + half=(n+1)/2-1 + i=0 + m=3 + while m <= mroot: + if s[i]: + j=(m*m-3)/2 + s[j]=0 + while j 0: # save any bytes that are not block aligned + self.bytesToEncrypt = self.bytesToEncrypt[-numExtraBytes:] + else: + self.bytesToEncrypt = '' + + if more == None: # no more data expected from caller + finalBytes = self.padding.addPad(self.bytesToEncrypt,self.blockSize) + if len(finalBytes) > 0: + ctBlock = self.encryptBlock(finalBytes) + self.encryptBlockCount += 1 + cipherText += ctBlock + self.resetEncrypt() + return cipherText + + def decrypt(self, cipherText, more = None): + """ Decrypt a string and return a string """ + self.bytesToDecrypt += cipherText # append to any bytes from prior decrypt + + numBlocks, numExtraBytes = divmod(len(self.bytesToDecrypt), self.blockSize) + if more == None: # no more calls to decrypt, should have all the data + if numExtraBytes != 0: + raise DecryptNotBlockAlignedError, 'Data not block aligned on decrypt' + + # hold back some bytes in case last decrypt has zero len + if (more != None) and (numExtraBytes == 0) and (numBlocks >0) : + numBlocks -= 1 + numExtraBytes = self.blockSize + + plainText = '' + for i in range(numBlocks): + bStart = i*self.blockSize + ptBlock = self.decryptBlock(self.bytesToDecrypt[bStart : bStart+self.blockSize]) + self.decryptBlockCount += 1 + plainText += ptBlock + + if numExtraBytes > 0: # save any bytes that are not block aligned + self.bytesToEncrypt = self.bytesToEncrypt[-numExtraBytes:] + else: + self.bytesToEncrypt = '' + + if more == None: # last decrypt remove padding + plainText = self.padding.removePad(plainText, self.blockSize) + self.resetDecrypt() + return plainText + + + class Pad: + def __init__(self): + pass # eventually could put in calculation of min and max size extension + + class padWithPadLen(Pad): + """ Pad a binary string with the length of the padding """ + + def addPad(self, extraBytes, blockSize): + """ Add padding to a binary string to make it an even multiple + of the block size """ + blocks, numExtraBytes = divmod(len(extraBytes), blockSize) + padLength = blockSize - numExtraBytes + return extraBytes + padLength*chr(padLength) + + def removePad(self, paddedBinaryString, blockSize): + """ Remove padding from a binary string """ + if not(0 6 and i%Nk == 4 : + temp = [ Sbox[byte] for byte in temp ] # SubWord(temp) + w.append( [ w[i-Nk][byte]^temp[byte] for byte in range(4) ] ) + return w + + Rcon = (0,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36, # note extra '0' !!! + 0x6c,0xd8,0xab,0x4d,0x9a,0x2f,0x5e,0xbc,0x63,0xc6, + 0x97,0x35,0x6a,0xd4,0xb3,0x7d,0xfa,0xef,0xc5,0x91) + + #------------------------------------- + def AddRoundKey(algInstance, keyBlock): + """ XOR the algorithm state with a block of key material """ + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] ^= keyBlock[column][row] + #------------------------------------- + + def SubBytes(algInstance): + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] = Sbox[algInstance.state[column][row]] + + def InvSubBytes(algInstance): + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] = InvSbox[algInstance.state[column][row]] + + Sbox = (0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5, + 0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0, + 0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc, + 0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a, + 0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0, + 0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b, + 0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85, + 0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5, + 0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17, + 0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88, + 0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c, + 0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9, + 0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6, + 0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e, + 0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94, + 0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68, + 0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16) + + InvSbox = (0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38, + 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, + 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87, + 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, + 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d, + 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, + 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2, + 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, + 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16, + 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, + 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda, + 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, + 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a, + 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, + 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02, + 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, + 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea, + 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, + 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85, + 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, + 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89, + 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, + 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20, + 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, + 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31, + 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, + 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d, + 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, + 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0, + 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, + 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26, + 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d) + + #------------------------------------- + """ For each block size (Nb), the ShiftRow operation shifts row i + by the amount Ci. Note that row 0 is not shifted. + Nb C1 C2 C3 + ------------------- """ + shiftOffset = { 4 : ( 0, 1, 2, 3), + 5 : ( 0, 1, 2, 3), + 6 : ( 0, 1, 2, 3), + 7 : ( 0, 1, 2, 4), + 8 : ( 0, 1, 3, 4) } + def ShiftRows(algInstance): + tmp = [0]*algInstance.Nb # list of size Nb + for r in range(1,4): # row 0 reamains unchanged and can be skipped + for c in range(algInstance.Nb): + tmp[c] = algInstance.state[(c+shiftOffset[algInstance.Nb][r]) % algInstance.Nb][r] + for c in range(algInstance.Nb): + algInstance.state[c][r] = tmp[c] + def InvShiftRows(algInstance): + tmp = [0]*algInstance.Nb # list of size Nb + for r in range(1,4): # row 0 reamains unchanged and can be skipped + for c in range(algInstance.Nb): + tmp[c] = algInstance.state[(c+algInstance.Nb-shiftOffset[algInstance.Nb][r]) % algInstance.Nb][r] + for c in range(algInstance.Nb): + algInstance.state[c][r] = tmp[c] + #------------------------------------- + def MixColumns(a): + Sprime = [0,0,0,0] + for j in range(a.Nb): # for each column + Sprime[0] = mul(2,a.state[j][0])^mul(3,a.state[j][1])^mul(1,a.state[j][2])^mul(1,a.state[j][3]) + Sprime[1] = mul(1,a.state[j][0])^mul(2,a.state[j][1])^mul(3,a.state[j][2])^mul(1,a.state[j][3]) + Sprime[2] = mul(1,a.state[j][0])^mul(1,a.state[j][1])^mul(2,a.state[j][2])^mul(3,a.state[j][3]) + Sprime[3] = mul(3,a.state[j][0])^mul(1,a.state[j][1])^mul(1,a.state[j][2])^mul(2,a.state[j][3]) + for i in range(4): + a.state[j][i] = Sprime[i] + + def InvMixColumns(a): + """ Mix the four bytes of every column in a linear way + This is the opposite operation of Mixcolumn """ + Sprime = [0,0,0,0] + for j in range(a.Nb): # for each column + Sprime[0] = mul(0x0E,a.state[j][0])^mul(0x0B,a.state[j][1])^mul(0x0D,a.state[j][2])^mul(0x09,a.state[j][3]) + Sprime[1] = mul(0x09,a.state[j][0])^mul(0x0E,a.state[j][1])^mul(0x0B,a.state[j][2])^mul(0x0D,a.state[j][3]) + Sprime[2] = mul(0x0D,a.state[j][0])^mul(0x09,a.state[j][1])^mul(0x0E,a.state[j][2])^mul(0x0B,a.state[j][3]) + Sprime[3] = mul(0x0B,a.state[j][0])^mul(0x0D,a.state[j][1])^mul(0x09,a.state[j][2])^mul(0x0E,a.state[j][3]) + for i in range(4): + a.state[j][i] = Sprime[i] + + #------------------------------------- + def mul(a, b): + """ Multiply two elements of GF(2^m) + needed for MixColumn and InvMixColumn """ + if (a !=0 and b!=0): + return Alogtable[(Logtable[a] + Logtable[b])%255] + else: + return 0 + + Logtable = ( 0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, + 100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, + 125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120, + 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142, + 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56, + 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16, + 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186, + 43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87, + 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, + 44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160, + 127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183, + 204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157, + 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209, + 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, + 68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, + 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7) + + Alogtable= ( 1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, + 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, + 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, + 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, + 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, + 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, + 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, + 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, + 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, + 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, + 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, + 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, + 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, + 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, + 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, + 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1) + + + + + """ + AES Encryption Algorithm + The AES algorithm is just Rijndael algorithm restricted to the default + blockSize of 128 bits. + """ + + class AES(Rijndael): + """ The AES algorithm is the Rijndael block cipher restricted to block + sizes of 128 bits and key sizes of 128, 192 or 256 bits + """ + def __init__(self, key = None, padding = padWithPadLen(), keySize=16): + """ Initialize AES, keySize is in bytes """ + if not (keySize == 16 or keySize == 24 or keySize == 32) : + raise BadKeySizeError, 'Illegal AES key size, must be 16, 24, or 32 bytes' + + Rijndael.__init__( self, key, padding=padding, keySize=keySize, blockSize=16 ) + + self.name = 'AES' + + + """ + CBC mode of encryption for block ciphers. + This algorithm mode wraps any BlockCipher to make a + Cipher Block Chaining mode. + """ + from random import Random # should change to crypto.random!!! + + + class CBC(BlockCipher): + """ The CBC class wraps block ciphers to make cipher block chaining (CBC) mode + algorithms. The initialization (IV) is automatic if set to None. Padding + is also automatic based on the Pad class used to initialize the algorithm + """ + def __init__(self, blockCipherInstance, padding = padWithPadLen()): + """ CBC algorithms are created by initializing with a BlockCipher instance """ + self.baseCipher = blockCipherInstance + self.name = self.baseCipher.name + '_CBC' + self.blockSize = self.baseCipher.blockSize + self.keySize = self.baseCipher.keySize + self.padding = padding + self.baseCipher.padding = noPadding() # baseCipher should NOT pad!! + self.r = Random() # for IV generation, currently uses + # mediocre standard distro version <---------------- + import time + newSeed = time.ctime()+str(self.r) # seed with instance location + self.r.seed(newSeed) # to make unique + self.reset() + + def setKey(self, key): + self.baseCipher.setKey(key) + + # Overload to reset both CBC state and the wrapped baseCipher + def resetEncrypt(self): + BlockCipher.resetEncrypt(self) # reset CBC encrypt state (super class) + self.baseCipher.resetEncrypt() # reset base cipher encrypt state + + def resetDecrypt(self): + BlockCipher.resetDecrypt(self) # reset CBC state (super class) + self.baseCipher.resetDecrypt() # reset base cipher decrypt state + + def encrypt(self, plainText, iv=None, more=None): + """ CBC encryption - overloads baseCipher to allow optional explicit IV + when iv=None, iv is auto generated! + """ + if self.encryptBlockCount == 0: + self.iv = iv + else: + assert(iv==None), 'IV used only on first call to encrypt' + + return BlockCipher.encrypt(self,plainText, more=more) + + def decrypt(self, cipherText, iv=None, more=None): + """ CBC decryption - overloads baseCipher to allow optional explicit IV + when iv=None, iv is auto generated! + """ + if self.decryptBlockCount == 0: + self.iv = iv + else: + assert(iv==None), 'IV used only on first call to decrypt' + + return BlockCipher.decrypt(self, cipherText, more=more) + + def encryptBlock(self, plainTextBlock): + """ CBC block encryption, IV is set with 'encrypt' """ + auto_IV = '' + if self.encryptBlockCount == 0: + if self.iv == None: + # generate IV and use + self.iv = ''.join([chr(self.r.randrange(256)) for i in range(self.blockSize)]) + self.prior_encr_CT_block = self.iv + auto_IV = self.prior_encr_CT_block # prepend IV if it's automatic + else: # application provided IV + assert(len(self.iv) == self.blockSize ),'IV must be same length as block' + self.prior_encr_CT_block = self.iv + """ encrypt the prior CT XORed with the PT """ + ct = self.baseCipher.encryptBlock( xor(self.prior_encr_CT_block, plainTextBlock) ) + self.prior_encr_CT_block = ct + return auto_IV+ct + + def decryptBlock(self, encryptedBlock): + """ Decrypt a single block """ + + if self.decryptBlockCount == 0: # first call, process IV + if self.iv == None: # auto decrypt IV? + self.prior_CT_block = encryptedBlock + return '' + else: + assert(len(self.iv)==self.blockSize),"Bad IV size on CBC decryption" + self.prior_CT_block = self.iv + + dct = self.baseCipher.decryptBlock(encryptedBlock) + """ XOR the prior decrypted CT with the prior CT """ + dct_XOR_priorCT = xor( self.prior_CT_block, dct ) + + self.prior_CT_block = encryptedBlock + + return dct_XOR_priorCT + + + """ + AES_CBC Encryption Algorithm + """ + + class aescbc_AES_CBC(CBC): + """ AES encryption in CBC feedback mode """ + def __init__(self, key=None, padding=padWithPadLen(), keySize=16): + CBC.__init__( self, AES(key, noPadding(), keySize), padding) + self.name = 'AES_CBC' + + class AES_CBC(object): + def __init__(self): + self._key = None + self._iv = None + self.aes = None + + def set_decrypt_key(self, userkey, iv): + self._key = userkey + self._iv = iv + self.aes = aescbc_AES_CBC(userkey, noPadding(), len(userkey)) + + def decrypt(self, data): + iv = self._iv + cleartext = self.aes.decrypt(iv + data) + return cleartext + + import hmac + + class KeyIVGen(object): + # this only exists in openssl so we will use pure python implementation instead + # PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', + # [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p]) + def pbkdf2(self, passwd, salt, iter, keylen): + + def xorstr( a, b ): + if len(a) != len(b): + raise Exception("xorstr(): lengths differ") + return ''.join((chr(ord(x)^ord(y)) for x, y in zip(a, b))) + + def prf( h, data ): + hm = h.copy() + hm.update( data ) + return hm.digest() + + def pbkdf2_F( h, salt, itercount, blocknum ): + U = prf( h, salt + pack('>i',blocknum ) ) + T = U + for i in range(2, itercount+1): + U = prf( h, U ) + T = xorstr( T, U ) + return T + + sha = hashlib.sha1 + digest_size = sha().digest_size + # l - number of output blocks to produce + l = keylen / digest_size + if keylen % digest_size != 0: + l += 1 + h = hmac.new( passwd, None, sha ) + T = "" + for i in range(1, l+1): + T += pbkdf2_F( h, salt, iter, i ) + return T[0: keylen] + + def UnprotectHeaderData(encryptedData): + passwdData = 'header_key_data' + salt = 'HEADER.2011' + iter = 0x80 + keylen = 0x100 + key_iv = KeyIVGen().pbkdf2(passwdData, salt, iter, keylen) + key = key_iv[0:32] + iv = key_iv[32:48] + aes=AES_CBC() + aes.set_decrypt_key(key, iv) + cleartext = aes.decrypt(encryptedData) + return cleartext + + # Various character maps used to decrypt kindle info values. + # Probably supposed to act as obfuscation + charMap2 = "AaZzB0bYyCc1XxDdW2wEeVv3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_" + charMap5 = "AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE" + # New maps in K4PC 1.9.0 + testMap1 = "n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M" + testMap6 = "9YzAb0Cd1Ef2n5Pr6St7Uvh3Jk4M8WxG" + testMap8 = "YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD" + + # interface with Windows OS Routines + class DataBlob(Structure): + _fields_ = [('cbData', c_uint), + ('pbData', c_void_p)] + DataBlob_p = POINTER(DataBlob) + + + def GetSystemDirectory(): + GetSystemDirectoryW = kernel32.GetSystemDirectoryW + GetSystemDirectoryW.argtypes = [c_wchar_p, c_uint] + GetSystemDirectoryW.restype = c_uint + def GetSystemDirectory(): + buffer = create_unicode_buffer(MAX_PATH + 1) + GetSystemDirectoryW(buffer, len(buffer)) + return buffer.value + return GetSystemDirectory + GetSystemDirectory = GetSystemDirectory() + + def GetVolumeSerialNumber(): + GetVolumeInformationW = kernel32.GetVolumeInformationW + GetVolumeInformationW.argtypes = [c_wchar_p, c_wchar_p, c_uint, + POINTER(c_uint), POINTER(c_uint), + POINTER(c_uint), c_wchar_p, c_uint] + GetVolumeInformationW.restype = c_uint + def GetVolumeSerialNumber(path = GetSystemDirectory().split('\\')[0] + '\\'): + vsn = c_uint(0) + GetVolumeInformationW(path, None, 0, byref(vsn), None, None, None, 0) + return str(vsn.value) + return GetVolumeSerialNumber + GetVolumeSerialNumber = GetVolumeSerialNumber() + + def GetIDString(): + vsn = GetVolumeSerialNumber() + #print('Using Volume Serial Number for ID: '+vsn) + return vsn + + def getLastError(): + GetLastError = kernel32.GetLastError + GetLastError.argtypes = None + GetLastError.restype = c_uint + def getLastError(): + return GetLastError() + return getLastError + getLastError = getLastError() + + def GetUserName(): + GetUserNameW = advapi32.GetUserNameW + GetUserNameW.argtypes = [c_wchar_p, POINTER(c_uint)] + GetUserNameW.restype = c_uint + def GetUserName(): + buffer = create_unicode_buffer(2) + size = c_uint(len(buffer)) + while not GetUserNameW(buffer, byref(size)): + errcd = getLastError() + if errcd == 234: + # bad wine implementation up through wine 1.3.21 + return "AlternateUserName" + buffer = create_unicode_buffer(len(buffer) * 2) + size.value = len(buffer) + return buffer.value.encode('utf-16-le')[::2] + return GetUserName + GetUserName = GetUserName() + + def CryptUnprotectData(): + _CryptUnprotectData = crypt32.CryptUnprotectData + _CryptUnprotectData.argtypes = [DataBlob_p, c_wchar_p, DataBlob_p, + c_void_p, c_void_p, c_uint, DataBlob_p] + _CryptUnprotectData.restype = c_uint + def CryptUnprotectData(indata, entropy, flags): + indatab = create_string_buffer(indata) + indata = DataBlob(len(indata), cast(indatab, c_void_p)) + entropyb = create_string_buffer(entropy) + entropy = DataBlob(len(entropy), cast(entropyb, c_void_p)) + outdata = DataBlob() + if not _CryptUnprotectData(byref(indata), None, byref(entropy), + None, None, flags, byref(outdata)): + # raise DrmException("Failed to Unprotect Data") + return 'failed' + return string_at(outdata.pbData, outdata.cbData) + return CryptUnprotectData + CryptUnprotectData = CryptUnprotectData() + + + # Locate all of the kindle-info style files and return as list + def getKindleInfoFiles(): + kInfoFiles = [] + # some 64 bit machines do not have the proper registry key for some reason + # or the pythonn interface to the 32 vs 64 bit registry is broken + path = "" + if 'LOCALAPPDATA' in os.environ.keys(): + path = os.environ['LOCALAPPDATA'] + else: + # User Shell Folders show take precedent over Shell Folders if present + try: + regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\") + path = winreg.QueryValueEx(regkey, 'Local AppData')[0] + if not os.path.isdir(path): + path = "" + try: + regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\") + path = winreg.QueryValueEx(regkey, 'Local AppData')[0] + if not os.path.isdir(path): + path = "" + except RegError: + pass + except RegError: + pass + + found = False + if path == "": + print ('Could not find the folder in which to look for kinfoFiles.') + else: + print('searching for kinfoFiles in ' + path) + + # look for (K4PC 1.9.0 and later) .kinf2011 file + kinfopath = path +'\\Amazon\\Kindle\\storage\\.kinf2011' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.9+ kinf2011 file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for (K4PC 1.6.0 and later) rainier.2.1.1.kinf file + kinfopath = path +'\\Amazon\\Kindle\\storage\\rainier.2.1.1.kinf' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.6-1.8 kinf file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for (K4PC 1.5.0 and later) rainier.2.1.1.kinf file + kinfopath = path +'\\Amazon\\Kindle For PC\\storage\\rainier.2.1.1.kinf' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.5 kinf file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for original (earlier than K4PC 1.5.0) kindle-info files + kinfopath = path +'\\Amazon\\Kindle For PC\\{AMAwzsaPaaZAzmZzZQzgZCAkZ3AjA_AY}\\kindle.info' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC kindle.info file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + if not found: + print('No K4PC kindle.info/kinf/kinf2011 files have been found.') + return kInfoFiles + + + # determine type of kindle info provided and return a + # database of keynames and values + def getDBfromFile(kInfoFile): + names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] + DB = {} + with open(kInfoFile, 'rb') as infoReader: + hdr = infoReader.read(1) + data = infoReader.read() + + if data.find('{') != -1 : + # older style kindle-info file + items = data.split('{') + for item in items: + if item != '': + keyhash, rawdata = item.split(':') + keyname = "unknown" + for name in names: + if encodeHash(name,charMap2) == keyhash: + keyname = name + break + if keyname == "unknown": + keyname = keyhash + encryptedValue = decode(rawdata,charMap2) + DB[keyname] = CryptUnprotectData(encryptedValue, "", 0) + elif hdr == '/': + # else rainier-2-1-1 .kinf file + # the .kinf file uses "/" to separate it into records + # so remove the trailing "/" to make it easy to use split + data = data[:-1] + items = data.split('/') + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + + # the raw keyhash string is used to create entropy for the actual + # CryptProtectData Blob that represents that keys contents + entropy = SHA1(keyhash) + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = "unknown" + for name in names: + if encodeHash(name,charMap5) == keyhash: + keyname = name + break + if keyname == "unknown": + keyname = keyhash + # the charMap5 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using charMap5 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the charMap5 encoded contents seems to be: + # len(contents)-largest prime number <= int(len(content)/3) + # (in other words split "about" 2/3rds of the way through) + + # move first offsets chars to end to align for decode by charMap5 + encdata = "".join(edlst) + contlen = len(encdata) + noffset = contlen - primes(int(contlen/3))[-1] + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using Map5 to get the CryptProtect Data + encryptedValue = decode(encdata,charMap5) + DB[keyname] = CryptUnprotectData(encryptedValue, entropy, 1) + else: + # else newest .kinf2011 style .kinf file + # the .kinf file uses "/" to separate it into records + # so remove the trailing "/" to make it easy to use split + # need to put back the first char read because it it part + # of the added entropy blob + data = hdr + data[:-1] + items = data.split('/') + + # starts with and encoded and encrypted header blob + headerblob = items.pop(0) + encryptedValue = decode(headerblob, testMap1) + cleartext = UnprotectHeaderData(encryptedValue) + # now extract the pieces that form the added entropy + pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) + for m in re.finditer(pattern, cleartext): + added_entropy = m.group(2) + m.group(4) + + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + + # the sha1 of raw keyhash string is used to create entropy along + # with the added entropy provided above from the headerblob + entropy = SHA1(keyhash) + added_entropy + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + # key names now use the new testMap8 encoding + keyname = "unknown" + for name in names: + if encodeHash(name,testMap8) == keyhash: + keyname = name + break + + # the testMap8 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using testMap8 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the testMap8 encoded contents seems to be: + # len(contents)-largest prime number <= int(len(content)/3) + # (in other words split "about" 2/3rds of the way through) + + # move first offsets chars to end to align for decode by testMap8 + # by moving noffset chars from the start of the + # string to the end of the string + encdata = "".join(edlst) + contlen = len(encdata) + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using new testMap8 to get the original CryptProtect Data + encryptedValue = decode(encdata,testMap8) + cleartext = CryptUnprotectData(encryptedValue, entropy, 1) + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName()) + # store values used in decryption + DB['IDString'] = GetIDString() + DB['UserName'] = GetUserName() + else: + DB = {} + return DB +elif isosx: + import copy + import subprocess + + # interface to needed routines in openssl's libcrypto + def _load_crypto_libcrypto(): + from ctypes import CDLL, byref, POINTER, c_void_p, c_char_p, c_int, c_long, \ + Structure, c_ulong, create_string_buffer, addressof, string_at, cast + from ctypes.util import find_library + + libcrypto = find_library('crypto') + if libcrypto is None: + raise DrmException(u"libcrypto not found") + libcrypto = CDLL(libcrypto) + + # From OpenSSL's crypto aes header + # + # AES_ENCRYPT 1 + # AES_DECRYPT 0 + # AES_MAXNR 14 (in bytes) + # AES_BLOCK_SIZE 16 (in bytes) + # + # struct aes_key_st { + # unsigned long rd_key[4 *(AES_MAXNR + 1)]; + # int rounds; + # }; + # typedef struct aes_key_st AES_KEY; + # + # int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); + # + # note: the ivec string, and output buffer are both mutable + # void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + # const unsigned long length, const AES_KEY *key, unsigned char *ivec, const int enc); + + AES_MAXNR = 14 + c_char_pp = POINTER(c_char_p) + c_int_p = POINTER(c_int) + + class AES_KEY(Structure): + _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), ('rounds', c_int)] + AES_KEY_p = POINTER(AES_KEY) + + def F(restype, name, argtypes): + func = getattr(libcrypto, name) + func.restype = restype + func.argtypes = argtypes + return func + + AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',[c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p,c_int]) + + AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',[c_char_p, c_int, AES_KEY_p]) + + # From OpenSSL's Crypto evp/p5_crpt2.c + # + # int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, + # const unsigned char *salt, int saltlen, int iter, + # int keylen, unsigned char *out); + + PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', + [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p]) + + class LibCrypto(object): + def __init__(self): + self._blocksize = 0 + self._keyctx = None + self._iv = 0 + + def set_decrypt_key(self, userkey, iv): + self._blocksize = len(userkey) + if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) : + raise DrmException(u"AES improper key used") + return + keyctx = self._keyctx = AES_KEY() + self._iv = iv + self._userkey = userkey + rv = AES_set_decrypt_key(userkey, len(userkey) * 8, keyctx) + if rv < 0: + raise DrmException(u"Failed to initialize AES key") + + def decrypt(self, data): + out = create_string_buffer(len(data)) + mutable_iv = create_string_buffer(self._iv, len(self._iv)) + keyctx = self._keyctx + rv = AES_cbc_encrypt(data, out, len(data), keyctx, mutable_iv, 0) + if rv == 0: + raise DrmException(u"AES decryption failed") + return out.raw + + def keyivgen(self, passwd, salt, iter, keylen): + saltlen = len(salt) + passlen = len(passwd) + out = create_string_buffer(keylen) + rv = PKCS5_PBKDF2_HMAC_SHA1(passwd, passlen, salt, saltlen, iter, keylen, out) + return out.raw + return LibCrypto + + def _load_crypto(): + LibCrypto = None + try: + LibCrypto = _load_crypto_libcrypto() + except (ImportError, DrmException): + pass + return LibCrypto + + LibCrypto = _load_crypto() + + # Various character maps used to decrypt books. Probably supposed to act as obfuscation + charMap1 = 'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' + charMap2 = 'ZB0bYyc1xDdW2wEV3Ff7KkPpL8UuGA4gz-Tme9Nn_tHh5SvXCsIiR6rJjQaqlOoM' + + # For kinf approach of K4Mac 1.6.X or later + # On K4PC charMap5 = 'AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE' + # For Mac they seem to re-use charMap2 here + charMap5 = charMap2 + + # new in K4M 1.9.X + testMap8 = 'YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD' + + # uses a sub process to get the Hard Drive Serial Number using ioreg + # returns serial numbers of all internal hard drive drives + def GetVolumesSerialNumbers(): + sernum = os.getenv('MYSERIALNUMBER') + if sernum != None: + return [sernum] + sernums = [] + cmdline = '/usr/sbin/ioreg -w 0 -r -c AppleAHCIDiskDriver' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + bsdname = None + sernum = None + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + pp = resline.find('\"Serial Number\" = \"') + if pp >= 0: + sernum = resline[pp+19:-1] + sernums.append(sernum.strip()) + return [sernum] + + def GetUserHomeAppSupKindleDirParitionName(): + home = os.getenv('HOME') + dpath = home + '/Library' + cmdline = '/sbin/mount' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + disk = '' + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + if resline.startswith('/dev'): + (devpart, mpath) = resline.split(' on ') + dpart = devpart[5:] + pp = mpath.find('(') + if pp >= 0: + mpath = mpath[:pp-1] + if dpath.startswith(mpath): + disk = dpart + return disk + + # uses a sub process to get the UUID of the specified disk partition using ioreg + def GetDiskPartitionUUID(diskpart): + uuidnum = os.getenv('MYUUIDNUMBER') + if uuidnum != None: + return uuidnum + cmdline = '/usr/sbin/ioreg -l -S -w 0 -r -c AppleAHCIDiskDriver' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + bsdname = None + uuidnum = None + foundIt = False + nest = 0 + uuidnest = -1 + partnest = -2 + for j in xrange(cnt): + resline = reslst[j] + if resline.find('{') >= 0: + nest += 1 + if resline.find('}') >= 0: + nest -= 1 + pp = resline.find('\"UUID\" = \"') + if pp >= 0: + uuidnum = resline[pp+10:-1] + uuidnum = uuidnum.strip() + uuidnest = nest + if partnest == uuidnest and uuidnest > 0: + foundIt = True + break + bb = resline.find('\"BSD Name\" = \"') + if bb >= 0: + bsdname = resline[bb+14:-1] + bsdname = bsdname.strip() + if (bsdname == diskpart): + partnest = nest + else : + partnest = -2 + if partnest == uuidnest and partnest > 0: + foundIt = True + break + if nest == 0: + partnest = -2 + uuidnest = -1 + uuidnum = None + bsdname = None + if not foundIt: + uuidnum = '' + return uuidnum + + def GetMACAddressMunged(): + macnum = os.getenv('MYMACNUM') + if macnum != None: + return macnum + cmdline = '/sbin/ifconfig en0' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + macnum = None + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + pp = resline.find('ether ') + if pp >= 0: + macnum = resline[pp+6:-1] + macnum = macnum.strip() + # print 'original mac', macnum + # now munge it up the way Kindle app does + # by xoring it with 0xa5 and swapping elements 3 and 4 + maclst = macnum.split(':') + n = len(maclst) + if n != 6: + fountIt = False + break + for i in range(6): + maclst[i] = int('0x' + maclst[i], 0) + mlst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + mlst[5] = maclst[5] ^ 0xa5 + mlst[4] = maclst[3] ^ 0xa5 + mlst[3] = maclst[4] ^ 0xa5 + mlst[2] = maclst[2] ^ 0xa5 + mlst[1] = maclst[1] ^ 0xa5 + mlst[0] = maclst[0] ^ 0xa5 + macnum = '%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x' % (mlst[0], mlst[1], mlst[2], mlst[3], mlst[4], mlst[5]) + foundIt = True + break + if not foundIt: + macnum = '' + return macnum + + + # uses unix env to get username instead of using sysctlbyname + def GetUserName(): + username = os.getenv('USER') + return username + + def GetIDStrings(): + # Return all possible ID Strings + strings = [] + strings.append(GetMACAddressMunged()) + strings.extend(GetVolumesSerialNumbers()) + diskpart = GetUserHomeAppSupKindleDirParitionName() + strings.append(GetDiskPartitionUUID(diskpart)) + strings.append('9999999999') + return strings + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used by Kindle for Mac versions < 1.6.0 + class CryptUnprotectData(object): + def __init__(self, IDString): + sp = IDString + '!@#' + GetUserName() + passwdData = encode(SHA256(sp),charMap1) + salt = '16743' + self.crp = LibCrypto() + iter = 0x3e8 + keylen = 0x80 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext,charMap1) + return cleartext + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used for Kindle for Mac Versions >= 1.6.0 + class CryptUnprotectDataV2(object): + def __init__(self, IDString): + sp = GetUserName() + ':&%:' + IDString + passwdData = encode(SHA256(sp),charMap5) + # salt generation as per the code + salt = 0x0512981d * 2 * 1 * 1 + salt = str(salt) + GetUserName() + salt = encode(salt,charMap5) + self.crp = LibCrypto() + iter = 0x800 + keylen = 0x400 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext, charMap5) + return cleartext + + + # unprotect the new header blob in .kinf2011 + # used in Kindle for Mac Version >= 1.9.0 + def UnprotectHeaderData(encryptedData): + passwdData = 'header_key_data' + salt = 'HEADER.2011' + iter = 0x80 + keylen = 0x100 + crp = LibCrypto() + key_iv = crp.keyivgen(passwdData, salt, iter, keylen) + key = key_iv[0:32] + iv = key_iv[32:48] + crp.set_decrypt_key(key,iv) + cleartext = crp.decrypt(encryptedData) + return cleartext + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used for Kindle for Mac Versions >= 1.9.0 + class CryptUnprotectDataV3(object): + def __init__(self, entropy, IDString): + sp = GetUserName() + '+@#$%+' + IDString + passwdData = encode(SHA256(sp),charMap2) + salt = entropy + self.crp = LibCrypto() + iter = 0x800 + keylen = 0x400 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext, charMap2) + return cleartext + + + # Locate the .kindle-info files + def getKindleInfoFiles(): + # file searches can take a long time on some systems, so just look in known specific places. + kInfoFiles=[] + found = False + home = os.getenv('HOME') + # check for .kinf2011 file in new location (App Store Kindle for Mac) + testpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.kinf2011' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kinf2011 file: ' + testpath) + found = True + # check for .kinf2011 files + testpath = home + '/Library/Application Support/Kindle/storage/.kinf2011' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kinf2011 file: ' + testpath) + found = True + # check for .rainier-2.1.1-kinf files + testpath = home + '/Library/Application Support/Kindle/storage/.rainier-2.1.1-kinf' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac rainier file: ' + testpath) + found = True + # check for .kindle-info files + testpath = home + '/Library/Application Support/Kindle/storage/.kindle-info' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kindle-info file: ' + testpath) + found = True + if not found: + print('No k4Mac kindle-info/rainier/kinf2011 files have been found.') + return kInfoFiles + + # determine type of kindle info provided and return a + # database of keynames and values + def getDBfromFile(kInfoFile): + names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] + with open(kInfoFile, 'rb') as infoReader: + filehdr = infoReader.read(1) + filedata = infoReader.read() + + IDStrings = GetIDStrings() + for IDString in IDStrings: + DB = {} + #print "trying IDString:",IDString + try: + hdr = filehdr + data = filedata + if data.find('[') != -1 : + # older style kindle-info file + cud = CryptUnprotectData(IDString) + items = data.split('[') + for item in items: + if item != '': + keyhash, rawdata = item.split(':') + keyname = 'unknown' + for name in names: + if encodeHash(name,charMap2) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + encryptedValue = decode(rawdata,charMap2) + cleartext = cud.decrypt(encryptedValue) + if len(cleartext) > 0: + DB[keyname] = cleartext + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + elif hdr == '/': + # else newer style .kinf file used by K4Mac >= 1.6.0 + # the .kinf file uses '/' to separate it into records + # so remove the trailing '/' to make it easy to use split + data = data[:-1] + items = data.split('/') + cud = CryptUnprotectDataV2(IDString) + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + keyname = 'unknown' + + # the raw keyhash string is also used to create entropy for the actual + # CryptProtectData Blob that represents that keys contents + # 'entropy' not used for K4Mac only K4PC + # entropy = SHA1(keyhash) + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = 'unknown' + for name in names: + if encodeHash(name,charMap5) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + + # the charMap5 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using charMap5 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the charMap5 encoded contents seems to be: + # len(contents) - largest prime number less than or equal to int(len(content)/3) + # (in other words split 'about' 2/3rds of the way through) + + # move first offsets chars to end to align for decode by charMap5 + encdata = ''.join(edlst) + contlen = len(encdata) + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using charMap5 to get the CryptProtect Data + encryptedValue = decode(encdata,charMap5) + cleartext = cud.decrypt(encryptedValue) + if len(cleartext) > 0: + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + else: + # the latest .kinf2011 version for K4M 1.9.1 + # put back the hdr char, it is needed + data = hdr + data + data = data[:-1] + items = data.split('/') + + # the headerblob is the encrypted information needed to build the entropy string + headerblob = items.pop(0) + encryptedValue = decode(headerblob, charMap1) + cleartext = UnprotectHeaderData(encryptedValue) + + # now extract the pieces in the same way + # this version is different from K4PC it scales the build number by multipying by 735 + pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) + for m in re.finditer(pattern, cleartext): + entropy = str(int(m.group(2)) * 0x2df) + m.group(4) + + cud = CryptUnprotectDataV3(entropy,IDString) + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + keyname = 'unknown' + + # unlike K4PC the keyhash is not used in generating entropy + # entropy = SHA1(keyhash) + added_entropy + # entropy = added_entropy + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = 'unknown' + for name in names: + if encodeHash(name,testMap8) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + + # the testMap8 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using testMap8 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the testMap8 encoded contents seems to be: + # len(contents) - largest prime number less than or equal to int(len(content)/3) + # (in other words split 'about' 2/3rds of the way through) + + # move first offsets chars to end to align for decode by testMap8 + encdata = ''.join(edlst) + contlen = len(encdata) + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using testMap8 to get the CryptProtect Data + encryptedValue = decode(encdata,testMap8) + cleartext = cud.decrypt(encryptedValue) + # print keyname + # print cleartext + if len(cleartext) > 0: + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + except: + pass + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + # store values used in decryption + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(IDString, GetUserName()) + DB['IDString'] = IDString + DB['UserName'] = GetUserName() + else: + print u"Couldn't decrypt file." + DB = {} + return DB +else: + def getDBfromFile(kInfoFile): + raise DrmException(u"This script only runs under Windows or Mac OS X.") + return {} + +def kindlekeys(files = []): + keys = [] + if files == []: + files = getKindleInfoFiles() + for file in files: + key = getDBfromFile(file) + if key: + # convert all values to hex, just in case. + for keyname in key: + key[keyname]=key[keyname].encode('hex') + keys.append(key) + return keys + +# interface for Python DeDRM +# returns single key or multiple keys, depending on path or file passed in +def getkey(outpath, files=[]): + keys = kindlekeys(files) + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(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"kindlekey{0:d}.k4i".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(key)) + print u"Saved a key to {0}".format(outfile) + return True + return False + +def usage(progname): + print u"Finds, decrypts and saves the default Kindle For Mac/PC encryption keys." + print u"Keys are saved to the current directory, or a specified output directory." + print u"If a file name is passed instead of a directory, only the first key is saved, in that file." + print u"Usage:" + print u" {0:s} [-h] [-k ] []".format(progname) + + +def cli_main(argv=unicode_argv()): + progname = os.path.basename(argv[0]) + print u"{0} v{1}\nCopyright © 2010-2013 some_updates and Apprentice Alf".format(progname,__version__) + + try: + opts, args = getopt.getopt(argv[1:], "hk:") + except getopt.GetoptError, err: + print u"Error in options or arguments: {0}".format(err.args[0]) + usage(progname) + sys.exit(2) + + files = [] + for o, a in opts: + if o == "-h": + usage(progname) + sys.exit(0) + if o == "-k": + files = [a] + + if len(args) > 1: + usage(progname) + sys.exit(2) + + if len(args) == 1: + # save to the specified file or directory + outpath = args[0] + if not os.path.isabs(outpath): + outpath = os.path.abspath(outpath) + else: + # save to the same directory as the script + outpath = os.path.dirname(argv[0]) + + # make sure the outpath is the + outpath = os.path.realpath(os.path.normpath(outpath)) + + if not getkey(outpath, files): + print u"Could not retrieve Kindle for Mac/PC key." + return 0 + + +def gui_main(argv=unicode_argv()): + import Tkinter + import Tkconstants + import tkMessageBox + import traceback + + class ExceptionDialog(Tkinter.Frame): + def __init__(self, root, text): + Tkinter.Frame.__init__(self, root, border=5) + label = Tkinter.Label(self, text=u"Unexpected error:", + anchor=Tkconstants.W, justify=Tkconstants.LEFT) + label.pack(fill=Tkconstants.X, expand=0) + self.text = Tkinter.Text(self) + self.text.pack(fill=Tkconstants.BOTH, expand=1) + + self.text.insert(Tkconstants.END, text) + + + root = Tkinter.Tk() + root.withdraw() + progpath, progname = os.path.split(argv[0]) + success = False + try: + keys = kindlekeys() + keycount = 0 + for key in keys: + while True: + keycount += 1 + outfile = os.path.join(progpath,u"kindlekey{0:d}.k4i".format(keycount)) + if not os.path.exists(outfile): + break + + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(key)) + success = True + tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile)) + except DrmException, e: + tkMessageBox.showerror(progname, u"Error: {0}".format(str(e))) + except Exception: + root.wm_state('normal') + root.title(progname) + text = traceback.format_exc() + ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1) + root.mainloop() + if not success: + return 1 + return 0 + +if __name__ == '__main__': + if len(sys.argv) > 1: + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + sys.exit(cli_main()) + sys.exit(gui_main()) diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/kindlepid.py b/DeDRM_calibre_plugin/DeDRM_plugin/kindlepid.py similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/kindlepid.py rename to DeDRM_calibre_plugin/DeDRM_plugin/kindlepid.py diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/libalfcrypto.dylib b/DeDRM_calibre_plugin/DeDRM_plugin/libalfcrypto.dylib similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/libalfcrypto.dylib rename to DeDRM_calibre_plugin/DeDRM_plugin/libalfcrypto.dylib diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/libalfcrypto32.so b/DeDRM_calibre_plugin/DeDRM_plugin/libalfcrypto32.so similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/libalfcrypto32.so rename to DeDRM_calibre_plugin/DeDRM_plugin/libalfcrypto32.so diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/libalfcrypto64.so b/DeDRM_calibre_plugin/DeDRM_plugin/libalfcrypto64.so similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/libalfcrypto64.so rename to DeDRM_calibre_plugin/DeDRM_plugin/libalfcrypto64.so diff --git a/Calibre_Plugins/k4mobidedrm_plugin/mobidedrm.py b/DeDRM_calibre_plugin/DeDRM_plugin/mobidedrm.py similarity index 99% rename from Calibre_Plugins/k4mobidedrm_plugin/mobidedrm.py rename to DeDRM_calibre_plugin/DeDRM_plugin/mobidedrm.py index 264c175..ccbac4e 100644 --- a/Calibre_Plugins/k4mobidedrm_plugin/mobidedrm.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/mobidedrm.py @@ -462,7 +462,7 @@ class MobiBook: raise DrmException(u"Encryption not initialised. Must be opened with Mobipocket Reader first.") found_key, pid = self.parseDRM(self.sect[drm_ptr:drm_ptr+drm_size], drm_count, goodpids) if not found_key: - raise DrmException(u"No key found in {0:d} keys tried. Read the FAQs at Alf's blog: http://apprenticealf.wordpress.com/".format(len(goodpids))) + raise DrmException(u"No key found in {0:d} keys tried.".format(len(goodpids))) # kill the drm keys self.patchSection(0, '\0' * drm_size, drm_ptr) # kill the drm pointers diff --git a/Calibre_Plugins/eReaderPDB2PML_plugin/openssl_des.py b/DeDRM_calibre_plugin/DeDRM_plugin/openssl_des.py similarity index 98% rename from Calibre_Plugins/eReaderPDB2PML_plugin/openssl_des.py rename to DeDRM_calibre_plugin/DeDRM_plugin/openssl_des.py index a4a40ca..9a84e58 100644 --- a/Calibre_Plugins/eReaderPDB2PML_plugin/openssl_des.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/openssl_des.py @@ -65,7 +65,7 @@ def load_libcrypto(): class DES(object): def __init__(self, key): if len(key) != 8 : - raise Error('DES improper key used') + raise Exception('DES improper key used') return self.key = key self.keyschedule = DES_KEY_SCHEDULE() diff --git a/Calibre_Plugins/eReaderPDB2PML_plugin/plugin-import-name-erdrpdb2pml.txt b/DeDRM_calibre_plugin/DeDRM_plugin/plugin-import-name-dedrm.txt similarity index 100% rename from Calibre_Plugins/eReaderPDB2PML_plugin/plugin-import-name-erdrpdb2pml.txt rename to DeDRM_calibre_plugin/DeDRM_plugin/plugin-import-name-dedrm.txt diff --git a/Calibre_Plugins/eReaderPDB2PML_plugin/pycrypto_des.py b/DeDRM_calibre_plugin/DeDRM_plugin/pycrypto_des.py similarity index 100% rename from Calibre_Plugins/eReaderPDB2PML_plugin/pycrypto_des.py rename to DeDRM_calibre_plugin/DeDRM_plugin/pycrypto_des.py diff --git a/Calibre_Plugins/eReaderPDB2PML_plugin/python_des.py b/DeDRM_calibre_plugin/DeDRM_plugin/python_des.py similarity index 100% rename from Calibre_Plugins/eReaderPDB2PML_plugin/python_des.py rename to DeDRM_calibre_plugin/DeDRM_plugin/python_des.py diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/stylexml2css.py b/DeDRM_calibre_plugin/DeDRM_plugin/stylexml2css.py similarity index 100% rename from Calibre_Plugins/K4MobiDeDRM_plugin/stylexml2css.py rename to DeDRM_calibre_plugin/DeDRM_plugin/stylexml2css.py diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/topazextract.py b/DeDRM_calibre_plugin/DeDRM_plugin/topazextract.py similarity index 97% rename from Calibre_Plugins/K4MobiDeDRM_plugin/topazextract.py rename to DeDRM_calibre_plugin/DeDRM_plugin/topazextract.py index 3e4db39..71fe8ab 100644 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/topazextract.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/topazextract.py @@ -74,7 +74,7 @@ debug = False if 'calibre' in sys.modules: inCalibre = True - from calibre_plugins.k4mobidedrm import kgenpids + from calibre_plugins.dedrm import kgenpids else: inCalibre = False import kgenpids @@ -321,7 +321,7 @@ class TopazBook: self.extractFiles() print u"Successfully Extracted Topaz contents" if inCalibre: - from calibre_plugins.k4mobidedrm import genbook + from calibre_plugins.dedrm import genbook else: import genbook @@ -355,7 +355,7 @@ class TopazBook: self.extractFiles() print u"Successfully Extracted Topaz contents" if inCalibre: - from calibre_plugins.k4mobidedrm import genbook + from calibre_plugins.dedrm import genbook else: import genbook @@ -439,7 +439,7 @@ class TopazBook: def usage(progname): print u"Removes DRM protection from Topaz ebooks and extracts the contents" print u"Usage:" - print u" {0} [-k ] [-p ] [-s ] ".format(progname) + print u" {0} [-k ] [-p ] [-s ] ".format(progname) # Main def cli_main(argv=unicode_argv()): @@ -466,7 +466,7 @@ def cli_main(argv=unicode_argv()): print u"Output Directory {0} Does Not Exist.".format(outdir) return 1 - kInfoFiles = [] + kDatabaseFiles = [] serials = [] pids = [] @@ -474,7 +474,7 @@ def cli_main(argv=unicode_argv()): if o == '-k': if a == None : raise DrmException("Invalid parameter for -k") - kInfoFiles.append(a) + kDatabaseFiles.append(a) if o == '-p': if a == None : raise DrmException("Invalid parameter for -p") @@ -490,7 +490,7 @@ def cli_main(argv=unicode_argv()): title = tb.getBookTitle() print u"Processing Book: {0}".format(title) md1, md2 = tb.getPIDMetaInfo() - pids.extend(kgenpids.getPidList(md1, md2, serials, kInfoFiles)) + pids.extend(kgenpids.getPidList(md1, md2, serials, kDatabaseFiles)) try: print u"Decrypting Book" diff --git a/DeDRM_calibre_plugin/DeDRM_plugin/utilities.py b/DeDRM_calibre_plugin/DeDRM_plugin/utilities.py new file mode 100644 index 0000000..c730607 --- /dev/null +++ b/DeDRM_calibre_plugin/DeDRM_plugin/utilities.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +__license__ = 'GPL v3' + +DETAILED_MESSAGE = \ +'You have personal information stored in this plugin\'s customization '+ \ +'string from a previous version of this plugin.\n\n'+ \ +'This new version of the plugin can convert that info '+ \ +'into key data that the new plugin can then use (which doesn\'t '+ \ +'require personal information to be stored/displayed in an insecure '+ \ +'manner like the old plugin did).\n\nIf you choose NOT to migrate this data at this time '+ \ +'you will be prompted to save that personal data to a file elsewhere; and you\'ll have '+ \ +'to manually re-configure this plugin with your information.\n\nEither way... ' + \ +'this new version of the plugin will not be responsible for storing that personal '+ \ +'info in plain sight any longer.' + +def uStrCmp (s1, s2, caseless=False): + import unicodedata as ud + str1 = s1 if isinstance(s1, unicode) else unicode(s1) + str2 = s2 if isinstance(s2, unicode) else unicode(s2) + if caseless: + return ud.normalize('NFC', str1.lower()) == ud.normalize('NFC', str2.lower()) + else: + return ud.normalize('NFC', str1) == ud.normalize('NFC', str2) + +def parseCustString(keystuff): + userkeys = [] + ar = keystuff.split(':') + for i in ar: + try: + name, ccn = i.split(',') + # Generate Barnes & Noble EPUB user key from name and credit card number. + userkeys.append(generate_key(name, ccn)) + except: + pass + return userkeys diff --git a/Calibre_Plugins/ineptepub_plugin/zipfilerugged.py b/DeDRM_calibre_plugin/DeDRM_plugin/zipfilerugged.py similarity index 99% rename from Calibre_Plugins/ineptepub_plugin/zipfilerugged.py rename to DeDRM_calibre_plugin/DeDRM_plugin/zipfilerugged.py index adf3c53..4a55a69 100644 --- a/Calibre_Plugins/ineptepub_plugin/zipfilerugged.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/zipfilerugged.py @@ -354,7 +354,7 @@ class ZipInfo (object): def _decodeFilename(self): if self.flag_bits & 0x800: try: - print "decoding filename",self.filename + #print "decoding filename",self.filename return self.filename.decode('utf-8') except: return self.filename diff --git a/Calibre_Plugins/ineptepub_plugin/zipfix.py b/DeDRM_calibre_plugin/DeDRM_plugin/zipfix.py similarity index 70% rename from Calibre_Plugins/ineptepub_plugin/zipfix.py rename to DeDRM_calibre_plugin/DeDRM_plugin/zipfix.py index eaee20d..8ddfae3 100644 --- a/Calibre_Plugins/ineptepub_plugin/zipfix.py +++ b/DeDRM_calibre_plugin/DeDRM_plugin/zipfix.py @@ -1,6 +1,23 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# zipfix.py, version 1.1 +# Copyright © 2010-2013 by some_updates, DiapDealer and Apprentice Alf + +# Released under the terms of the GNU General Public Licence, version 3 +# + +# Revision history: +# 1.0 - Initial release +# 1.1 - Updated to handle zip file metadata correctly + +""" +Re-write zip (or ePub) fixing problems with file names (and mimetype entry). +""" + +__license__ = 'GPL v3' +__version__ = "1.1" + import sys import zlib import zipfilerugged @@ -96,25 +113,41 @@ class fixZip: # if epub write mimetype file first, with no compression if self.ztype == 'epub': - nzinfo = ZipInfo('mimetype', compress_type=zipfilerugged.ZIP_STORED) - self.outzip.writestr(nzinfo, _MIMETYPE) + # first get a ZipInfo with current time and no compression + mimeinfo = ZipInfo('mimetype',compress_type=zipfilerugged.ZIP_STORED) + mimeinfo.internal_attr = 1 # text file + try: + # if the mimetype is present, get its info, including time-stamp + oldmimeinfo = self.inzip.getinfo('mimetype') + # copy across useful fields + mimeinfo.date_time = oldmimeinfo.date_time + mimeinfo.comment = oldmimeinfo.comment + mimeinfo.extra = oldmimeinfo.extra + mimeinfo.internal_attr = oldmimeinfo.internal_attr + mimeinfo.external_attr = oldmimeinfo.external_attr + mimeinfo.create_system = oldmimeinfo.create_system + except: + pass + self.outzip.writestr(mimeinfo, _MIMETYPE) # write the rest of the files for zinfo in self.inzip.infolist(): - if zinfo.filename != "mimetype" or self.ztype == '.zip': + if zinfo.filename != "mimetype" or self.ztype != 'epub': data = None - nzinfo = zinfo try: data = self.inzip.read(zinfo.filename) except zipfilerugged.BadZipfile or zipfilerugged.error: local_name = self.getlocalname(zinfo) data = self.getfiledata(zinfo) - nzinfo.filename = local_name + zinfo.filename = local_name - nzinfo.date_time = zinfo.date_time - nzinfo.compress_type = zinfo.compress_type - nzinfo.flag_bits = 0 - nzinfo.internal_attr = 0 + # create new ZipInfo with only the useful attributes from the old info + nzinfo = ZipInfo(zinfo.filename, zinfo.date_time, compress_type=zinfo.compress_type) + nzinfo.comment=zinfo.comment + nzinfo.extra=zinfo.extra + nzinfo.internal_attr=zinfo.internal_attr + nzinfo.external_attr=zinfo.external_attr + nzinfo.create_system=zinfo.create_system self.outzip.writestr(nzinfo,data) self.bzf.close() diff --git a/Calibre_Plugins/K4MobiDeDRM_ReadMe.txt b/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt similarity index 53% rename from Calibre_Plugins/K4MobiDeDRM_ReadMe.txt rename to DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt index 66cce14..a047ff2 100644 --- a/Calibre_Plugins/K4MobiDeDRM_ReadMe.txt +++ b/DeDRM_calibre_plugin/DeDRM_plugin_ReadMe.txt @@ -1,65 +1,83 @@ -Kindle and Mobipocket Plugin - K4MobiDeDRM_v04.19_plugin.zip -============================================================ +DeDRM_plugin.zip +================ -Credit given to The Dark Reverser for the original standalone script. Credit also to the many people who have updated and expanded that script since then. +This calibre plugin replaces all previous DRM removal plugins. When you install this plugin, the older separate plugins should be removed. -Plugin for K4PC, K4Mac, eInk Kindles and Mobipocket. - -This plugin supersedes MobiDeDRM, K4DeDRM, and K4PCDeDRM and K4X plugins. If you install this plugin, those plugins should be removed, as should any earlier versions of this plugin. - -This plugin is meant to remove the DRM from .prc, .mobi, .azw, .azw1, .azw3, .azw4 and .tpz ebooks. Calibre can then convert them to whatever format you desire. It is meant to function without having to install any dependencies except for Calibre being on your same machine and in the same account as your "Kindle for PC" or "Kindle for Mac" application if you are going to remove the DRM from books from those programs. +This plugin will remove the DRM from Amazon Kindle ebooks (Mobi, KF8, Topaz and Print Replica), Mobipocket, Adobe Digital Edition ePubs (including Kobo ePubs), Barnes and Noble ePubs, Adobe Digital Edition PDFs, and Fictionwise eReader ebooks. Installation ------------ - -Do **NOT** select "Get plugins to enhance calibre" as this is reserved for "official" calibre plugins, instead select "Change calibre behavior" to go to Calibre's Preferences page. Under "Advanced" click on the Plugins button. Use the "Load plugin from file" button to select the plugin's zip file (K4MobiDeDRM_v04.19_plugin.zip) and click the 'Add' button. Click 'Yes' in the the "Are you sure?" dialog. Click OK in the "Success" dialog. - -Make sure that you delete any old versions of the plugin. They might interfere with the operation of the new one. +Do **NOT** select "Get plugins to enhance calibre" as this is reserved for "official" calibre plugins, instead select "Change calibre behavior" to go to Calibre's Preferences page. Under "Advanced" click on the Plugins button. Use the "Load plugin from file" button to select the plugin's zip file (DeDRM_plugin.zip) and click the 'Add' button. Click 'Yes' in the the "Are you sure?" dialog. Click OK in the "Success" dialog. Customization ------------- +On Windows and Mac, the keys for ebooks downloaded for Kindle for Mac/PC and Adobe Digital Editions are automatically generated. If all your DRMed ebooks can be opened and read in Kindle for Mac/PC and/or Adobe Digital Editions on the same computer on which you are running calibre, you do not need to do any configuration of this plugin. On Linux, keys for Kindle for PC and Adobe Figital Editions need to be generated separately (see Linux systems section) -Highlight the plugin (K4MobiDeDRM under the "File type plugins" category) and click the "Customize Plugin" button on Calibre's Preferences->Plugins page. +Otherwise, highlight the plugin (DeDRM under the "File type plugins" category) and click the "Customize Plugin" button. -If you have an eInk Kindle enter the 16 character serial number (these all begin a "B" or a "9") in the serial numbers field. The easiest way to make sure that you have the serial number right is to copy it from your Amazon account pages (the "Manage Your Devices" page). If you have more than one eInk Kindle, you can enter multiple serial numbers separated by commas. +The buttons in the configuration dialog will open individual configuration dialogs that will allow you to enter the needed information, depending on the type and source of your DRMed eBooks. Additional help on the information required is available in each of the the dialogs. -If you have Mobipocket books, enter your 8 or 10 digit PID in the Mobipocket PIDs field. If you have more than one PID, separate them with commas. +If you have used previous versions of the various DeDRM plugins on this machine, you may find that some of the configuration dialogs already contain the information you entered through those previous plugins. -These configuration steps are not needed if you only want to decode "Kindle for PC" or "Kindle for Mac" books. +When you have finished entering your configuration information, you must click the OK button to save it. If you click the Cancel button, all your changes in all the configuration dialogs will be lost. Troubleshooting --------------- - -If you find that it's not working for you (imported ebooks still have DRM), you can save a lot of time and trouble by first deleting the DRMed ebook from calibre and then trying to add the ebook to calibre with the command line tools. This will print out a lot of helpful debugging info that can be copied into any online help requests. I'm going to ask you to do it first, anyway, so you might as well get used to it. ;) +If you find that it's not working for you (imported ebooks still have DRM), you can save a lot of time and trouble by deleting the DRMed ebook from calibre and then trying to add the ebook to calibre in debug mode with the command line tools. This will print out a lot of helpful debugging info that can be copied into any online help requests. On Macintosh only you must first run calibre, open Preferences, open Miscellaneous, and click on the “Install command line tools” button. (On Windows and Linux the command line tools are installed automatically.) On Windows, open a terminal/command window. (Start/Run… and then type 'cmd' (without the 's) as the program to run). On Macintosh, open the Terminal application (in your Utilities folder). -On Linux open a command window. Hopefully all Linux users know how to do this, as I do not. +On Linux open a command window. Hopefully all Linux users know how to do this. -You should now have a text-based command-line window open. Also have open the folder containing the ebook to be imported. Make sure that book isn’t already in calibre, and that calibre isn’t running. +You should now have a text-based command-line window open. -Now type in "calibredb add " (without the " but don’t miss that final space) and now drag the book to be imported onto the window. The full path to the book should be inserted into the command line. Now press the return/enter key. The import routines will run and produce some logging information. +Type in "calibre-debug -g" (without the ") and press the return/enter key. Calibre will launch and run as normal, but with debugging information output to the terminal window. -Now copy the output from the terminal window. +Import the drmed eBook into calibre in any of the the normal ways. (I usually drag&drop onto the calibre window.) + +More debug information will be written to the terminal window. + +Copy the output from the terminal window. On Windows, you must use the window menu (little icon at left of window bar) to select all the text and then to copy it. On Macintosh and Linux, just use the normal text select and copy commands. Paste the information into a comment at my blog, http://apprenticealf.wordpress.com/ describing your problem. +Credits +------- +The mobidedrm and erdr2pml scripts were created by The Dark Reverser +The ignobleepub, ignoblekeygen, ineptepub and adobe key scripts were created by i♥cabbages +The k4mobidedrm script and supporting scripts were written by some_updates with help from DiapDealer and Apprentice Alf, based on code by Bart Simpson (aka Skindle), CMBDTC and clarknova +The alfcrypto library was created by some_updates +The ePub encryption detection script was adapted by Apprentice Alf from a script by Paul Durrant +The DeDRM all-in-one AppleScript was created by Apprentice Alf +The DeDRM all-in-one python script was created by some_updates and Apprentice Alf + + + Linux Systems Only ------------------ +================== -If you install Kindle for PC in Wine, the plugin should be able to decode files from that Kindle for PC installation under Wine. You might need to enter a Wine Prefix if it's not already set in your Environment variables. You will need to install Python and PyCrypto under Wine as detailed below. In addition, some people who have successfully used the plugin in this way have commented as follows: +Generating decryption keys for Adobe Digital Editions and Kindle for PC +----------------------------------------------------------------------- +If you install Kindle for PC and/or Adobe Digital Editions in Wine, you will be able to download DRMed ebooks to them under Wine. To be able to remove the DRM, you will need to generate key files and add them in the plugin's customisation dialogs. -Here are the instructions for using Kindle for PC on Linux under Wine. (Thank you Eyeless and Pete) +To generate the key files you will need to install Python and PyCrypto under the same Wine setup as your Kindle for PC and/or Adobe Digital Editions installations. (Kindle for PC, Python and Pycrypto installation instructions are below.) +Once everything's installed under Wine, you'll need to run the adobekey.pyw script (for Adobe Digital Editions) and kindlekey.pyw (For Kindle for PC) using the python installation in your Wine system. The scripts can be found in Other_Tools/Key_Retrieval_Scripts. + +Each script will create a key file in the same folder as the script. Copy the key files to your Linux system and use the plugin customisation dialog in calibre to load the key files. + + +Instructions for installing Kindle for PC on Linux under Wine. (Thank you Eyeless and Pete) +------------------------------------------------------------------------------------------- 1. upgrade to very recent versions of Wine; This has been tested with Wine 1.3.15 – 1.3.2X. It may work with earlier versions but no promises. It does not work with wine 1.2.X versions. If you have not already installed Kindle for PC under wine, follow steps 2 and 3 otherwise jump to step 4 @@ -72,11 +90,11 @@ echo deadbeef > .windows-serial Replace "deadbeef" with whatever hex value you want but I would stay away from the default setting of "ffffffff" which does not seem to work. BTW: deadbeef is itself a valid possible hex value if you want to use it -3. Only ***after*** setting the volume serial number properly – download and install under wine K4PC version for Windows. Register it and download from your Archive one of your Kindle ebooks. Versions known to work are K4PC 1.7.1 and earlier. Later version may work but no promises. +3. Only ***after*** setting the volume serial number properly – download and install under wine K4PC version for Windows. Register it and download from your Archive one of your Kindle ebooks. -FIRST user ----------- +More such Instructions +---------------------- Hi everyone, I struggled to get this working on Ubuntu 12.04. Here are the secrets for everyone: 1. Make sure your Wine installation is set up to be 32 bit. 64 bit is not going to work! To do this, remove your .wine directory (or use a different wineprefix). Then use WINEARCH=win32 winecfg @@ -87,8 +105,9 @@ Hi everyone, I struggled to get this working on Ubuntu 12.04. Here are the secre 4. Now download and install Python 2.7 32 bit for Windows from python.org, 32 bit, install it the usual way, and you can now run the Kindle DRM tools. -SECOND USER ------------ + +Yet more such Instructions +-------------------------- It took a while to figure out that I needed wine 32 bit, plus Python 27 32 bit, plus the winetricks, to get all this working together but once it’s done, it’s great and I can read my Kindle content on my Nook Color running Cyanogenmod!!! Linux Systems Only: For all of the following wine installs, use WINEARCH=win32 if you are on x86_64. Also remember that in order to execute a *.msi file, you have to run ‘WINEARCH=win32 wine msiexec /i xxxxx.msi’. diff --git a/Other_Tools/DRM_Key_Scripts/Adobe_Digital_Editions/adobekey.pyw b/Other_Tools/DRM_Key_Scripts/Adobe_Digital_Editions/adobekey.pyw new file mode 100644 index 0000000..94f7522 --- /dev/null +++ b/Other_Tools/DRM_Key_Scripts/Adobe_Digital_Editions/adobekey.pyw @@ -0,0 +1,594 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +# adobekey.pyw, version 5.7 +# Copyright © 2009-2010 i♥cabbages + +# Released under the terms of the GNU General Public Licence, version 3 +# + +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf + +# Windows users: Before running this program, you must first install Python. +# We recommend ActiveState Python 2.7.X for Windows (x86) from +# http://www.activestate.com/activepython/downloads. +# You must also install PyCrypto from +# http://www.voidspace.org.uk/python/modules.shtml#pycrypto +# (make certain to install the version for Python 2.7). +# Then save this script file as adobekey.pyw and double-click on it to run it. +# It will create a file named adobekey_1.der in in the same directory as the script. +# This is your Adobe Digital Editions user key. +# +# Mac OS X users: Save this script file as adobekey.pyw. You can run this +# program from the command line (python adobekey.pyw) or by double-clicking +# it when it has been associated with PythonLauncher. It will create a file +# named adobekey_1.der in the same directory as the script. +# This is your Adobe Digital Editions user key. + +# Revision history: +# 1 - Initial release, for Adobe Digital Editions 1.7 +# 2 - Better algorithm for finding pLK; improved error handling +# 3 - Rename to INEPT +# 4 - Series of changes by joblack (and others?) -- +# 4.1 - quick beta fix for ADE 1.7.2 (anon) +# 4.2 - added old 1.7.1 processing +# 4.3 - better key search +# 4.4 - Make it working on 64-bit Python +# 5 - Clean up and improve 4.x changes; +# Clean up and merge OS X support by unknown +# 5.1 - add support for using OpenSSL on Windows in place of PyCrypto +# 5.2 - added support for output of key to a particular file +# 5.3 - On Windows try PyCrypto first, OpenSSL next +# 5.4 - Modify interface to allow use of import +# 5.5 - Fix for potential problem with PyCrypto +# 5.6 - Revised to allow use in Plugins to eliminate need for duplicate code +# 5.7 - Unicode support added, renamed adobekey from ineptkey +# 5.8 - Added getkey interface for Windows DeDRM application + +""" +Retrieve Adobe ADEPT user key. +""" + +__license__ = 'GPL v3' +__version__ = '5.8' + +import sys, os, struct, getopt + +# 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) + +try: + from calibre.constants import iswindows, isosx +except: + 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 '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 + + 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"adobekey.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] + +class ADEPTError(Exception): + pass + +if iswindows: + from ctypes import windll, c_char_p, c_wchar_p, c_uint, POINTER, byref, \ + create_unicode_buffer, create_string_buffer, CFUNCTYPE, addressof, \ + string_at, Structure, c_void_p, cast, c_size_t, memmove, CDLL, c_int, \ + c_long, c_ulong + + from ctypes.wintypes import LPVOID, DWORD, BOOL + import _winreg as winreg + + def _load_crypto_libcrypto(): + from ctypes.util import find_library + libcrypto = find_library('libeay32') + if libcrypto is None: + raise ADEPTError('libcrypto not found') + libcrypto = CDLL(libcrypto) + AES_MAXNR = 14 + c_char_pp = POINTER(c_char_p) + c_int_p = POINTER(c_int) + class AES_KEY(Structure): + _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), + ('rounds', c_int)] + AES_KEY_p = POINTER(AES_KEY) + + def F(restype, name, argtypes): + func = getattr(libcrypto, name) + func.restype = restype + func.argtypes = argtypes + return func + + AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key', + [c_char_p, c_int, AES_KEY_p]) + AES_cbc_encrypt = F(None, 'AES_cbc_encrypt', + [c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p, + c_int]) + class AES(object): + def __init__(self, userkey): + self._blocksize = len(userkey) + if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) : + raise ADEPTError('AES improper key used') + key = self._key = AES_KEY() + rv = AES_set_decrypt_key(userkey, len(userkey) * 8, key) + if rv < 0: + raise ADEPTError('Failed to initialize AES key') + def decrypt(self, data): + out = create_string_buffer(len(data)) + iv = ("\x00" * self._blocksize) + rv = AES_cbc_encrypt(data, out, len(data), self._key, iv, 0) + if rv == 0: + raise ADEPTError('AES decryption failed') + return out.raw + return AES + + def _load_crypto_pycrypto(): + from Crypto.Cipher import AES as _AES + class AES(object): + def __init__(self, key): + self._aes = _AES.new(key, _AES.MODE_CBC, '\x00'*16) + def decrypt(self, data): + return self._aes.decrypt(data) + return AES + + def _load_crypto(): + AES = None + for loader in (_load_crypto_pycrypto, _load_crypto_libcrypto): + try: + AES = loader() + break + except (ImportError, ADEPTError): + pass + return AES + + AES = _load_crypto() + + + DEVICE_KEY_PATH = r'Software\Adobe\Adept\Device' + PRIVATE_LICENCE_KEY_PATH = r'Software\Adobe\Adept\Activation' + + MAX_PATH = 255 + + kernel32 = windll.kernel32 + advapi32 = windll.advapi32 + crypt32 = windll.crypt32 + + def GetSystemDirectory(): + GetSystemDirectoryW = kernel32.GetSystemDirectoryW + GetSystemDirectoryW.argtypes = [c_wchar_p, c_uint] + GetSystemDirectoryW.restype = c_uint + def GetSystemDirectory(): + buffer = create_unicode_buffer(MAX_PATH + 1) + GetSystemDirectoryW(buffer, len(buffer)) + return buffer.value + return GetSystemDirectory + GetSystemDirectory = GetSystemDirectory() + + def GetVolumeSerialNumber(): + GetVolumeInformationW = kernel32.GetVolumeInformationW + GetVolumeInformationW.argtypes = [c_wchar_p, c_wchar_p, c_uint, + POINTER(c_uint), POINTER(c_uint), + POINTER(c_uint), c_wchar_p, c_uint] + GetVolumeInformationW.restype = c_uint + def GetVolumeSerialNumber(path): + vsn = c_uint(0) + GetVolumeInformationW( + path, None, 0, byref(vsn), None, None, None, 0) + return vsn.value + return GetVolumeSerialNumber + GetVolumeSerialNumber = GetVolumeSerialNumber() + + def GetUserName(): + GetUserNameW = advapi32.GetUserNameW + GetUserNameW.argtypes = [c_wchar_p, POINTER(c_uint)] + GetUserNameW.restype = c_uint + def GetUserName(): + buffer = create_unicode_buffer(32) + size = c_uint(len(buffer)) + while not GetUserNameW(buffer, byref(size)): + buffer = create_unicode_buffer(len(buffer) * 2) + size.value = len(buffer) + return buffer.value.encode('utf-16-le')[::2] + return GetUserName + GetUserName = GetUserName() + + PAGE_EXECUTE_READWRITE = 0x40 + MEM_COMMIT = 0x1000 + MEM_RESERVE = 0x2000 + + def VirtualAlloc(): + _VirtualAlloc = kernel32.VirtualAlloc + _VirtualAlloc.argtypes = [LPVOID, c_size_t, DWORD, DWORD] + _VirtualAlloc.restype = LPVOID + def VirtualAlloc(addr, size, alloctype=(MEM_COMMIT | MEM_RESERVE), + protect=PAGE_EXECUTE_READWRITE): + return _VirtualAlloc(addr, size, alloctype, protect) + return VirtualAlloc + VirtualAlloc = VirtualAlloc() + + MEM_RELEASE = 0x8000 + + def VirtualFree(): + _VirtualFree = kernel32.VirtualFree + _VirtualFree.argtypes = [LPVOID, c_size_t, DWORD] + _VirtualFree.restype = BOOL + def VirtualFree(addr, size=0, freetype=MEM_RELEASE): + return _VirtualFree(addr, size, freetype) + return VirtualFree + VirtualFree = VirtualFree() + + class NativeFunction(object): + def __init__(self, restype, argtypes, insns): + self._buf = buf = VirtualAlloc(None, len(insns)) + memmove(buf, insns, len(insns)) + ftype = CFUNCTYPE(restype, *argtypes) + self._native = ftype(buf) + + def __call__(self, *args): + return self._native(*args) + + def __del__(self): + if self._buf is not None: + VirtualFree(self._buf) + self._buf = None + + if struct.calcsize("P") == 4: + CPUID0_INSNS = ( + "\x53" # push %ebx + "\x31\xc0" # xor %eax,%eax + "\x0f\xa2" # cpuid + "\x8b\x44\x24\x08" # mov 0x8(%esp),%eax + "\x89\x18" # mov %ebx,0x0(%eax) + "\x89\x50\x04" # mov %edx,0x4(%eax) + "\x89\x48\x08" # mov %ecx,0x8(%eax) + "\x5b" # pop %ebx + "\xc3" # ret + ) + CPUID1_INSNS = ( + "\x53" # push %ebx + "\x31\xc0" # xor %eax,%eax + "\x40" # inc %eax + "\x0f\xa2" # cpuid + "\x5b" # pop %ebx + "\xc3" # ret + ) + else: + CPUID0_INSNS = ( + "\x49\x89\xd8" # mov %rbx,%r8 + "\x49\x89\xc9" # mov %rcx,%r9 + "\x48\x31\xc0" # xor %rax,%rax + "\x0f\xa2" # cpuid + "\x4c\x89\xc8" # mov %r9,%rax + "\x89\x18" # mov %ebx,0x0(%rax) + "\x89\x50\x04" # mov %edx,0x4(%rax) + "\x89\x48\x08" # mov %ecx,0x8(%rax) + "\x4c\x89\xc3" # mov %r8,%rbx + "\xc3" # retq + ) + CPUID1_INSNS = ( + "\x53" # push %rbx + "\x48\x31\xc0" # xor %rax,%rax + "\x48\xff\xc0" # inc %rax + "\x0f\xa2" # cpuid + "\x5b" # pop %rbx + "\xc3" # retq + ) + + def cpuid0(): + _cpuid0 = NativeFunction(None, [c_char_p], CPUID0_INSNS) + buf = create_string_buffer(12) + def cpuid0(): + _cpuid0(buf) + return buf.raw + return cpuid0 + cpuid0 = cpuid0() + + cpuid1 = NativeFunction(c_uint, [], CPUID1_INSNS) + + class DataBlob(Structure): + _fields_ = [('cbData', c_uint), + ('pbData', c_void_p)] + DataBlob_p = POINTER(DataBlob) + + def CryptUnprotectData(): + _CryptUnprotectData = crypt32.CryptUnprotectData + _CryptUnprotectData.argtypes = [DataBlob_p, c_wchar_p, DataBlob_p, + c_void_p, c_void_p, c_uint, DataBlob_p] + _CryptUnprotectData.restype = c_uint + def CryptUnprotectData(indata, entropy): + indatab = create_string_buffer(indata) + indata = DataBlob(len(indata), cast(indatab, c_void_p)) + entropyb = create_string_buffer(entropy) + entropy = DataBlob(len(entropy), cast(entropyb, c_void_p)) + outdata = DataBlob() + if not _CryptUnprotectData(byref(indata), None, byref(entropy), + None, None, 0, byref(outdata)): + raise ADEPTError("Failed to decrypt user key key (sic)") + return string_at(outdata.pbData, outdata.cbData) + return CryptUnprotectData + CryptUnprotectData = CryptUnprotectData() + + def adeptkeys(): + if AES is None: + raise ADEPTError("PyCrypto or OpenSSL must be installed") + root = GetSystemDirectory().split('\\')[0] + '\\' + serial = GetVolumeSerialNumber(root) + vendor = cpuid0() + signature = struct.pack('>I', cpuid1())[1:] + user = GetUserName() + entropy = struct.pack('>I12s3s13s', serial, vendor, signature, user) + cuser = winreg.HKEY_CURRENT_USER + try: + regkey = winreg.OpenKey(cuser, DEVICE_KEY_PATH) + device = winreg.QueryValueEx(regkey, 'key')[0] + except WindowsError: + raise ADEPTError("Adobe Digital Editions not activated") + keykey = CryptUnprotectData(device, entropy) + userkey = None + keys = [] + try: + plkroot = winreg.OpenKey(cuser, PRIVATE_LICENCE_KEY_PATH) + except WindowsError: + raise ADEPTError("Could not locate ADE activation") + for i in xrange(0, 16): + try: + plkparent = winreg.OpenKey(plkroot, "%04d" % (i,)) + except WindowsError: + break + ktype = winreg.QueryValueEx(plkparent, None)[0] + if ktype != 'credentials': + continue + for j in xrange(0, 16): + try: + plkkey = winreg.OpenKey(plkparent, "%04d" % (j,)) + except WindowsError: + break + ktype = winreg.QueryValueEx(plkkey, None)[0] + if ktype != 'privateLicenseKey': + continue + userkey = winreg.QueryValueEx(plkkey, 'value')[0] + userkey = userkey.decode('base64') + aes = AES(keykey) + userkey = aes.decrypt(userkey) + userkey = userkey[26:-ord(userkey[-1])] + keys.append(userkey) + if len(keys) == 0: + raise ADEPTError('Could not locate privateLicenseKey') + return keys + + +elif isosx: + import xml.etree.ElementTree as etree + import subprocess + + NSMAP = {'adept': 'http://ns.adobe.com/adept', + 'enc': 'http://www.w3.org/2001/04/xmlenc#'} + + def findActivationDat(): + import warnings + warnings.filterwarnings('ignore', category=FutureWarning) + + home = os.getenv('HOME') + cmdline = 'find "' + home + '/Library/Application Support/Adobe/Digital Editions" -name "activation.dat"' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p2 = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p2.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + ActDatPath = "activation.dat" + for j in xrange(cnt): + resline = reslst[j] + pp = resline.find('activation.dat') + if pp >= 0: + ActDatPath = resline + break + if os.path.exists(ActDatPath): + return ActDatPath + return None + + def adeptkeys(): + actpath = findActivationDat() + if actpath is None: + raise ADEPTError("Could not find ADE activation.dat file.") + tree = etree.parse(actpath) + adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag) + expr = '//%s/%s' % (adept('credentials'), adept('privateLicenseKey')) + userkey = tree.findtext(expr) + userkey = userkey.decode('base64') + userkey = userkey[26:] + return [userkey] + +else: + def adeptkeys(): + raise ADEPTError("This script only supports Windows and Mac OS X.") + return [] + +# interface for Python DeDRM +def getkey(outpath): + keys = adeptkeys() + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'wb') 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"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + print u"Saved a key to {0}".format(outfile) + return True + return False + +def usage(progname): + print u"Finds, decrypts and saves the default Adobe Adept encryption key(s)." + print u"Keys are saved to the current directory, or a specified output directory." + print u"If a file name is passed instead of a directory, only the first key is saved, in that file." + print u"Usage:" + print u" {0:s} [-h] []".format(progname) + +def cli_main(argv=unicode_argv()): + progname = os.path.basename(argv[0]) + print u"{0} v{1}\nCopyright © 2009-2013 i♥cabbages and 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) > 1: + usage(progname) + sys.exit(2) + + if len(args) == 1: + # save to the specified file or directory + outpath = args[0] + if not os.path.isabs(outpath): + outpath = os.path.abspath(outpath) + else: + # save to the same directory as the script + outpath = os.path.dirname(argv[0]) + + # make sure the outpath is the + outpath = os.path.realpath(os.path.normpath(outpath)) + + keys = adeptkeys() + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'wb') 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"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + print u"Saved a key to {0}".format(outfile) + else: + print u"Could not retrieve Adobe Adept key." + return 0 + + +def gui_main(argv=unicode_argv()): + import Tkinter + import Tkconstants + import tkMessageBox + import traceback + + class ExceptionDialog(Tkinter.Frame): + def __init__(self, root, text): + Tkinter.Frame.__init__(self, root, border=5) + label = Tkinter.Label(self, text=u"Unexpected error:", + anchor=Tkconstants.W, justify=Tkconstants.LEFT) + label.pack(fill=Tkconstants.X, expand=0) + self.text = Tkinter.Text(self) + self.text.pack(fill=Tkconstants.BOTH, expand=1) + + self.text.insert(Tkconstants.END, text) + + + root = Tkinter.Tk() + root.withdraw() + progpath, progname = os.path.split(argv[0]) + success = False + try: + keys = adeptkeys() + keycount = 0 + for key in keys: + while True: + keycount += 1 + outfile = os.path.join(progpath,u"adobekey_{0:d}.der".format(keycount)) + if not os.path.exists(outfile): + break + + with file(outfile, 'wb') as keyfileout: + keyfileout.write(key) + success = True + tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile)) + except DrmException, e: + tkMessageBox.showerror(progname, u"Error: {0}".format(str(e))) + except Exception: + root.wm_state('normal') + root.title(progname) + text = traceback.format_exc() + ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1) + root.mainloop() + if not success: + return 1 + return 0 + +if __name__ == '__main__': + if len(sys.argv) > 1: + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + sys.exit(cli_main()) + sys.exit(gui_main()) diff --git a/Other_Tools/DRM_Key_Scripts/Barnes_and_Noble_ePubs/ignoblekeygen.pyw b/Other_Tools/DRM_Key_Scripts/Barnes_and_Noble_ePubs/ignoblekeygen.pyw new file mode 100644 index 0000000..ec78e65 --- /dev/null +++ b/Other_Tools/DRM_Key_Scripts/Barnes_and_Noble_ePubs/ignoblekeygen.pyw @@ -0,0 +1,324 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +# ignoblekeygen.pyw, version 2.5 +# Copyright © 2009-2010 i♥cabbages + +# Released under the terms of the GNU General Public Licence, version 3 +# + +# Modified 2010–2013 by some_updates, DiapDealer and Apprentice Alf + +# Windows users: Before running this program, you must first install Python. +# We recommend ActiveState Python 2.7.X for Windows (x86) from +# http://www.activestate.com/activepython/downloads. +# You must also install PyCrypto from +# http://www.voidspace.org.uk/python/modules.shtml#pycrypto +# (make certain to install the version for Python 2.7). +# Then save this script file as ignoblekeygen.pyw and double-click on it to run it. +# +# Mac OS X users: Save this script file as ignoblekeygen.pyw. You can run this +# program from the command line (python ignoblekeygen.pyw) or by double-clicking +# it when it has been associated with PythonLauncher. + +# Revision history: +# 1 - Initial release +# 2 - Add OS X support by using OpenSSL when available (taken/modified from ineptepub v5) +# 2.1 - Allow Windows versions of libcrypto to be found +# 2.2 - On Windows try PyCrypto first and then OpenSSL next +# 2.3 - Modify interface to allow use of import +# 2.4 - Improvements to UI and now works in plugins +# 2.5 - Additional improvement for unicode and plugin support + +""" +Generate Barnes & Noble EPUB user key from name and credit card number. +""" + +__license__ = 'GPL v3' +__version__ = "2.5" + +import sys +import os +import hashlib + +# 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) + +try: + from calibre.constants import iswindows, isosx +except: + 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 '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 + + 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"ignoblekeygen.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] + + +class IGNOBLEError(Exception): + pass + +def _load_crypto_libcrypto(): + from ctypes import CDLL, POINTER, c_void_p, c_char_p, c_int, c_long, \ + Structure, c_ulong, create_string_buffer, cast + from ctypes.util import find_library + + if iswindows: + libcrypto = find_library('libeay32') + else: + libcrypto = find_library('crypto') + + if libcrypto is None: + raise IGNOBLEError('libcrypto not found') + libcrypto = CDLL(libcrypto) + + AES_MAXNR = 14 + + c_char_pp = POINTER(c_char_p) + c_int_p = POINTER(c_int) + + class AES_KEY(Structure): + _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), + ('rounds', c_int)] + AES_KEY_p = POINTER(AES_KEY) + + def F(restype, name, argtypes): + func = getattr(libcrypto, name) + func.restype = restype + func.argtypes = argtypes + return func + + AES_set_encrypt_key = F(c_int, 'AES_set_encrypt_key', + [c_char_p, c_int, AES_KEY_p]) + AES_cbc_encrypt = F(None, 'AES_cbc_encrypt', + [c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p, + c_int]) + + class AES(object): + def __init__(self, userkey, iv): + self._blocksize = len(userkey) + self._iv = iv + key = self._key = AES_KEY() + rv = AES_set_encrypt_key(userkey, len(userkey) * 8, key) + if rv < 0: + raise IGNOBLEError('Failed to initialize AES Encrypt key') + + def encrypt(self, data): + out = create_string_buffer(len(data)) + rv = AES_cbc_encrypt(data, out, len(data), self._key, self._iv, 1) + if rv == 0: + raise IGNOBLEError('AES encryption failed') + return out.raw + + return AES + +def _load_crypto_pycrypto(): + from Crypto.Cipher import AES as _AES + + class AES(object): + def __init__(self, key, iv): + self._aes = _AES.new(key, _AES.MODE_CBC, iv) + + def encrypt(self, data): + return self._aes.encrypt(data) + + return AES + +def _load_crypto(): + AES = None + cryptolist = (_load_crypto_libcrypto, _load_crypto_pycrypto) + if sys.platform.startswith('win'): + cryptolist = (_load_crypto_pycrypto, _load_crypto_libcrypto) + for loader in cryptolist: + try: + AES = loader() + break + except (ImportError, IGNOBLEError): + pass + return AES + +AES = _load_crypto() + +def normalize_name(name): + return ''.join(x for x in name.lower() if x != ' ') + + +def generate_key(name, ccn): + # remove spaces and case from name and CC numbers. + if type(name)==unicode: + name = name.encode('utf-8') + if type(ccn)==unicode: + ccn = ccn.encode('utf-8') + + name = normalize_name(name) + '\x00' + ccn = normalize_name(ccn) + '\x00' + + name_sha = hashlib.sha1(name).digest()[:16] + ccn_sha = hashlib.sha1(ccn).digest()[:16] + both_sha = hashlib.sha1(name + ccn).digest() + aes = AES(ccn_sha, name_sha) + crypt = aes.encrypt(both_sha + ('\x0c' * 0x0c)) + userkey = hashlib.sha1(crypt).digest() + return userkey.encode('base64') + + + + +def cli_main(argv=unicode_argv()): + progname = os.path.basename(argv[0]) + if AES is None: + print "%s: This script requires OpenSSL or PyCrypto, which must be installed " \ + "separately. Read the top-of-script comment for details." % \ + (progname,) + return 1 + if len(argv) != 4: + print u"usage: {0} ".format(progname) + return 1 + name, ccn, keypath = argv[1:] + userkey = generate_key(name, ccn) + open(keypath,'wb').write(userkey) + return 0 + + +def gui_main(): + import Tkinter + import Tkconstants + import tkFileDialog + import tkMessageBox + + 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"Account Name").grid(row=0) + self.name = Tkinter.Entry(body, width=40) + self.name.grid(row=0, column=1, sticky=sticky) + Tkinter.Label(body, text=u"CC#").grid(row=1) + self.ccn = Tkinter.Entry(body, width=40) + self.ccn.grid(row=1, column=1, sticky=sticky) + Tkinter.Label(body, text=u"Output file").grid(row=2) + self.keypath = Tkinter.Entry(body, width=40) + self.keypath.grid(row=2, column=1, sticky=sticky) + self.keypath.insert(2, u"bnepubkey.b64") + button = Tkinter.Button(body, text=u"...", command=self.get_keypath) + button.grid(row=2, column=2) + buttons = Tkinter.Frame(self) + buttons.pack() + botton = Tkinter.Button( + buttons, text=u"Generate", width=10, command=self.generate) + botton.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 get_keypath(self): + keypath = tkFileDialog.asksaveasfilename( + parent=None, title=u"Select B&N ePub key file to produce", + defaultextension=u".b64", + filetypes=[('base64-encoded files', '.b64'), + ('All Files', '.*')]) + if keypath: + keypath = os.path.normpath(keypath) + self.keypath.delete(0, Tkconstants.END) + self.keypath.insert(0, keypath) + return + + def generate(self): + name = self.name.get() + ccn = self.ccn.get() + keypath = self.keypath.get() + if not name: + self.status['text'] = u"Name not specified" + return + if not ccn: + self.status['text'] = u"Credit card number not specified" + return + if not keypath: + self.status['text'] = u"Output keyfile path not specified" + return + self.status['text'] = u"Generating..." + try: + userkey = generate_key(name, ccn) + except Exception, e: + self.status['text'] = u"Error: (0}".format(e.args[0]) + return + open(keypath,'wb').write(userkey) + self.status['text'] = u"Keyfile successfully generated" + + root = Tkinter.Tk() + if AES is None: + root.withdraw() + tkMessageBox.showerror( + "Ignoble EPUB Keyfile Generator", + "This script requires OpenSSL or PyCrypto, which must be installed " + "separately. Read the top-of-script comment for details.") + return 1 + root.title(u"Barnes & Noble ePub Keyfile 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.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + sys.exit(cli_main()) + sys.exit(gui_main()) 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 new file mode 100644 index 0000000..e79622b --- /dev/null +++ b/Other_Tools/DRM_Key_Scripts/Kindle_for_Mac_and_PC/kindlekey.pyw @@ -0,0 +1,1893 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +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 + +# Revision history: +# 1.0 - Kindle info file decryption, extracted from k4mobidedrm, etc. +# 1.1 - Added Tkinter to match adobekey.py +# 1.2 - Fixed testing of successful retrieval on Mac +# 1.3 - Added getkey interface for Windows DeDRM application +# Simplified some of the Kindle for Mac code. +# 1.4 - Remove dependency on alfcrypto + +""" +Retrieve Kindle for PC/Mac user key. +""" + +__license__ = 'GPL v3' +__version__ = '1.4' + +import sys, os, re +from struct import pack, unpack, unpack_from +import json +import getopt + +# Routines common to Mac and PC + +# 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) + +try: + from calibre.constants import iswindows, isosx +except: + 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 '?'. So use shell32.GetCommandLineArgvW to get sys.argv + # as a list of Unicode strings and encode them as utf-8 + + 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"kindlekey.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] + +class DrmException(Exception): + pass + +# crypto digestroutines +import hashlib + +def MD5(message): + ctx = hashlib.md5() + ctx.update(message) + return ctx.digest() + +def SHA1(message): + ctx = hashlib.sha1() + ctx.update(message) + return ctx.digest() + +def SHA256(message): + ctx = hashlib.sha256() + ctx.update(message) + return ctx.digest() + +# For K4M/PC 1.6.X and later +# generate table of prime number less than or equal to int n +def primes(n): + if n==2: return [2] + elif n<2: return [] + s=range(3,n+1,2) + mroot = n ** 0.5 + half=(n+1)/2-1 + i=0 + m=3 + while m <= mroot: + if s[i]: + j=(m*m-3)/2 + s[j]=0 + while j 0: # save any bytes that are not block aligned + self.bytesToEncrypt = self.bytesToEncrypt[-numExtraBytes:] + else: + self.bytesToEncrypt = '' + + if more == None: # no more data expected from caller + finalBytes = self.padding.addPad(self.bytesToEncrypt,self.blockSize) + if len(finalBytes) > 0: + ctBlock = self.encryptBlock(finalBytes) + self.encryptBlockCount += 1 + cipherText += ctBlock + self.resetEncrypt() + return cipherText + + def decrypt(self, cipherText, more = None): + """ Decrypt a string and return a string """ + self.bytesToDecrypt += cipherText # append to any bytes from prior decrypt + + numBlocks, numExtraBytes = divmod(len(self.bytesToDecrypt), self.blockSize) + if more == None: # no more calls to decrypt, should have all the data + if numExtraBytes != 0: + raise DecryptNotBlockAlignedError, 'Data not block aligned on decrypt' + + # hold back some bytes in case last decrypt has zero len + if (more != None) and (numExtraBytes == 0) and (numBlocks >0) : + numBlocks -= 1 + numExtraBytes = self.blockSize + + plainText = '' + for i in range(numBlocks): + bStart = i*self.blockSize + ptBlock = self.decryptBlock(self.bytesToDecrypt[bStart : bStart+self.blockSize]) + self.decryptBlockCount += 1 + plainText += ptBlock + + if numExtraBytes > 0: # save any bytes that are not block aligned + self.bytesToEncrypt = self.bytesToEncrypt[-numExtraBytes:] + else: + self.bytesToEncrypt = '' + + if more == None: # last decrypt remove padding + plainText = self.padding.removePad(plainText, self.blockSize) + self.resetDecrypt() + return plainText + + + class Pad: + def __init__(self): + pass # eventually could put in calculation of min and max size extension + + class padWithPadLen(Pad): + """ Pad a binary string with the length of the padding """ + + def addPad(self, extraBytes, blockSize): + """ Add padding to a binary string to make it an even multiple + of the block size """ + blocks, numExtraBytes = divmod(len(extraBytes), blockSize) + padLength = blockSize - numExtraBytes + return extraBytes + padLength*chr(padLength) + + def removePad(self, paddedBinaryString, blockSize): + """ Remove padding from a binary string """ + if not(0 6 and i%Nk == 4 : + temp = [ Sbox[byte] for byte in temp ] # SubWord(temp) + w.append( [ w[i-Nk][byte]^temp[byte] for byte in range(4) ] ) + return w + + Rcon = (0,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36, # note extra '0' !!! + 0x6c,0xd8,0xab,0x4d,0x9a,0x2f,0x5e,0xbc,0x63,0xc6, + 0x97,0x35,0x6a,0xd4,0xb3,0x7d,0xfa,0xef,0xc5,0x91) + + #------------------------------------- + def AddRoundKey(algInstance, keyBlock): + """ XOR the algorithm state with a block of key material """ + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] ^= keyBlock[column][row] + #------------------------------------- + + def SubBytes(algInstance): + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] = Sbox[algInstance.state[column][row]] + + def InvSubBytes(algInstance): + for column in range(algInstance.Nb): + for row in range(4): + algInstance.state[column][row] = InvSbox[algInstance.state[column][row]] + + Sbox = (0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5, + 0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0, + 0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc, + 0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a, + 0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0, + 0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b, + 0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85, + 0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5, + 0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17, + 0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88, + 0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c, + 0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9, + 0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6, + 0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e, + 0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94, + 0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68, + 0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16) + + InvSbox = (0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38, + 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, + 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87, + 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, + 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d, + 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, + 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2, + 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, + 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16, + 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, + 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda, + 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, + 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a, + 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, + 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02, + 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, + 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea, + 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, + 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85, + 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, + 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89, + 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, + 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20, + 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, + 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31, + 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, + 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d, + 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, + 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0, + 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, + 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26, + 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d) + + #------------------------------------- + """ For each block size (Nb), the ShiftRow operation shifts row i + by the amount Ci. Note that row 0 is not shifted. + Nb C1 C2 C3 + ------------------- """ + shiftOffset = { 4 : ( 0, 1, 2, 3), + 5 : ( 0, 1, 2, 3), + 6 : ( 0, 1, 2, 3), + 7 : ( 0, 1, 2, 4), + 8 : ( 0, 1, 3, 4) } + def ShiftRows(algInstance): + tmp = [0]*algInstance.Nb # list of size Nb + for r in range(1,4): # row 0 reamains unchanged and can be skipped + for c in range(algInstance.Nb): + tmp[c] = algInstance.state[(c+shiftOffset[algInstance.Nb][r]) % algInstance.Nb][r] + for c in range(algInstance.Nb): + algInstance.state[c][r] = tmp[c] + def InvShiftRows(algInstance): + tmp = [0]*algInstance.Nb # list of size Nb + for r in range(1,4): # row 0 reamains unchanged and can be skipped + for c in range(algInstance.Nb): + tmp[c] = algInstance.state[(c+algInstance.Nb-shiftOffset[algInstance.Nb][r]) % algInstance.Nb][r] + for c in range(algInstance.Nb): + algInstance.state[c][r] = tmp[c] + #------------------------------------- + def MixColumns(a): + Sprime = [0,0,0,0] + for j in range(a.Nb): # for each column + Sprime[0] = mul(2,a.state[j][0])^mul(3,a.state[j][1])^mul(1,a.state[j][2])^mul(1,a.state[j][3]) + Sprime[1] = mul(1,a.state[j][0])^mul(2,a.state[j][1])^mul(3,a.state[j][2])^mul(1,a.state[j][3]) + Sprime[2] = mul(1,a.state[j][0])^mul(1,a.state[j][1])^mul(2,a.state[j][2])^mul(3,a.state[j][3]) + Sprime[3] = mul(3,a.state[j][0])^mul(1,a.state[j][1])^mul(1,a.state[j][2])^mul(2,a.state[j][3]) + for i in range(4): + a.state[j][i] = Sprime[i] + + def InvMixColumns(a): + """ Mix the four bytes of every column in a linear way + This is the opposite operation of Mixcolumn """ + Sprime = [0,0,0,0] + for j in range(a.Nb): # for each column + Sprime[0] = mul(0x0E,a.state[j][0])^mul(0x0B,a.state[j][1])^mul(0x0D,a.state[j][2])^mul(0x09,a.state[j][3]) + Sprime[1] = mul(0x09,a.state[j][0])^mul(0x0E,a.state[j][1])^mul(0x0B,a.state[j][2])^mul(0x0D,a.state[j][3]) + Sprime[2] = mul(0x0D,a.state[j][0])^mul(0x09,a.state[j][1])^mul(0x0E,a.state[j][2])^mul(0x0B,a.state[j][3]) + Sprime[3] = mul(0x0B,a.state[j][0])^mul(0x0D,a.state[j][1])^mul(0x09,a.state[j][2])^mul(0x0E,a.state[j][3]) + for i in range(4): + a.state[j][i] = Sprime[i] + + #------------------------------------- + def mul(a, b): + """ Multiply two elements of GF(2^m) + needed for MixColumn and InvMixColumn """ + if (a !=0 and b!=0): + return Alogtable[(Logtable[a] + Logtable[b])%255] + else: + return 0 + + Logtable = ( 0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, + 100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, + 125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120, + 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142, + 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56, + 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16, + 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186, + 43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87, + 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, + 44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160, + 127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183, + 204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157, + 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209, + 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, + 68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, + 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7) + + Alogtable= ( 1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, + 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, + 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, + 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, + 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, + 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, + 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, + 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, + 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, + 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, + 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, + 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, + 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, + 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, + 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, + 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1) + + + + + """ + AES Encryption Algorithm + The AES algorithm is just Rijndael algorithm restricted to the default + blockSize of 128 bits. + """ + + class AES(Rijndael): + """ The AES algorithm is the Rijndael block cipher restricted to block + sizes of 128 bits and key sizes of 128, 192 or 256 bits + """ + def __init__(self, key = None, padding = padWithPadLen(), keySize=16): + """ Initialize AES, keySize is in bytes """ + if not (keySize == 16 or keySize == 24 or keySize == 32) : + raise BadKeySizeError, 'Illegal AES key size, must be 16, 24, or 32 bytes' + + Rijndael.__init__( self, key, padding=padding, keySize=keySize, blockSize=16 ) + + self.name = 'AES' + + + """ + CBC mode of encryption for block ciphers. + This algorithm mode wraps any BlockCipher to make a + Cipher Block Chaining mode. + """ + from random import Random # should change to crypto.random!!! + + + class CBC(BlockCipher): + """ The CBC class wraps block ciphers to make cipher block chaining (CBC) mode + algorithms. The initialization (IV) is automatic if set to None. Padding + is also automatic based on the Pad class used to initialize the algorithm + """ + def __init__(self, blockCipherInstance, padding = padWithPadLen()): + """ CBC algorithms are created by initializing with a BlockCipher instance """ + self.baseCipher = blockCipherInstance + self.name = self.baseCipher.name + '_CBC' + self.blockSize = self.baseCipher.blockSize + self.keySize = self.baseCipher.keySize + self.padding = padding + self.baseCipher.padding = noPadding() # baseCipher should NOT pad!! + self.r = Random() # for IV generation, currently uses + # mediocre standard distro version <---------------- + import time + newSeed = time.ctime()+str(self.r) # seed with instance location + self.r.seed(newSeed) # to make unique + self.reset() + + def setKey(self, key): + self.baseCipher.setKey(key) + + # Overload to reset both CBC state and the wrapped baseCipher + def resetEncrypt(self): + BlockCipher.resetEncrypt(self) # reset CBC encrypt state (super class) + self.baseCipher.resetEncrypt() # reset base cipher encrypt state + + def resetDecrypt(self): + BlockCipher.resetDecrypt(self) # reset CBC state (super class) + self.baseCipher.resetDecrypt() # reset base cipher decrypt state + + def encrypt(self, plainText, iv=None, more=None): + """ CBC encryption - overloads baseCipher to allow optional explicit IV + when iv=None, iv is auto generated! + """ + if self.encryptBlockCount == 0: + self.iv = iv + else: + assert(iv==None), 'IV used only on first call to encrypt' + + return BlockCipher.encrypt(self,plainText, more=more) + + def decrypt(self, cipherText, iv=None, more=None): + """ CBC decryption - overloads baseCipher to allow optional explicit IV + when iv=None, iv is auto generated! + """ + if self.decryptBlockCount == 0: + self.iv = iv + else: + assert(iv==None), 'IV used only on first call to decrypt' + + return BlockCipher.decrypt(self, cipherText, more=more) + + def encryptBlock(self, plainTextBlock): + """ CBC block encryption, IV is set with 'encrypt' """ + auto_IV = '' + if self.encryptBlockCount == 0: + if self.iv == None: + # generate IV and use + self.iv = ''.join([chr(self.r.randrange(256)) for i in range(self.blockSize)]) + self.prior_encr_CT_block = self.iv + auto_IV = self.prior_encr_CT_block # prepend IV if it's automatic + else: # application provided IV + assert(len(self.iv) == self.blockSize ),'IV must be same length as block' + self.prior_encr_CT_block = self.iv + """ encrypt the prior CT XORed with the PT """ + ct = self.baseCipher.encryptBlock( xor(self.prior_encr_CT_block, plainTextBlock) ) + self.prior_encr_CT_block = ct + return auto_IV+ct + + def decryptBlock(self, encryptedBlock): + """ Decrypt a single block """ + + if self.decryptBlockCount == 0: # first call, process IV + if self.iv == None: # auto decrypt IV? + self.prior_CT_block = encryptedBlock + return '' + else: + assert(len(self.iv)==self.blockSize),"Bad IV size on CBC decryption" + self.prior_CT_block = self.iv + + dct = self.baseCipher.decryptBlock(encryptedBlock) + """ XOR the prior decrypted CT with the prior CT """ + dct_XOR_priorCT = xor( self.prior_CT_block, dct ) + + self.prior_CT_block = encryptedBlock + + return dct_XOR_priorCT + + + """ + AES_CBC Encryption Algorithm + """ + + class aescbc_AES_CBC(CBC): + """ AES encryption in CBC feedback mode """ + def __init__(self, key=None, padding=padWithPadLen(), keySize=16): + CBC.__init__( self, AES(key, noPadding(), keySize), padding) + self.name = 'AES_CBC' + + class AES_CBC(object): + def __init__(self): + self._key = None + self._iv = None + self.aes = None + + def set_decrypt_key(self, userkey, iv): + self._key = userkey + self._iv = iv + self.aes = aescbc_AES_CBC(userkey, noPadding(), len(userkey)) + + def decrypt(self, data): + iv = self._iv + cleartext = self.aes.decrypt(iv + data) + return cleartext + + import hmac + + class KeyIVGen(object): + # this only exists in openssl so we will use pure python implementation instead + # PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', + # [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p]) + def pbkdf2(self, passwd, salt, iter, keylen): + + def xorstr( a, b ): + if len(a) != len(b): + raise Exception("xorstr(): lengths differ") + return ''.join((chr(ord(x)^ord(y)) for x, y in zip(a, b))) + + def prf( h, data ): + hm = h.copy() + hm.update( data ) + return hm.digest() + + def pbkdf2_F( h, salt, itercount, blocknum ): + U = prf( h, salt + pack('>i',blocknum ) ) + T = U + for i in range(2, itercount+1): + U = prf( h, U ) + T = xorstr( T, U ) + return T + + sha = hashlib.sha1 + digest_size = sha().digest_size + # l - number of output blocks to produce + l = keylen / digest_size + if keylen % digest_size != 0: + l += 1 + h = hmac.new( passwd, None, sha ) + T = "" + for i in range(1, l+1): + T += pbkdf2_F( h, salt, iter, i ) + return T[0: keylen] + + def UnprotectHeaderData(encryptedData): + passwdData = 'header_key_data' + salt = 'HEADER.2011' + iter = 0x80 + keylen = 0x100 + key_iv = KeyIVGen().pbkdf2(passwdData, salt, iter, keylen) + key = key_iv[0:32] + iv = key_iv[32:48] + aes=AES_CBC() + aes.set_decrypt_key(key, iv) + cleartext = aes.decrypt(encryptedData) + return cleartext + + # Various character maps used to decrypt kindle info values. + # Probably supposed to act as obfuscation + charMap2 = "AaZzB0bYyCc1XxDdW2wEeVv3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_" + charMap5 = "AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE" + # New maps in K4PC 1.9.0 + testMap1 = "n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M" + testMap6 = "9YzAb0Cd1Ef2n5Pr6St7Uvh3Jk4M8WxG" + testMap8 = "YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD" + + # interface with Windows OS Routines + class DataBlob(Structure): + _fields_ = [('cbData', c_uint), + ('pbData', c_void_p)] + DataBlob_p = POINTER(DataBlob) + + + def GetSystemDirectory(): + GetSystemDirectoryW = kernel32.GetSystemDirectoryW + GetSystemDirectoryW.argtypes = [c_wchar_p, c_uint] + GetSystemDirectoryW.restype = c_uint + def GetSystemDirectory(): + buffer = create_unicode_buffer(MAX_PATH + 1) + GetSystemDirectoryW(buffer, len(buffer)) + return buffer.value + return GetSystemDirectory + GetSystemDirectory = GetSystemDirectory() + + def GetVolumeSerialNumber(): + GetVolumeInformationW = kernel32.GetVolumeInformationW + GetVolumeInformationW.argtypes = [c_wchar_p, c_wchar_p, c_uint, + POINTER(c_uint), POINTER(c_uint), + POINTER(c_uint), c_wchar_p, c_uint] + GetVolumeInformationW.restype = c_uint + def GetVolumeSerialNumber(path = GetSystemDirectory().split('\\')[0] + '\\'): + vsn = c_uint(0) + GetVolumeInformationW(path, None, 0, byref(vsn), None, None, None, 0) + return str(vsn.value) + return GetVolumeSerialNumber + GetVolumeSerialNumber = GetVolumeSerialNumber() + + def GetIDString(): + vsn = GetVolumeSerialNumber() + #print('Using Volume Serial Number for ID: '+vsn) + return vsn + + def getLastError(): + GetLastError = kernel32.GetLastError + GetLastError.argtypes = None + GetLastError.restype = c_uint + def getLastError(): + return GetLastError() + return getLastError + getLastError = getLastError() + + def GetUserName(): + GetUserNameW = advapi32.GetUserNameW + GetUserNameW.argtypes = [c_wchar_p, POINTER(c_uint)] + GetUserNameW.restype = c_uint + def GetUserName(): + buffer = create_unicode_buffer(2) + size = c_uint(len(buffer)) + while not GetUserNameW(buffer, byref(size)): + errcd = getLastError() + if errcd == 234: + # bad wine implementation up through wine 1.3.21 + return "AlternateUserName" + buffer = create_unicode_buffer(len(buffer) * 2) + size.value = len(buffer) + return buffer.value.encode('utf-16-le')[::2] + return GetUserName + GetUserName = GetUserName() + + def CryptUnprotectData(): + _CryptUnprotectData = crypt32.CryptUnprotectData + _CryptUnprotectData.argtypes = [DataBlob_p, c_wchar_p, DataBlob_p, + c_void_p, c_void_p, c_uint, DataBlob_p] + _CryptUnprotectData.restype = c_uint + def CryptUnprotectData(indata, entropy, flags): + indatab = create_string_buffer(indata) + indata = DataBlob(len(indata), cast(indatab, c_void_p)) + entropyb = create_string_buffer(entropy) + entropy = DataBlob(len(entropy), cast(entropyb, c_void_p)) + outdata = DataBlob() + if not _CryptUnprotectData(byref(indata), None, byref(entropy), + None, None, flags, byref(outdata)): + # raise DrmException("Failed to Unprotect Data") + return 'failed' + return string_at(outdata.pbData, outdata.cbData) + return CryptUnprotectData + CryptUnprotectData = CryptUnprotectData() + + + # Locate all of the kindle-info style files and return as list + def getKindleInfoFiles(): + kInfoFiles = [] + # some 64 bit machines do not have the proper registry key for some reason + # or the pythonn interface to the 32 vs 64 bit registry is broken + path = "" + if 'LOCALAPPDATA' in os.environ.keys(): + path = os.environ['LOCALAPPDATA'] + else: + # User Shell Folders show take precedent over Shell Folders if present + try: + regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\") + path = winreg.QueryValueEx(regkey, 'Local AppData')[0] + if not os.path.isdir(path): + path = "" + try: + regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\") + path = winreg.QueryValueEx(regkey, 'Local AppData')[0] + if not os.path.isdir(path): + path = "" + except RegError: + pass + except RegError: + pass + + found = False + if path == "": + print ('Could not find the folder in which to look for kinfoFiles.') + else: + print('searching for kinfoFiles in ' + path) + + # look for (K4PC 1.9.0 and later) .kinf2011 file + kinfopath = path +'\\Amazon\\Kindle\\storage\\.kinf2011' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.9+ kinf2011 file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for (K4PC 1.6.0 and later) rainier.2.1.1.kinf file + kinfopath = path +'\\Amazon\\Kindle\\storage\\rainier.2.1.1.kinf' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.6-1.8 kinf file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for (K4PC 1.5.0 and later) rainier.2.1.1.kinf file + kinfopath = path +'\\Amazon\\Kindle For PC\\storage\\rainier.2.1.1.kinf' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC 1.5 kinf file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + # look for original (earlier than K4PC 1.5.0) kindle-info files + kinfopath = path +'\\Amazon\\Kindle For PC\\{AMAwzsaPaaZAzmZzZQzgZCAkZ3AjA_AY}\\kindle.info' + if os.path.isfile(kinfopath): + found = True + print('Found K4PC kindle.info file: ' + kinfopath) + kInfoFiles.append(kinfopath) + + if not found: + print('No K4PC kindle.info/kinf/kinf2011 files have been found.') + return kInfoFiles + + + # determine type of kindle info provided and return a + # database of keynames and values + def getDBfromFile(kInfoFile): + names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] + DB = {} + with open(kInfoFile, 'rb') as infoReader: + hdr = infoReader.read(1) + data = infoReader.read() + + if data.find('{') != -1 : + # older style kindle-info file + items = data.split('{') + for item in items: + if item != '': + keyhash, rawdata = item.split(':') + keyname = "unknown" + for name in names: + if encodeHash(name,charMap2) == keyhash: + keyname = name + break + if keyname == "unknown": + keyname = keyhash + encryptedValue = decode(rawdata,charMap2) + DB[keyname] = CryptUnprotectData(encryptedValue, "", 0) + elif hdr == '/': + # else rainier-2-1-1 .kinf file + # the .kinf file uses "/" to separate it into records + # so remove the trailing "/" to make it easy to use split + data = data[:-1] + items = data.split('/') + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + + # the raw keyhash string is used to create entropy for the actual + # CryptProtectData Blob that represents that keys contents + entropy = SHA1(keyhash) + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = "unknown" + for name in names: + if encodeHash(name,charMap5) == keyhash: + keyname = name + break + if keyname == "unknown": + keyname = keyhash + # the charMap5 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using charMap5 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the charMap5 encoded contents seems to be: + # len(contents)-largest prime number <= int(len(content)/3) + # (in other words split "about" 2/3rds of the way through) + + # move first offsets chars to end to align for decode by charMap5 + encdata = "".join(edlst) + contlen = len(encdata) + noffset = contlen - primes(int(contlen/3))[-1] + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using Map5 to get the CryptProtect Data + encryptedValue = decode(encdata,charMap5) + DB[keyname] = CryptUnprotectData(encryptedValue, entropy, 1) + else: + # else newest .kinf2011 style .kinf file + # the .kinf file uses "/" to separate it into records + # so remove the trailing "/" to make it easy to use split + # need to put back the first char read because it it part + # of the added entropy blob + data = hdr + data[:-1] + items = data.split('/') + + # starts with and encoded and encrypted header blob + headerblob = items.pop(0) + encryptedValue = decode(headerblob, testMap1) + cleartext = UnprotectHeaderData(encryptedValue) + # now extract the pieces that form the added entropy + pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) + for m in re.finditer(pattern, cleartext): + added_entropy = m.group(2) + m.group(4) + + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + + # the sha1 of raw keyhash string is used to create entropy along + # with the added entropy provided above from the headerblob + entropy = SHA1(keyhash) + added_entropy + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + # key names now use the new testMap8 encoding + keyname = "unknown" + for name in names: + if encodeHash(name,testMap8) == keyhash: + keyname = name + break + + # the testMap8 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using testMap8 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the testMap8 encoded contents seems to be: + # len(contents)-largest prime number <= int(len(content)/3) + # (in other words split "about" 2/3rds of the way through) + + # move first offsets chars to end to align for decode by testMap8 + # by moving noffset chars from the start of the + # string to the end of the string + encdata = "".join(edlst) + contlen = len(encdata) + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using new testMap8 to get the original CryptProtect Data + encryptedValue = decode(encdata,testMap8) + cleartext = CryptUnprotectData(encryptedValue, entropy, 1) + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(GetIDString(), GetUserName()) + # store values used in decryption + DB['IDString'] = GetIDString() + DB['UserName'] = GetUserName() + else: + DB = {} + return DB +elif isosx: + import copy + import subprocess + + # interface to needed routines in openssl's libcrypto + def _load_crypto_libcrypto(): + from ctypes import CDLL, byref, POINTER, c_void_p, c_char_p, c_int, c_long, \ + Structure, c_ulong, create_string_buffer, addressof, string_at, cast + from ctypes.util import find_library + + libcrypto = find_library('crypto') + if libcrypto is None: + raise DrmException(u"libcrypto not found") + libcrypto = CDLL(libcrypto) + + # From OpenSSL's crypto aes header + # + # AES_ENCRYPT 1 + # AES_DECRYPT 0 + # AES_MAXNR 14 (in bytes) + # AES_BLOCK_SIZE 16 (in bytes) + # + # struct aes_key_st { + # unsigned long rd_key[4 *(AES_MAXNR + 1)]; + # int rounds; + # }; + # typedef struct aes_key_st AES_KEY; + # + # int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); + # + # note: the ivec string, and output buffer are both mutable + # void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + # const unsigned long length, const AES_KEY *key, unsigned char *ivec, const int enc); + + AES_MAXNR = 14 + c_char_pp = POINTER(c_char_p) + c_int_p = POINTER(c_int) + + class AES_KEY(Structure): + _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), ('rounds', c_int)] + AES_KEY_p = POINTER(AES_KEY) + + def F(restype, name, argtypes): + func = getattr(libcrypto, name) + func.restype = restype + func.argtypes = argtypes + return func + + AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',[c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p,c_int]) + + AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',[c_char_p, c_int, AES_KEY_p]) + + # From OpenSSL's Crypto evp/p5_crpt2.c + # + # int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, + # const unsigned char *salt, int saltlen, int iter, + # int keylen, unsigned char *out); + + PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', + [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p]) + + class LibCrypto(object): + def __init__(self): + self._blocksize = 0 + self._keyctx = None + self._iv = 0 + + def set_decrypt_key(self, userkey, iv): + self._blocksize = len(userkey) + if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) : + raise DrmException(u"AES improper key used") + return + keyctx = self._keyctx = AES_KEY() + self._iv = iv + self._userkey = userkey + rv = AES_set_decrypt_key(userkey, len(userkey) * 8, keyctx) + if rv < 0: + raise DrmException(u"Failed to initialize AES key") + + def decrypt(self, data): + out = create_string_buffer(len(data)) + mutable_iv = create_string_buffer(self._iv, len(self._iv)) + keyctx = self._keyctx + rv = AES_cbc_encrypt(data, out, len(data), keyctx, mutable_iv, 0) + if rv == 0: + raise DrmException(u"AES decryption failed") + return out.raw + + def keyivgen(self, passwd, salt, iter, keylen): + saltlen = len(salt) + passlen = len(passwd) + out = create_string_buffer(keylen) + rv = PKCS5_PBKDF2_HMAC_SHA1(passwd, passlen, salt, saltlen, iter, keylen, out) + return out.raw + return LibCrypto + + def _load_crypto(): + LibCrypto = None + try: + LibCrypto = _load_crypto_libcrypto() + except (ImportError, DrmException): + pass + return LibCrypto + + LibCrypto = _load_crypto() + + # Various character maps used to decrypt books. Probably supposed to act as obfuscation + charMap1 = 'n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M' + charMap2 = 'ZB0bYyc1xDdW2wEV3Ff7KkPpL8UuGA4gz-Tme9Nn_tHh5SvXCsIiR6rJjQaqlOoM' + + # For kinf approach of K4Mac 1.6.X or later + # On K4PC charMap5 = 'AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE' + # For Mac they seem to re-use charMap2 here + charMap5 = charMap2 + + # new in K4M 1.9.X + testMap8 = 'YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD' + + # uses a sub process to get the Hard Drive Serial Number using ioreg + # returns serial numbers of all internal hard drive drives + def GetVolumesSerialNumbers(): + sernum = os.getenv('MYSERIALNUMBER') + if sernum != None: + return [sernum] + sernums = [] + cmdline = '/usr/sbin/ioreg -w 0 -r -c AppleAHCIDiskDriver' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + bsdname = None + sernum = None + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + pp = resline.find('\"Serial Number\" = \"') + if pp >= 0: + sernum = resline[pp+19:-1] + sernums.append(sernum.strip()) + return [sernum] + + def GetUserHomeAppSupKindleDirParitionName(): + home = os.getenv('HOME') + dpath = home + '/Library' + cmdline = '/sbin/mount' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + disk = '' + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + if resline.startswith('/dev'): + (devpart, mpath) = resline.split(' on ') + dpart = devpart[5:] + pp = mpath.find('(') + if pp >= 0: + mpath = mpath[:pp-1] + if dpath.startswith(mpath): + disk = dpart + return disk + + # uses a sub process to get the UUID of the specified disk partition using ioreg + def GetDiskPartitionUUID(diskpart): + uuidnum = os.getenv('MYUUIDNUMBER') + if uuidnum != None: + return uuidnum + cmdline = '/usr/sbin/ioreg -l -S -w 0 -r -c AppleAHCIDiskDriver' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + bsdname = None + uuidnum = None + foundIt = False + nest = 0 + uuidnest = -1 + partnest = -2 + for j in xrange(cnt): + resline = reslst[j] + if resline.find('{') >= 0: + nest += 1 + if resline.find('}') >= 0: + nest -= 1 + pp = resline.find('\"UUID\" = \"') + if pp >= 0: + uuidnum = resline[pp+10:-1] + uuidnum = uuidnum.strip() + uuidnest = nest + if partnest == uuidnest and uuidnest > 0: + foundIt = True + break + bb = resline.find('\"BSD Name\" = \"') + if bb >= 0: + bsdname = resline[bb+14:-1] + bsdname = bsdname.strip() + if (bsdname == diskpart): + partnest = nest + else : + partnest = -2 + if partnest == uuidnest and partnest > 0: + foundIt = True + break + if nest == 0: + partnest = -2 + uuidnest = -1 + uuidnum = None + bsdname = None + if not foundIt: + uuidnum = '' + return uuidnum + + def GetMACAddressMunged(): + macnum = os.getenv('MYMACNUM') + if macnum != None: + return macnum + cmdline = '/sbin/ifconfig en0' + cmdline = cmdline.encode(sys.getfilesystemencoding()) + p = subprocess.Popen(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + out1, out2 = p.communicate() + reslst = out1.split('\n') + cnt = len(reslst) + macnum = None + foundIt = False + for j in xrange(cnt): + resline = reslst[j] + pp = resline.find('ether ') + if pp >= 0: + macnum = resline[pp+6:-1] + macnum = macnum.strip() + # print 'original mac', macnum + # now munge it up the way Kindle app does + # by xoring it with 0xa5 and swapping elements 3 and 4 + maclst = macnum.split(':') + n = len(maclst) + if n != 6: + fountIt = False + break + for i in range(6): + maclst[i] = int('0x' + maclst[i], 0) + mlst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + mlst[5] = maclst[5] ^ 0xa5 + mlst[4] = maclst[3] ^ 0xa5 + mlst[3] = maclst[4] ^ 0xa5 + mlst[2] = maclst[2] ^ 0xa5 + mlst[1] = maclst[1] ^ 0xa5 + mlst[0] = maclst[0] ^ 0xa5 + macnum = '%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x' % (mlst[0], mlst[1], mlst[2], mlst[3], mlst[4], mlst[5]) + foundIt = True + break + if not foundIt: + macnum = '' + return macnum + + + # uses unix env to get username instead of using sysctlbyname + def GetUserName(): + username = os.getenv('USER') + return username + + def GetIDStrings(): + # Return all possible ID Strings + strings = [] + strings.append(GetMACAddressMunged()) + strings.extend(GetVolumesSerialNumbers()) + diskpart = GetUserHomeAppSupKindleDirParitionName() + strings.append(GetDiskPartitionUUID(diskpart)) + strings.append('9999999999') + return strings + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used by Kindle for Mac versions < 1.6.0 + class CryptUnprotectData(object): + def __init__(self, IDString): + sp = IDString + '!@#' + GetUserName() + passwdData = encode(SHA256(sp),charMap1) + salt = '16743' + self.crp = LibCrypto() + iter = 0x3e8 + keylen = 0x80 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext,charMap1) + return cleartext + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used for Kindle for Mac Versions >= 1.6.0 + class CryptUnprotectDataV2(object): + def __init__(self, IDString): + sp = GetUserName() + ':&%:' + IDString + passwdData = encode(SHA256(sp),charMap5) + # salt generation as per the code + salt = 0x0512981d * 2 * 1 * 1 + salt = str(salt) + GetUserName() + salt = encode(salt,charMap5) + self.crp = LibCrypto() + iter = 0x800 + keylen = 0x400 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext, charMap5) + return cleartext + + + # unprotect the new header blob in .kinf2011 + # used in Kindle for Mac Version >= 1.9.0 + def UnprotectHeaderData(encryptedData): + passwdData = 'header_key_data' + salt = 'HEADER.2011' + iter = 0x80 + keylen = 0x100 + crp = LibCrypto() + key_iv = crp.keyivgen(passwdData, salt, iter, keylen) + key = key_iv[0:32] + iv = key_iv[32:48] + crp.set_decrypt_key(key,iv) + cleartext = crp.decrypt(encryptedData) + return cleartext + + + # implements an Pseudo Mac Version of Windows built-in Crypto routine + # used for Kindle for Mac Versions >= 1.9.0 + class CryptUnprotectDataV3(object): + def __init__(self, entropy, IDString): + sp = GetUserName() + '+@#$%+' + IDString + passwdData = encode(SHA256(sp),charMap2) + salt = entropy + self.crp = LibCrypto() + iter = 0x800 + keylen = 0x400 + key_iv = self.crp.keyivgen(passwdData, salt, iter, keylen) + self.key = key_iv[0:32] + self.iv = key_iv[32:48] + self.crp.set_decrypt_key(self.key, self.iv) + + def decrypt(self, encryptedData): + cleartext = self.crp.decrypt(encryptedData) + cleartext = decode(cleartext, charMap2) + return cleartext + + + # Locate the .kindle-info files + def getKindleInfoFiles(): + # file searches can take a long time on some systems, so just look in known specific places. + kInfoFiles=[] + found = False + home = os.getenv('HOME') + # check for .kinf2011 file in new location (App Store Kindle for Mac) + testpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.kinf2011' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kinf2011 file: ' + testpath) + found = True + # check for .kinf2011 files + testpath = home + '/Library/Application Support/Kindle/storage/.kinf2011' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kinf2011 file: ' + testpath) + found = True + # check for .rainier-2.1.1-kinf files + testpath = home + '/Library/Application Support/Kindle/storage/.rainier-2.1.1-kinf' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac rainier file: ' + testpath) + found = True + # check for .kindle-info files + testpath = home + '/Library/Application Support/Kindle/storage/.kindle-info' + if os.path.isfile(testpath): + kInfoFiles.append(testpath) + print('Found k4Mac kindle-info file: ' + testpath) + found = True + if not found: + print('No k4Mac kindle-info/rainier/kinf2011 files have been found.') + return kInfoFiles + + # determine type of kindle info provided and return a + # database of keynames and values + def getDBfromFile(kInfoFile): + names = ['kindle.account.tokens','kindle.cookie.item','eulaVersionAccepted','login_date','kindle.token.item','login','kindle.key.item','kindle.name.info','kindle.device.info', 'MazamaRandomNumber', 'max_date', 'SIGVERIF'] + with open(kInfoFile, 'rb') as infoReader: + filehdr = infoReader.read(1) + filedata = infoReader.read() + + IDStrings = GetIDStrings() + for IDString in IDStrings: + DB = {} + #print "trying IDString:",IDString + try: + hdr = filehdr + data = filedata + if data.find('[') != -1 : + # older style kindle-info file + cud = CryptUnprotectData(IDString) + items = data.split('[') + for item in items: + if item != '': + keyhash, rawdata = item.split(':') + keyname = 'unknown' + for name in names: + if encodeHash(name,charMap2) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + encryptedValue = decode(rawdata,charMap2) + cleartext = cud.decrypt(encryptedValue) + if len(cleartext) > 0: + DB[keyname] = cleartext + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + elif hdr == '/': + # else newer style .kinf file used by K4Mac >= 1.6.0 + # the .kinf file uses '/' to separate it into records + # so remove the trailing '/' to make it easy to use split + data = data[:-1] + items = data.split('/') + cud = CryptUnprotectDataV2(IDString) + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + keyname = 'unknown' + + # the raw keyhash string is also used to create entropy for the actual + # CryptProtectData Blob that represents that keys contents + # 'entropy' not used for K4Mac only K4PC + # entropy = SHA1(keyhash) + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = 'unknown' + for name in names: + if encodeHash(name,charMap5) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + + # the charMap5 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using charMap5 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the charMap5 encoded contents seems to be: + # len(contents) - largest prime number less than or equal to int(len(content)/3) + # (in other words split 'about' 2/3rds of the way through) + + # move first offsets chars to end to align for decode by charMap5 + encdata = ''.join(edlst) + contlen = len(encdata) + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using charMap5 to get the CryptProtect Data + encryptedValue = decode(encdata,charMap5) + cleartext = cud.decrypt(encryptedValue) + if len(cleartext) > 0: + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + else: + # the latest .kinf2011 version for K4M 1.9.1 + # put back the hdr char, it is needed + data = hdr + data + data = data[:-1] + items = data.split('/') + + # the headerblob is the encrypted information needed to build the entropy string + headerblob = items.pop(0) + encryptedValue = decode(headerblob, charMap1) + cleartext = UnprotectHeaderData(encryptedValue) + + # now extract the pieces in the same way + # this version is different from K4PC it scales the build number by multipying by 735 + pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE) + for m in re.finditer(pattern, cleartext): + entropy = str(int(m.group(2)) * 0x2df) + m.group(4) + + cud = CryptUnprotectDataV3(entropy,IDString) + + # loop through the item records until all are processed + while len(items) > 0: + + # get the first item record + item = items.pop(0) + + # the first 32 chars of the first record of a group + # is the MD5 hash of the key name encoded by charMap5 + keyhash = item[0:32] + keyname = 'unknown' + + # unlike K4PC the keyhash is not used in generating entropy + # entropy = SHA1(keyhash) + added_entropy + # entropy = added_entropy + + # the remainder of the first record when decoded with charMap5 + # has the ':' split char followed by the string representation + # of the number of records that follow + # and make up the contents + srcnt = decode(item[34:],charMap5) + rcnt = int(srcnt) + + # read and store in rcnt records of data + # that make up the contents value + edlst = [] + for i in xrange(rcnt): + item = items.pop(0) + edlst.append(item) + + keyname = 'unknown' + for name in names: + if encodeHash(name,testMap8) == keyhash: + keyname = name + break + if keyname == 'unknown': + keyname = keyhash + + # the testMap8 encoded contents data has had a length + # of chars (always odd) cut off of the front and moved + # to the end to prevent decoding using testMap8 from + # working properly, and thereby preventing the ensuing + # CryptUnprotectData call from succeeding. + + # The offset into the testMap8 encoded contents seems to be: + # len(contents) - largest prime number less than or equal to int(len(content)/3) + # (in other words split 'about' 2/3rds of the way through) + + # move first offsets chars to end to align for decode by testMap8 + encdata = ''.join(edlst) + contlen = len(encdata) + + # now properly split and recombine + # by moving noffset chars from the start of the + # string to the end of the string + noffset = contlen - primes(int(contlen/3))[-1] + pfx = encdata[0:noffset] + encdata = encdata[noffset:] + encdata = encdata + pfx + + # decode using testMap8 to get the CryptProtect Data + encryptedValue = decode(encdata,testMap8) + cleartext = cud.decrypt(encryptedValue) + # print keyname + # print cleartext + if len(cleartext) > 0: + DB[keyname] = cleartext + + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + break + except: + pass + if 'MazamaRandomNumber' in DB and 'kindle.account.tokens' in DB: + # store values used in decryption + print u"Decrypted key file using IDString '{0:s}' and UserName '{1:s}'".format(IDString, GetUserName()) + DB['IDString'] = IDString + DB['UserName'] = GetUserName() + else: + print u"Couldn't decrypt file." + DB = {} + return DB +else: + def getDBfromFile(kInfoFile): + raise DrmException(u"This script only runs under Windows or Mac OS X.") + return {} + +def kindlekeys(files = []): + keys = [] + if files == []: + files = getKindleInfoFiles() + for file in files: + key = getDBfromFile(file) + if key: + # convert all values to hex, just in case. + for keyname in key: + key[keyname]=key[keyname].encode('hex') + keys.append(key) + return keys + +# interface for Python DeDRM +# returns single key or multiple keys, depending on path or file passed in +def getkey(outpath, files=[]): + keys = kindlekeys(files) + if len(keys) > 0: + if not os.path.isdir(outpath): + outfile = outpath + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(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"kindlekey{0:d}.k4i".format(keycount)) + if not os.path.exists(outfile): + break + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(key)) + print u"Saved a key to {0}".format(outfile) + return True + return False + +def usage(progname): + print u"Finds, decrypts and saves the default Kindle For Mac/PC encryption keys." + print u"Keys are saved to the current directory, or a specified output directory." + print u"If a file name is passed instead of a directory, only the first key is saved, in that file." + print u"Usage:" + print u" {0:s} [-h] [-k ] []".format(progname) + + +def cli_main(argv=unicode_argv()): + progname = os.path.basename(argv[0]) + print u"{0} v{1}\nCopyright © 2010-2013 some_updates and Apprentice Alf".format(progname,__version__) + + try: + opts, args = getopt.getopt(argv[1:], "hk:") + except getopt.GetoptError, err: + print u"Error in options or arguments: {0}".format(err.args[0]) + usage(progname) + sys.exit(2) + + files = [] + for o, a in opts: + if o == "-h": + usage(progname) + sys.exit(0) + if o == "-k": + files = [a] + + if len(args) > 1: + usage(progname) + sys.exit(2) + + if len(args) == 1: + # save to the specified file or directory + outpath = args[0] + if not os.path.isabs(outpath): + outpath = os.path.abspath(outpath) + else: + # save to the same directory as the script + outpath = os.path.dirname(argv[0]) + + # make sure the outpath is the + outpath = os.path.realpath(os.path.normpath(outpath)) + + if not getkey(outpath, files): + print u"Could not retrieve Kindle for Mac/PC key." + return 0 + + +def gui_main(argv=unicode_argv()): + import Tkinter + import Tkconstants + import tkMessageBox + import traceback + + class ExceptionDialog(Tkinter.Frame): + def __init__(self, root, text): + Tkinter.Frame.__init__(self, root, border=5) + label = Tkinter.Label(self, text=u"Unexpected error:", + anchor=Tkconstants.W, justify=Tkconstants.LEFT) + label.pack(fill=Tkconstants.X, expand=0) + self.text = Tkinter.Text(self) + self.text.pack(fill=Tkconstants.BOTH, expand=1) + + self.text.insert(Tkconstants.END, text) + + + root = Tkinter.Tk() + root.withdraw() + progpath, progname = os.path.split(argv[0]) + success = False + try: + keys = kindlekeys() + keycount = 0 + for key in keys: + while True: + keycount += 1 + outfile = os.path.join(progpath,u"kindlekey{0:d}.k4i".format(keycount)) + if not os.path.exists(outfile): + break + + with file(outfile, 'w') as keyfileout: + keyfileout.write(json.dumps(key)) + success = True + tkMessageBox.showinfo(progname, u"Key successfully retrieved to {0}".format(outfile)) + except DrmException, e: + tkMessageBox.showerror(progname, u"Error: {0}".format(str(e))) + except Exception: + root.wm_state('normal') + root.title(progname) + text = traceback.format_exc() + ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1) + root.mainloop() + if not success: + return 1 + return 0 + +if __name__ == '__main__': + if len(sys.argv) > 1: + sys.stdout=SafeUnbuffered(sys.stdout) + sys.stderr=SafeUnbuffered(sys.stderr) + sys.exit(cli_main()) + sys.exit(gui_main()) diff --git a/Other_Tools/Rocket_ebooks/rebhack.zip b/Other_Tools/Rocket_ebooks/rebhack.zip new file mode 100644 index 0000000000000000000000000000000000000000..252628eec86771e78f6084dcee59f678f41f8bb1 GIT binary patch literal 206771 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 literal 0 HcmV?d00001 diff --git a/Other_Tools/Rocket_ebooks/rebhack_ReadMe.txt b/Other_Tools/Rocket_ebooks/rebhack_ReadMe.txt new file mode 100644 index 0000000..b8b8430 --- /dev/null +++ b/Other_Tools/Rocket_ebooks/rebhack_ReadMe.txt @@ -0,0 +1,8 @@ +Rocket eBooks +============= + +Rocket ebooks (.rb) are no longer sold. + +This is the only archive of tools for decrypting Rocket ebooks that I have been able to find. It is included here without further comment or support. + +— Alf. diff --git a/ReadMe_First.txt b/ReadMe_First.txt index 04048a6..72fe78b 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 v5.6.2 archive. +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.0 archive from Apprentice Alf's Blog: http://apprenticealf.wordpress.com/ The is archive includes tools to remove DRM from: @@ -19,9 +19,7 @@ These tools do NOT work with Apple's iBooks FairPlay DRM (see end of this file.) About the tools --------------- These tools have been updated and maintained by Apprentice Alf, DiapDealer and some_updates. - You can find the latest updates and get support at Apprentice Alf's blog: http://www.apprenticealf.wordpress.com/ - If you re-post these tools, a link to the blog would be appreciated. The original inept and ignoble scripts were by i♥cabbages @@ -29,35 +27,33 @@ The original mobidedrm and erdr2pml scripts were by The Dark Reverser The original topaz DRM removal script was by CMBDTC The original topaz format conversion scripts were by some_updates, clarknova and Bart Simpson The Scuolabooks tool is by Hex - The calibre plugin conversions were originally by DiapDealer -The DeDRM AppleScript application was by Apprentice Alf -The DeDRM python GUI was by some_updates -Many fixes, updates and enhancements to the scripts and applicatons have been by Apprentice Alf, some_updates and DiapDealer. +The DeDRM plugin is by Apprentice Alf +The DeDRM AppleScript application is by Apprentice Alf +The DeDRM python GUI is by some_updates and Apprentice Alf + +Many fixes, updates and enhancements to the scripts and applicatons have been by Apprentice Alf, some_updates and DiapDealer and others. Calibre Users (Mac OS X, Windows, and Linux) -------------------------------------------- -If you are a calibre user, the quickest and easiest way, especially on Windows, to remove DRM from your ebooks is to install the relevant plugins from the Calibre_Plugins folder, following the instructions and configuration directions provided in each plugin's ReadMe file. +If you are a calibre user, the quickest and easiest way, especially on Windows, to remove DRM from your ebooks is to install the DeDRM plugin from the DeDRM_plugin folder, following the instructions and configuration directions provided in the ReadMe and the help links. Once installed and configured, you can simply add a DRM book to calibre and the DeDRMed version will be imported into the calibre database. Note that DRM removal ONLY occurs on import. If you have already imported DRM books you'll need to remove them from calibre and re-import them. -These plugins work for Windows, Mac OS X and Linux. For ebooks from Kindle 4 PC and Adobe Digital Editions, Linux users should read the section at the end of this ReadMe. - +These plugins work for Windows, Mac OS X and Linux. For ebooks from Kindle 4 PC and Adobe Digital Editions, Linux users should read the section at the end the DeDRM_plugin_ReadMe.txt file. DeDRM application for Mac OS X users: (Mac OS X 10.4 and above) ---------------------------------------------------------------------- This application combines all the tools into one easy-to-use tool for Mac OS X users. -Drag the "DeDRM 5.6.2.app" application from the DeDRM_Applications/Macintosh folder to your Desktop (or your Applications Folder, or anywhere else you find convenient). Double-click on the application to run it and it will guide you through collecting the data it needs to remove the DRM from any of the kinds of DRMed ebook listed in the first section of this ReadMe. +Drag the "DeDRM 6.0.0.app" application from the DeDRM_Application_Macintosh folder to your Desktop (or your Applications Folder, or anywhere else you find convenient). Double-click on the application to run it and it will guide you through collecting the data it needs to remove the DRM from any of the kinds of DRMed ebook listed in the first section of this ReadMe. To use the DeDRM application, simply drag ebooks, or folders containing ebooks, onto the DeDRM application and it will remove the DRM of the kinds listed above. -For more detailed instructions, see the "DeDRM ReadMe.rtf" file in the DeDRM_Applications/Macintosh folder, including details of the extra step that Mac OS X 10.4 users need to take to use the application. - - +For more detailed instructions, see the "DeDRM ReadMe.rtf" file in the DeDRM_Application_Macintosh folder, including details of the extra step that Mac OS X 10.4 users need to take to use the application. DeDRM application for Windows users: (Windows XP through Windows 8) @@ -67,28 +63,30 @@ DeDRM application for Windows users: (Windows XP through Windows 8) This application combines all the tools into one easy-to-use tool for Windows users. -Drag the DeDRM_5.6.2 folder that's in the DeDRM_Applications/Windows folder, to your "My Documents" folder (or anywhere else you find convenient). Make a short-cut on your Desktop of the DeDRM_Drop_Target.bat file that's in the DeDRM_5.6.2 folder. Double-click on the shortcut and the DeDRM application will run and guide you through collecting the data it needs to remove the DRM from any of the kinds of DRMed ebook listed in the first section of this ReadMe. +Drag the DeDRM_6.0.0 folder that's in the DeDRM_Application_Windows folder, to your "My Documents" folder (or anywhere else you find convenient). Make a short-cut on your Desktop of the DeDRM_Drop_Target.bat file that's in the DeDRM_6.0.0 folder. Double-click on the shortcut and the DeDRM application will run and guide you through collecting the data it needs to remove the DRM from any of the kinds of DRMed ebook listed in the first section of this ReadMe. To use the DeDRM application, simply drag ebooks, or folders containing ebooks, onto the DeDRM_Drop_Target.bat shortcut and it will remove the DRM of the kinds listed above. -For more detailed instructions, see the DeDRM_ReadMe.txt file in the DeDRM_Applications/Windows folder. - +For more detailed instructions, see the DeDRM_Application_ReadMe.txt file in the DeDRM_Applications/Windows folder. Other_Tools ----------- -This folder includes three non-python tools: +This folder includes other useful tools: + +Key_Generation_Script +This folder contains a python script that creates a hashed keyfile for Barnes and Noble ePubs, and will be useful to Windows and Linux users who don't want to use the plugin. + +Key_Retrieval_Scripts +This folder contains python script that retrieve keyfiles for Kindle for Mac and Adobe Digital Editions, and will be useful to all Linux Users. Kindle_for_Android_Patches - Definitely only for the adventurous, this folder contains information on how to modify the Kindel for Android app to b able to get a PID for use with the other Kindle tools (DeDRM apps and calibre plugin). B&N_Download_Helper - A Javascript to enable a download button at the B&N website for ebooks that normally won't download to your PC. Another one only for the adventurous. Scuolabook_DRM - A windows-only application (including source code) for removing DRM from ScuolaBooks PDFs, created by "Hex" and included with permission.