def unwrapKeyForClass(self, clas, persistent_key, printError=True): if not self.classKeys.has_key(clas) or not self.classKeys[clas].has_key("KEY"): if printError: print "Keybag key %d missing or locked" % clas return "" ck = self.classKeys[clas]["KEY"] #if self.attrs.get("VERS", 2) >= 3 and clas == 2: if self.attrs.get("VERS", 2) >= 3 and self.classKeys[clas].get("KTYP", 0) == 1: return self.unwrapCurve25519(clas, persistent_key) if len(persistent_key) == 0x28: return AESUnwrap(ck, persistent_key) return
def Decryption(self): if self.keybag['version'] >= 5: wrap_iv_digest = sha256(struct.pack('<ll', 0, 5)) wrap_iv_digest.update(unhexlify(self.keybag['salt'])) key_store_wrap_iv = wrap_iv_digest.digest()[:16] dict = {} for type, data in tlvs(self.fbuf[KEYBAG_DATA_SIZE + KEYBAG_HEADER_SIZE:self.endofdata]): #if type == 'UUID': #print '%s : %s'%(type, uuid.UUID(bytes=data) ) if type == 'CLAS': print ' [-] %s : %s %d' % ( type, get_class_name(int(hexlify(data), 16)), int(hexlify(data), 16)) dict['CLAS'] = int(hexlify(data), 16) elif type == 'WRAP': print ' [-] %s : %s' % (type, get_wrap_name(int(hexlify(data), 16))) dict['WRAP'] = int(hexlify(data), 16) elif type == 'KTYP': print ' [-] %s : %s' % (type, get_key_type(int(hexlify(data), 16))) dict['KTYP'] = int(hexlify(data), 16) elif type == 'WPKY': decryptedkey = '' if dict['WRAP'] == 1: if self.keybag['version'] >= 5: decryptedkey = AESdecryptCBC(data, self.devicekey, key_store_wrap_iv) else: decryptedkey = AESdecryptCBC(data, self.devicekey) print ' [-] Decrypted Key : %s' % hexlify(decryptedkey) elif dict['WRAP'] == 3: if self.keybag['version'] >= 5: data = AESdecryptCBC(data[:32], self.devicekey, key_store_wrap_iv) + data[32:40] try: unwrapped = AESUnwrap(self.passcodekey, data) except ValueError: print '[!] Invalid Password. Enter the valid user password' sys.exit() if self.keybag['version'] >= 5: decryptedkey = unwrapped else: decryptedkey = AESdecryptCBC(unwrapped, self.devicekey) print ' [-] Decrypted Key : %s' % hexlify(decryptedkey) self.keyring[dict['CLAS']] = decryptedkey # Key
def device_key_validation(self): if self.devicekey == '': return False if self.keybag['sign']: hmackey = AESUnwrap(self.devicekey, unhexlify(self.keybag['hmck'])) sigcheck = hmac.new(key=hmackey, msg=self.keybag['data'], digestmod=sha1).digest() if hexlify(sigcheck) != self.keybag['sign']: return False else: return False return True
def createWithDataSignBlob(blob, deviceKey=None): keybag = tlvToDict(blob) kb = Keybag(keybag["DATA"]) kb.deviceKey = deviceKey if len(keybag.get("SIGN", "")): hmackey = AESUnwrap(deviceKey, kb.attrs["HMCK"]) #hmac key and data are swapped (on purpose or by mistake ?) sigcheck = hmac.new(keybag["DATA"], hmackey, hashlib.sha1).digest() if sigcheck == keybag.get("SIGN", ""): print "Keybag: SIGN check OK" else: print "Keybag: SIGN check FAIL" return kb
def createWithDataSignBlob(blob, deviceKey=None): keybag = tlvToDict(blob) kb = Keybag(keybag.get("DATA", "")) kb.deviceKey = deviceKey kb.KeyBagKeys = blob kb.unlockAlwaysAccessible() if len(keybag.get("SIGN", "")): hmackey = AESUnwrap(deviceKey, kb.attrs["HMCK"]) #hmac key and data are swapped (on purpose or by mistake ?) sigcheck = hmac.new(keybag["DATA"], hmackey, sha1).digest() if sigcheck != keybag.get("SIGN", ""): print "Keybag: SIGN check FAIL" return kb
def try_password(password, iosFlag, dpsl, dpic, salt, iter, kb): if iosFlag: password = pbkdf2_hmac('sha256', password, dpsl, dpic, 32) code = pbkdf2_hmac('sha1', password, salt, iter, 32) for classkey in kb.classKeys.values(): k = classkey["WPKY"] if classkey["WRAP"] & WRAP_PASSCODE: k = AESUnwrap(code, classkey["WPKY"]) if not k: break if classkey["WRAP"] & WRAP_DEVICE: if not kb.deviceKey: continue k = AESdecryptCBC(k, kb.deviceKey) else: return password
def decrypt_secret_data(self, class_key): key = AESUnwrap(class_key, self.encrypted_secret_data_wrapped_key) if not key: raise ValueError("Failed to unwrap key. Bad class key?") plist = readPlistFromString(self.protobuf_item.encryptedSecretData.ciphertext) authenticated = ns_keyed_unarchiver(plist) decrypted = gcm_decrypt(key, authenticated['SFInitializationVector'], authenticated['SFCiphertext'], '', authenticated['SFAuthenticationCode']) if not decrypted: raise ValueError("Failed to decrypt") return decrypted
def unlockWithPasscodeKey(self, passcodekey): if self.type != BACKUP_KEYBAG: if not self.deviceKey: print "ERROR, need device key to unlock keybag" return False for classkey in self.classKeys.values(): k = classkey["WPKY"] if classkey["WRAP"] & WRAP_PASSCODE: k = AESUnwrap(passcodekey, classkey["WPKY"]) if not k: return False if classkey["WRAP"] & WRAP_DEVICE: if not self.deviceKey: continue k = AESdecryptCBC(k, self.deviceKey) classkey["KEY"] = k self.unlocked = True return True
def main(): parser = argparse.ArgumentParser( description='Tool for iCloud Keychain Analysis by @n0fate') parser.add_argument( '-p', '--path', nargs=1, help='iCloud Keychain Path(~/Library/Keychains/[UUID]/)', required=True) parser.add_argument('-k', '--key', nargs=1, help='User Password', required=True) parser.add_argument( '-x', '--exportfile', nargs=1, help='Write a decrypted contents to SQLite file (optional)', required=False) parser.add_argument('-v', '--version', nargs=1, help='macOS version(ex. 10.13)', required=True) args = parser.parse_args() Pathoficloudkeychain = args.path[0] if os.path.isdir(Pathoficloudkeychain) is False: print '[!] Path is not directory' parser.print_help() sys.exit() if os.path.exists(Pathoficloudkeychain) is False: print '[!] Path is not exists' parser.print_help() sys.exit() # version check import re gcmIV = '' re1 = '(10)' # Integer Number 1 re2 = '(\\.)' # Any Single Character 1 re3 = '(\\d+)' # Integer Number 2 rg = re.compile(re1 + re2 + re3, re.IGNORECASE | re.DOTALL) m = rg.match(args.version[0]) if m: minorver = m.group(3) if minorver >= 12: # Security-57740.51.3/OSX/sec/securityd/SecDbKeychainItem.c:97 # # // echo "keychainblobstaticiv" | openssl dgst -sha256 | cut -c1-24 | xargs -I {} echo "0x{}" | xxd -r | xxd -p -i # static const uint8_t gcmIV[kIVSizeAESGCM] = { # 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24 # }; gcmIV = '\x1e\xa0\x5c\xa9\x98\x2e\x87\xdc\xf1\x45\xe8\x24' else: gcmIV = '' else: print '[!] Invalid version' parser.print_help() sys.exit() export = 0 if args.exportfile is not None: if os.path.exists(args.exportfile[0]): print '[*] Export DB File is exists.' sys.exit() export = 1 # Start to analysis print 'Tool for iCloud Keychain Analysis by @n0fate' MachineUUID = os.path.basename(os.path.normpath(Pathoficloudkeychain)) PathofKeybag = os.path.join(Pathoficloudkeychain, 'user.kb') PathofKeychain = os.path.join(Pathoficloudkeychain, 'keychain-2.db') print '[*] macOS version is %s' % args.version[0] print '[*] UUID : %s' % MachineUUID print '[*] Keybag : %s' % PathofKeybag print '[*] iCloud Keychain File : %s' % PathofKeychain if os.path.exists(PathofKeybag) is False or os.path.exists( PathofKeychain) is False: print '[!] Can not found KeyBag or iCloud Keychain File' sys.exit() keybag = Keybag(PathofKeybag) keybag.load_keybag_header() keybag.debug_print_header() devicekey = keybag.device_key_init(uuid.UUID(MachineUUID).bytes) print '[*] The Device key : %s' % hexlify(devicekey) bresult = keybag.device_key_validation() if bresult == False: print '[!] Device Key validation : Failed. Maybe Invalid PlatformUUID' return else: print '[*] Device Key validation : Pass' passcodekey = keybag.generatepasscodekey(args.key[0]) print '[*] The passcode key : %s' % hexlify(passcodekey) keybag.Decryption() con = lite.connect(PathofKeychain) con.text_factory = str cur = con.cursor() tablelist = ['genp', 'inet', 'cert', 'keys'] if export: # Create DB exportDB = ExporySQLiteDB() exportDB.createDB(args.exportfile[0]) print '[*] Export DB Name : %s' % args.exportfile[0] for tablename in tablelist: if export is not 1: print '[+] Table Name : %s' % GetTableFullName(tablename) try: cur.execute("SELECT data FROM %s" % tablename) except lite.OperationalError: continue if export: # Get Table Schema sql = con.execute("pragma table_info('%s')" % tablename).fetchall() # Create a table exportDB.createTable(tablename, sql) for data, in cur: encblobheader = _memcpy(data[:sizeof(_EncryptedBlobHeader)], _EncryptedBlobHeader) encblobheader.clas &= 0x0F wrappedkey = data[sizeof(_EncryptedBlobHeader ):sizeof(_EncryptedBlobHeader) + encblobheader.length] if encblobheader.clas == 11: encrypted_data = data[sizeof(_EncryptedBlobHeader) + encblobheader.length:] auth_tag = data[-20:-4] else: encrypted_data = data[sizeof(_EncryptedBlobHeader) + encblobheader.length:-16] auth_tag = data[-16:] key = keybag.GetKeybyClass(encblobheader.clas) if key == '': print '[!] Could not found any key at %d' % encblobheader.clas continue unwrappedkey = AESUnwrap(key, wrappedkey) decrypted = gcm_decrypt(unwrappedkey, gcmIV, encrypted_data, data[:sizeof(_EncryptedBlobHeader)], auth_tag) if len(decrypted) is 0: #print(" [-] Decryption Process Failed. Invalid Key or Data is corrupted.") continue if export is 0: print '[+] DECRYPTED INFO' blobparse = BlobParser() record = blobparse.ParseIt(decrypted, tablename, export) if export is 0: for k, v in record.items(): if k == 'Data': print ' [-]', k hexdump(v) elif k == 'Type' and GetTableFullName(tablename) == 'Keys': print ' [-]', k, ':', blobparse.GetKeyType(int(v)) else: print ' [-]', k, ':', v print '' else: # export is 1 record_lst = [] for k, v in record.items(): record_lst.append([k, v]) exportDB.insertData(tablename, record_lst) if export: exportDB.commit() exportDB.close() cur.close() con.close()
def get_DKey(self, k835): if self.lockers.has_key("Dkey"): return AESUnwrap(k835, self.lockers["Dkey"])
z = x * zmone % CURVE_P return number.long_to_bytes(z)[::-1] if __name__ == "__main__": from crypto.aeswrap import AESUnwrap from Crypto.Hash import SHA256 z = "04000000080000000200000048000000000000000000000000000000000000000000000002917dc2542198edeb1078c4d1ebab74d9ca87890657ba02b9825dadf20a002f44360c6f87743fac0236df1f9eedbea801e31677aef3a09adfb4e10a37ae27facf419ab3ea3f39f4".decode( "hex") mysecret = "99b66345829d8c05041eea1ba1ed5b2984c3e5ec7a756ef053473c7f22b49f14".decode( "hex") mypublic = "b1c652786697a5feef36a56f36fde524a21193f4e563627977ab515f600fdb3a".decode( "hex") hispublic = z[36:36 + 32] #c4d9fe462a2ebbf0745195ce7dc5e8b49947bbd5b42da74175d5f8125b44582b shared = curve25519(mysecret, hispublic) print shared.encode("hex") h = SHA256.new() h.update('\x00\x00\x00\x01') h.update(shared) h.update(hispublic) h.update(mypublic) md = h.digest() #e442c81b91ea876d3cf42d3aea75f4b0c3f90f9fd045e1f5784b91260f3bdc9c print AESUnwrap(md, z[32 + 36:]).encode("hex")
def main(): if len(sys.argv) not in [3, 4]: print "Usage: %s <backup path> <output path> [password]" % sys.argv[0] sys.exit(1) backup_path = sys.argv[1] output_path = sys.argv[2] if len(sys.argv) == 4: password = sys.argv[3] else: password = '' mbdb = MBDB(backup_path) kb = getBackupKeyBag(backup_path, password) if kb is None: raise Exception("Cannot decrypt keybag. Wrong pass?") for record in mbdb.files.values(): # create directories if they do not exist # makedirs throw an exception, my code is ugly =) if record.is_directory(): try: os.makedirs(output_path + '/' + record.path) except: pass for (filename, record) in mbdb.files.items(): # skip directories if record.is_directory(): continue # adjust output file name if record.is_symbolic_link(): out_file = record.target else: out_file = record.path # read backup file try: f = file(backup_path + '/' + filename, 'rb') file_data = f.read() f.close() except (IOError): warn("File %s (%s) has not been found" % (filename, record.path)) continue if record.encryption_key is not None: # file is encrypted! if kb.classKeys.has_key(record.protection_class): kek = kb.classKeys[record.protection_class]['KEY'] k = AESUnwrap(kek, record.encryption_key[4:]) if k is not None: c = AES.new(k, AES.MODE_CBC) file_data = c.decrypt(file_data) padding = file_data[record.size:] if len(padding) > AES.block_size or padding != chr( len(padding)) * len(padding): warn("Incorrect padding for file %s" % record.path) file_data = file_data[:record.size] else: warn("Cannot unwrap key") continue else: warn("Cannot load encryption key for file %s" % f) # write output file print("Writing %s" % out_file) f = file(output_path + '/' + out_file, 'wb') f.write(file_data) f.close() pass
def main(): # Get the arguments if len(sys.argv) != 3: print "Usage: backup_passwd_guess.py iOS_Backup_Dir Password_Dictionary" sys.exit(1) backup = sys.argv[1] pwddict = sys.argv[2] # Open the manifest plist manifest_loc = backup + "/Manifest.plist" if not os.path.exists(manifest_loc): print "Can't find Manifest.plist - bad backup?" sys.exit(1) manifest = readPlist(manifest_loc) # Open the dictionary if not os.path.exists(pwddict): print "Can't find dictionary" sys.exit(1) dictfile = open(pwddict) # Get the backup information info = readPlist(backup + "/Info.plist") print "Backup Details:" print " Device: %s" % (info['Product Name']) print " Serial: %s" % (info['Serial Number']) print " Firmware: %s" % (info['Product Version']) print "" # Make sure the backup is encrypted if not manifest["IsEncrypted"]: print "Backup is not encrypted" sys.exit(1) # Determine if we have the new format of the backup encryption iosFlag = False if 'ManifestKey' in manifest: print "***** Backup is encrypted using newer algorithm. Time per try is now minutes instead of seconds *****" print "" iosFlag = True # Get the keybag kb = Keybag(manifest["BackupKeyBag"].data) kb.deviceKey = None if kb.type != BACKUP_KEYBAG and kb.type != OTA_KEYBAG: print "Backup does not contain a backup keybag" sys.exit(1) salt = kb.attrs["SALT"] iter = kb.attrs["ITER"] if iosFlag: dpsl = kb.attrs["DPSL"] dpic = kb.attrs["DPIC"] # Loop through the passwords in the file while True: password = dictfile.readline() if password == "": break password = password[:-1] opassword = password print "Trying %s" % (opassword) # Check the password if iosFlag: password = PBKDF2(password, dpsl, iterations = dpic, digestmodule=SHA256).read(32) code = PBKDF2(password, salt, iterations=iter).read(32) success = 0 for classkey in kb.classKeys.values(): k = classkey["WPKY"] if classkey["WRAP"] & WRAP_PASSCODE: k = AESUnwrap(code, classkey["WPKY"]) if not k: success = 1 break if classkey["WRAP"] & WRAP_DEVICE: if not kb.deviceKey: continue k = AESdecryptCBC(k, kb.deviceKey) if success == 0: print "Password found - ",opassword break