def Decryption(self): 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: decryptedkey = AESdecryptCBC(data, self.devicekey) #print ' [-] Decrypted Key : %s'%hexlify(decryptedkey) elif dict['WRAP'] == 3: try: unwrapped = AESUnwrap(self.passcodekey, data) except ValueError: print '[!] Invalid Password. Enter the valid user password' sys.exit() decryptedkey = AESdecryptCBC(unwrapped, self.devicekey) #print ' [-] Decrypted Key : %s'%hexlify(decryptedkey) self.keyring[dict['CLAS']] = decryptedkey # Key
def getEMFkeyFromCRPT(data, key89B): assert data.startswith("tprc") z = AESdecryptCBC(data[4:0x44], key89B) assert z.startswith("TPRC"), "wrong key89B" #last_byte = struct.unpack("<Q", z[4:4+8])[0] emf = z[16:16+32] return emf
def read_file(self, filename, record): # read backup file try: f = file(self.backup_path + '/' + filename, 'rb') file_data = f.read() f.close() except (IOError): warn("File %s (%s) has not been found" % (filename, record.path)) return if record.encryption_key is not None and self.keybag: # file is encrypted! key = self.keybag.unwrapKeyForClass(record.protection_class, record.encryption_key[4:]) if not key: warn("Cannot unwrap key") return file_data = AESdecryptCBC(file_data, key) padding = file_data[record.size:] if len(padding) > 16 or padding != chr( len(padding)) * len(padding): warn("Incorrect padding for file %s %d %d" % (record.path, len(file_data), record.size)) c = file_data[-1] i = ord(c) if i < 17 and file_data.endswith(c * i): warn("But good padding of %d anyway" % i) file_data = file_data[:-i] return file_data file_data = file_data[:record.size] return file_data
def decrypt_blob(blob, auth_key): len = struct.unpack(">H", blob[0:2])[0] if len != 66: print "blob len != 66" magic = struct.unpack(">H", blob[2:4])[0] if magic != 0x0100: print "magic != 0x0100" iv = blob[4:20] blob_key = AESdecryptCBC(blob[20:68], auth_key, iv)[:32] return AESdecryptCBC(blob[68:], blob_key, iv, padding=True)
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 decryptFileBlock2(self, ciphertext, filekey, lbn, decrypt_offset): if not self.encrypted: return ciphertext if not self.image.isIOS5(): return AESdecryptCBC(ciphertext, filekey, self.volume.ivForLBA(lbn, add=False)) clear = "" ivkey = hashlib.sha1(filekey).digest()[:16] for i in xrange(len(ciphertext)/0x1000): iv = self.volume.ivForLBA(decrypt_offset, False) iv = AESencryptCBC(iv, ivkey) clear += AESdecryptCBC(ciphertext[i*0x1000:(i+1)*0x1000], filekey, iv) decrypt_offset += 0x1000 return clear
def processBlock(self, block, lba): iv = self.volume.ivForLBA(lba) ciphertext = AESencryptCBC(block, self.volume.emfkey, iv) if not self.ivkey: clear = AESdecryptCBC(ciphertext, self.filekey, iv) else: clear = "" for i in xrange(len(block) / 0x1000): iv = self.volume.ivForLBA(self.decrypt_offset, False) iv = AESencryptCBC(iv, self.ivkey) clear += AESdecryptCBC(ciphertext[i * 0x1000:(i + 1) * 0x1000], self.filekey, iv) self.decrypt_offset += 0x1000 return clear
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 readLPN(self, lpn, key=None): z = self.conn.execute( "SELECT ce,block,page,weaveSeq from lpn_to_phys WHERE lpn=? ORDER BY weaveSeq DESC LIMIT 1", (lpn, )).fetchone() if z: #weave,ce,block,page = a[-1] ce, block, page, weaveSeq = z else: print "lpn %d => blank" % lpn return self.blankPage #print "lpn=%d weaveSeq=%d" % (lpn, weaveSeq) s, d = self.nand.readBlockPage(ce, block, page, None, lpn, spareType=self.spareType) for i in xrange(len(s)): if s[i].lpn == lpn: o = i * self.logicalPageSize data = d[o:o + self.logicalPageSize] if key: data = AESdecryptCBC(data, key, ivForPage(lpn)) return data raise Exception("readLPN %d failed" % lpn)
def decrypt_protected_file(self, path, filekey, decrypted_size=0): ivkey = hashlib.sha1(filekey).digest()[:16] hash = hashlib.sha1() sz = os.path.getsize(path) oldpath = path + ".encrypted" try: os.rename(path, oldpath) except: pass with open(oldpath, "rb") as old_file: with open(path, "wb") as new_file: n = sz / 0x1000 if decrypted_size: n += 1 for block in xrange(n): iv = AESencryptCBC(self.computeIV(block * 0x1000), ivkey) old_data = old_file.read(0x1000) hash.update(old_data) new_file.write(AESdecryptCBC(old_data, filekey, iv)) if decrypted_size == 0: #old iOS 5 format trailer = old_file.read(0x1C) decrypted_size = struct.unpack(">Q", trailer[:8])[0] assert hash.digest() == trailer[8:] new_file.truncate(decrypted_size) os.remove(oldpath) # Delete the encrypted file
def decryptProtectedFile(self, path, filekey, DecryptedSize=0): ivkey = hashlib.sha1(filekey).digest()[:16] h = hashlib.sha1() sz = os.path.getsize(path) #iOS 5 trailer = uint64 sz + sha1 of encrypted file #assert (sz % 0x1000) == 0x1C oldpath = path + ".encrypted" try: os.rename(path, oldpath) except: pass f1 = open(oldpath, "rb") f2 = open(path, "wb") n = (sz / 0x1000) if DecryptedSize: n += 1 for block in xrange(n): iv = AESencryptCBC(self.computeIV(block * 0x1000), ivkey) data = f1.read(0x1000) h.update(data) f2.write(AESdecryptCBC(data, filekey, iv)) if DecryptedSize == 0: #old iOS 5 format trailer = f1.read(0x1C) DecryptedSize = struct.unpack(">Q", trailer[:8])[0] assert h.digest() == trailer[8:] f1.close() f2.truncate(DecryptedSize) f2.close()
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 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 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 unlockAlwaysAccessible(self): for classkey in self.classKeys.values(): k = classkey["WPKY"] if classkey["WRAP"] == WRAP_DEVICE: if not self.deviceKey: continue k = AESdecryptCBC(k, self.deviceKey) classkey["KEY"] = k return True
def carveEMFemptySpace(volume, file_keys, outdir): for lba, block in volume.unallocatedBlocks(): iv = volume.ivForLBA(lba) for filekey in file_keys: ciphertext = AESencryptCBC(block, volume.emfkey, iv) clear = AESdecryptCBC(ciphertext, filekey, iv) if isDecryptedCorrectly(clear): print "Decrypted stuff at lba %x" % lba open(outdir + "/%x.bin" % lba, "wb").write(clear)
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 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 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_data(self, data): if data == None: return "" data = str(data) if not self.key835: print "Key 835 not availaible" return "" data = AESdecryptCBC(data[16:], self.key835, data[:16], padding=True) #data_column = iv + AES128_K835(iv, data + sha1(data)) if hashlib.sha1(data[:-20]).digest() != data[-20:]: print "data field hash mismatch : bad key ?" return "ERROR decrypting data : bad key ?" return data[:-20]
def decryptData(self, key=None, iv=None): if not self.sections.has_key("KBAG"): return self.getRawData() if not key or not iv: if not self.decryptKBAG(): return key = self.key iv = self.iv data = AESdecryptCBC(self.sections["DATA"], key, iv) x = self.isValidDecryptedData(data) if not x: print >> sys.stderr, "%s : Decrypted data seems invalid" % self.shortname print >> sys.stderr, data[:50].encode("hex") return False print "%s : decrypted OK (%s)" % (self.shortname, x) return data[:self.datalen]
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 readPage1(self, addr, key, lpn): weave, ce, block, page = addr #ce, block, page = addr s, d = self.nand.readBlockPage(ce, block, page, None, lpn, spareType=self.spareType) for i in xrange(len(s)): if s[i].lpn == lpn: o = i * self.logicalPageSize data = d[o:o + self.logicalPageSize] if key: data = AESdecryptCBC(data, key, ivForPage(lpn)) return data return data raise Exception("FAIL")
def change_key835(self, newkey): tables = { "genp": "SELECT rowid, data FROM genp", "inet": "SELECT rowid, data FROM inet", "cert": "SELECT rowid, data FROM cert", "keys": "SELECT rowid, data FROM keys" } for t in tables.keys(): for row in self.conn.execute(tables[t]): rowid = row["rowid"] data = str(row["data"]) iv = data[:16] data = AESdecryptCBC(data[16:], self.key835, iv) data = AESencryptCBC(data, newkey, iv) data = iv + data data = buffer(data) self.conn.execute("UPDATE %s SET data=? WHERE rowid=?" % t, (data, rowid)) self.conn.commit()
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 decryptPage(self, data, key, pageNum): return AESdecryptCBC(data, key, ivForPage(pageNum))
def decryptPseudoGID(data): pseudogid = "5F650295E1FFFC97CE77ABD49DD955B3".decode("hex") return AESdecryptCBC(data, pseudogid, padding=False)
def sigcheck(self, k89A=None): if not self.sections.has_key("SHSH"): print "[x] FAIL sigcheck %s : no SHSH section" % self.shortname return False if not self.leaf_cert: #print "Extracting certificates" self.extractCertificates() cert = self.leaf_cert #print "Leaf cert subject: %s" % cert.get_subject() certChainOk = False while True: issuer = cert.get_issuer().as_text() #print "issuer: %s" % issuer if not self.certs.has_key(issuer): if not Img3.rootCert: print "Cert chain stops at %s" % issuer certChainOk = False break #print "Verifying cert.", certChainOk = cert.verify(Img3.rootCert.get_pubkey()) break issuer = self.certs[issuer] if not cert.verify(issuer.get_pubkey()): print "%s is not signed by %s (verify fail)" % ( cert.get_subject().as_text(), issuer.get_subject().as_text()) return False cert = issuer shsh = self.sections["SHSH"] print "Got SHSH" try: sig = self.leaf_cert.get_pubkey().get_rsa().public_decrypt( shsh, M2Crypto.RSA.pkcs1_padding) except: if k89A == None: print "SHSH RSA decrypt FAIL, IMG3 must be personalized (SHSH encrypted with k89A)" return False try: shsh = AESdecryptCBC(shsh, k89A) sig = self.leaf_cert.get_pubkey().get_rsa().public_decrypt( shsh, M2Crypto.RSA.pkcs1_padding) except: raise return False #DigestInfo SHA1 http://www.ietf.org/rfc/rfc3447.txt sha1_digestInfo = "3021300906052b0e03021a05000414".decode("hex") if sig[:len(sha1_digestInfo)] == sha1_digestInfo: pass #print "DigestInfo SHA1 OK" self.sig = sig = sig[len(sha1_digestInfo):] ok = sig == self.fileHash.digest() if ok: print "%s : signature check OK (%s)" % (self.shortname, self.leaf_name) else: print "Signature check for %s failed" % self.shortname print "Decrypted SHA1 " + sig.encode("hex") print "Sigcheck area SHA1 " + self.fileHash.hexdigest() return ok
def get_EMF(self, k89b): if self.lockers.has_key("LwVM"): lwvm = AESdecryptCBC(self.lockers["LwVM"], k89b) return lwvm[-32:] elif self.lockers.has_key("EMF!"): return AESdecryptCBC(self.lockers["EMF!"][4:], k89b)
def readBlock(self, blockNum): os.lseek(self.fd, self.offset + self.blockSize * blockNum, os.SEEK_SET) data = os.read(self.fd, self.blockSize) if self.encrypted: data = AESdecryptCBC(data, self.key, self.getIVforBlock(blockNum)) return data