"""
-Comprehensive Mazama Book DRM with Topaz Cryptography V1.1
+Comprehensive Mazama Book DRM with Topaz Cryptography V2.0
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdBHJ4CNc6DNFCw4MRCw4SWAK6
global bookHeaderRecords
global bookMetadata
global bookKey
+global command
#
# Various character maps used to decrypt books. Probably supposed to act as obfuscation
return getKindleInfoValueForHash(encodeHash(key,charMap2))
#
-# Get a 7 bit encoded number form the book file
+# Get a 7 bit encoded number from the book file
#
def bookReadEncodedNumber():
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 : break
+
+ if negative:
+ result += chr(0xFF)
+
+ return result[::-1]
#
# Get a length prefixed string from the file
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],...]
#
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 you are reading this, you might want to uncomment the next line :-D
+ #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
#
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")
+ print("-o Output file name to write records and decrypted books")
print("-v Verbose (can be used several times)")
- print("-i Print kindle.info database")
+ print("-i Prints kindle.info database")
#
# Main
global bookMetadata
global bookKey
global bookFile
+ global command
+
progname = os.path.basename(argv[0])
verbose = 0
- printInfo = False
recordName = ""
recordIndex = 0
outputFile = ""
PIDs = []
kindleDatabase = None
+ command = ""
try:
if o == "-v":
verbose+=1
if o == "-i":
- printInfo = True
+ setCommand("printInfo")
if o =="-o":
+ if a == None :
+ raise CMBDTCFatal("Invalid parameter for -o")
outputFile = a
if o =="-r":
- recordName,recordIndex = a.split(':')
+ 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
print(message)
if kindleDatabase != None :
- if printInfo:
+ if command == "printInfo" :
printKindleInfo()
#
bookKey = bookKeys[0]
if verbose > 0:
print("Book key: " + bookKey.encode('hex'))
+
+
- if recordName != "" :
+ if command == "printRecord" :
extractBookPayloadRecord(recordName,int(recordIndex),outputFile)
- if outputFile != "" and verbose>0 :
- print("Wrote record to file: "+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