kInfoFiles=[]
found = False
home = os.getenv('HOME')
+ # check for .kinf2018 file in new location (App Store Kindle for Mac)
+ testpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.kinf2018'
+ if os.path.isfile(testpath):
+ kInfoFiles.append(testpath)
+ print('Found k4Mac kinf2018 file: ' + testpath)
+ found = True
+ # check for .kinf2018 files
+ testpath = home + '/Library/Application Support/Kindle/storage/.kinf2018'
+ if os.path.isfile(testpath):
+ kInfoFiles.append(testpath)
+ print('Found k4Mac kinf2018 file: ' + testpath)
+ found = True
# check for .kinf2011 file in new location (App Store Kindle for Mac)
testpath = home + '/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/storage/.kinf2011'
if os.path.isfile(testpath):
cleartext = UnprotectHeaderData(encryptedValue)
# now extract the pieces in the same way
- # this version is different from K4PC it scales the build number by multipying by 735
pattern = re.compile(r'''\[Version:(\d+)\]\[Build:(\d+)\]\[Cksum:([^\]]+)\]\[Guid:([\{\}a-z0-9\-]+)\]''', re.IGNORECASE)
for m in re.finditer(pattern, cleartext):
- entropy = str(int(m.group(2)) * 0x2df) + m.group(4)
+ version = int(m.group(1))
+ build = m.group(2)
+ guid = m.group(4)
- cud = CryptUnprotectData(entropy,IDString)
+ if version == 5: # .kinf2011: identical to K4PC, except the build number gets multiplied
+ entropy = str(0x2df * int(build)) + guid
+ cud = CryptUnprotectData(entropy,IDString)
+
+ elif version == 6: # .kinf2018: identical to K4PC
+ salt = str(0x6d8 * int(build)) + guid
+ sp = GetUserName() + '+@#$%+' + IDString
+ passwd = encode(SHA256(sp), charMap5)
+ key = LibCrypto().keyivgen(passwd, salt, 10000, 0x400)[:32]
# loop through the item records until all are processed
while len(items) > 0:
encdata = encdata[noffset:]
encdata = encdata + pfx
- # decode using testMap8 to get the CryptProtect Data
- encryptedValue = decode(encdata,testMap8)
- cleartext = cud.decrypt(encryptedValue)
+ if version == 5:
+ # decode using testMap8 to get the CryptProtect Data
+ encryptedValue = decode(encdata,testMap8)
+ cleartext = cud.decrypt(encryptedValue)
+
+ elif version == 6:
+ from Crypto.Cipher import AES
+ from Crypto.Util import Counter
+ # decode using new testMap8 to get IV + ciphertext
+ iv_ciphertext = decode(encdata, testMap8)
+ # pad IV so that we can substitute AES-CTR for GCM
+ iv = iv_ciphertext[:12] + b'\x00\x00\x00\x02'
+ ciphertext = iv_ciphertext[12:]
+ # convert IV to int for use with pycrypto
+ iv_ints = unpack('>QQ', iv)
+ iv = iv_ints[0] << 64 | iv_ints[1]
+ # set up AES-CTR
+ ctr = Counter.new(128, initial_value=iv)
+ cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
+ # decrypt and decode
+ cleartext = decode(cipher.decrypt(ciphertext), charMap5)
+
# print keyname
# print cleartext
if len(cleartext) > 0: