Как расшифровать зашифрованную резервную копию iPhone Apple iTunes?

Несколько несчастных пользователей iPhone попросили помочь им восстановить данные из своих резервных копий iTunes. Это легко, когда они незашифрованы, но не тогда, когда они зашифрованы, независимо от того, известен ли пароль.

Как таковой, я пытаюсь выяснить схему шифрования, используемую в файлах mddata и mdinfo при зашифрованном виде. У меня нет проблем с чтением этих файлов в противном случае, и для этого созданы встроенные библиотеки С#. (Если вы в состоянии помочь, мне все равно, какой язык вы используете. Это принцип, который я здесь здесь!)

В "Руководстве по развертыванию операционной системы iPhone OS для Apple" указано, что "Резервные копии устройств могут храниться в зашифрованном формате, выбирая Encrypt iPhone Резервная копия в панели сводок устройства iTunes. Файлы шифруются с использованием AES128 с 256-битным ключом. Ключ надежно хранится в цепочке ключей iPhone. "

Это неплохая подсказка, и здесь есть некоторая полезная информация о взаимодействии Aack/Rijndael на AES/Rijndael, предлагающая использовать ключи 128 и CBC.

Помимо любой другой обфускации, необходим ключ и инициализирующий вектор (IV)/соль.

Можно предположить, что ключ - это манипулирование "резервным паролем", на который пользователю предлагается ввести iTunes и передать " AppleMobileBackup.exe", дополненная модой, продиктованной CBC. Однако, учитывая ссылку на брелок для iPhone, я задаюсь вопросом, может ли "пароль резервного копирования" не использоваться в качестве пароля для сертификата X509 или симметричного закрытого ключа, а сам ключ или сам секретный ключ могут использоваться в качестве ключа. (AES и процесс шифрования/дешифрования iTunes симметричен.)

IV - это другое дело, и это может быть несколько вещей. Возможно, это один из ключей жестко закодированный в iTunes или в устройствах сами.

Хотя комментарий Apple выше говорит о том, что ключ присутствует в брелках устройства, я думаю, что это не так важно. Можно восстановить зашифрованную резервную копию на другое устройство, которое предполагает, что вся информация, относящаяся к расшифровке, присутствует в конфигурации резервного копирования и iTunes, и что что-либо исключительно на устройстве не имеет значения и заменяется в этом контексте. Итак, где может быть ключ?

Я перечислил пути ниже с Windows-машины, но это большая часть того, что мы используем.

"\ appdata\Roaming\Apple Computer\iTunes\itunesprefs.xml" содержит PList с записью "Keychain" dict. "\ Programdata\apple\Lockdown\09037027da8f4bdefdea97d706703ca034c88bab.plist" содержит PList с "DeviceCertificate", "HostCertificate" и "RootCertificate", все из которых кажутся действительными сертификатами X509. В том же файле также содержатся асимметричные ключи "RootPrivateKey" и "HostPrivateKey" (мое чтение предполагает, что это может быть оболочка PKCS # 7). Кроме того, в каждой резервной копии есть значения "AuthSignature" и "AuthData" в файле Manifest.plist, хотя они кажутся поворотными, поскольку каждый файл получает поэтапную резервную копию, предположил, что они не так полезны в качестве ключа, если только что-то действительно все это делается.

Там много вводящих в заблуждение вещей, предлагающих получать данные из зашифрованных резервных копий. Это не так, и, насколько мне известно, этого не было сделано. Обход или отключение резервное шифрование - это совсем другое дело, и я не хочу этого делать.

Речь идет не о взломе iPhone или что-то в этом роде. Все, что я здесь сделаю, - это средство для извлечения данных (фотографий, контактов и т.д.) Из зашифрованных резервных копий iTunes, поскольку я могу их использовать без шифрования. Я пробовал всевозможные перестановки с информацией, которую я поставил выше, но не получил нигде. Я был бы признателен за любые мысли или методы, которые я, возможно, пропустил.

Ответ 1

Исследователи безопасности Жан-Батист Бедрун и Жан Сигвальд рассказали, как сделать это в Hack-in-the-the-the Amsterdam 2011 . С тех пор Apple выпустила

Технический документ по безопасности iOS с более подробной информацией о ключах и алгоритмах, а также Charlie Miller et al. имеют выпустила Руководство по хакерам iOS , которое охватывает некоторые из земля в стиле с практическими рекомендациями. Когда вышла iOS 10, произошли изменения в формат резервного копирования, который Apple сначала не публиковала, но люди перепроектировали изменения формата . Зашифрованные резервные копии великолепны

Самое замечательное в зашифрованных резервных копиях iPhone состоит в том, что они содержат как пароли WiFi, которые не находятся в обычных незашифрованных резервных копиях. Как обсуждается в

Информационном документе по безопасности iOS , зашифрованные резервные копии считаются более "безопасными", поэтому Apple считает, что можно включать больше конфиденциальная информация в них. Важное предупреждение: очевидно, расшифровка резервного копирования ваших устройств iOS удаляет свое шифрование Чтобы защитить вашу конфиденциальность и безопасность,

вам следует запускать эти сценарии только на компьютере с полным шифрованием диска. Пока Эксперт по безопасности может написать программное обеспечение, которое защищает ключи в память, например используя такие функции, как VirtualLock() и SecureZeroMemory()среди прочего, эти Сценарии Python будут хранить ваши ключи шифрования и пароли в строках для быть сборщиком мусора Python. Это означает, что ваши секретные ключи и пароли некоторое время будет жить в оперативной памяти, откуда они попадут в ваш своп файл и на ваш диск, где противник может восстановить их. Этот полностью устраняет необходимость иметь зашифрованную резервную копию. Как расшифровать резервные копии: теоретически

iOS Security Whitepaper

объясняет фундаментальные концепции отдельных файлов, классов защиты, ключей классов защиты и пакетов ключей лучше чем могу. Если вы еще не знакомы с ними, возьмите несколько минут, чтобы прочитать соответствующие части. Теперь вы знаете, что каждый файл в iOS зашифрован со своим собственным случайным ключ шифрования для каждого файла, принадлежит к классу защиты, а для каждого файла ключи шифрования хранятся в метаданных файловой системы, ключ класса защиты. Для расшифровки:

Декодировать сумку с ключами, хранящуюся в записи BackupKeyBag Manifest.plist. Общий обзор этой структуры приведен в

официальный документ

  1. . iPhone Wiki описывает двоичный формат: 4-байтовое поле типа строки, 4-байтовое поле поле длины с прямым порядком байтов, а затем само значение. Важными значениями являются PBKDF2 ITER и SALT, двойной защитная соль DPSL и число итераций DPIC, а затем для каждого защита CLS, завернутый ключ WPKY. Используя резервный пароль, получите 32-байтовый ключ, используя правильный PBKDF2 соль и количество итераций. Сначала используйте раунд SHA256 с DPSL и DPIC, затем раунд SHA1 с ITER и SALT.

    Разверните каждый завернутый ключ в соответствии с

  2. RFC 3394

    . Расшифруйте базу данных манифеста, вытянув 4-байтовый класс защиты и более длинный ключ из ManifestKey в Manifest.plist, и разверните его. Теперь у вас есть База данных SQLite со всеми метаданными файла. Для каждого интересующего вас файла получите шифрование по классам для каждого файла ключ и код класса защиты, просматривая базу данных Files.file колонка для двоичного списка, содержащая EncryptionKey и ProtectionClass записей. Убрать начальный четырехбайтовый тег длины из EncryptionKey перед использованием.

  3. Затем получите окончательный ключ дешифрования, развернув его вместе с классом. ключ, который был развернут с резервным паролем. Затем расшифруйте файл используя AES в режиме CBC с нулевым IV.

  4. Как расшифровать резервные копии: на практике

    Для начала вам понадобятся некоторые библиотечные зависимости. Если вы работаете на Mac, используя Python 2.7 или 3.7, установленный в homebrew, вы можете установить зависимости с помощью:

CFLAGS="-I$(brew --prefix)/opt/openssl/include" \
LDFLAGS="-L$(brew --prefix)/opt/openssl/lib" \    
    pip install biplist fastpbkdf2 pycrypto

В исполняемой форме исходного кода, вот как расшифровать один файл настроек из зашифрованной резервной копии iPhone:

#!/usr/bin/env python3.7
# coding: UTF-8

from __future__ import print_function
from __future__ import division

import argparse
import getpass
import os.path
import pprint
import random
import shutil
import sqlite3
import string
import struct
import tempfile
from binascii import hexlify

import Crypto.Cipher.AES # https://www.dlitz.net/software/pycrypto/
import biplist
import fastpbkdf2
from biplist import InvalidPlistException


def main():
    ## Parse options
    parser = argparse.ArgumentParser()
    parser.add_argument('--backup-directory', dest='backup_directory',
                    default='testdata/encrypted')
    parser.add_argument('--password-pipe', dest='password_pipe',
                        help="""\
Keeps password from being visible in system process list.
Typical use: --password-pipe=<(echo -n foo)
""")
    parser.add_argument('--no-anonymize-output', dest='anonymize',
                        action='store_false')
    args = parser.parse_args()
    global ANONYMIZE_OUTPUT
    ANONYMIZE_OUTPUT = args.anonymize
    if ANONYMIZE_OUTPUT:
        print('Warning: All output keys are FAKE to protect your privacy')

    manifest_file = os.path.join(args.backup_directory, 'Manifest.plist')
    with open(manifest_file, 'rb') as infile:
        manifest_plist = biplist.readPlist(infile)
    keybag = Keybag(manifest_plist['BackupKeyBag'])
    # the actual keys are unknown, but the wrapped keys are known
    keybag.printClassKeys()

    if args.password_pipe:
        password = readpipe(args.password_pipe)
        if password.endswith(b'\n'):
            password = password[:-1]
    else:
        password = getpass.getpass('Backup password: ').encode('utf-8')

    ## Unlock keybag with password
    if not keybag.unlockWithPasscode(password):
        raise Exception('Could not unlock keybag; bad password?')
    # now the keys are known too
    keybag.printClassKeys()

    ## Decrypt metadata DB
    manifest_key = manifest_plist['ManifestKey'][4:]
    with open(os.path.join(args.backup_directory, 'Manifest.db'), 'rb') as db:
        encrypted_db = db.read()

    manifest_class = struct.unpack('<l', manifest_plist['ManifestKey'][:4])[0]
    key = keybag.unwrapKeyForClass(manifest_class, manifest_key)
    decrypted_data = AESdecryptCBC(encrypted_db, key)

    temp_dir = tempfile.mkdtemp()
    try:
        # Does anyone know how to get Pythons SQLite module to open some
        # bytes in memory as a database?
        db_filename = os.path.join(temp_dir, 'db.sqlite3')
        with open(db_filename, 'wb') as db_file:
            db_file.write(decrypted_data)
        conn = sqlite3.connect(db_filename)
        conn.row_factory = sqlite3.Row
        c = conn.cursor()
        # c.execute("select * from Files limit 1");
        # r = c.fetchone()
        c.execute("""
            SELECT fileID, domain, relativePath, file
            FROM Files
            WHERE relativePath LIKE 'Media/PhotoData/MISC/DCIM_APPLE.plist'
            ORDER BY domain, relativePath""")
        results = c.fetchall()
    finally:
        shutil.rmtree(temp_dir)

    for item in results:
        fileID, domain, relativePath, file_bplist = item

        plist = biplist.readPlistFromString(file_bplist)
        file_data = plist['$objects'][plist['$top']['root'].integer]
        size = file_data['Size']

        protection_class = file_data['ProtectionClass']
        encryption_key = plist['$objects'][
            file_data['EncryptionKey'].integer]['NS.data'][4:]

        backup_filename = os.path.join(args.backup_directory,
                                    fileID[:2], fileID)
        with open(backup_filename, 'rb') as infile:
            data = infile.read()
            key = keybag.unwrapKeyForClass(protection_class, encryption_key)
            # truncate to actual length, as encryption may introduce padding
            decrypted_data = AESdecryptCBC(data, key)[:size]

        print('== decrypted data:')
        print(wrap(decrypted_data))
        print()

        print('== pretty-printed plist')
        pprint.pprint(biplist.readPlistFromString(decrypted_data))

##
# this section is mostly copied from parts of iphone-dataprotection
# http://code.google.com/p/iphone-dataprotection/

CLASSKEY_TAGS = [b"CLAS",b"WRAP",b"WPKY", b"KTYP", b"PBKY"]  #UUID
KEYBAG_TYPES = ["System", "Backup", "Escrow", "OTA (icloud)"]
KEY_TYPES = ["AES", "Curve25519"]
PROTECTION_CLASSES={
    1:"NSFileProtectionComplete",
    2:"NSFileProtectionCompleteUnlessOpen",
    3:"NSFileProtectionCompleteUntilFirstUserAuthentication",
    4:"NSFileProtectionNone",
    5:"NSFileProtectionRecovery?",

    6: "kSecAttrAccessibleWhenUnlocked",
    7: "kSecAttrAccessibleAfterFirstUnlock",
    8: "kSecAttrAccessibleAlways",
    9: "kSecAttrAccessibleWhenUnlockedThisDeviceOnly",
    10: "kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly",
    11: "kSecAttrAccessibleAlwaysThisDeviceOnly"
}
WRAP_DEVICE = 1
WRAP_PASSCODE = 2

class Keybag(object):
    def __init__(self, data):
        self.type = None
        self.uuid = None
        self.wrap = None
        self.deviceKey = None
        self.attrs = {}
        self.classKeys = {}
        self.KeyBagKeys = None #DATASIGN blob
        self.parseBinaryBlob(data)

    def parseBinaryBlob(self, data):
        currentClassKey = None

        for tag, data in loopTLVBlocks(data):
            if len(data) == 4:
                data = struct.unpack(">L", data)[0]
            if tag == b"TYPE":
                self.type = data
                if self.type > 3:
                    print("FAIL: keybag type > 3 : %d" % self.type)
            elif tag == b"UUID" and self.uuid is None:
                self.uuid = data
            elif tag == b"WRAP" and self.wrap is None:
                self.wrap = data
            elif tag == b"UUID":
                if currentClassKey:
                    self.classKeys[currentClassKey[b"CLAS"]] = currentClassKey
                currentClassKey = {b"UUID": data}
            elif tag in CLASSKEY_TAGS:
                currentClassKey[tag] = data
            else:
                self.attrs[tag] = data
        if currentClassKey:
            self.classKeys[currentClassKey[b"CLAS"]] = currentClassKey

    def unlockWithPasscode(self, passcode):
        passcode1 = fastpbkdf2.pbkdf2_hmac('sha256', passcode,
                                        self.attrs[b"DPSL"],
                                        self.attrs[b"DPIC"], 32)
        passcode_key = fastpbkdf2.pbkdf2_hmac('sha1', passcode1,
                                            self.attrs[b"SALT"],
                                            self.attrs[b"ITER"], 32)
        print('== Passcode key')
        print(anonymize(hexlify(passcode_key)))
        for classkey in self.classKeys.values():
            if b"WPKY" not in classkey:
                continue
            k = classkey[b"WPKY"]
            if classkey[b"WRAP"] & WRAP_PASSCODE:
                k = AESUnwrap(passcode_key, classkey[b"WPKY"])
                if not k:
                    return False
                classkey[b"KEY"] = k
        return True

    def unwrapKeyForClass(self, protection_class, persistent_key):
        ck = self.classKeys[protection_class][b"KEY"]
        if len(persistent_key) != 0x28:
            raise Exception("Invalid key length")
        return AESUnwrap(ck, persistent_key)

    def printClassKeys(self):
        print("== Keybag")
        print("Keybag type: %s keybag (%d)" % (KEYBAG_TYPES[self.type], self.type))
        print("Keybag version: %d" % self.attrs[b"VERS"])
        print("Keybag UUID: %s" % anonymize(hexlify(self.uuid)))
        print("-"*209)
        print("".join(["Class".ljust(53),
                    "WRAP".ljust(5),
                    "Type".ljust(11),
                    "Key".ljust(65),
                    "WPKY".ljust(65),
                    "Public key"]))
        print("-"*208)
        for k, ck in self.classKeys.items():
            if k == 6:print("")

            print("".join(
                [PROTECTION_CLASSES.get(k).ljust(53),
                str(ck.get(b"WRAP","")).ljust(5),
                KEY_TYPES[ck.get(b"KTYP",0)].ljust(11),
                anonymize(hexlify(ck.get(b"KEY", b""))).ljust(65),
                anonymize(hexlify(ck.get(b"WPKY", b""))).ljust(65),
            ]))
        print()

def loopTLVBlocks(blob):
    i = 0
    while i + 8 <= len(blob):
        tag = blob[i:i+4]
        length = struct.unpack(">L",blob[i+4:i+8])[0]
        data = blob[i+8:i+8+length]
        yield (tag,data)
        i += 8 + length

def unpack64bit(s):
    return struct.unpack(">Q",s)[0]
def pack64bit(s):
    return struct.pack(">Q",s)

def AESUnwrap(kek, wrapped):
    C = []
    for i in range(len(wrapped)//8):
        C.append(unpack64bit(wrapped[i*8:i*8+8]))
    n = len(C) - 1
    R = [0] * (n+1)
    A = C[0]

    for i in range(1,n+1):
        R[i] = C[i]

    for j in reversed(range(0,6)):
        for i in reversed(range(1,n+1)):
            todec = pack64bit(A ^ (n*j+i))
            todec += pack64bit(R[i])
            B = Crypto.Cipher.AES.new(kek).decrypt(todec)
            A = unpack64bit(B[:8])
            R[i] = unpack64bit(B[8:])

    if A != 0xa6a6a6a6a6a6a6a6:
        return None
    res = b"".join(map(pack64bit, R[1:]))
    return res

ZEROIV = "\x00"*16
def AESdecryptCBC(data, key, iv=ZEROIV, padding=False):
    if len(data) % 16:
        print("AESdecryptCBC: data length not /16, truncating")
        data = data[0:(len(data)/16) * 16]
    data = Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_CBC, iv).decrypt(data)
    if padding:
        return removePadding(16, data)
    return data

##
# here are some utility functions, one making sure I dont leak my
# secret keys when posting the output on Stack Exchange

anon_random = random.Random(0)
memo = {}
def anonymize(s):
    if type(s) == str:
        s = s.encode('utf-8')
    global anon_random, memo
    if ANONYMIZE_OUTPUT:
        if s in memo:
            return memo[s]
        possible_alphabets = [
            string.digits,
            string.digits + 'abcdef',
            string.ascii_letters,
            "".join(chr(x) for x in range(0, 256)),
        ]
        for a in possible_alphabets:
            if all((chr(c) if type(c) == int else c) in a for c in s):
                alphabet = a
                break
        ret = "".join([anon_random.choice(alphabet) for i in range(len(s))])
        memo[s] = ret
        return ret
    else:
        return s

def wrap(s, width=78):
    "Return a width-wrapped repr(s)-like string without breaking on \s"
    s = repr(s)
    quote = s[0]
    s = s[1:-1]
    ret = []
    while len(s):
        i = s.rfind('\\', 0, width)
        if i <= width - 4: # "\x??" is four characters
            i = width
        ret.append(s[:i])
        s = s[i:]
    return '\n'.join("%s%s%s" % (quote, line ,quote) for line in ret)

def readpipe(path):
    if stat.S_ISFIFO(os.stat(path).st_mode):
        with open(path, 'rb') as pipe:
            return pipe.read()
    else:
        raise Exception("Not a pipe: {!r}".format(path))

if __name__ == '__main__':
    main()

Который затем печатает этот вывод:

Warning: All output keys are FAKE to protect your privacy
== Keybag
Keybag type: Backup keybag (1)
Keybag version: 3
Keybag UUID: dc6486c479e84c94efce4bea7169ef7d
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Class                                                WRAP Type       Key                                                              WPKY                                                             Public key
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NSFileProtectionComplete                             2    AES                                                                         4c80b6da07d35d393fc7158e18b8d8f9979694329a71ceedee86b4cde9f97afec197ad3b13c5d12b
NSFileProtectionCompleteUnlessOpen                   2    AES                                                                         09e8a0a9965f00f213ce06143a52801f35bde2af0ad54972769845d480b5043f545fa9b66a0353a6
NSFileProtectionCompleteUntilFirstUserAuthentication 2    AES                                                                         e966b6a0742878ce747cec3fa1bf6a53b0d811ad4f1d6147cd28a5d400a8ffe0bbabea5839025cb5
NSFileProtectionNone                                 2    AES                                                                         902f46847302816561e7df57b64beea6fa11b0068779a65f4c651dbe7a1630f323682ff26ae7e577
NSFileProtectionRecovery?                            3    AES                                                                         a3935fed024cd9bc11d0300d522af8e89accfbe389d7c69dca02841df46c0a24d0067dba2f696072

kSecAttrAccessibleWhenUnlocked                       2    AES                                                                         09a1856c7e97a51a9c2ecedac8c3c7c7c10e7efa931decb64169ee61cb07a0efb115050fd1e33af1
kSecAttrAccessibleAfterFirstUnlock                   2    AES                                                                         0509d215f2f574efa2f192efc53c460201168b26a175f066b5347fc48bc76c637e27a730b904ca82
kSecAttrAccessibleAlways                             2    AES                                                                         b7ac3c4f1e04896144ce90c4583e26489a86a6cc45a2b692a5767b5a04b0907e081daba009fdbb3c
kSecAttrAccessibleWhenUnlockedThisDeviceOnly         3    AES                                                                         417526e67b82e7c6c633f9063120a299b84e57a8ffee97b34020a2caf6e751ec5750053833ab4d45
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly     3    AES                                                                         b0e17b0cf7111c6e716cd0272de5684834798431c1b34bab8d1a1b5aba3d38a3a42c859026f81ccc
kSecAttrAccessibleAlwaysThisDeviceOnly               3    AES                                                                         9b3bdc59ae1d85703aa7f75d49bdc600bf57ba4a458b20a003a10f6e36525fb6648ba70e6602d8b2

== Passcode key
ee34f5bb635830d698074b1e3e268059c590973b0f1138f1954a2a4e1069e612

== Keybag
Keybag type: Backup keybag (1)
Keybag version: 3
Keybag UUID: dc6486c479e84c94efce4bea7169ef7d
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Class                                                WRAP Type       Key                                                              WPKY                                                             Public key
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NSFileProtectionComplete                             2    AES        64e8fc94a7b670b0a9c4a385ff395fe9ba5ee5b0d9f5a5c9f0202ef7fdcb386f 4c80b6da07d35d393fc7158e18b8d8f9979694329a71ceedee86b4cde9f97afec197ad3b13c5d12b
NSFileProtectionCompleteUnlessOpen                   2    AES        22a218c9c446fbf88f3ccdc2ae95f869c308faaa7b3e4fe17b78cbf2eeaf4ec9 09e8a0a9965f00f213ce06143a52801f35bde2af0ad54972769845d480b5043f545fa9b66a0353a6
NSFileProtectionCompleteUntilFirstUserAuthentication 2    AES        1004c6ca6e07d2b507809503180edf5efc4a9640227ac0d08baf5918d34b44ef e966b6a0742878ce747cec3fa1bf6a53b0d811ad4f1d6147cd28a5d400a8ffe0bbabea5839025cb5
NSFileProtectionNone                                 2    AES        2e809a0cd1a73725a788d5d1657d8fd150b0e360460cb5d105eca9c60c365152 902f46847302816561e7df57b64beea6fa11b0068779a65f4c651dbe7a1630f323682ff26ae7e577
NSFileProtectionRecovery?                            3    AES        9a078d710dcd4a1d5f70ea4062822ea3e9f7ea034233e7e290e06cf0d80c19ca a3935fed024cd9bc11d0300d522af8e89accfbe389d7c69dca02841df46c0a24d0067dba2f696072

kSecAttrAccessibleWhenUnlocked                       2    AES        606e5328816af66736a69dfe5097305cf1e0b06d6eb92569f48e5acac3f294a4 09a1856c7e97a51a9c2ecedac8c3c7c7c10e7efa931decb64169ee61cb07a0efb115050fd1e33af1
kSecAttrAccessibleAfterFirstUnlock                   2    AES        6a4b5292661bac882338d5ebb51fd6de585befb4ef5f8ffda209be8ba3af1b96 0509d215f2f574efa2f192efc53c460201168b26a175f066b5347fc48bc76c637e27a730b904ca82
kSecAttrAccessibleAlways                             2    AES        c0ed717947ce8d1de2dde893b6026e9ee1958771d7a7282dd2116f84312c2dd2 b7ac3c4f1e04896144ce90c4583e26489a86a6cc45a2b692a5767b5a04b0907e081daba009fdbb3c
kSecAttrAccessibleWhenUnlockedThisDeviceOnly         3    AES        80d8c7be8d5103d437f8519356c3eb7e562c687a5e656cfd747532f71668ff99 417526e67b82e7c6c633f9063120a299b84e57a8ffee97b34020a2caf6e751ec5750053833ab4d45
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly     3    AES        a875a15e3ff901351c5306019e3b30ed123e6c66c949bdaa91fb4b9a69a3811e b0e17b0cf7111c6e716cd0272de5684834798431c1b34bab8d1a1b5aba3d38a3a42c859026f81ccc
kSecAttrAccessibleAlwaysThisDeviceOnly               3    AES        1e7756695d337e0b06c764734a9ef8148af20dcc7a636ccfea8b2eb96a9e9373 9b3bdc59ae1d85703aa7f75d49bdc600bf57ba4a458b20a003a10f6e36525fb6648ba70e6602d8b2

== decrypted data:
'<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD '
'PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist versi'
'on="1.0">\n<dict>\n\t<key>DCIMLastDirectoryNumber</key>\n\t<integer>100</integ'
'er>\n\t<key>DCIMLastFileNumber</key>\n\t<integer>3</integer>\n</dict>\n</plist'
'>\n'

== pretty-printed plist
{'DCIMLastDirectoryNumber': 100, 'DCIMLastFileNumber': 3}

Дополнительный кредит

код защиты данных iphone

опубликованный Бедруном и Сигвальдом, может расшифровать брелок из резервной копии, в том числе забавные вещи, такие как сохраненный Wi-Fi и пароли сайта:

$ python iphone-dataprotection/python_scripts/keychain_tool.py ...

--------------------------------------------------------------------------------------
|                              Passwords                                             |
--------------------------------------------------------------------------------------
|Service           |Account          |Data           |Access group  |Protection class|
--------------------------------------------------------------------------------------
|AirPort           |Eds Coffee Shop |<3FrenchRoast  |apple         |AfterFirstUnlock|
...
Этот код больше не работает для резервного копирования с телефонов, использующих последнюю версию iOS, но есть

$ python iphone-dataprotection/python_scripts/keychain_tool.py ...

--------------------------------------------------------------------------------------
|                              Passwords                                             |
--------------------------------------------------------------------------------------
|Service           |Account          |Data           |Access group  |Protection class|
--------------------------------------------------------------------------------------
|AirPort           |Eds Coffee Shop |<3FrenchRoast  |apple         |AfterFirstUnlock|
...

порты golang ports, которые были обновлены разрешить доступ к связке ключей.

Ответ 2

Извините, но это может быть даже сложнее, включая pbkdf2 или даже его вариант. Прослушайте сессию WWDC 2010 № 209, в которой в основном говорится о мерах безопасности в iOS 4, но также кратко упоминается о отдельном шифровании резервных копий и о том, как они связаны.

Вы можете быть уверены, что, не зная пароля, вы не сможете его расшифровать даже грубой силой.

Предположим, вы хотите попытаться включить людей, которые ЗНАЮ пароль, чтобы получить данные своих резервных копий.

Я боюсь, что нет никакого способа взглянуть на фактический код в iTunes, чтобы выяснить, какие альго используются.

Вернувшись в дни Ньютона, мне пришлось расшифровать данные из программы, и я смог вызвать его функцию дешифрования напрямую (зная пароль, конечно), не требуя даже отменить его алгоритм. Это не так просто, к сожалению.

Я уверен, что вокруг есть опытные люди, которые могли бы перепроектировать этот код iTunes - вам просто нужно заинтересовать их.

В теории, Apple algos должен быть спроектирован таким образом, чтобы данные все еще были безопасными (т.е. практически нерушимыми методами грубой силы) любому злоумышленнику, зная точный метод шифрования. И на сессии WWDC 209 они довольно подробно разобрались в деталях о том, что они делают для достижения этого. Может быть, вы можете получить ответы непосредственно от Apple, если вы сообщите им свои добрые намерения. В конце концов, даже они должны знать, что безопасность от обфускации не очень эффективна. Попробуйте их список рассылки по безопасности. Даже если они не ответят, возможно, кто-то еще молча в списке ответит с некоторой помощью.

Удачи!

Ответ 3

Не пробовал, но Elcomsoft выпустил продукт, который, по их утверждению, способен расшифровать резервные копии для целей судебной экспертизы. Может быть, не так круто, как инженерное решение самостоятельно, но это может быть быстрее.

http://www.elcomsoft.com/eppb.html

Ответ 4

Вам следует взять копию утилиты командной строки Erica Sadun mdhelper (OS X binary и источник). Он поддерживает листинг и извлечение содержимого резервных копий iPhone/iPod Touch, включая базы данных адресной книги и SMS, а также другие метаданные и настройки приложения.