from crypto.aes import AESdecryptCBC import struct """ iOS 4 keychain-2.db data column format version 0x00000000 key class 0x00000008 kSecAttrAccessibleWhenUnlocked 6 kSecAttrAccessibleAfterFirstUnlock 7 kSecAttrAccessibleAlways 8 kSecAttrAccessibleWhenUnlockedThisDeviceOnly 9 kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly 10 kSecAttrAccessibleAlwaysThisDeviceOnly 11 wrapped AES256 key 0x28 bytes (passed to kAppleKeyStoreKeyUnwrap) encrypted data (AES 256 CBC zero IV) """ from keychain import Keychain from crypto.gcm import gcm_decrypt from util.bplist import BPlistReader KSECATTRACCESSIBLE = { 6: "kSecAttrAccessibleWhenUnlocked", 7: "kSecAttrAccessibleAfterFirstUnlock", 8: "kSecAttrAccessibleAlways", 9: "kSecAttrAccessibleWhenUnlockedThisDeviceOnly", 10: "kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly", 11: "kSecAttrAccessibleAlwaysThisDeviceOnly" } class Keychain4(Keychain): def __init__(self, filename, keybag): if not keybag.unlocked: print "Keychain object created with locked keybag, some items won't be decrypted" Keychain.__init__(self, filename) self.keybag = keybag def decrypt_item(self, row): version, clas = struct.unpack("= 9 and not self.keybag.deviceKey: return {} if version >= 2: dict = self.decrypt_blob(row["data"]) if not dict: return {"clas": clas, "rowid": row["rowid"]} if dict.has_key("v_Data"): dict["data"] = dict["v_Data"].data else: dict["data"] = "" dict["rowid"] = row["rowid"] dict["clas"] = clas return dict row["clas"] = clas return Keychain.decrypt_item(self, row) def decrypt_data(self, data): data = self.decrypt_blob(data) if type(data) == dict: return data["v_Data"].data return data def decrypt_blob(self, blob): if blob == None: return "" if len(blob) < 48: print "keychain blob length must be >= 48" return version, clas = struct.unpack("