def get_managed_configuration(self): for row in self.conn.execute("SELECT data FROM genp WHERE acct='Private' AND svce='com.apple.managedconfiguration' AND agrp='apple'"): return BPlistReader.plistWithString(self.decrypt_data(row["data"])) #HAX iOS 5 h1 = sqlite3.Binary(hashlib.sha1("Private").digest()) h2 = sqlite3.Binary(hashlib.sha1("com.apple.managedconfiguration").digest()) for row in self.conn.execute("SELECT data FROM genp WHERE acct=? AND svce=? AND agrp='apple'", (h1, h2)): return BPlistReader.plistWithString(self.decrypt_data(row["data"]))
def createWithSystemkbfile(filename, wipeablekey, deviceKey=None): mkb = BPlistReader.plistWithFile(filename) decryptedPlist = AESdecryptCBC(mkb["_MKBPAYLOAD"], wipeablekey, mkb["_MKBIV"], padding=True) decryptedPlist = BPlistReader.plistWithString(decryptedPlist) blob = decryptedPlist["KeyBagKeys"] return Keybag.createWithDataSignBlob(blob, deviceKey)
def get_managed_configuration(self): for row in self.conn.execute( "SELECT data FROM genp WHERE acct='Private' AND svce='com.apple.managedconfiguration' AND agrp='apple'" ): return BPlistReader.plistWithString(self.decrypt_data(row["data"])) #HAX iOS 5 h1 = sqlite3.Binary(hashlib.sha1("Private").digest()) h2 = sqlite3.Binary( hashlib.sha1("com.apple.managedconfiguration").digest()) for row in self.conn.execute( "SELECT data FROM genp WHERE acct=? AND svce=? AND agrp='apple'", (h1, h2)): return BPlistReader.plistWithString(self.decrypt_data(row["data"]))
def createWithSystemkbfile(filename, bag1key, deviceKey=None): if filename.startswith("bplist"): #HAX mkb = BPlistReader.plistWithString(filename) else: mkb = BPlistReader.plistWithFile(filename) try: decryptedPlist = AESdecryptCBC(mkb["_MKBPAYLOAD"].data, bag1key, mkb["_MKBIV"].data, padding=True) except: print "FAIL: AESdecryptCBC _MKBPAYLOAD => wrong BAG1 key ?" return None if not decryptedPlist.startswith("bplist"): print "FAIL: decrypted _MKBPAYLOAD is not bplist" return None decryptedPlist = BPlistReader.plistWithString(decryptedPlist) blob = decryptedPlist["KeyBagKeys"].data return Keybag.createWithDataSignBlob(blob, deviceKey)
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("<LL", blob[0:8]) if version == 0: wrappedkey = blob[8:8 + 40] encrypted_data = blob[48:] elif version == 2: wrappedkey = blob[12:12 + 40] encrypted_data = blob[52:-16] else: raise Exception("unknown keychain verson ", version) return unwrappedkey = self.keybag.unwrapKeyForClass(clas, wrappedkey) if not unwrappedkey: print "keychain unwrap fail for item with class=%d (%s)" % ( clas, KSECATTRACCESSIBLE.get(clas)) return if version == 0: return AESdecryptCBC(encrypted_data, unwrappedkey, padding=True) elif version == 2: binaryplist = gcm_decrypt(unwrappedkey, "", encrypted_data, "", blob[-16:]) return BPlistReader(binaryplist).parse()
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("<LL", blob[0:8]) self.clas = clas if version == 0: wrappedkey = blob[8:8 + 40] encrypted_data = blob[48:] elif version == 2: l = struct.unpack("<L", blob[8:12])[0] wrappedkey = blob[12:12 + l] encrypted_data = blob[12 + l:-16] else: raise Exception("unknown keychain verson ", version) return unwrappedkey = self.keybag.unwrapKeyForClass(clas, wrappedkey, False) if not unwrappedkey: return if version == 0: return AESdecryptCBC(encrypted_data, unwrappedkey, padding=True) elif version == 2: binaryplist = gcm_decrypt(unwrappedkey, "", encrypted_data, "", blob[-16:]) return BPlistReader(binaryplist).parse()
def getBackupKeyBag(backupfolder, passphrase): manifest = BPlistReader.plistWithFile(backupfolder + "/Manifest.plist") kb = Keybag(manifest["BackupKeyBag"].data) if kb.unlockBackupKeybagWithPasscode(passphrase): print "BackupKeyBag unlock OK" return kb else: return None
def decrypt_backup(backupfolder, outputfolder, passphrase): manifest = plistlib.readPlist(backupfolder + "/Manifest.plist") if not manifest["IsEncrypted"]: print "backup is not encrypted manifest[IsEncrypted]" return manifest_data = manifest["Data"].data authdata = manifest["AuthData"].data pkbdf_salt = authdata[:8] iv = authdata[8:24] key = PBKDF2(passphrase,pkbdf_salt,iterations=2000).read(32) data = AES.new(key, AES.MODE_CBC, iv).decrypt(authdata[24:]) auth_key = data[:32] if hashlib.sha1(auth_key).digest() != data[32:52]: print "wrong auth key (hash mismatch) => wrong passphrase" return print "Passphrase seems OK" for mdinfo_name in glob.glob(backupfolder + "/*.mdinfo"): mddata_name = mdinfo_name[:-7] + ".mddata" mdinfo = BPlistReader.plistWithFile(mdinfo_name) if mdinfo["IsEncrypted"]: metadata = decrypt_blob(mdinfo["Metadata"], auth_key) metadata = BPlistReader.plistWithString(metadata) print metadata["Path"] filedata = read_file(mddata_name) filedata = decrypt_blob(filedata, auth_key) filename = metadata["Path"].replace("/","_") write_file(outputfolder + "/" + filename, filedata)
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("<LL", blob[0:8]) clas &= 0xF self.clas = clas if version == 0: wrappedkey = blob[8:8 + 40] encrypted_data = blob[48:] elif version == 2: l = struct.unpack("<L", blob[8:12])[0] wrappedkey = blob[12:12 + l] encrypted_data = blob[12 + l:-16] elif version == 3: l = struct.unpack("<L", blob[8:12])[0] wrappedkey = blob[12:12 + l] encrypted_data = blob[12 + l:-16] else: raise Exception("unknown keychain verson ", version) return unwrappedkey = self.keybag.unwrapKeyForClass(clas, wrappedkey, False) if not unwrappedkey: return if version == 0: return AESdecryptCBC(encrypted_data, unwrappedkey, padding=True) elif version == 2: binaryplist = gcm_decrypt(unwrappedkey, "", encrypted_data, "", blob[-16:]) return BPlistReader(binaryplist).parse() elif version == 3: der = gcm_decrypt(unwrappedkey, "", encrypted_data, "", blob[-16:]) stuff, tail = der_decode(der) rval = {} try: index = 0 while True: k = stuff.getComponentByPosition( index).getComponentByPosition(0) v = stuff.getComponentByPosition( index).getComponentByPosition(1) rval[str(k)] = str(v) index += 1 except: pass return rval
def createWithSystemkbfile(filename, bag1key, deviceKey=None): if filename.startswith("bplist"): #HAX mkb = BPlistReader.plistWithString(filename) else: mkb = BPlistReader.plistWithFile(filename) try: decryptedPlist = AESdecryptCBC(mkb["_MKBPAYLOAD"].data, bag1key, mkb["_MKBIV"].data, padding=True) except: print "FAIL: AESdecryptCBC _MKBPAYLOAD => wrong BAG1 key ?" return None if not decryptedPlist.startswith("bplist"): print "FAIL: decrypted _MKBPAYLOAD is not bplist" return None decryptedPlist = BPlistReader.plistWithString(decryptedPlist) blob = decryptedPlist["KeyBagKeys"].data kb = Keybag.createWithDataSignBlob(blob, deviceKey) if decryptedPlist.has_key("OpaqueStuff"): OpaqueStuff = BPlistReader.plistWithString(decryptedPlist["OpaqueStuff"].data) kb.passcodeComplexity = OpaqueStuff.get("keyboardType") return kb
def render_password(p): data = p["data"] if data != None and data.startswith("bplist") and data.find("\x00") != -1: pl = BPlistReader.plistWithString(p["data"]) filename = "%s_%s_%d.plist" % (p["svce"],p["acct"],p["rowid"]) plistlib.writePlist(pl, filename) #write_file("bin_"+filename, p["data"]) data = filename if p.has_key("srvr"): return "%s:%d;%s;%s" % (p["srvr"],p["port"],p["acct"],data) else: return "%s;%s;%s" % (p["svce"],p["acct"],data)
def recvPlist(self): payload = self.recv_raw() if not payload: return if payload.startswith("bplist00"): return BPlistReader(payload).parse() elif payload.startswith("<?xml"): #HAX lockdown HardwarePlatform with null bytes payload = sub('[^\w<>\/ \-_0-9\"\'\\=\.\?\!\+]+', '', payload.decode('utf-8')).encode('utf-8') return plistlib.readPlistFromString(payload) else: raise Exception("recvPlist invalid data : %s" % payload[:100].encode("hex"))
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("<LL", blob[0:8]) clas &= 0xF self.clas = clas if version == 0: wrappedkey = blob[8:8 + 40] encrypted_data = blob[48:] elif version == 2: l = struct.unpack("<L", blob[8:12])[0] wrappedkey = blob[12:12 + l] encrypted_data = blob[12 + l:-16] elif version == 3: l = struct.unpack("<L", blob[8:12])[0] wrappedkey = blob[12:12 + l] encrypted_data = blob[12 + l:-16] else: raise Exception("unknown keychain verson ", version) return unwrappedkey = self.keybag.unwrapKeyForClass(clas, wrappedkey, False) if not unwrappedkey: return if version == 0: return AESdecryptCBC(encrypted_data, unwrappedkey, padding=True) elif version == 2: binaryplist = gcm_decrypt(unwrappedkey, "", encrypted_data, "", blob[-16:]) return BPlistReader(binaryplist).parse() elif version == 3: der = gcm_decrypt(unwrappedkey, "", encrypted_data, "", blob[-16:]) stuff = der_decode(der)[0] rval = {} for k, v in stuff: k = str(k) # NB - this is binary and may not be valid UTF8 data v = str(v) rval[k] = v return rval
def decrypt_backup3(backupfolder, outputfolder, passphrase): auth_key = None manifest = readPlist(backupfolder + "/Manifest.plist") if manifest["IsEncrypted"]: manifest_data = manifest["Data"].data authdata = manifest["AuthData"].data pkbdf_salt = authdata[:8] iv = authdata[8:24] key = PBKDF2(passphrase, pkbdf_salt, iterations=2000).read(32) data = AESdecryptCBC(authdata[24:], key, iv) auth_key = data[:32] if hashlib.sha1(auth_key).digest() != data[32:52]: print ("wrong auth key (hash mismatch) => wrong passphrase") return print ("Passphrase seems OK") for mdinfo_name in glob.glob(backupfolder + "/*.mdinfo"): mddata_name = mdinfo_name[:-7] + ".mddata" mdinfo = readPlist(mdinfo_name) metadata = mdinfo["Metadata"].data if mdinfo["IsEncrypted"]: metadata = decrypt_blob(metadata, auth_key) metadata = BPlistReader.plistWithString(metadata) print metadata["Path"] filedata = read_file(mddata_name) if mdinfo["IsEncrypted"]: filedata = decrypt_blob(filedata, auth_key) filename = re.sub(r'[:|*<>?"]', "_", metadata["Path"]) makedirs(outputfolder + "/" + os.path.dirname(filename)) write_file(outputfolder + "/" + filename, filedata)
def decrypt_backup3(backupfolder, outputfolder, passphrase): auth_key = None manifest = readPlist(backupfolder + "/Manifest.plist") if manifest["IsEncrypted"]: manifest_data = manifest["Data"].data authdata = manifest["AuthData"].data pkbdf_salt = authdata[:8] iv = authdata[8:24] key = PBKDF2(passphrase, pkbdf_salt, iterations=2000).read(32) data = AESdecryptCBC(authdata[24:], key, iv) auth_key = data[:32] if hashlib.sha1(auth_key).digest() != data[32:52]: print "wrong auth key (hash mismatch) => wrong passphrase" return print "Passphrase seems OK" for mdinfo_name in glob.glob(backupfolder + "/*.mdinfo"): mddata_name = mdinfo_name[:-7] + ".mddata" mdinfo = readPlist(mdinfo_name) metadata = mdinfo["Metadata"].data if mdinfo["IsEncrypted"]: metadata = decrypt_blob(metadata, auth_key) metadata = BPlistReader.plistWithString(metadata) print metadata["Path"] filedata = read_file(mddata_name) if mdinfo["IsEncrypted"]: filedata = decrypt_blob(filedata, auth_key) filename = re.sub(r'[:|*<>?"]', "_", metadata["Path"]) makedirs(outputfolder + "/" + os.path.dirname(filename)) write_file(outputfolder + "/" + filename, filedata)
def __init__(self, filename, keybag): self.keychain = BPlistReader.plistWithFile(filename) self.keybag = keybag
def getSystemkbfileWipeID(filename): mkb = BPlistReader.plistWithFile(filename) return mkb["_MKBWIPEID"]
def get_managed_configuration(self): for p in self.get_passwords(): if p["acct"] == "Private" and p["svce"] == "com.apple.managedconfiguration" and p["agrp"] == "apple": return BPlistReader.plistWithString(p["data"])