from crypto.PBKDF2 import PBKDF2 from crypto.aes import AESdecryptCBC from util import read_file, write_file, makedirs, readPlist from util.bplist import BPlistReader import hashlib import struct import glob import sys import os """ decrypt iOS 3 backup blob (metadata and file contents) """ 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 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 = metadata["Path"] makedirs(outputfolder + "/" + os.path.dirname(filename)) write_file(outputfolder + "/" + filename, filedata)