tools v3.3

This commit is contained in:
Apprentice Alf 2011-02-02 14:41:15 +00:00
parent bc968f8eca
commit 8b632e309f
38 changed files with 454 additions and 1366 deletions

View File

@ -68,7 +68,7 @@ class DocParser(object):
ys = [] ys = []
gdefs = [] gdefs = []
# get path defintions, positions, dimensions for ecah glyph # get path defintions, positions, dimensions for each glyph
# that makes up the image, and find min x and min y to reposition origin # that makes up the image, and find min x and min y to reposition origin
minx = -1 minx = -1
miny = -1 miny = -1
@ -305,6 +305,15 @@ class DocParser(object):
lastGlyph = firstglyphList[last] lastGlyph = firstglyphList[last]
else : else :
lastGlyph = len(gidList) lastGlyph = len(gidList)
# handle case of white sapce paragraphs with no actual glyphs in them
# by reverting to text based paragraph
if firstGlyph >= lastGlyph:
# revert to standard text based paragraph
for wordnum in xrange(first, last):
result.append(('ocr', wordnum))
return pclass, result
for glyphnum in xrange(firstGlyph, lastGlyph): for glyphnum in xrange(firstGlyph, lastGlyph):
glyphList.append(glyphnum) glyphList.append(glyphnum)
# include any extratokens if they exist # include any extratokens if they exist

View File

@ -57,8 +57,9 @@
# 0.16 - convert to use openssl DES (very very fast) or pure python DES if openssl's libcrypto is not available # 0.16 - convert to use openssl DES (very very fast) or pure python DES if openssl's libcrypto is not available
# 0.17 - added support for pycrypto's DES as well # 0.17 - added support for pycrypto's DES as well
# 0.18 - on Windows try PyCrypto first and OpenSSL next # 0.18 - on Windows try PyCrypto first and OpenSSL next
# 0.19 - Modify the interface to allow use of import
__version__='0.18' __version__='0.19'
class Unbuffered: class Unbuffered:
def __init__(self, stream): def __init__(self, stream):
@ -111,12 +112,14 @@ except ImportError:
# older Python release # older Python release
import sha import sha
sha1 = lambda s: sha.new(s) sha1 = lambda s: sha.new(s)
import cgi import cgi
import logging import logging
logging.basicConfig() logging.basicConfig()
#logging.basicConfig(level=logging.DEBUG) #logging.basicConfig(level=logging.DEBUG)
class Sectionizer(object): class Sectionizer(object):
def __init__(self, filename, ident): def __init__(self, filename, ident):
self.contents = file(filename, 'rb').read() self.contents = file(filename, 'rb').read()
@ -364,7 +367,7 @@ def cleanPML(pml):
def convertEreaderToPml(infile, name, cc, outdir): def convertEreaderToPml(infile, name, cc, outdir):
if not os.path.exists(outdir): if not os.path.exists(outdir):
os.makedirs(outdir) os.makedirs(outdir)
bookname = os.path.splitext(os.path.basename(infile))[0]
print " Decoding File" print " Decoding File"
sect = Sectionizer(infile, 'PNRdPPrs') sect = Sectionizer(infile, 'PNRdPPrs')
er = EreaderProcessor(sect.loadSection, name, cc) er = EreaderProcessor(sect.loadSection, name, cc)
@ -390,6 +393,47 @@ def convertEreaderToPml(infile, name, cc, outdir):
# file(os.path.join(outdir, 'bookinfo.txt'),'wb').write(bkinfo) # file(os.path.join(outdir, 'bookinfo.txt'),'wb').write(bkinfo)
def decryptBook(infile, outdir, name, cc, make_pmlz):
if make_pmlz :
# ignore specified outdir, use tempdir instead
outdir = tempfile.mkdtemp()
try:
print "Processing..."
convertEreaderToPml(infile, name, cc, outdir)
if make_pmlz :
import zipfile
import shutil
print " Creating PMLZ file"
zipname = infile[:-4] + '.pmlz'
myZipFile = zipfile.ZipFile(zipname,'w',zipfile.ZIP_STORED, False)
list = os.listdir(outdir)
for file in list:
localname = file
filePath = os.path.join(outdir,file)
if os.path.isfile(filePath):
myZipFile.write(filePath, localname)
elif os.path.isdir(filePath):
imageList = os.listdir(filePath)
localimgdir = os.path.basename(filePath)
for image in imageList:
localname = os.path.join(localimgdir,image)
imagePath = os.path.join(filePath,image)
if os.path.isfile(imagePath):
myZipFile.write(imagePath, localname)
myZipFile.close()
# remove temporary directory
shutil.rmtree(outdir, True)
print 'output is %s' % zipname
else :
print 'output in %s' % outdir
print "done"
except ValueError, e:
print "Error: %s" % e
return 1
return 0
def usage(): def usage():
print "Converts DRMed eReader books to PML Source" print "Converts DRMed eReader books to PML Source"
print "Usage:" print "Usage:"
@ -404,8 +448,8 @@ def usage():
print " It's enough to enter the last 8 digits of the credit card number" print " It's enough to enter the last 8 digits of the credit card number"
return return
def main(argv=None): def main(argv=None):
global bookname
try: try:
opts, args = getopt.getopt(sys.argv[1:], "h", ["make-pmlz"]) opts, args = getopt.getopt(sys.argv[1:], "h", ["make-pmlz"])
except getopt.GetoptError, err: except getopt.GetoptError, err:
@ -413,75 +457,27 @@ def main(argv=None):
usage() usage()
return 1 return 1
make_pmlz = False make_pmlz = False
zipname = None
for o, a in opts: for o, a in opts:
if o == "-h": if o == "-h":
usage() usage()
return 0 return 0
elif o == "--make-pmlz": elif o == "--make-pmlz":
make_pmlz = True make_pmlz = True
zipname = ''
print "eRdr2Pml v%s. Copyright (c) 2009 The Dark Reverser" % __version__ print "eRdr2Pml v%s. Copyright (c) 2009 The Dark Reverser" % __version__
if len(args)!=3 and len(args)!=4: if len(args)!=3 and len(args)!=4:
usage() usage()
return 1 return 1
else:
if len(args)==3:
infile, name, cc = args[0], args[1], args[2]
outdir = infile[:-4] + '_Source'
elif len(args)==4:
infile, outdir, name, cc = args[0], args[1], args[2], args[3]
if make_pmlz : if len(args)==3:
# ignore specified outdir, use tempdir instead infile, name, cc = args[0], args[1], args[2]
outdir = tempfile.mkdtemp() outdir = infile[:-4] + '_Source'
elif len(args)==4:
infile, outdir, name, cc = args[0], args[1], args[2], args[3]
bookname = os.path.splitext(os.path.basename(infile))[0] return decryptBook(infile, outdir, name, cc, make_pmlz)
try:
print "Processing..."
import time
start_time = time.time()
convertEreaderToPml(infile, name, cc, outdir)
if make_pmlz :
import zipfile
import shutil
print " Creating PMLZ file"
zipname = infile[:-4] + '.pmlz'
myZipFile = zipfile.ZipFile(zipname,'w',zipfile.ZIP_STORED, False)
list = os.listdir(outdir)
for file in list:
localname = file
filePath = os.path.join(outdir,file)
if os.path.isfile(filePath):
myZipFile.write(filePath, localname)
elif os.path.isdir(filePath):
imageList = os.listdir(filePath)
localimgdir = os.path.basename(filePath)
for image in imageList:
localname = os.path.join(localimgdir,image)
imagePath = os.path.join(filePath,image)
if os.path.isfile(imagePath):
myZipFile.write(imagePath, localname)
myZipFile.close()
# remove temporary directory
shutil.rmtree(outdir, True)
end_time = time.time()
search_time = end_time - start_time
print 'elapsed time: %.2f seconds' % (search_time, )
if make_pmlz :
print 'output is %s' % zipname
else :
print 'output in %s' % outdir
print "done"
except ValueError, e:
print "Error: %s" % e
return 1
return 0
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())

View File

@ -271,7 +271,7 @@ class IgnobleDeDRM(FileTypePlugin):
Credit given to I <3 Cabbages for the original stand-alone scripts.' Credit given to I <3 Cabbages for the original stand-alone scripts.'
supported_platforms = ['linux', 'osx', 'windows'] supported_platforms = ['linux', 'osx', 'windows']
author = 'DiapDealer' author = 'DiapDealer'
version = (0, 1, 3) version = (0, 1, 4)
minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions. minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions.
file_types = set(['epub']) file_types = set(['epub'])
on_import = True on_import = True

View File

@ -81,23 +81,44 @@ class fixZip:
# get the zipinfo for each member of the input archive # get the zipinfo for each member of the input archive
# and copy member over to output archive # and copy member over to output archive
# if problems exist with local vs central filename, fix them # if problems exist with local vs central filename, fix them
# also fix bad epub compression
for i, zinfo in enumerate(self.inzip.infolist()): # write mimetype file first, if present, and with no compression
data = None for zinfo in self.inzip.infolist():
nzinfo = zinfo if zinfo.filename == "mimetype":
nzinfo = zinfo
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
try: nzinfo.date_time = zinfo.date_time
data = self.inzip.read(zinfo) nzinfo.compress_type = zipfile.ZIP_STORED
except zipfile.BadZipfile or zipfile.error: nzinfo.flag_bits = 0
local_name = self.getlocalname(zinfo) nzinfo.internal_attr = 0
data = self.getfiledata(zinfo) nzinfo.extra = ""
nzinfo.filename = local_name self.outzip.writestr(nzinfo,data)
break
nzinfo.date_time = zinfo.date_time # write the rest of the files
nzinfo.compress_type = zinfo.compress_type for zinfo in self.inzip.infolist():
nzinfo.flag_bits = 0 if zinfo.filename != "mimetype":
nzinfo.internal_attr = 0 data = None
self.outzip.writestr(nzinfo,data) nzinfo = zinfo
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
nzinfo.date_time = zinfo.date_time
nzinfo.compress_type = zinfo.compress_type
nzinfo.flag_bits = 0
nzinfo.internal_attr = 0
self.outzip.writestr(nzinfo,data)
self.bzf.close() self.bzf.close()
self.inzip.close() self.inzip.close()
@ -111,14 +132,7 @@ def usage():
""" """
def main(argv=sys.argv): def repairBook(infile, outfile):
if len(argv)!=3:
usage()
return 1
infile = None
outfile = None
infile = argv[1]
outfile = argv[2]
if not os.path.exists(infile): if not os.path.exists(infile):
print "Error: Input Zip File does not exist" print "Error: Input Zip File does not exist"
return 1 return 1
@ -130,6 +144,16 @@ def main(argv=sys.argv):
print "Error Occurred ", e print "Error Occurred ", e
return 2 return 2
def main(argv=sys.argv):
if len(argv)!=3:
usage()
return 1
infile = argv[1]
outfile = argv[2]
return repairBook(infile, outfile)
if __name__ == '__main__' : if __name__ == '__main__' :
sys.exit(main()) sys.exit(main())

Binary file not shown.

View File

@ -371,7 +371,7 @@ class IneptDeDRM(FileTypePlugin):
Credit given to I <3 Cabbages for the original stand-alone scripts.' Credit given to I <3 Cabbages for the original stand-alone scripts.'
supported_platforms = ['linux', 'osx', 'windows'] supported_platforms = ['linux', 'osx', 'windows']
author = 'DiapDealer' author = 'DiapDealer'
version = (0, 1, 4) version = (0, 1, 5)
minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions. minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions.
file_types = set(['epub']) file_types = set(['epub'])
on_import = True on_import = True

View File

@ -81,23 +81,44 @@ class fixZip:
# get the zipinfo for each member of the input archive # get the zipinfo for each member of the input archive
# and copy member over to output archive # and copy member over to output archive
# if problems exist with local vs central filename, fix them # if problems exist with local vs central filename, fix them
# also fix bad epub compression
for i, zinfo in enumerate(self.inzip.infolist()): # write mimetype file first, if present, and with no compression
data = None for zinfo in self.inzip.infolist():
nzinfo = zinfo if zinfo.filename == "mimetype":
nzinfo = zinfo
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
try: nzinfo.date_time = zinfo.date_time
data = self.inzip.read(zinfo) nzinfo.compress_type = zipfile.ZIP_STORED
except zipfile.BadZipfile or zipfile.error: nzinfo.flag_bits = 0
local_name = self.getlocalname(zinfo) nzinfo.internal_attr = 0
data = self.getfiledata(zinfo) nzinfo.extra = ""
nzinfo.filename = local_name self.outzip.writestr(nzinfo,data)
break
nzinfo.date_time = zinfo.date_time # write the rest of the files
nzinfo.compress_type = zinfo.compress_type for zinfo in self.inzip.infolist():
nzinfo.flag_bits = 0 if zinfo.filename != "mimetype":
nzinfo.internal_attr = 0 data = None
self.outzip.writestr(nzinfo,data) nzinfo = zinfo
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
nzinfo.date_time = zinfo.date_time
nzinfo.compress_type = zinfo.compress_type
nzinfo.flag_bits = 0
nzinfo.internal_attr = 0
self.outzip.writestr(nzinfo,data)
self.bzf.close() self.bzf.close()
self.inzip.close() self.inzip.close()
@ -111,14 +132,7 @@ def usage():
""" """
def main(argv=sys.argv): def repairBook(infile, outfile):
if len(argv)!=3:
usage()
return 1
infile = None
outfile = None
infile = argv[1]
outfile = argv[2]
if not os.path.exists(infile): if not os.path.exists(infile):
print "Error: Input Zip File does not exist" print "Error: Input Zip File does not exist"
return 1 return 1
@ -130,6 +144,16 @@ def main(argv=sys.argv):
print "Error Occurred ", e print "Error Occurred ", e
return 2 return 2
def main(argv=sys.argv):
if len(argv)!=3:
usage()
return 1
infile = argv[1]
outfile = argv[2]
return repairBook(infile, outfile)
if __name__ == '__main__' : if __name__ == '__main__' :
sys.exit(main()) sys.exit(main())

Binary file not shown.

View File

@ -29,7 +29,7 @@ from __future__ import with_statement
# and import that ZIP into Calibre using its plugin configuration GUI. # and import that ZIP into Calibre using its plugin configuration GUI.
__version__ = '2.1' __version__ = '2.2'
class Unbuffered: class Unbuffered:
def __init__(self, stream): def __init__(self, stream):
@ -75,6 +75,7 @@ def zipUpDir(myzip, tempdir,localname):
# borrowed from calibre from calibre/src/calibre/__init__.py # borrowed from calibre from calibre/src/calibre/__init__.py
# added in removal of non-printing chars # added in removal of non-printing chars
# and removal of . at start # and removal of . at start
# convert spaces to underscores
def cleanup_name(name): def cleanup_name(name):
_filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]') _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]')
substitute='_' substitute='_'
@ -89,6 +90,7 @@ def cleanup_name(name):
# Mac and Unix don't like file names that begin with a full stop # Mac and Unix don't like file names that begin with a full stop
if len(one) > 0 and one[0] == '.': if len(one) > 0 and one[0] == '.':
one = substitute+one[1:] one = substitute+one[1:]
one = one.replace(' ','_')
return one return one
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
@ -248,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.' Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
author = 'DiapDealer, SomeUpdates' # The author of this plugin author = 'DiapDealer, SomeUpdates' # The author of this plugin
version = (0, 2, 1) # The version number of this plugin version = (0, 2, 2) # The version number of this plugin
file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
on_import = True # Run this plugin during the import on_import = True # Run this plugin during the import
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm

View File

@ -189,6 +189,6 @@ def openKindleInfo(kInfoFile=None):
raise DrmException('Error: .kindle-info file can not be found') raise DrmException('Error: .kindle-info file can not be found')
return open(kinfopath,'r') return open(kinfopath,'r')
else: else:
if not os.path.isfile(kinfoFile): if not os.path.isfile(kInfoFile):
raise DrmException('Error: kindle-info file can not be found') raise DrmException('Error: kindle-info file can not be found')
return open(kInfoFile, 'r') return open(kInfoFile, 'r')

View File

@ -24,7 +24,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>droplet</string> <string>droplet</string>
<key>CFBundleGetInfoString</key> <key>CFBundleGetInfoString</key>
<string>DeDRM 2.0, Copyright © 20102011 by Apprentice Alf.</string> <string>DeDRM 2.1, Copyright © 20102011 by Apprentice Alf and others.</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>droplet</string> <string>droplet</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
@ -34,7 +34,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2.0</string> <string>2.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>dplt</string> <string>dplt</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
@ -43,14 +43,18 @@
<true/> <true/>
<key>WindowState</key> <key>WindowState</key>
<dict> <dict>
<key>dividerCollapsed</key>
<true/>
<key>eventLogLevel</key>
<integer>-1</integer>
<key>name</key> <key>name</key>
<string>ScriptWindowState</string> <string>ScriptWindowState</string>
<key>positionOfDivider</key> <key>positionOfDivider</key>
<real>709</real> <real>0.0</real>
<key>savedFrame</key> <key>savedFrame</key>
<string>1617 62 862 788 1440 -150 1680 1050 </string> <string>1578 27 862 788 1440 -150 1680 1050 </string>
<key>selectedTabView</key> <key>selectedTabView</key>
<string>result</string> <string>event log</string>
</dict> </dict>
</dict> </dict>
</plist> </plist>

View File

@ -1,900 +0,0 @@
#! /usr/bin/python
"""
Comprehensive Mazama Book DRM with Topaz Cryptography V2.2
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdBHJ4CNc6DNFCw4MRCw4SWAK6
M8hYfnNEI0yQmn5Ti+W8biT7EatpauE/5jgQMPBmdNrDr1hbHyHBSP7xeC2qlRWC
B62UCxeu/fpfnvNHDN/wPWWH4jynZ2M6cdcnE5LQ+FfeKqZn7gnG2No1U9h7oOHx
y2/pHuYme7U1TsgSjwIDAQAB
-----END PUBLIC KEY-----
"""
from __future__ import with_statement
import csv
import sys
import os
import getopt
import zlib
from struct import pack
from struct import unpack
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
import Tkinter
import Tkconstants
import tkMessageBox
import traceback
import hashlib
MAX_PATH = 255
kernel32 = windll.kernel32
advapi32 = windll.advapi32
crypt32 = windll.crypt32
global kindleDatabase
global bookFile
global bookPayloadOffset
global bookHeaderRecords
global bookMetadata
global bookKey
global command
#
# Various character maps used to decrypt books. Probably supposed to act as obfuscation
#
charMap1 = "n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M"
charMap2 = "AaZzB0bYyCc1XxDdW2wEeVv3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_"
charMap3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
charMap4 = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789"
#
# Exceptions for all the problems that might happen during the script
#
class CMBDTCError(Exception):
pass
class CMBDTCFatal(Exception):
pass
#
# Stolen stuff
#
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):
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()
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 CMBDTCFatal("Failed to Unprotect Data")
return string_at(outdata.pbData, outdata.cbData)
return CryptUnprotectData
CryptUnprotectData = CryptUnprotectData()
#
# Returns the MD5 digest of "message"
#
def MD5(message):
ctx = hashlib.md5()
ctx.update(message)
return ctx.digest()
#
# Returns the MD5 digest of "message"
#
def SHA1(message):
ctx = hashlib.sha1()
ctx.update(message)
return ctx.digest()
#
# Open the book file at path
#
def openBook(path):
try:
return open(path,'rb')
except:
raise CMBDTCFatal("Could not open book file: " + path)
#
# Encode the bytes in data with the characters in map
#
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),2):
high = map.find(data[i])
low = map.find(data[i+1])
value = (((high * 0x40) ^ 0x80) & 0xFF) + low
result += pack("B",value)
return result
#
# Locate and open the Kindle.info file (Hopefully in the way it is done in the Kindle application)
#
def openKindleInfo():
regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\")
path = winreg.QueryValueEx(regkey, 'Local AppData')[0]
return open(path+'\\Amazon\\Kindle For PC\\{AMAwzsaPaaZAzmZzZQzgZCAkZ3AjA_AY}\\kindle.info','r')
#
# Parse the Kindle.info file and return the records as a list of key-values
#
def parseKindleInfo():
DB = {}
infoReader = openKindleInfo()
infoReader.read(1)
data = infoReader.read()
items = data.split('{')
for item in items:
splito = item.split(':')
DB[splito[0]] =splito[1]
return DB
#
# Find if the original string for a hashed/encoded string is known. If so return the original string othwise return an empty string. (Totally not optimal)
#
def findNameForHash(hash):
names = ["kindle.account.tokens","kindle.cookie.item","eulaVersionAccepted","login_date","kindle.token.item","login","kindle.key.item","kindle.name.info","kindle.device.info", "MazamaRandomNumber"]
result = ""
for name in names:
if hash == encodeHash(name, charMap2):
result = name
break
return name
#
# Print all the records from the kindle.info file (option -i)
#
def printKindleInfo():
for record in kindleDatabase:
name = findNameForHash(record)
if name != "" :
print (name)
print ("--------------------------\n")
else :
print ("Unknown Record")
print getKindleInfoValueForHash(record)
print "\n"
#
# Get a record from the Kindle.info file for the key "hashedKey" (already hashed and encoded). Return the decoded and decrypted record
#
def getKindleInfoValueForHash(hashedKey):
global kindleDatabase
encryptedValue = decode(kindleDatabase[hashedKey],charMap2)
return CryptUnprotectData(encryptedValue,"")
#
# Get a record from the Kindle.info file for the string in "key" (plaintext). Return the decoded and decrypted record
#
def getKindleInfoValueForKey(key):
return getKindleInfoValueForHash(encodeHash(key,charMap2))
#
# Get a 7 bit encoded number from the book file
#
def bookReadEncodedNumber():
flag = False
data = ord(bookFile.read(1))
if data == 0xFF:
flag = True
data = ord(bookFile.read(1))
if data >= 0x80:
datax = (data & 0x7F)
while data >= 0x80 :
data = ord(bookFile.read(1))
datax = (datax <<7) + (data & 0x7F)
data = datax
if flag:
data = -data
return data
#
# Encode a number in 7 bit format
#
def encodeNumber(number):
result = ""
negative = False
flag = 0
if number < 0 :
number = -number + 1
negative = True
while True:
byte = number & 0x7F
number = number >> 7
byte += flag
result += chr(byte)
flag = 0x80
if number == 0 :
if (byte == 0xFF and negative == False) :
result += chr(0x80)
break
if negative:
result += chr(0xFF)
return result[::-1]
#
# Get a length prefixed string from the file
#
def bookReadString():
stringLength = bookReadEncodedNumber()
return unpack(str(stringLength)+"s",bookFile.read(stringLength))[0]
#
# Returns a length prefixed string
#
def lengthPrefixString(data):
return encodeNumber(len(data))+data
#
# Read and return the data of one header record at the current book file position [[offset,compressedLength,decompressedLength],...]
#
def bookReadHeaderRecordData():
nbValues = bookReadEncodedNumber()
values = []
for i in range (0,nbValues):
values.append([bookReadEncodedNumber(),bookReadEncodedNumber(),bookReadEncodedNumber()])
return values
#
# Read and parse one header record at the current book file position and return the associated data [[offset,compressedLength,decompressedLength],...]
#
def parseTopazHeaderRecord():
if ord(bookFile.read(1)) != 0x63:
raise CMBDTCFatal("Parse Error : Invalid Header")
tag = bookReadString()
record = bookReadHeaderRecordData()
return [tag,record]
#
# Parse the header of a Topaz file, get all the header records and the offset for the payload
#
def parseTopazHeader():
global bookHeaderRecords
global bookPayloadOffset
magic = unpack("4s",bookFile.read(4))[0]
if magic != 'TPZ0':
raise CMBDTCFatal("Parse Error : Invalid Header, not a Topaz file")
nbRecords = bookReadEncodedNumber()
bookHeaderRecords = {}
for i in range (0,nbRecords):
result = parseTopazHeaderRecord()
bookHeaderRecords[result[0]] = result[1]
if ord(bookFile.read(1)) != 0x64 :
raise CMBDTCFatal("Parse Error : Invalid Header")
bookPayloadOffset = bookFile.tell()
#
# Get a record in the book payload, given its name and index. If necessary the record is decrypted. The record is not decompressed
#
def getBookPayloadRecord(name, index):
encrypted = False
try:
recordOffset = bookHeaderRecords[name][index][0]
except:
raise CMBDTCFatal("Parse Error : Invalid Record, record not found")
bookFile.seek(bookPayloadOffset + recordOffset)
tag = bookReadString()
if tag != name :
raise CMBDTCFatal("Parse Error : Invalid Record, record name doesn't match")
recordIndex = bookReadEncodedNumber()
if recordIndex < 0 :
encrypted = True
recordIndex = -recordIndex -1
if recordIndex != index :
raise CMBDTCFatal("Parse Error : Invalid Record, index doesn't match")
if bookHeaderRecords[name][index][2] != 0 :
record = bookFile.read(bookHeaderRecords[name][index][2])
else:
record = bookFile.read(bookHeaderRecords[name][index][1])
if encrypted:
ctx = topazCryptoInit(bookKey)
record = topazCryptoDecrypt(record,ctx)
return record
#
# Extract, decrypt and decompress a book record indicated by name and index and print it or save it in "filename"
#
def extractBookPayloadRecord(name, index, filename):
compressed = False
try:
compressed = bookHeaderRecords[name][index][2] != 0
record = getBookPayloadRecord(name,index)
except:
print("Could not find record")
if compressed:
try:
record = zlib.decompress(record)
except:
raise CMBDTCFatal("Could not decompress record")
if filename != "":
try:
file = open(filename,"wb")
file.write(record)
file.close()
except:
raise CMBDTCFatal("Could not write to destination file")
else:
print(record)
#
# return next record [key,value] from the book metadata from the current book position
#
def readMetadataRecord():
return [bookReadString(),bookReadString()]
#
# Parse the metadata record from the book payload and return a list of [key,values]
#
def parseMetadata():
global bookHeaderRecords
global bookPayloadAddress
global bookMetadata
bookMetadata = {}
bookFile.seek(bookPayloadOffset + bookHeaderRecords["metadata"][0][0])
tag = bookReadString()
if tag != "metadata" :
raise CMBDTCFatal("Parse Error : Record Names Don't Match")
flags = ord(bookFile.read(1))
nbRecords = ord(bookFile.read(1))
for i in range (0,nbRecords) :
record =readMetadataRecord()
bookMetadata[record[0]] = record[1]
#
# Returns two bit at offset from a bit field
#
def getTwoBitsFromBitField(bitField,offset):
byteNumber = offset // 4
bitPosition = 6 - 2*(offset % 4)
return ord(bitField[byteNumber]) >> bitPosition & 3
#
# Returns the six bits at offset from a bit field
#
def getSixBitsFromBitField(bitField,offset):
offset *= 3
value = (getTwoBitsFromBitField(bitField,offset) <<4) + (getTwoBitsFromBitField(bitField,offset+1) << 2) +getTwoBitsFromBitField(bitField,offset+2)
return value
#
# 8 bits to six bits encoding from hash to generate PID string
#
def encodePID(hash):
global charMap3
PID = ""
for position in range (0,8):
PID += charMap3[getSixBitsFromBitField(hash,position)]
return PID
#
# Context initialisation for the Topaz Crypto
#
def topazCryptoInit(key):
ctx1 = 0x0CAFFE19E
for keyChar in key:
keyByte = ord(keyChar)
ctx2 = ctx1
ctx1 = ((((ctx1 >>2) * (ctx1 >>7))&0xFFFFFFFF) ^ (keyByte * keyByte * 0x0F902007)& 0xFFFFFFFF )
return [ctx1,ctx2]
#
# decrypt data with the context prepared by topazCryptoInit()
#
def topazCryptoDecrypt(data, ctx):
ctx1 = ctx[0]
ctx2 = ctx[1]
plainText = ""
for dataChar in data:
dataByte = ord(dataChar)
m = (dataByte ^ ((ctx1 >> 3) &0xFF) ^ ((ctx2<<3) & 0xFF)) &0xFF
ctx2 = ctx1
ctx1 = (((ctx1 >> 2) * (ctx1 >> 7)) &0xFFFFFFFF) ^((m * m * 0x0F902007) &0xFFFFFFFF)
plainText += chr(m)
return plainText
#
# Decrypt a payload record with the PID
#
def decryptRecord(data,PID):
ctx = topazCryptoInit(PID)
return topazCryptoDecrypt(data, ctx)
#
# Try to decrypt a dkey record (contains the book PID)
#
def decryptDkeyRecord(data,PID):
record = decryptRecord(data,PID)
fields = unpack("3sB8sB8s3s",record)
if fields[0] != "PID" or fields[5] != "pid" :
raise CMBDTCError("Didn't find PID magic numbers in record")
elif fields[1] != 8 or fields[3] != 8 :
raise CMBDTCError("Record didn't contain correct length fields")
elif fields[2] != PID :
raise CMBDTCError("Record didn't contain PID")
return fields[4]
#
# Decrypt all the book's dkey records (contain the book PID)
#
def decryptDkeyRecords(data,PID):
nbKeyRecords = ord(data[0])
records = []
data = data[1:]
for i in range (0,nbKeyRecords):
length = ord(data[0])
try:
key = decryptDkeyRecord(data[1:length+1],PID)
records.append(key)
except CMBDTCError:
pass
data = data[1+length:]
return records
#
# Encryption table used to generate the device PID
#
def generatePidEncryptionTable() :
table = []
for counter1 in range (0,0x100):
value = counter1
for counter2 in range (0,8):
if (value & 1 == 0) :
value = value >> 1
else :
value = value >> 1
value = value ^ 0xEDB88320
table.append(value)
return table
#
# Seed value used to generate the device PID
#
def generatePidSeed(table,dsn) :
value = 0
for counter in range (0,4) :
index = (ord(dsn[counter]) ^ value) &0xFF
value = (value >> 8) ^ table[index]
return value
#
# Generate the device PID
#
def generateDevicePID(table,dsn,nbRoll):
seed = generatePidSeed(table,dsn)
pidAscii = ""
pid = [(seed >>24) &0xFF,(seed >> 16) &0xff,(seed >> 8) &0xFF,(seed) & 0xFF,(seed>>24) & 0xFF,(seed >> 16) &0xff,(seed >> 8) &0xFF,(seed) & 0xFF]
index = 0
for counter in range (0,nbRoll):
pid[index] = pid[index] ^ ord(dsn[counter])
index = (index+1) %8
for counter in range (0,8):
index = ((((pid[counter] >>5) & 3) ^ pid[counter]) & 0x1f) + (pid[counter] >> 7)
pidAscii += charMap4[index]
return pidAscii
#
# Create decrypted book payload
#
def createDecryptedPayload(payload):
# store data to be able to create the header later
headerData= []
currentOffset = 0
# Add social DRM to decrypted files
try:
data = getKindleInfoValueForKey("kindle.name.info")+":"+ getKindleInfoValueForKey("login")
if payload!= None:
payload.write(lengthPrefixString("sdrm"))
payload.write(encodeNumber(0))
payload.write(data)
else:
currentOffset += len(lengthPrefixString("sdrm"))
currentOffset += len(encodeNumber(0))
currentOffset += len(data)
except:
pass
for headerRecord in bookHeaderRecords:
name = headerRecord
newRecord = []
if name != "dkey" :
for index in range (0,len(bookHeaderRecords[name])) :
offset = currentOffset
if payload != None:
# write tag
payload.write(lengthPrefixString(name))
# write data
payload.write(encodeNumber(index))
payload.write(getBookPayloadRecord(name, index))
else :
currentOffset += len(lengthPrefixString(name))
currentOffset += len(encodeNumber(index))
currentOffset += len(getBookPayloadRecord(name, index))
newRecord.append([offset,bookHeaderRecords[name][index][1],bookHeaderRecords[name][index][2]])
headerData.append([name,newRecord])
return headerData
#
# Create decrypted book
#
def createDecryptedBook(outputFile):
outputFile = open(outputFile,"wb")
# Write the payload in a temporary file
headerData = createDecryptedPayload(None)
outputFile.write("TPZ0")
outputFile.write(encodeNumber(len(headerData)))
for header in headerData :
outputFile.write(chr(0x63))
outputFile.write(lengthPrefixString(header[0]))
outputFile.write(encodeNumber(len(header[1])))
for numbers in header[1] :
outputFile.write(encodeNumber(numbers[0]))
outputFile.write(encodeNumber(numbers[1]))
outputFile.write(encodeNumber(numbers[2]))
outputFile.write(chr(0x64))
createDecryptedPayload(outputFile)
outputFile.close()
#
# Set the command to execute by the programm according to cmdLine parameters
#
def setCommand(name) :
global command
if command != "" :
raise CMBDTCFatal("Invalid command line parameters")
else :
command = name
#
# Program usage
#
def usage():
print("\nUsage:")
print("\nCMBDTC.py [options] bookFileName\n")
print("-p Adds a PID to the list of PIDs that are tried to decrypt the book key (can be used several times)")
print("-d Saves a decrypted copy of the book")
print("-r Prints or writes to disk a record indicated in the form name:index (e.g \"img:0\")")
print("-o Output file name to write records and decrypted books")
print("-v Verbose (can be used several times)")
print("-i Prints kindle.info database")
#
# Main
#
def main(argv=sys.argv):
global kindleDatabase
global bookMetadata
global bookKey
global bookFile
global command
progname = os.path.basename(argv[0])
verbose = 0
recordName = ""
recordIndex = 0
outputFile = ""
PIDs = []
kindleDatabase = None
command = ""
try:
opts, args = getopt.getopt(sys.argv[1:], "vdir:o:p:")
except getopt.GetoptError, err:
# print help information and exit:
print str(err) # will print something like "option -a not recognized"
usage()
sys.exit(2)
if len(opts) == 0 and len(args) == 0 :
usage()
sys.exit(2)
for o, a in opts:
if o == "-v":
verbose+=1
if o == "-i":
setCommand("printInfo")
if o =="-o":
if a == None :
raise CMBDTCFatal("Invalid parameter for -o")
outputFile = a
if o =="-r":
setCommand("printRecord")
try:
recordName,recordIndex = a.split(':')
except:
raise CMBDTCFatal("Invalid parameter for -r")
if o =="-p":
PIDs.append(a)
if o =="-d":
setCommand("doit")
if command == "" :
raise CMBDTCFatal("No action supplied on command line")
#
# Read the encrypted database
#
try:
kindleDatabase = parseKindleInfo()
except Exception, message:
if verbose>0:
print(message)
if kindleDatabase != None :
if command == "printInfo" :
printKindleInfo()
#
# Compute the DSN
#
# Get the Mazama Random number
MazamaRandomNumber = getKindleInfoValueForKey("MazamaRandomNumber")
# Get the HDD serial
encodedSystemVolumeSerialNumber = encodeHash(str(GetVolumeSerialNumber(GetSystemDirectory().split('\\')[0] + '\\')),charMap1)
# Get the current user name
encodedUsername = encodeHash(GetUserName(),charMap1)
# concat, hash and encode
DSN = encode(SHA1(MazamaRandomNumber+encodedSystemVolumeSerialNumber+encodedUsername),charMap1)
if verbose >1:
print("DSN: " + DSN)
#
# Compute the device PID
#
table = generatePidEncryptionTable()
devicePID = generateDevicePID(table,DSN,4)
PIDs.append(devicePID)
if verbose > 0:
print("Device PID: " + devicePID)
#
# Open book and parse metadata
#
if len(args) == 1:
bookFile = openBook(args[0])
parseTopazHeader()
parseMetadata()
#
# Compute book PID
#
# Get the account token
if kindleDatabase != None:
kindleAccountToken = getKindleInfoValueForKey("kindle.account.tokens")
if verbose >1:
print("Account Token: " + kindleAccountToken)
keysRecord = bookMetadata["keys"]
keysRecordRecord = bookMetadata[keysRecord]
pidHash = SHA1(DSN+kindleAccountToken+keysRecord+keysRecordRecord)
bookPID = encodePID(pidHash)
PIDs.append(bookPID)
if verbose > 0:
print ("Book PID: " + bookPID )
#
# Decrypt book key
#
dkey = getBookPayloadRecord('dkey', 0)
bookKeys = []
for PID in PIDs :
bookKeys+=decryptDkeyRecords(dkey,PID)
if len(bookKeys) == 0 :
if verbose > 0 :
print ("Book key could not be found. Maybe this book is not registered with this device.")
else :
bookKey = bookKeys[0]
if verbose > 0:
print("Book key: " + bookKey.encode('hex'))
if command == "printRecord" :
extractBookPayloadRecord(recordName,int(recordIndex),outputFile)
if outputFile != "" and verbose>0 :
print("Wrote record to file: "+outputFile)
elif command == "doit" :
if outputFile!="" :
createDecryptedBook(outputFile)
if verbose >0 :
print ("Decrypted book saved. Don't pirate!")
elif verbose > 0:
print("Output file name was not supplied.")
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@ -1,4 +1,4 @@
{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 {\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350
{\fonttbl} {\fonttbl}
{\colortbl;\red255\green255\blue255;} {\colortbl;\red255\green255\blue255;}
} }

View File

@ -68,7 +68,7 @@ class DocParser(object):
ys = [] ys = []
gdefs = [] gdefs = []
# get path defintions, positions, dimensions for ecah glyph # get path defintions, positions, dimensions for each glyph
# that makes up the image, and find min x and min y to reposition origin # that makes up the image, and find min x and min y to reposition origin
minx = -1 minx = -1
miny = -1 miny = -1
@ -305,6 +305,15 @@ class DocParser(object):
lastGlyph = firstglyphList[last] lastGlyph = firstglyphList[last]
else : else :
lastGlyph = len(gidList) lastGlyph = len(gidList)
# handle case of white sapce paragraphs with no actual glyphs in them
# by reverting to text based paragraph
if firstGlyph >= lastGlyph:
# revert to standard text based paragraph
for wordnum in xrange(first, last):
result.append(('ocr', wordnum))
return pclass, result
for glyphnum in xrange(firstGlyph, lastGlyph): for glyphnum in xrange(firstGlyph, lastGlyph):
glyphList.append(glyphnum) glyphList.append(glyphnum)
# include any extratokens if they exist # include any extratokens if they exist

View File

@ -1,145 +0,0 @@
#! /usr/bin/python
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
# For use with Topaz Scripts Version 2.6
class Unbuffered:
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
import sys
sys.stdout=Unbuffered(sys.stdout)
import os, getopt
# local routines
import convert2xml
import flatxml2html
import decode_meta
def usage():
print 'Usage: '
print ' '
print ' genxml.py dict0000.dat unencryptedBookDir'
print ' '
def main(argv):
bookDir = ''
if len(argv) == 0:
argv = sys.argv
try:
opts, args = getopt.getopt(argv[1:], "h:")
except getopt.GetoptError, err:
print str(err)
usage()
sys.exit(1)
if len(opts) == 0 and len(args) == 0 :
usage()
sys.exit(1)
for o, a in opts:
if o =="-h":
usage()
sys.exit(0)
bookDir = args[0]
if not os.path.exists(bookDir) :
print "Can not find directory with unencrypted book"
sys.exit(1)
dictFile = os.path.join(bookDir,'dict0000.dat')
if not os.path.exists(dictFile) :
print "Can not find dict0000.dat file"
sys.exit(1)
pageDir = os.path.join(bookDir,'page')
if not os.path.exists(pageDir) :
print "Can not find page directory in unencrypted book"
sys.exit(1)
glyphsDir = os.path.join(bookDir,'glyphs')
if not os.path.exists(glyphsDir) :
print "Can not find glyphs directory in unencrypted book"
sys.exit(1)
otherFile = os.path.join(bookDir,'other0000.dat')
if not os.path.exists(otherFile) :
print "Can not find other0000.dat in unencrypted book"
sys.exit(1)
metaFile = os.path.join(bookDir,'metadata0000.dat')
if not os.path.exists(metaFile) :
print "Can not find metadata0000.dat in unencrypted book"
sys.exit(1)
xmlDir = os.path.join(bookDir,'xml')
if not os.path.exists(xmlDir):
os.makedirs(xmlDir)
print 'Processing ... '
print ' ', 'metadata0000.dat'
fname = os.path.join(bookDir,'metadata0000.dat')
xname = os.path.join(xmlDir, 'metadata.txt')
metastr = decode_meta.getMetaData(fname)
file(xname, 'wb').write(metastr)
print ' ', 'other0000.dat'
fname = os.path.join(bookDir,'other0000.dat')
xname = os.path.join(xmlDir, 'stylesheet.xml')
pargv=[]
pargv.append('convert2xml.py')
pargv.append(dictFile)
pargv.append(fname)
xmlstr = convert2xml.main(pargv)
file(xname, 'wb').write(xmlstr)
filenames = os.listdir(pageDir)
filenames = sorted(filenames)
for filename in filenames:
print ' ', filename
fname = os.path.join(pageDir,filename)
xname = os.path.join(xmlDir, filename.replace('.dat','.xml'))
pargv=[]
pargv.append('convert2xml.py')
pargv.append(dictFile)
pargv.append(fname)
xmlstr = convert2xml.main(pargv)
file(xname, 'wb').write(xmlstr)
filenames = os.listdir(glyphsDir)
filenames = sorted(filenames)
for filename in filenames:
print ' ', filename
fname = os.path.join(glyphsDir,filename)
xname = os.path.join(xmlDir, filename.replace('.dat','.xml'))
pargv=[]
pargv.append('convert2xml.py')
pargv.append(dictFile)
pargv.append(fname)
xmlstr = convert2xml.main(pargv)
file(xname, 'wb').write(xmlstr)
print 'Processing Complete'
return 0
if __name__ == '__main__':
sys.exit(main(''))

View File

@ -1,6 +1,8 @@
#! /usr/bin/python #! /usr/bin/python
# ignobleepub.pyw, version 3.3 from __future__ import with_statement
# ignobleepub.pyw, version 3.4
# To run this program install Python 2.6 from <http://www.python.org/download/> # To run this program install Python 2.6 from <http://www.python.org/download/>
# and OpenSSL or PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto # and OpenSSL or PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto
@ -14,10 +16,9 @@
# 3.1 - Allow Windows versions of libcrypto to be found # 3.1 - Allow Windows versions of libcrypto to be found
# 3.2 - add support for encoding to 'utf-8' when building up list of files to cecrypt from encryption.xml # 3.2 - add support for encoding to 'utf-8' when building up list of files to cecrypt from encryption.xml
# 3.3 - On Windows try PyCrypto first and OpenSSL next # 3.3 - On Windows try PyCrypto first and OpenSSL next
# 3.4 - Modify interace to allow use with import
from __future__ import with_statement
__license__ = 'GPL v3' __license__ = 'GPL v3'
import sys import sys
@ -170,49 +171,6 @@ class Decryptor(object):
return data return data
def cli_main(argv=sys.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 "usage: %s KEYFILE INBOOK OUTBOOK" % (progname,)
return 1
keypath, inpath, outpath = argv[1:]
with open(keypath, 'rb') as f:
keyb64 = f.read()
key = keyb64.decode('base64')[:16]
# aes = AES.new(key, AES.MODE_CBC)
aes = AES(key)
with closing(ZipFile(open(inpath, 'rb'))) as inf:
namelist = set(inf.namelist())
if 'META-INF/rights.xml' not in namelist or \
'META-INF/encryption.xml' not in namelist:
raise IGNOBLEError('%s: not an B&N ADEPT EPUB' % (inpath,))
for name in META_NAMES:
namelist.remove(name)
rights = etree.fromstring(inf.read('META-INF/rights.xml'))
adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag)
expr = './/%s' % (adept('encryptedKey'),)
bookkey = ''.join(rights.findtext(expr))
bookkey = aes.decrypt(bookkey.decode('base64'))
bookkey = bookkey[:-ord(bookkey[-1])]
encryption = inf.read('META-INF/encryption.xml')
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)
outf.writestr(zi, inf.read('mimetype'))
for path in namelist:
data = inf.read(path)
outf.writestr(path, decryptor.decrypt(path, data))
return 0
class DecryptionDialog(Tkinter.Frame): class DecryptionDialog(Tkinter.Frame):
def __init__(self, root): def __init__(self, root):
Tkinter.Frame.__init__(self, root, border=5) Tkinter.Frame.__init__(self, root, border=5)
@ -308,6 +266,53 @@ class DecryptionDialog(Tkinter.Frame):
return return
self.status['text'] = 'File successfully decrypted' self.status['text'] = 'File successfully decrypted'
def decryptBook(keypath, inpath, outpath):
with open(keypath, 'rb') as f:
keyb64 = f.read()
key = keyb64.decode('base64')[:16]
# aes = AES.new(key, AES.MODE_CBC)
aes = AES(key)
with closing(ZipFile(open(inpath, 'rb'))) as inf:
namelist = set(inf.namelist())
if 'META-INF/rights.xml' not in namelist or \
'META-INF/encryption.xml' not in namelist:
raise IGNOBLEError('%s: not an B&N ADEPT EPUB' % (inpath,))
for name in META_NAMES:
namelist.remove(name)
rights = etree.fromstring(inf.read('META-INF/rights.xml'))
adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag)
expr = './/%s' % (adept('encryptedKey'),)
bookkey = ''.join(rights.findtext(expr))
bookkey = aes.decrypt(bookkey.decode('base64'))
bookkey = bookkey[:-ord(bookkey[-1])]
encryption = inf.read('META-INF/encryption.xml')
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)
outf.writestr(zi, inf.read('mimetype'))
for path in namelist:
data = inf.read(path)
outf.writestr(path, decryptor.decrypt(path, data))
return 0
def cli_main(argv=sys.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 "usage: %s KEYFILE INBOOK OUTBOOK" % (progname,)
return 1
keypath, inpath, outpath = argv[1:]
return decryptBook(keypath, inpath, outpath)
def gui_main(): def gui_main():
root = Tkinter.Tk() root = Tkinter.Tk()
if AES is None: if AES is None:
@ -324,6 +329,7 @@ def gui_main():
root.mainloop() root.mainloop()
return 0 return 0
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) > 1: if len(sys.argv) > 1:
sys.exit(cli_main()) sys.exit(cli_main())

View File

@ -1,6 +1,8 @@
#! /usr/bin/python #! /usr/bin/python
# ignoblekeygen.pyw, version 2.2 from __future__ import with_statement
# ignoblekeygen.pyw, version 2.3
# To run this program install Python 2.6 from <http://www.python.org/download/> # To run this program install Python 2.6 from <http://www.python.org/download/>
# and OpenSSL or PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto # and OpenSSL or PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto
@ -12,12 +14,12 @@
# 2 - Add OS X support by using OpenSSL when available (taken/modified from ineptepub v5) # 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.1 - Allow Windows versions of libcrypto to be found
# 2.2 - On Windows try PyCrypto first and then OpenSSL next # 2.2 - On Windows try PyCrypto first and then OpenSSL next
# 2.3 - Modify interface to allow use of import
""" """
Generate Barnes & Noble EPUB user key from name and credit card number. Generate Barnes & Noble EPUB user key from name and credit card number.
""" """
from __future__ import with_statement
__license__ = 'GPL v3' __license__ = 'GPL v3'
import sys import sys
@ -120,6 +122,7 @@ AES = _load_crypto()
def normalize_name(name): def normalize_name(name):
return ''.join(x for x in name.lower() if x != ' ') return ''.join(x for x in name.lower() if x != ' ')
def generate_keyfile(name, ccn, outpath): def generate_keyfile(name, ccn, outpath):
name = normalize_name(name) + '\x00' name = normalize_name(name) + '\x00'
ccn = ccn + '\x00' ccn = ccn + '\x00'
@ -133,19 +136,6 @@ def generate_keyfile(name, ccn, outpath):
f.write(userkey.encode('base64')) f.write(userkey.encode('base64'))
return userkey return userkey
def cli_main(argv=sys.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 "usage: %s NAME CC# OUTFILE" % (progname,)
return 1
name, ccn, outpath = argv[1:]
generate_keyfile(name, ccn, outpath)
return 0
class DecryptionDialog(Tkinter.Frame): class DecryptionDialog(Tkinter.Frame):
def __init__(self, root): def __init__(self, root):
@ -211,6 +201,22 @@ class DecryptionDialog(Tkinter.Frame):
return return
self.status['text'] = 'Keyfile successfully generated' self.status['text'] = 'Keyfile successfully generated'
def cli_main(argv=sys.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 "usage: %s NAME CC# OUTFILE" % (progname,)
return 1
name, ccn, outpath = argv[1:]
generate_keyfile(name, ccn, outpath)
return 0
def gui_main(): def gui_main():
root = Tkinter.Tk() root = Tkinter.Tk()
if AES is None: if AES is None:

View File

@ -1,7 +1,9 @@
#! /usr/bin/python #! /usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# ineptepub.pyw, version 5.5 from __future__ import with_statement
# ineptepub.pyw, version 5.6
# Copyright © 2009-2010 i♥cabbages # Copyright © 2009-2010 i♥cabbages
# Released under the terms of the GNU General Public Licence, version 3 or # Released under the terms of the GNU General Public Licence, version 3 or
@ -27,13 +29,11 @@
# 5.3 - add support for OpenSSL on Windows, fix bug with some versions of libcrypto 0.9.8 prior to path level o # 5.3 - add support for OpenSSL on Windows, fix bug with some versions of libcrypto 0.9.8 prior to path level o
# 5.4 - add support for encoding to 'utf-8' when building up list of files to decrypt from encryption.xml # 5.4 - add support for encoding to 'utf-8' when building up list of files to decrypt from encryption.xml
# 5.5 - On Windows try PyCrypto first, OpenSSL next # 5.5 - On Windows try PyCrypto first, OpenSSL next
# 5.6 - Modify interface to allow use with import
""" """
Decrypt Adobe ADEPT-encrypted EPUB books. Decrypt Adobe ADEPT-encrypted EPUB books.
""" """
from __future__ import with_statement
__license__ = 'GPL v3' __license__ = 'GPL v3'
import sys import sys
@ -312,45 +312,6 @@ class Decryptor(object):
data = self.decompress(data) data = self.decompress(data)
return data return data
def cli_main(argv=sys.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 "usage: %s KEYFILE INBOOK OUTBOOK" % (progname,)
return 1
keypath, inpath, outpath = argv[1:]
with open(keypath, 'rb') as f:
keyder = f.read()
rsa = RSA(keyder)
with closing(ZipFile(open(inpath, 'rb'))) as inf:
namelist = set(inf.namelist())
if 'META-INF/rights.xml' not in namelist or \
'META-INF/encryption.xml' not in namelist:
raise ADEPTError('%s: not an ADEPT EPUB' % (inpath,))
for name in META_NAMES:
namelist.remove(name)
rights = etree.fromstring(inf.read('META-INF/rights.xml'))
adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag)
expr = './/%s' % (adept('encryptedKey'),)
bookkey = ''.join(rights.findtext(expr))
bookkey = rsa.decrypt(bookkey.decode('base64'))
# Padded as per RSAES-PKCS1-v1_5
if bookkey[-17] != '\x00':
raise ADEPTError('problem decrypting session key')
encryption = inf.read('META-INF/encryption.xml')
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)
outf.writestr(zi, inf.read('mimetype'))
for path in namelist:
data = inf.read(path)
outf.writestr(path, decryptor.decrypt(path, data))
return 0
class DecryptionDialog(Tkinter.Frame): class DecryptionDialog(Tkinter.Frame):
def __init__(self, root): def __init__(self, root):
@ -446,6 +407,52 @@ class DecryptionDialog(Tkinter.Frame):
return return
self.status['text'] = 'File successfully decrypted' self.status['text'] = 'File successfully decrypted'
def decryptBook(keypath, inpath, outpath):
with open(keypath, 'rb') as f:
keyder = f.read()
rsa = RSA(keyder)
with closing(ZipFile(open(inpath, 'rb'))) as inf:
namelist = set(inf.namelist())
if 'META-INF/rights.xml' not in namelist or \
'META-INF/encryption.xml' not in namelist:
raise ADEPTError('%s: not an ADEPT EPUB' % (inpath,))
for name in META_NAMES:
namelist.remove(name)
rights = etree.fromstring(inf.read('META-INF/rights.xml'))
adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag)
expr = './/%s' % (adept('encryptedKey'),)
bookkey = ''.join(rights.findtext(expr))
bookkey = rsa.decrypt(bookkey.decode('base64'))
# Padded as per RSAES-PKCS1-v1_5
if bookkey[-17] != '\x00':
raise ADEPTError('problem decrypting session key')
encryption = inf.read('META-INF/encryption.xml')
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)
outf.writestr(zi, inf.read('mimetype'))
for path in namelist:
data = inf.read(path)
outf.writestr(path, decryptor.decrypt(path, data))
return 0
def cli_main(argv=sys.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 "usage: %s KEYFILE INBOOK OUTBOOK" % (progname,)
return 1
keypath, inpath, outpath = argv[1:]
return decryptBook(keypath, inpath, outpath)
def gui_main(): def gui_main():
root = Tkinter.Tk() root = Tkinter.Tk()
if AES is None: if AES is None:

View File

@ -1,7 +1,9 @@
#! /usr/bin/python #! /usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# ineptkey.pyw, version 5.3 from __future__ import with_statement
# ineptkey.pyw, version 5.4
# Copyright © 2009-2010 i♥cabbages # Copyright © 2009-2010 i♥cabbages
# Released under the terms of the GNU General Public Licence, version 3 or # Released under the terms of the GNU General Public Licence, version 3 or
@ -33,13 +35,12 @@
# 5.1 - add support for using OpenSSL on Windows in place of PyCrypto # 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.2 - added support for output of key to a particular file
# 5.3 - On Windows try PyCrypto first, OpenSSL next # 5.3 - On Windows try PyCrypto first, OpenSSL next
# 5.4 - Modify interface to allow use of import
""" """
Retrieve Adobe ADEPT user key. Retrieve Adobe ADEPT user key.
""" """
from __future__ import with_statement
__license__ = 'GPL v3' __license__ = 'GPL v3'
import sys import sys
@ -415,10 +416,11 @@ class ExceptionDialog(Tkinter.Frame):
label.pack(fill=Tkconstants.X, expand=0) label.pack(fill=Tkconstants.X, expand=0)
self.text = Tkinter.Text(self) self.text = Tkinter.Text(self)
self.text.pack(fill=Tkconstants.BOTH, expand=1) self.text.pack(fill=Tkconstants.BOTH, expand=1)
self.text.insert(Tkconstants.END, text) self.text.insert(Tkconstants.END, text)
def cli_main(argv=sys.argv):
keypath = argv[1] def extractKeyfile(keypath):
try: try:
success = retrieve_key(keypath) success = retrieve_key(keypath)
except ADEPTError, e: except ADEPTError, e:
@ -431,6 +433,12 @@ def cli_main(argv=sys.argv):
return 1 return 1
return 0 return 0
def cli_main(argv=sys.argv):
keypath = argv[1]
return extractKeyfile(keypath)
def main(argv=sys.argv): def main(argv=sys.argv):
root = Tkinter.Tk() root = Tkinter.Tk()
root.withdraw() root.withdraw()

View File

@ -1,6 +1,8 @@
#! /usr/bin/env python #! /usr/bin/env python
# ineptpdf.pyw, version 7.7 # ineptpdf.pyw, version 7.7
from __future__ import with_statement
# To run this program install Python 2.6 from http://www.python.org/download/ # To run this program install Python 2.6 from http://www.python.org/download/
# and OpenSSL (already installed on Mac OS X and Linux) OR # and OpenSSL (already installed on Mac OS X and Linux) OR
# PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto # PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto
@ -30,13 +32,12 @@
# fixed minor typos # fixed minor typos
# 7.6 - backported AES and other fixes from version 8.4.48 # 7.6 - backported AES and other fixes from version 8.4.48
# 7.7 - On Windows try PyCrypto first and OpenSSL next # 7.7 - On Windows try PyCrypto first and OpenSSL next
# 7.8 - Modify interface to allow use of import
""" """
Decrypts Adobe ADEPT-encrypted PDF files. Decrypts Adobe ADEPT-encrypted PDF files.
""" """
from __future__ import with_statement
__license__ = 'GPL v3' __license__ = 'GPL v3'
import sys import sys
@ -2076,25 +2077,6 @@ class PDFSerializer(object):
self.write('\n') self.write('\n')
self.write('endobj\n') self.write('endobj\n')
def cli_main(argv=sys.argv):
progname = os.path.basename(argv[0])
if RSA 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 "usage: %s KEYFILE INBOOK OUTBOOK" % (progname,)
return 1
keypath, inpath, outpath = argv[1:]
with open(inpath, 'rb') as inf:
serializer = PDFSerializer(inf, keypath)
# hope this will fix the 'bad file descriptor' problem
with open(outpath, 'wb') as outf:
# help construct to make sure the method runs to the end
serializer.dump(outf)
return 0
class DecryptionDialog(Tkinter.Frame): class DecryptionDialog(Tkinter.Frame):
def __init__(self, root): def __init__(self, root):
@ -2198,6 +2180,31 @@ class DecryptionDialog(Tkinter.Frame):
'Close this window or decrypt another pdf file.' 'Close this window or decrypt another pdf file.'
return return
def decryptBook(keypath, inpath, outpath):
with open(inpath, 'rb') as inf:
serializer = PDFSerializer(inf, keypath)
# hope this will fix the 'bad file descriptor' problem
with open(outpath, 'wb') as outf:
# help construct to make sure the method runs to the end
serializer.dump(outf)
return 0
def cli_main(argv=sys.argv):
progname = os.path.basename(argv[0])
if RSA 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 "usage: %s KEYFILE INBOOK OUTBOOK" % (progname,)
return 1
keypath, inpath, outpath = argv[1:]
return decryptBook(keypath, inpath, outpath)
def gui_main(): def gui_main():
root = Tkinter.Tk() root = Tkinter.Tk()
if RSA is None: if RSA is None:

View File

@ -29,7 +29,7 @@ from __future__ import with_statement
# and import that ZIP into Calibre using its plugin configuration GUI. # and import that ZIP into Calibre using its plugin configuration GUI.
__version__ = '2.1' __version__ = '2.2'
class Unbuffered: class Unbuffered:
def __init__(self, stream): def __init__(self, stream):
@ -75,21 +75,23 @@ def zipUpDir(myzip, tempdir,localname):
# borrowed from calibre from calibre/src/calibre/__init__.py # borrowed from calibre from calibre/src/calibre/__init__.py
# added in removal of non-printing chars # added in removal of non-printing chars
# and removal of . at start # and removal of . at start
# convert spaces to underscores
def cleanup_name(name): def cleanup_name(name):
_filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]') _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]')
substitute='_' substitute='_'
one = ''.join(char for char in name if char in string.printable) one = ''.join(char for char in name if char in string.printable)
one = _filename_sanitize.sub(substitute, one) one = _filename_sanitize.sub(substitute, one)
one = re.sub(r'\s', ' ', one).strip() one = re.sub(r'\s', ' ', one).strip()
one = re.sub(r'^\.+$', '_', one) one = re.sub(r'^\.+$', '_', one)
one = one.replace('..', substitute) one = one.replace('..', substitute)
# Windows doesn't like path components that end with a period # Windows doesn't like path components that end with a period
if one.endswith('.'): if one.endswith('.'):
one = one[:-1]+substitute one = one[:-1]+substitute
# Mac and Unix don't like file names that begin with a full stop # Mac and Unix don't like file names that begin with a full stop
if len(one) > 0 and one[0] == '.': if len(one) > 0 and one[0] == '.':
one = substitute+one[1:] one = substitute+one[1:]
return one one = one.replace(' ','_')
return one
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
import mobidedrm import mobidedrm
@ -119,7 +121,7 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
filenametitle = cleanup_name(title) filenametitle = cleanup_name(title)
outfilename = bookname outfilename = bookname
if len(bookname)>4 and len(filenametitle)>4 and bookname[:4] != filenametitle[:4]: if len(bookname)>4 and len(filenametitle)>4 and bookname[:4] != filenametitle[:4]:
outfilename = outfilename + "_"+filenametitle outfilename = outfilename + "_" + filenametitle
# build pid list # build pid list
md1, md2 = mb.getPIDMetaInfo() md1, md2 = mb.getPIDMetaInfo()
@ -134,15 +136,17 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
except mobidedrm.DrmException, e: except mobidedrm.DrmException, e:
print "Error: " + str(e) + "\nDRM Removal Failed.\n" print "Error: " + str(e) + "\nDRM Removal Failed.\n"
return 1 return 1
except topazextract.TpzDRMError, e: except Exception, e:
print str(e) if not mobi:
print " Creating DeBug Full Zip Archive of Book" print "Error: " + str(e) + "\nDRM Removal Failed.\n"
zipname = os.path.join(outdir, bookname + '_debug' + '.zip') print " Creating DeBug Full Zip Archive of Book"
myzip = zipfile.ZipFile(zipname,'w',zipfile.ZIP_DEFLATED, False) zipname = os.path.join(outdir, bookname + '_debug' + '.zip')
zipUpDir(myzip, tempdir, '') myzip = zipfile.ZipFile(zipname,'w',zipfile.ZIP_DEFLATED, False)
myzip.close() zipUpDir(myzip, tempdir, '')
shutil.rmtree(tempdir, True) myzip.close()
return 1 shutil.rmtree(tempdir, True)
return 1
pass
if mobi: if mobi:
outfile = os.path.join(outdir,outfilename + '_nodrm' + '.mobi') outfile = os.path.join(outdir,outfilename + '_nodrm' + '.mobi')
@ -198,7 +202,7 @@ def main(argv=sys.argv):
pids = [] pids = []
print ('K4MobiDeDrm v%(__version__)s ' print ('K4MobiDeDrm v%(__version__)s '
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals()) 'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
print ' ' print ' '
try: try:
@ -246,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.' Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
author = 'DiapDealer, SomeUpdates' # The author of this plugin author = 'DiapDealer, SomeUpdates' # The author of this plugin
version = (0, 2, 1) # The version number of this plugin version = (0, 2, 2) # The version number of this plugin
file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
on_import = True # Run this plugin during the import on_import = True # Run this plugin during the import
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm
@ -272,15 +276,15 @@ if not __name__ == "__main__" and inCalibre:
for customvalue in customvalues: for customvalue in customvalues:
customvalue = str(customvalue) customvalue = str(customvalue)
customvalue = customvalue.strip() customvalue = customvalue.strip()
if len(customvalue) == 10 or len(customvalue) == 8: if len(customvalue) == 10 or len(customvalue) == 8:
pids.append(customvalue) pids.append(customvalue)
else : else :
if len(customvalue) == 16 and customvalue[0] == 'B': if len(customvalue) == 16 and customvalue[0] == 'B':
serials.append(customvalue) serials.append(customvalue)
else: else:
print "%s is not a valid Kindle serial number or PID." % str(customvalue) print "%s is not a valid Kindle serial number or PID." % str(customvalue)
# Load any kindle info files (*.info) included Calibre's config directory. # Load any kindle info files (*.info) included Calibre's config directory.
try: try:
# Find Calibre's configuration directory. # Find Calibre's configuration directory.
confpath = os.path.split(os.path.split(self.plugin_path)[0])[0] confpath = os.path.split(os.path.split(self.plugin_path)[0])[0]

View File

@ -189,6 +189,6 @@ def openKindleInfo(kInfoFile=None):
raise DrmException('Error: .kindle-info file can not be found') raise DrmException('Error: .kindle-info file can not be found')
return open(kinfopath,'r') return open(kinfopath,'r')
else: else:
if not os.path.isfile(kinfoFile): if not os.path.isfile(kInfoFile):
raise DrmException('Error: kindle-info file can not be found') raise DrmException('Error: kindle-info file can not be found')
return open(kInfoFile, 'r') return open(kInfoFile, 'r')

View File

@ -2,8 +2,8 @@
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
import sys import sys
sys.path.append('lib')
import os, os.path import os, os.path
sys.path.append(sys.path[0]+os.sep+'lib')
import shutil import shutil
import Tkinter import Tkinter
from Tkinter import * from Tkinter import *
@ -22,10 +22,11 @@ class DrmException(Exception):
pass pass
class MainApp(Tk): class MainApp(Tk):
def __init__(self, dnd=False, filenames=[]): def __init__(self, apphome, dnd=False, filenames=[]):
Tk.__init__(self) Tk.__init__(self)
self.withdraw() self.withdraw()
self.dnd = dnd self.dnd = dnd
self.apphome = apphome
# preference settings # preference settings
# [dictionary key, file in preferences directory where info is stored] # [dictionary key, file in preferences directory where info is stored]
description = [ ['pids' , 'pidlist.txt' ], description = [ ['pids' , 'pidlist.txt' ],
@ -312,6 +313,7 @@ class ConvDialog(Toplevel):
self.protocol("WM_DELETE_WINDOW", self.withdraw) self.protocol("WM_DELETE_WINDOW", self.withdraw)
self.title("DeDRM Processing") self.title("DeDRM Processing")
self.master = master self.master = master
self.apphome = self.master.apphome
self.prefs_array = prefs_array self.prefs_array = prefs_array
self.filenames = filenames self.filenames = filenames
self.interval = 50 self.interval = 50
@ -328,11 +330,11 @@ class ConvDialog(Toplevel):
body.grid_columnconfigure(1, weight=2) body.grid_columnconfigure(1, weight=2)
Tkinter.Label(body, text='Activity Bar').grid(row=0, sticky=Tkconstants.E) Tkinter.Label(body, text='Activity Bar').grid(row=0, sticky=Tkconstants.E)
self.bar = ActivityBar(body, length=50, height=15, barwidth=5) self.bar = ActivityBar(body, length=80, height=15, barwidth=5)
self.bar.grid(row=0, column=1, sticky=sticky) self.bar.grid(row=0, column=1, sticky=sticky)
msg1 = '' msg1 = ''
self.stext = ScrolledText(body, bd=5, relief=Tkconstants.RIDGE, height=4, width=50, wrap=Tkconstants.WORD) self.stext = ScrolledText(body, bd=5, relief=Tkconstants.RIDGE, height=4, width=80, wrap=Tkconstants.WORD)
self.stext.grid(row=2, column=0, columnspan=2,sticky=sticky) self.stext.grid(row=2, column=0, columnspan=2,sticky=sticky)
self.stext.insert(Tkconstants.END,msg1) self.stext.insert(Tkconstants.END,msg1)
@ -435,7 +437,6 @@ class ConvDialog(Toplevel):
if poll != 0: if poll != 0:
msg = 'Failed\n' msg = 'Failed\n'
text = self.p2.read() text = self.p2.read()
text = self.p2.read()
text += self.p2.readerr() text += self.p2.readerr()
msg += text msg += text
msg += '\n' msg += '\n'
@ -451,42 +452,43 @@ class ConvDialog(Toplevel):
return return
def decrypt_ebook(self, infile, outdir, rscpath): def decrypt_ebook(self, infile, outdir, rscpath):
apphome = self.apphome
rv = 1 rv = 1
name, ext = os.path.splitext(os.path.basename(infile)) name, ext = os.path.splitext(os.path.basename(infile))
ext = ext.lower() ext = ext.lower()
if ext == '.epub': if ext == '.epub':
outfile = os.path.join(outdir, name + '_nodrm.epub') outfile = os.path.join(outdir, name + '_nodrm.epub')
self.p2 = processEPUB(infile, outfile, rscpath) self.p2 = processEPUB(apphome, infile, outfile, rscpath)
return 0 return 0
if ext == '.pdb': if ext == '.pdb':
self.p2 = processPDB(infile, outdir, rscpath) self.p2 = processPDB(apphome, infile, outdir, rscpath)
return 0 return 0
if ext in ['.azw', '.azw1', '.prc', '.mobi', '.tpz']: if ext in ['.azw', '.azw1', '.prc', '.mobi', '.tpz']:
self.p2 = processK4MOBI(infile, outdir, rscpath) self.p2 = processK4MOBI(apphome, infile, outdir, rscpath)
return 0 return 0
if ext == '.pdf': if ext == '.pdf':
outfile = os.path.join(outdir, name + '_nodrm.pdf') outfile = os.path.join(outdir, name + '_nodrm.pdf')
self.p2 = processPDF(infile, outfile, rscpath) self.p2 = processPDF(apphome, infile, outfile, rscpath)
return 0 return 0
return rv return rv
# run as a subprocess via pipes and collect stdout, stderr, and return value # run as a subprocess via pipes and collect stdout, stderr, and return value
def runit(ncmd, nparms): def runit(apphome, ncmd, nparms):
cmdline = 'python ' + ncmd cmdline = 'python ' + '"' + os.path.join(apphome, ncmd) + '" '
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
search_path = os.environ['PATH'] search_path = os.environ['PATH']
search_path = search_path.lower() search_path = search_path.lower()
if search_path.find('python') < 0: if search_path.find('python') < 0:
# if no python hope that win registry finds what is associated with py extension # if no python hope that win registry finds what is associated with py extension
cmdline = ncmd cmdline = '"' + os.path.join(apphome, ncmd) + '" '
cmdline += nparms cmdline += nparms
cmdline = cmdline.encode(sys.getfilesystemencoding()) cmdline = cmdline.encode(sys.getfilesystemencoding())
p2 = subasyncio.Process(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) p2 = subasyncio.Process(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False)
return p2 return p2
def processK4MOBI(infile, outdir, rscpath): def processK4MOBI(apphome, infile, outdir, rscpath):
cmd = '"' + os.path.join('lib','k4mobidedrm.py') + '" ' cmd = os.path.join('lib','k4mobidedrm.py')
parms = '' parms = ''
pidnums = '' pidnums = ''
pidspath = os.path.join(rscpath,'pidlist.txt') pidspath = os.path.join(rscpath,'pidlist.txt')
@ -511,30 +513,33 @@ def processK4MOBI(infile, outdir, rscpath):
dpath = os.path.join(rscpath,filename) dpath = os.path.join(rscpath,filename)
parms += '-k "' + dpath + '" ' parms += '-k "' + dpath + '" '
parms += '"' + infile +'" "' + outdir + '"' parms += '"' + infile +'" "' + outdir + '"'
p2 = runit(cmd, parms) p2 = runit(apphome, cmd, parms)
return p2 return p2
def processPDF(infile, outfile, rscpath): def processPDF(apphome, infile, outfile, rscpath):
cmd = '"' + os.path.join('lib','decryptpdf.py') + '" ' cmd = os.path.join('lib','decryptpdf.py')
parms = '"' + infile + '" "' + outfile + '" "' + rscpath + '"' parms = '"' + infile + '" "' + outfile + '" "' + rscpath + '"'
p2 = runit(cmd, parms) p2 = runit(apphome, cmd, parms)
return p2 return p2
def processEPUB(infile, outfile, rscpath): def processEPUB(apphome, infile, outfile, rscpath):
# invoke routine to check both Adept and Barnes and Noble # invoke routine to check both Adept and Barnes and Noble
cmd = '"' + os.path.join('lib','decryptepub.py') + '" ' cmd = os.path.join('lib','decryptepub.py')
parms = '"' + infile + '" "' + outfile + '" "' + rscpath + '"' parms = '"' + infile + '" "' + outfile + '" "' + rscpath + '"'
p2 = runit(cmd, parms) p2 = runit(apphome, cmd, parms)
return p2 return p2
def processPDB(infile, outdir, rscpath): def processPDB(apphome, infile, outdir, rscpath):
cmd = '"' + os.path.join('lib','decryptpdb.py') + '" ' cmd = os.path.join('lib','decryptpdb.py')
parms = '"' + infile + '" "' + outdir + '" "' + rscpath + '"' parms = '"' + infile + '" "' + outdir + '" "' + rscpath + '"'
p2 = runit(cmd, parms) p2 = runit(apphome, cmd, parms)
return p2 return p2
def main(argv=sys.argv): def main(argv=sys.argv):
apphome = os.path.dirname(sys.argv[0])
apphome = os.path.abspath(apphome)
# windows may pass a spurious quoted null string as argv[1] from bat file # windows may pass a spurious quoted null string as argv[1] from bat file
# simply work around this until we can figure out a better way to handle things # simply work around this until we can figure out a better way to handle things
if len(argv) == 2: if len(argv) == 2:
@ -571,7 +576,7 @@ def main(argv=sys.argv):
filenames.append(infile) filenames.append(infile)
# start up gui app # start up gui app
app = MainApp(dnd, filenames) app = MainApp(apphome, dnd, filenames)
app.mainloop() app.mainloop()
return 0 return 0

View File

@ -68,7 +68,7 @@ class DocParser(object):
ys = [] ys = []
gdefs = [] gdefs = []
# get path defintions, positions, dimensions for ecah glyph # get path defintions, positions, dimensions for each glyph
# that makes up the image, and find min x and min y to reposition origin # that makes up the image, and find min x and min y to reposition origin
minx = -1 minx = -1
miny = -1 miny = -1
@ -305,6 +305,15 @@ class DocParser(object):
lastGlyph = firstglyphList[last] lastGlyph = firstglyphList[last]
else : else :
lastGlyph = len(gidList) lastGlyph = len(gidList)
# handle case of white sapce paragraphs with no actual glyphs in them
# by reverting to text based paragraph
if firstGlyph >= lastGlyph:
# revert to standard text based paragraph
for wordnum in xrange(first, last):
result.append(('ocr', wordnum))
return pclass, result
for glyphnum in xrange(firstGlyph, lastGlyph): for glyphnum in xrange(firstGlyph, lastGlyph):
glyphList.append(glyphnum) glyphList.append(glyphnum)
# include any extratokens if they exist # include any extratokens if they exist

View File

@ -29,7 +29,7 @@ from __future__ import with_statement
# and import that ZIP into Calibre using its plugin configuration GUI. # and import that ZIP into Calibre using its plugin configuration GUI.
__version__ = '2.1' __version__ = '2.2'
class Unbuffered: class Unbuffered:
def __init__(self, stream): def __init__(self, stream):
@ -75,6 +75,7 @@ def zipUpDir(myzip, tempdir,localname):
# borrowed from calibre from calibre/src/calibre/__init__.py # borrowed from calibre from calibre/src/calibre/__init__.py
# added in removal of non-printing chars # added in removal of non-printing chars
# and removal of . at start # and removal of . at start
# convert spaces to underscores
def cleanup_name(name): def cleanup_name(name):
_filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]') _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]')
substitute='_' substitute='_'
@ -89,6 +90,7 @@ def cleanup_name(name):
# Mac and Unix don't like file names that begin with a full stop # Mac and Unix don't like file names that begin with a full stop
if len(one) > 0 and one[0] == '.': if len(one) > 0 and one[0] == '.':
one = substitute+one[1:] one = substitute+one[1:]
one = one.replace(' ','_')
return one return one
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
@ -248,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.' Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
author = 'DiapDealer, SomeUpdates' # The author of this plugin author = 'DiapDealer, SomeUpdates' # The author of this plugin
version = (0, 2, 1) # The version number of this plugin version = (0, 2, 2) # The version number of this plugin
file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
on_import = True # Run this plugin during the import on_import = True # Run this plugin during the import
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm

View File

@ -189,6 +189,6 @@ def openKindleInfo(kInfoFile=None):
raise DrmException('Error: .kindle-info file can not be found') raise DrmException('Error: .kindle-info file can not be found')
return open(kinfopath,'r') return open(kinfopath,'r')
else: else:
if not os.path.isfile(kinfoFile): if not os.path.isfile(kInfoFile):
raise DrmException('Error: kindle-info file can not be found') raise DrmException('Error: kindle-info file can not be found')
return open(kInfoFile, 'r') return open(kInfoFile, 'r')

View File

@ -1,5 +1,5 @@
ReadMe_DeDRM_WinApp_v1.2 ReadMe_DeDRM_WinApp_v1.3
----------------------- ------------------------
DeDRM_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto theDeDRM_Drop_Target to have the DRM removed. It repackages the"tools" python software in one easy to use program. DeDRM_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto theDeDRM_Drop_Target to have the DRM removed. It repackages the"tools" python software in one easy to use program.

View File

@ -207,11 +207,11 @@ class MainDialog(Tkinter.Frame):
tpz = False tpz = False
# Identify any Topaz Files # Identify any Topaz Files
with open(mobipath, 'rb') as f: f = file(mobipath, 'rb')
raw = f.read(3) raw = f.read(3)
if raw.startswith('TPZ'): if raw.startswith('TPZ'):
tpz = True tpz = True
f.close() f.close()
if not outpath: if not outpath:
self.status['text'] = 'No output directory specified' self.status['text'] = 'No output directory specified'
self.sbotton.configure(state='normal') self.sbotton.configure(state='normal')

View File

@ -68,7 +68,7 @@ class DocParser(object):
ys = [] ys = []
gdefs = [] gdefs = []
# get path defintions, positions, dimensions for ecah glyph # get path defintions, positions, dimensions for each glyph
# that makes up the image, and find min x and min y to reposition origin # that makes up the image, and find min x and min y to reposition origin
minx = -1 minx = -1
miny = -1 miny = -1
@ -305,6 +305,15 @@ class DocParser(object):
lastGlyph = firstglyphList[last] lastGlyph = firstglyphList[last]
else : else :
lastGlyph = len(gidList) lastGlyph = len(gidList)
# handle case of white sapce paragraphs with no actual glyphs in them
# by reverting to text based paragraph
if firstGlyph >= lastGlyph:
# revert to standard text based paragraph
for wordnum in xrange(first, last):
result.append(('ocr', wordnum))
return pclass, result
for glyphnum in xrange(firstGlyph, lastGlyph): for glyphnum in xrange(firstGlyph, lastGlyph):
glyphList.append(glyphnum) glyphList.append(glyphnum)
# include any extratokens if they exist # include any extratokens if they exist

View File

@ -29,7 +29,7 @@ from __future__ import with_statement
# and import that ZIP into Calibre using its plugin configuration GUI. # and import that ZIP into Calibre using its plugin configuration GUI.
__version__ = '2.1' __version__ = '2.2'
class Unbuffered: class Unbuffered:
def __init__(self, stream): def __init__(self, stream):
@ -75,6 +75,7 @@ def zipUpDir(myzip, tempdir,localname):
# borrowed from calibre from calibre/src/calibre/__init__.py # borrowed from calibre from calibre/src/calibre/__init__.py
# added in removal of non-printing chars # added in removal of non-printing chars
# and removal of . at start # and removal of . at start
# convert spaces to underscores
def cleanup_name(name): def cleanup_name(name):
_filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]') _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]')
substitute='_' substitute='_'
@ -89,6 +90,7 @@ def cleanup_name(name):
# Mac and Unix don't like file names that begin with a full stop # Mac and Unix don't like file names that begin with a full stop
if len(one) > 0 and one[0] == '.': if len(one) > 0 and one[0] == '.':
one = substitute+one[1:] one = substitute+one[1:]
one = one.replace(' ','_')
return one return one
def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
@ -248,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.' Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
author = 'DiapDealer, SomeUpdates' # The author of this plugin author = 'DiapDealer, SomeUpdates' # The author of this plugin
version = (0, 2, 1) # The version number of this plugin version = (0, 2, 2) # The version number of this plugin
file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
on_import = True # Run this plugin during the import on_import = True # Run this plugin during the import
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm

View File

@ -189,6 +189,6 @@ def openKindleInfo(kInfoFile=None):
raise DrmException('Error: .kindle-info file can not be found') raise DrmException('Error: .kindle-info file can not be found')
return open(kinfopath,'r') return open(kinfopath,'r')
else: else:
if not os.path.isfile(kinfoFile): if not os.path.isfile(kInfoFile):
raise DrmException('Error: kindle-info file can not be found') raise DrmException('Error: kindle-info file can not be found')
return open(kInfoFile, 'r') return open(kInfoFile, 'r')

View File

@ -1,8 +1,8 @@
ePub_Fixer ePub_Fixer
ePubs are specially crafted zip archives. Unfortunately, many of the DRM encoded Adobe Adept and Barnes & Noble ePubs are not "proper" zip archives in that the names of some files in the zip central directory do NOT match the local name given in archive itself. This type of zip archive is technically incorrect/corrupted and can not be read by many other programs. ePubs are specially crafted zip archives whose first file is an uncompresssed "mimetype" file. Unfortunately, many of the DRM encoded Adobe Adept and Barnes & Noble ePubs are not "proper" zip archives in that the names of some files in the zip central directory do NOT match the local name given in archive itself, or they do not have an uncompressed mimetype file as the first file in the archive. These types of epubs are technically incorrect/corrupted and can not be read by many other programs.
ePub_Fixer was designed to fix improperly created zip archives of this type. ePub_Fixer was designed to fix improperly created zip archives of these types.
1. Simply double-click to launch ePub_Fixer.pyw. 1. Simply double-click to launch ePub_Fixer.pyw.

View File

@ -42,7 +42,7 @@ class eRdrDeDRM(FileTypePlugin):
Credit given to The Dark Reverser for the original standalone script.' Credit given to The Dark Reverser for the original standalone script.'
supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on
author = 'DiapDealer' # The author of this plugin author = 'DiapDealer' # The author of this plugin
version = (0, 0, 3) # The version number of this plugin version = (0, 0, 4) # The version number of this plugin
file_types = set(['pdb']) # The file types that this plugin will be applied to file_types = set(['pdb']) # The file types that this plugin will be applied to
on_import = True # Run this plugin during the import on_import = True # Run this plugin during the import