Skip to content

How iTunes backup hashes are extracted

A technical walkthrough of how Hash Extractor parses a Manifest.plist BackupKeyBag to produce a crackable $itunes_backup$ hash for hashcat and John the Ripper.

Published on 4 min read

Hash Extractor parses Apple iTunes and iOS device backups entirely in the browser — no upload, no server — and emits the $itunes_backup$ hash that hashcat and John the Ripper understand. This post walks through exactly how that parsing works, from the binary keybag to the final hash string.

Where the key material lives

When you enable encryption on an iOS backup (either through iTunes or the Finder on macOS), Apple wraps the backup's class keys with a passphrase-derived key. The relevant material is stored in a property-list file called Manifest.plist, which sits at the root of the backup folder on your computer. Inside that plist, a blob called BackupKeyBag holds the wrapped key and the parameters needed to re-derive the passphrase key.

The BackupKeyBag is encoded as a sequence of TLV records:

TAG (4 bytes, ASCII) || LEN (4 bytes, big-endian u32) || DATA (LEN bytes)

The parser scans the blob linearly for the following tags:

TagLengthMeaning
SALT20 bytesPBKDF2-SHA1 salt
ITER4 bytes (u32 BE)PBKDF2 iteration count
WPKY40 bytesAES-wrapped class key
DPIC4 bytes (u32 BE)Second-stage PBKDF2-SHA256 iterations (iOS 10.2+)
DPSL20 bytesSecond-stage PBKDF2-SHA256 salt (iOS 10.2+)

Tags are matched in document order: SALT first, then ITER after the salt, then WPKY after the iter. The two optional iOS 10.2+ tags (DPIC / DPSL) are searched independently and only if both are present does the parser emit the iOS 10 hash variant.

Detection

The file is identified as an encrypted backup if it starts with the binary plist magic bplist00 and the blob contains both a WPKY and a SALT tag. A filename match on manifest.plist (case-insensitive) also triggers the parser, allowing drag-and-drop without knowing the file extension.

The hash formats

iOS 9 and earlier

When neither DPIC nor DPSL is found, the parser emits:

$itunes_backup$*9*<wpky_hex>*<iter>*<salt_hex>**

The trailing ** are placeholders for the missing second-stage fields — they are required by hashcat and John to keep the field count consistent.

Here is the exact hash from the parser's iOS 9 test case, using WPKY bytes 0x00–0x27, ITER 10000, and SALT bytes 0x01–0x14:

$itunes_backup$*9*000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627*10000*0102030405060708090a0b0c0d0e0f1011121314**

Breaking it down field by field:

FieldValueMeaning
version9iOS ≤ 9 path
wpky000102…262740-byte AES-wrapped key, hex
iter10000PBKDF2-SHA1 iteration count
salt010203…131420-byte PBKDF2-SHA1 salt, hex
dpic(empty)not present
dpsl(empty)not present

iOS 10 and later

When DPIC and DPSL are both present, the parser emits:

$itunes_backup$*10*<wpky_hex>*<iter>*<salt_hex>*<dpic>*<dpsl_hex>

Apple added a second PBKDF2 round (SHA-256 this time, controlled by DPIC and DPSL) in iOS 10.2 to increase the cost of offline attacks independently of the first-stage round count. The cracker must compute both derivations before it can attempt to unwrap the class key.

Here is the iOS 10 hash from the test suite (same WPKY/ITER/SALT as above, plus DPIC 5000 and DPSL bytes 0x32–0x45):

$itunes_backup$*10*000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627*10000*0102030405060708090a0b0c0d0e0f1011121314*5000*32333435363738393a3b3c3d3e3f404142434445

Breaking it down:

FieldValueMeaning
version10iOS ≥ 10 path
wpky000102…262740-byte AES-wrapped key, hex
iter10000First-stage PBKDF2-SHA1 iterations
salt010203…1314First-stage PBKDF2-SHA1 salt, hex
dpic5000Second-stage PBKDF2-SHA256 iterations
dpsl323334…4445Second-stage PBKDF2-SHA256 salt, hex

Cracking the hash

hashcat maps the two variants to separate modes:

ModeVariant
-m 14700$itunes_backup$*9*… — iOS ≤ 9
-m 14800$itunes_backup$*10*… — iOS 10+

hashcat

echo '$itunes_backup$*10*000102...2627*10000*010203...1314*5000*323334...4445' > hash.txt
hashcat -m 14800 hash.txt /usr/share/wordlists/rockyou.txt

For an iOS 9 backup, swap -m 14800 for -m 14700.

John the Ripper

echo '$itunes_backup$*10*000102...2627*10000*010203...1314*5000*323334...4445' > hash.txt
john --format=itunes-backup --wordlist=/usr/share/wordlists/rockyou.txt hash.txt

The iteration counts in a real backup are considerably higher than in the test fixture. Apple's defaults sit in the tens of thousands for the first stage and hundreds of thousands for the second stage on modern iOS versions. On a mid-range GPU, expect roughly a few hundred to a few thousand candidates per second for mode 14800 — PBKDF2-SHA256 at that iteration depth is deliberately punishing.

Why client-side matters

An iOS backup can contain messages, photos, health data, and authentication tokens. Uploading it to a remote service to extract a hash would hand that entire encrypted vault to a third party. Hash Extractor compiles the extractor to WebAssembly and runs it in your browser: the backup file never leaves your machine, and the hash it produces contains no plaintext — only the parameters the cracker needs to test candidates locally.

The extraction logic mirrors itunes_backup2john from the John the Ripper project. The hashes it produces are structurally identical to the reference tool's output, so any existing hashcat or John workflow applies without modification.

Related articles

A technical walkthrough of how Hash Extractor parses Apple macOS keychain files to produce a crackable $keychain$ hash for hashcat and John the Ripper.
Why 7z is the trickiest archive to crack: LZMA-compressed headers, AES coder property encoding, and the full $7z$ hash format explained.
Inside the adb backup text header: how PBKDF2 salts, round counts, and a master-key blob become a crackable $ab$ hash.