68 lines
2.1 KiB
Python
68 lines
2.1 KiB
Python
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)
|