@ -39,6 +39,12 @@ from struct import pack, unpack, unpack_from
import json
import getopt
# import sys
# from IPython.core import ultratb
# sys.excepthook = ultratb.VerboseTB(color_scheme='NoColor')
# Routines common to Mac and PC
# Wrap a stream so that output gets flushed immediately
@ -92,7 +98,7 @@ def unicode_argv():
# Remove Python executable and commands if present
start = argc . value - len ( sys . argv )
return [ argv [ i ] for i in
x range( start , argc . value ) ]
range( start , argc . value ) ]
# if we don't have any arguments at all, just pass back script name
# this should never happen
return [ u " kindlekey.py " ]
@ -128,14 +134,14 @@ def SHA256(message):
def primes ( n ) :
if n == 2 : return [ 2 ]
elif n < 2 : return [ ]
s = range( 3 , n + 1 , 2 )
s = list( range( 3 , n + 1 , 2 ) )
mroot = n * * 0.5
half = ( n + 1 ) / 2 - 1
half = ( n + 1 ) / / 2 - 1
i = 0
m = 3
while m < = mroot :
if s [ i ] :
j = ( m * m - 3 ) / 2
j = ( m * m - 3 ) / / 2
s [ j ] = 0
while j < half :
s [ j ] = 0
@ -146,13 +152,12 @@ def primes(n):
# Encode the bytes in data with the characters in map
def encode ( data , map ) :
result = ' '
result = b ' '
for char in data :
value = ord ( char )
value = char
Q = ( value ^ 0x80 ) / / len ( map )
R = value % len ( map )
result + = map [ Q ]
result + = map [ R ]
result + = bytes ( [ map [ Q ] , map [ R ] ] )
return result
# Hash the bytes in data and then encode the digest with the characters in map
@ -161,7 +166,7 @@ def encodeHash(data,map):
# Decode the string in data with the characters in map. Returns the decoded bytes
def decode ( data , map ) :
result = ' '
result = b ' '
for i in range ( 0 , len ( data ) - 1 , 2 ) :
high = map . find ( data [ i ] )
low = map . find ( data [ i + 1 ] )
@ -223,18 +228,18 @@ if iswindows:
def xorS ( a , b ) :
""" XOR two strings """
assert len ( a ) == len ( b )
x = [ ]
for i in range ( len ( a ) ) :
x . append ( chr ( ord ( a [ i ] ) ^ ord ( b [ i ] ) ) )
return ' ' . join ( x )
for i in range ( min ( len ( a ) , len ( b ) ) ) :
x . append ( a [ i ] ^ b [ i ] )
return bytes ( x )
def xor ( a , b ) :
""" XOR two strings """
x = [ ]
for i in range ( min ( len ( a ) , len ( b ) ) ) :
x . append ( chr ( ord ( a [ i ] ) ^ ord ( b [ i ] ) ) )
return ' ' . join ( x )
x . append ( a [ i ] ^ b [ i ] )
return bytes ( x )
"""
Base ' BlockCipher ' and Pad classes for cipher instances .
@ -253,16 +258,16 @@ if iswindows:
self . resetDecrypt ( )
def resetEncrypt ( self ) :
self . encryptBlockCount = 0
self . bytesToEncrypt = ' '
self . bytesToEncrypt = b ' '
def resetDecrypt ( self ) :
self . decryptBlockCount = 0
self . bytesToDecrypt = ' '
self . bytesToDecrypt = b ' '
def encrypt ( self , plainText , more = None ) :
""" Encrypt a string and return a binary string """
self . bytesToEncrypt + = plainText # append plainText to any bytes from prior encrypt
numBlocks , numExtraBytes = divmod ( len ( self . bytesToEncrypt ) , self . blockSize )
cipherText = ' '
cipherText = b ' '
for i in range ( numBlocks ) :
bStart = i * self . blockSize
ctBlock = self . encryptBlock ( self . bytesToEncrypt [ bStart : bStart + self . blockSize ] )
@ -271,7 +276,7 @@ if iswindows:
if numExtraBytes > 0 : # save any bytes that are not block aligned
self . bytesToEncrypt = self . bytesToEncrypt [ - numExtraBytes : ]
else :
self . bytesToEncrypt = ' '
self . bytesToEncrypt = b ' '
if more == None : # no more data expected from caller
finalBytes = self . padding . addPad ( self . bytesToEncrypt , self . blockSize )
@ -289,14 +294,14 @@ if iswindows:
numBlocks , numExtraBytes = divmod ( len ( self . bytesToDecrypt ) , self . blockSize )
if more == None : # no more calls to decrypt, should have all the data
if numExtraBytes != 0 :
raise DecryptNotBlockAlignedError , ' Data not block aligned on decrypt '
raise DecryptNotBlockAlignedError ( ' Data not block aligned on decrypt ' )
# hold back some bytes in case last decrypt has zero len
if ( more != None ) and ( numExtraBytes == 0 ) and ( numBlocks > 0 ) :
numBlocks - = 1
numExtraBytes = self . blockSize
plainText = ' '
plainText = b ' '
for i in range ( numBlocks ) :
bStart = i * self . blockSize
ptBlock = self . decryptBlock ( self . bytesToDecrypt [ bStart : bStart + self . blockSize ] )
@ -306,7 +311,7 @@ if iswindows:
if numExtraBytes > 0 : # save any bytes that are not block aligned
self . bytesToEncrypt = self . bytesToEncrypt [ - numExtraBytes : ]
else :
self . bytesToEncrypt = ' '
self . bytesToEncrypt = b ' '
if more == None : # last decrypt remove padding
plainText = self . padding . removePad ( plainText , self . blockSize )
@ -331,7 +336,7 @@ if iswindows:
def removePad ( self , paddedBinaryString , blockSize ) :
""" Remove padding from a binary string """
if not ( 0 < len ( paddedBinaryString ) ) :
raise DecryptNotBlockAlignedError , ' Expected More Data '
raise DecryptNotBlockAlignedError ( ' Expected More Data ' )
return paddedBinaryString [ : - ord ( paddedBinaryString [ - 1 ] ) ]
class noPadding ( Pad ) :
@ -361,11 +366,11 @@ if iswindows:
self . blockSize = blockSize # blockSize is in bytes
self . padding = padding # change default to noPadding() to get normal ECB behavior
assert ( keySize % 4 == 0 and NrTable [ 4 ] . has_key ( keySize / 4 ) ) , ' key size must be 16,20,24,29 or 32 bytes '
assert ( blockSize % 4 == 0 and NrTable . has_key ( blockSize / 4 ) ) , ' block size must be 16,20,24,29 or 32 bytes '
assert ( keySize % 4 == 0 and ( keySize / / 4 ) in NrTable [ 4 ] ) , ' key size must be 16,20,24,29 or 32 bytes '
assert ( blockSize % 4 == 0 and ( blockSize / / 4 ) in NrTable ) , ' block size must be 16,20,24,29 or 32 bytes '
self . Nb = self . blockSize / 4 # Nb is number of columns of 32 bit words
self . Nk = keySize / 4 # Nk is the key length in 32-bit words
self . Nb = self . blockSize / / 4 # Nb is number of columns of 32 bit words
self . Nk = keySize / / 4 # Nk is the key length in 32-bit words
self . Nr = NrTable [ self . Nb ] [ self . Nk ] # The number of rounds (Nr) is a function of
# the block (Nb) and key (Nk) sizes.
if key != None :
@ -409,15 +414,15 @@ if iswindows:
def _toBlock ( self , bs ) :
""" Convert binary string to array of bytes, state[col][row] """
assert ( len ( bs ) == 4 * self . Nb ) , ' Rijndarl blocks must be of size blockSize '
return [ [ ord ( bs [ 4 * i ] ), ord ( bs [ 4 * i + 1 ] ) , ord ( bs [ 4 * i + 2 ] ) , ord ( bs [ 4 * i + 3 ] ) ] for i in range ( self . Nb ) ]
return [ [ bs [ 4 * i ] , bs [ 4 * i + 1 ] , bs [ 4 * i + 2 ] , bs [ 4 * i + 3 ] ] for i in range ( self . Nb ) ]
def _toBString ( self , block ) :
""" Convert block (array of bytes) to binary string """
l = [ ]
for col in block :
for rowElement in col :
l . append ( chr( rowElement ) )
return ' ' . join ( l )
l . append ( bytes( [ rowElement ] ) )
return b ' ' . join ( l )
#-------------------------------------
""" Number of rounds Nr = NrTable[Nb][Nk]
@ -432,14 +437,14 @@ if iswindows:
def keyExpansion ( algInstance , keyString ) :
""" Expand a string of size keySize into a larger array """
Nk , Nb , Nr = algInstance . Nk , algInstance . Nb , algInstance . Nr # for readability
key = [ ord ( byte ) for byte in keyString ] # convert string to list
key = [ byte for byte in keyString ] # convert string to list
w = [ [ key [ 4 * i ] , key [ 4 * i + 1 ] , key [ 4 * i + 2 ] , key [ 4 * i + 3 ] ] for i in range ( Nk ) ]
for i in range ( Nk , Nb * ( Nr + 1 ) ) :
temp = w [ i - 1 ] # a four byte column
if ( i % Nk ) == 0 :
temp = temp [ 1 : ] + [ temp [ 0 ] ] # RotWord(temp)
temp = [ Sbox [ byte ] for byte in temp ]
temp [ 0 ] ^ = Rcon [ i / Nk ]
temp [ 0 ] ^ = Rcon [ i / / Nk ]
elif Nk > 6 and i % Nk == 4 :
temp = [ Sbox [ byte ] for byte in temp ] # SubWord(temp)
w . append ( [ w [ i - Nk ] [ byte ] ^ temp [ byte ] for byte in range ( 4 ) ] )
@ -639,7 +644,7 @@ if iswindows:
def __init__ ( self , key = None , padding = padWithPadLen ( ) , keySize = 16 ) :
""" Initialize AES, keySize is in bytes """
if not ( keySize == 16 or keySize == 24 or keySize == 32 ) :
raise BadKeySizeError , ' Illegal AES key size, must be 16, 24, or 32 bytes '
raise BadKeySizeError ( ' Illegal AES key size, must be 16, 24, or 32 bytes ' )
Rijndael . __init__ ( self , key , padding = padding , keySize = keySize , blockSize = 16 )
@ -714,7 +719,7 @@ if iswindows:
if self . encryptBlockCount == 0 :
if self . iv == None :
# generate IV and use
self . iv = ' ' . join ( [ chr ( self . r . randrange ( 256 ) ) for i in range ( self . blockSize ) ] )
self . iv = bytes ( self . r . randrange ( 256 ) for i in range ( self . blockSize ) )
self . prior_encr_CT_block = self . iv
auto_IV = self . prior_encr_CT_block # prepend IV if it's automatic
else : # application provided IV
@ -731,7 +736,7 @@ if iswindows:
if self . decryptBlockCount == 0 : # first call, process IV
if self . iv == None : # auto decrypt IV?
self . prior_CT_block = encryptedBlock
return ' '
return b ' '
else :
assert ( len ( self . iv ) == self . blockSize ) , " Bad IV size on CBC decryption "
self . prior_CT_block = self . iv
@ -782,7 +787,7 @@ if iswindows:
def xorstr ( a , b ) :
if len ( a ) != len ( b ) :
raise Exception ( " xorstr(): lengths differ " )
return ' ' . join ( ( chr ( ord ( x ) ^ ord ( y ) ) for x , y in zip ( a , b ) ) )
return bytes ( ( x ^ y for x , y in zip ( a , b ) ) )
def prf ( h , data ) :
hm = h . copy ( )
@ -800,18 +805,18 @@ if iswindows:
sha = hashlib . sha1
digest_size = sha ( ) . digest_size
# l - number of output blocks to produce
l = keylen / digest_size
l = keylen / / digest_size
if keylen % digest_size != 0 :
l + = 1
h = hmac . new ( passwd , None , sha )
T = " "
T = b " "
for i in range ( 1 , l + 1 ) :
T + = pbkdf2_F ( h , salt , iter , i )
return T [ 0 : keylen ]
def UnprotectHeaderData ( encryptedData ) :
passwdData = ' header_key_data '
salt = ' HEADER.2011 '
passwdData = b ' header_key_data '
salt = b ' HEADER.2011 '
iter = 0x80
keylen = 0x100
key_iv = KeyIVGen ( ) . pbkdf2 ( passwdData , salt , iter , keylen )
@ -824,12 +829,12 @@ if iswindows:
# Various character maps used to decrypt kindle info values.
# Probably supposed to act as obfuscation
charMap2 = " AaZzB0bYyCc1XxDdW2wEeVv3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_ "
charMap5 = " AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE "
charMap2 = b " AaZzB0bYyCc1XxDdW2wEeVv3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_ "
charMap5 = b " AzB0bYyCeVvaZ3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_c1XxDdW2wE "
# New maps in K4PC 1.9.0
testMap1 = " n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M "
testMap6 = " 9YzAb0Cd1Ef2n5Pr6St7Uvh3Jk4M8WxG "
testMap8 = " YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD "
testMap1 = b " n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M "
testMap6 = b " 9YzAb0Cd1Ef2n5Pr6St7Uvh3Jk4M8WxG "
testMap8 = b " YvaZ3FfUm9Nn_c1XuG4yCAzB0beVg-TtHh5SsIiR6rJjQdW2wEq7KkPpL8lOoMxD "
# interface with Windows OS Routines
class DataBlob ( Structure ) :
@ -891,9 +896,9 @@ if iswindows:
# double the buffer size
buffer = create_unicode_buffer ( len ( buffer ) * 2 )
size . value = len ( buffer )
# replace any non-ASCII values with 0xfffd
for i in x range( 0 , len ( buffer ) ) :
for i in range( 0 , len ( buffer ) ) :
if buffer [ i ] > u " \u007f " :
#print u"swapping char "+str(i)+" ("+buffer[i]+")"
buffer [ i ] = u " \ufffd "
@ -969,13 +974,13 @@ if iswindows:
print ( ' Could not find the folder in which to look for kinfoFiles. ' )
else :
# Probably not the best. To Fix (shouldn't ignore in encoding) or use utf-8
print ( u ' searching for kinfoFiles in ' + path . encode ( ' ascii ' , ' ignore ' ) )
print ( ' searching for kinfoFiles in ' + path )
# look for (K4PC 1.9.0 and later) .kinf2011 file
kinfopath = path + ' \\ Amazon \\ Kindle \\ storage \\ .kinf2011 '
if os . path . isfile ( kinfopath ) :
found = True
print ( ' Found K4PC 1.9+ kinf2011 file: ' + kinfopath . encode ( ' ascii ' , ' ignore ' ) )
print ( ' Found K4PC 1.9+ kinf2011 file: ' + kinfopath )
kInfoFiles . append ( kinfopath )
# look for (K4PC 1.6.0 and later) rainier.2.1.1.kinf file
@ -1038,7 +1043,7 @@ if iswindows:
# the .kinf file uses "/" to separate it into records
# so remove the trailing "/" to make it easy to use split
data = data [ : - 1 ]
items = data . split ( ' / ' )
items = data . split ( b ' / ' )
# starts with an encoded and encrypted header blob
headerblob = items . pop ( 0 )
@ -1047,7 +1052,8 @@ if iswindows:
#print "header cleartext:",cleartext
# now extract the pieces that form the added entropy
pattern = re . compile ( r ''' \ [Version:( \ d+) \ ] \ [Build:( \ d+) \ ] \ [Cksum:([^ \ ]]+) \ ] \ [Guid:([ \ { \ }a-z0-9 \ -]+) \ ] ''' , re . IGNORECASE )
for m in re . finditer ( pattern , cleartext ) :
for m in re . finditer ( pattern , cleartext . decode ( ' ascii ' ) ) :
added_entropy = m . group ( 2 ) + m . group ( 4 )
@ -1063,7 +1069,7 @@ if iswindows:
# the sha1 of raw keyhash string is used to create entropy along
# with the added entropy provided above from the headerblob
entropy = SHA1 ( keyhash ) + added_entropy
entropy = SHA1 ( keyhash ) + added_entropy . encode ( ' ascii ' )
# the remainder of the first record when decoded with charMap5
# has the ':' split char followed by the string representation
@ -1075,14 +1081,14 @@ if iswindows:
# read and store in rcnt records of data
# that make up the contents value
edlst = [ ]
for i in x range( rcnt ) :
for i in range( rcnt ) :
item = items . pop ( 0 )
edlst . append ( item )
# key names now use the new testMap8 encoding
keyname = " unknown "
for name in names :
if encodeHash ( name , testMap8 ) == keyhash :
if encodeHash ( name . encode ( ' ascii ' ) , testMap8 ) == keyhash :
keyname = name
#print "keyname found from hash:",keyname
break
@ -1103,10 +1109,10 @@ if iswindows:
# move first offsets chars to end to align for decode by testMap8
# by moving noffset chars from the start of the
# string to the end of the string
encdata = " " . join ( edlst )
encdata = b " " . join ( edlst )
#print "encrypted data:",encdata
contlen = len ( encdata )
noffset = contlen - primes ( int ( contlen / 3 ) ) [ - 1 ]
noffset = contlen - primes ( int ( contlen / / 3 ) ) [ - 1 ]
pfx = encdata [ 0 : noffset ]
encdata = encdata [ noffset : ]
encdata = encdata + pfx
@ -1126,9 +1132,9 @@ if iswindows:
# store values used in decryption
DB [ ' IDString ' ] = GetIDString ( )
DB [ ' UserName ' ] = GetUserName ( )
print u " Decrypted key file using IDString ' {0:s} ' and UserName ' {1:s} ' " . format ( GetIDString ( ) , GetUserName ( ) . encode( ' hex ' ) )
print ( u " Decrypted key file using IDString ' {0:s} ' and UserName ' {1:s} ' " . format ( GetIDString ( ) , GetUserName ( ) . hex( ) ) )
else :
print u " Couldn ' t decrypt file. "
print ( u " Couldn ' t decrypt file. " )
DB = { }
return DB
elif isosx :
@ -1263,7 +1269,7 @@ elif isosx:
#print out1
reslst = out1 . split ( ' \n ' )
cnt = len ( reslst )
for j in x range( cnt ) :
for j in range( cnt ) :
resline = reslst [ j ]
pp = resline . find ( ' \" Serial Number \" = \" ' )
if pp > = 0 :
@ -1279,7 +1285,7 @@ elif isosx:
out1 , out2 = p . communicate ( )
reslst = out1 . split ( ' \n ' )
cnt = len ( reslst )
for j in x range( cnt ) :
for j in range( cnt ) :
resline = reslst [ j ]
if resline . startswith ( ' /dev ' ) :
( devpart , mpath ) = resline . split ( ' on ' ) [ : 2 ]
@ -1300,7 +1306,7 @@ elif isosx:
#print out1
reslst = out1 . split ( ' \n ' )
cnt = len ( reslst )
for j in x range( cnt ) :
for j in range( cnt ) :
resline = reslst [ j ]
pp = resline . find ( ' \" UUID \" = \" ' )
if pp > = 0 :
@ -1320,7 +1326,7 @@ elif isosx:
out1 , out2 = p . communicate ( )
reslst = out1 . split ( ' \n ' )
cnt = len ( reslst )
for j in x range( cnt ) :
for j in range( cnt ) :
resline = reslst [ j ]
pp = resline . find ( ' Ethernet Address: ' )
if pp > = 0 :
@ -1370,8 +1376,8 @@ elif isosx:
# unprotect the new header blob in .kinf2011
# used in Kindle for Mac Version >= 1.9.0
def UnprotectHeaderData ( encryptedData ) :
passwdData = ' header_key_data '
salt = ' HEADER.2011 '
passwdData = b ' header_key_data '
salt = b ' HEADER.2011 '
iter = 0x80
keylen = 0x100
crp = LibCrypto ( )
@ -1482,7 +1488,7 @@ elif isosx:
try :
DB = { }
items = data . split ( ' / ' )
# the headerblob is the encrypted information needed to build the entropy string
headerblob = items . pop ( 0 )
encryptedValue = decode ( headerblob , charMap1 )
@ -1521,7 +1527,7 @@ elif isosx:
# read and store in rcnt records of data
# that make up the contents value
edlst = [ ]
for i in x range( rcnt ) :
for i in range( rcnt ) :
item = items . pop ( 0 )
edlst . append ( item )
@ -1544,7 +1550,7 @@ elif isosx:
# (in other words split 'about' 2/3rds of the way through)
# move first offsets chars to end to align for decode by testMap8
encdata = ' ' . join ( edlst )
encdata = b ' ' . join ( edlst )
contlen = len ( encdata )
# now properly split and recombine
@ -1569,11 +1575,11 @@ elif isosx:
pass
if len ( DB ) > 6 :
# store values used in decryption
print u " Decrypted key file using IDString ' {0:s} ' and UserName ' {1:s} ' " . format ( IDString , GetUserName ( ) )
print ( u " Decrypted key file using IDString ' {0:s} ' and UserName ' {1:s} ' " . format ( IDString , GetUserName ( ) ) )
DB [ ' IDString ' ] = IDString
DB [ ' UserName ' ] = GetUserName ( )
else :
print u " Couldn ' t decrypt file. "
print ( u " Couldn ' t decrypt file. " )
DB = { }
return DB
else :
@ -1590,7 +1596,12 @@ def kindlekeys(files = []):
if key :
# convert all values to hex, just in case.
for keyname in key :
key [ keyname ] = key [ keyname ] . encode ( ' hex ' )
v = key [ keyname ]
if isinstance ( v , str ) :
v = v . encode ( ' ascii ' ) . hex ( )
else :
v = v . hex ( )
key [ keyname ] = v
keys . append ( key )
return keys
@ -1601,9 +1612,9 @@ def getkey(outpath, files=[]):
if len ( keys ) > 0 :
if not os . path . isdir ( outpath ) :
outfile = outpath
with file ( outfile , ' w ' ) as keyfileout :
with open ( outfile , ' w ' ) as keyfileout :
keyfileout . write ( json . dumps ( keys [ 0 ] ) )
print u " Saved a key to {0} " . format ( outfile )
print ( u " Saved a key to {0} " . format ( outfile ) )
else :
keycount = 0
for key in keys :
@ -1612,31 +1623,31 @@ def getkey(outpath, files=[]):
outfile = os . path . join ( outpath , u " kindlekey {0:d} .k4i " . format ( keycount ) )
if not os . path . exists ( outfile ) :
break
with file ( outfile , ' w ' ) as keyfileout :
with open ( outfile , ' w ' ) as keyfileout :
keyfileout . write ( json . dumps ( key ) )
print u " Saved a key to {0} " . format ( outfile )
print ( u " Saved a key to {0} " . format ( outfile ) )
return True
return False
def usage ( progname ) :
print u " Finds, decrypts and saves the default Kindle For Mac/PC encryption keys. "
print u " Keys are saved to the current directory, or a specified output directory. "
print u " If a file name is passed instead of a directory, only the first key is saved, in that file. "
print u " Usage: "
print u " {0:s} [-h] [-k <kindle.info>] [<outpath>] " . format ( progname )
print ( u " Finds, decrypts and saves the default Kindle For Mac/PC encryption keys. " )
print ( u " Keys are saved to the current directory, or a specified output directory. " )
print ( u " If a file name is passed instead of a directory, only the first key is saved, in that file. " )
print ( u " Usage: " )
print ( u " {0:s} [-h] [-k <kindle.info>] [<outpath>] " . format ( progname ) )
def cli_main ( ) :
sys . stdout = SafeUnbuffered ( sys . stdout )
sys . stderr = SafeUnbuffered ( sys . stderr )
# sys.stdout=SafeUnbuffered(sys.stdout )
# sys.stderr=SafeUnbuffered(sys.stderr )
argv = unicode_argv ( )
progname = os . path . basename ( argv [ 0 ] )
print u " {0} v {1} \n Copyright © 2010-2016 by some_updates, Apprentice Alf and Apprentice Harper " . format ( progname , __version__ )
print ( u " {0} v {1} \n Copyright © 2010-2016 by some_updates, Apprentice Alf and Apprentice Harper " . format ( progname , __version__ ) )
try :
opts , args = getopt . getopt ( argv [ 1 : ] , " hk: " )
except getopt . GetoptError , err :
print u " Error in options or arguments: {0} " . format ( err . args [ 0 ] )
except getopt . GetoptError as err :
print ( u " Error in options or arguments: {0} " . format ( err . args [ 0 ] ) )
usage ( progname )
sys . exit ( 2 )
@ -1665,7 +1676,7 @@ def cli_main():
outpath = os . path . realpath ( os . path . normpath ( outpath ) )
if not getkey ( outpath , files ) :
print u " Could not retrieve Kindle for Mac/PC key. "
print ( u " Could not retrieve Kindle for Mac/PC key. " )
return 0
@ -1709,7 +1720,7 @@ def gui_main():
keyfileout . write ( json . dumps ( key ) )
success = True
tkMessageBox . showinfo ( progname , u " Key successfully retrieved to {0} " . format ( outfile ) )
except DrmException , e :
except DrmException as e :
tkMessageBox . showerror ( progname , u " Error: {0} " . format ( str ( e ) ) )
except Exception :
root . wm_state ( ' normal ' )
@ -1722,6 +1733,7 @@ def gui_main():
return 0
if __name__ == ' __main__ ' :
print ( 1 )
if len ( sys . argv ) > 1 :
sys . exit ( cli_main ( ) )
sys . exit ( gui_main ( ) )