I've been asked by a number of unfortunate iPhone users to help them restore data from their iTunes backups. This is easy when they are unencrypted, but not when they are encrypted, whether or not the password is known.
As such, I'm trying to figure out the encryption scheme used on mddata and mdinfo files when encrypted. I have no problems reading these files otherwise, and have built some robust C# libraries for doing so. (If you're able to help, I don't care which language you use. It's the principle I'm after here!)
The Apple "iPhone OS Enterprise Deployment Guide" states that "Device backups can be stored in encrypted format by selecting the Encrypt iPhone
Backup option in the device summary pane of iTunes. Files are encrypted using AES128 with a 256-bit key. The key is stored securely in the iPhone keychain."
That's a pretty good clue, and there's some good info here on Stackoverflow on iPhone AES/Rijndael interoperability suggesting a keysize of 128 and CBC mode may be used.
Aside from any other obfuscation, a key and initialisation vector (IV)/salt are required.
One might assume that the key is a manipulation of the "backup password" that users are prompted to enter by iTunes and passed to "AppleMobileBackup.exe", padded in a fashion dictated by CBC. However, given the reference to the iPhone keychain, I wonder whether the "backup password" might not be used as a password on an X509 certificate or symmetric private key, and that the certificate or private key itself might be used as the key. (AES and the iTunes encrypt/decrypt process is symmetric.)
The IV is another matter, and it could be a few things. Perhaps it's one of the keys hard-coded into iTunes, or into the devices themselves.
Although Apple's comment above suggests the key is present on the device's keychain, I think this isn't that important. One can restore an encrypted backup to a different device, which suggests all information relevant to the decryption is present in the backup and iTunes configuration, and that anything solely on the device is irrelevant and replacable in this context. So where might be the key be?
I've listed paths below from a Windows machine but it's much of a muchness whichever OS we use.
The "\appdata\Roaming\Apple Computer\iTunes\itunesprefs.xml" contains a PList with a "Keychain" dict entry in it. The "\programdata\apple\Lockdown\09037027da8f4bdefdea97d706703ca034c88bab.plist" contains a PList with "DeviceCertificate", "HostCertificate", and "RootCertificate", all of which appear to be valid X509 certs. The same file also appears to contain asymmetric keys "RootPrivateKey" and "HostPrivateKey" (my reading suggests these might be PKCS #7-enveloped). Also, within each backup there are "AuthSignature" and "AuthData" values in the Manifest.plist file, although these appear to be rotated as each file gets incrementally backed up, suggested they're not that useful as a key, unless something really quite involved is being done.
There's a lot of misleading stuff out there suggesting getting data from encrypted backups is easy. It's not, and to my knowledge it hasn't been done. Bypassing or disabling the backup encryption is another matter entirely, and is not what I'm looking to do.
This isn't about hacking apart the iPhone or anything like that. All I'm after here is a means to extract data (photos, contacts, etc.) from encrypted iTunes backups as I can unencrypted ones. I've tried all sorts of permutations with the information I've put down above but got nowhere. I'd appreciate any thoughts or techniques I might have missed.
Best Answer
Security researchers Jean-Baptiste Bédrune and Jean Sigwald presented how to do this at Hack-in-the-box Amsterdam 2011.
Since then, Apple has released an iOS Security Whitepaper with more details about keys and algorithms, and Charlie Miller et al. have released the iOS Hacker’s Handbook, which covers some of the same ground in a how-to fashion. When iOS 10 first came out there were changes to the backup format which Apple did not publicize at first, but various people reverse-engineered the format changes.
Encrypted backups are great
The great thing about encrypted iPhone backups is that they contain things like WiFi passwords that aren’t in regular unencrypted backups. As discussed in the iOS Security Whitepaper, encrypted backups are considered more “secure,” so Apple considers it ok to include more sensitive information in them.
An important warning: obviously, decrypting your iOS device’s backup removes its encryption. To protect your privacy and security, you should only run these scripts on a machine with full-disk encryption. While it is possible for a security expert to write software that protects keys in memory, e.g. by using functions like
VirtualLock()
andSecureZeroMemory()
among many other things, these Python scripts will store your encryption keys and passwords in strings to be garbage-collected by Python. This means your secret keys and passwords will live in RAM for a while, from whence they will leak into your swap file and onto your disk, where an adversary can recover them. This completely defeats the point of having an encrypted backup.How to decrypt backups: in theory
The iOS Security Whitepaper explains the fundamental concepts of per-file keys, protection classes, protection class keys, and keybags better than I can. If you’re not already familiar with these, take a few minutes to read the relevant parts.
Now you know that every file in iOS is encrypted with its own random per-file encryption key, belongs to a protection class, and the per-file encryption keys are stored in the filesystem metadata, wrapped in the protection class key.
To decrypt:
Decode the keybag stored in the
BackupKeyBag
entry ofManifest.plist
. A high-level overview of this structure is given in the whitepaper. The iPhone Wiki describes the binary format: a 4-byte string type field, a 4-byte big-endian length field, and then the value itself.The important values are the PBKDF2
ITER
ations andSALT
, the double protection saltDPSL
and iteration countDPIC
, and then for each protectionCLS
, theWPKY
wrapped key.Using the backup password derive a 32-byte key using the correct PBKDF2 salt and number of iterations. First use a SHA256 round with
DPSL
andDPIC
, then a SHA1 round withITER
andSALT
.Unwrap each wrapped key according to RFC 3394.
Decrypt the manifest database by pulling the 4-byte protection class and longer key from the
ManifestKey
inManifest.plist
, and unwrapping it. You now have a SQLite database with all file metadata.For each file of interest, get the class-encrypted per-file encryption key and protection class code by looking in the
Files.file
database column for a binary plist containingEncryptionKey
andProtectionClass
entries. Strip the initial four-byte length tag fromEncryptionKey
before using.Then, derive the final decryption key by unwrapping it with the class key that was unwrapped with the backup password. Then decrypt the file using AES in CBC mode with a zero IV.
How to decrypt backups: in practice
First you’ll need some library dependencies. If you’re on a mac using a homebrew-installed Python 2.7 or 3.7, you can install the dependencies with:
In runnable source code form, here is how to decrypt a single preferences file from an encrypted iPhone backup:
Which then prints this output:
Extra credit
The iphone-dataprotection code posted by Bédrune and Sigwald can decrypt the keychain from a backup, including fun things like saved wifi and website passwords:
That code no longer works on backups from phones using the latest iOS, but there are some golang ports that have been kept up to date allowing access to the keychain.