diff --git a/README.md b/README.md index 3a2bbe4..fde12de 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,62 @@ AEA OTA/IPSW decryption -## Grabbing keys with `get_key.py` +## Prerequisites -Gets a key from the key URL embedded in an AEA's auth data blob. +- `get_key.py` + - Python 3.10+ (might work with older, but not tested) + - `requests` + - `pyhpke` +- `aastuff` + - macOS 13+ + - macOS 14+ for HPKE support +- `aastuff_standalone` + - macOS 12+ + - macOS 14+ for HPKE support -> [!NOTE] -> OTAs before iOS 18.0 beta 3 did not have embedded auth data; for these OTAs, you must use the key provided with your response. macOS is the exception. +## Building and Installing + +### `get_key.py` ```shell pip3 install -r requirements.txt -python3 get_key.py ``` -Note: it is highly recommended to use a virtual environment: +> [!NOTE] +> It is highly recommended to use a virtual environment: +> +> ```shell +> python3 -m venv .env # only needed once +> source .env/bin/activate +> pip3 install -r requirements.txt # only needed once +> ``` +> +> On future runs, you only need to activate the virtual environment: +> +> ```shell +> source .env/bin/activate +> ``` + +### `aastuff`/`aastuff_standalone` + +You can pass two options to the makefile: + +- `DEBUG=1`: build debug (debug prints, no optimizations, debug information) +- `HPKE=1`: build with HPKE support (needs macOS 14.0+) + +```shell +make [DEBUG=1] [HPKE=1] +``` + +## Grabbing keys with `get_key.py` + +Unwrap the decryption key using the data embedded in an AEA's auth data blob. + +> [!NOTE] +> OTAs before iOS 18.0 beta 3 did not have embedded auth data; for these OTAs, you must use the decryption key provided with your response. macOS is the exception and has always had embedded auth data. ```shell -python3 -m venv .env # only needed once -source .env/bin/activate -pip3 install -r requirements.txt # only needed once +source .env/bin/activate # if you used a virtual environment python3 get_key.py ``` @@ -27,15 +65,19 @@ python3 get_key.py ```shell aea decrypt -i -o -key-value 'base64:' +# or +./aastuff -i -o -d -k +# or, to use the network to grab the private key +./aastuff -i -o -d -n ``` For IPSWs, you will get the unwrapped file (ie. `090-34187-052.dmg.aea` will decrypt to `090-34187-052.dmg`). -For assets, you will get specially crafted AppleArchives (see next section). +For assets, you will get specially crafted Apple Archives (see next section). ## Extracting assets -Assets (including OTA updates) are constructed specially and cannot be extracted with standard (`aa`) tooling. They can be decrypted normally, which will result in an AppleArchive that is not extractable with `aa` (we will call these "asset archives"). `aastuff` must be used to extract them. +Assets (including OTA updates) are constructed specially and cannot be extracted with standard (`aa`) tooling. They can be decrypted normally, which will result in an Apple Archive that is not extractable with `aa` (we will call these "asset archives"). `aastuff` must be used to extract them. ```shell # Decrypt if necessary @@ -68,7 +110,7 @@ For now, both are built and used in the same way. Once `aastuff_standalone` is f ## Credits -- Siguza - auth data parsing strategy, AppleArchive extraction sample code +- Siguza - auth data parsing strategy, Apple Archive extraction sample code - Nicolas - original HPKE code - Snoolie - auth data parsing strategy -- Flagers - AppleArchive assistance +- Flagers - Apple Archive assistance diff --git a/src/aea.m b/src/aea.m index ab691b8..2b3e98d 100644 --- a/src/aea.m +++ b/src/aea.m @@ -95,12 +95,14 @@ int fetchKey(AEAContext context, ExtractionConfiguration* config) { return 1; } + // Encapsulated symmetric key. This is what was used to encrypt the archive's encryption key. Also known as the shared secret. NSData* encryptedRequest = [[NSData alloc] initWithBase64EncodedString:response[@"enc-request"] options:0]; if (!encryptedRequest) { ERRLOG(@"Failed to decode encrypted request"); return 1; } + // Wrapped archive encryption key. Also known as the message, encrypted data, or ciphertext. NSData* wrappedKey = [[NSData alloc] initWithBase64EncodedString:response[@"wrapped-key"] options:0]; if (!wrappedKey) { ERRLOG(@"Failed to decode wrapped key"); @@ -109,9 +111,10 @@ int fetchKey(AEAContext context, ExtractionConfiguration* config) { DBGLOG(@"Key URL: %@", url); DBGLOG(@"Response data: %@", response); - DBGLOG(@"Encrypted request: %@", encryptedRequest); - DBGLOG(@"Wrapped key: %@", wrappedKey); + DBGLOG(@"Encrypted request (encapsulated symmetric key): %@", encryptedRequest); + DBGLOG(@"Wrapped key (ciphertext): %@", wrappedKey); + // Receipient's private key. The receipient's public key is what was used to encrypt the encapsulated symmetric key. NSData* privateKey = nil; PrivateKeyFormat privateKeyFormat = PrivateKeyFormatAll; if (config.unwrapKey) { @@ -141,8 +144,9 @@ int fetchKey(AEAContext context, ExtractionConfiguration* config) { } } - DBGLOG(@"Private key: %@", privateKey); + DBGLOG(@"Private key (recepient's private key): %@", privateKey); + // The unwrapped encryption key. This is the data that was encrypted. Also known as the plaintext/cleartext. NSData* unwrappedKey = [HPKEWrapper unwrapPrivateKey:privateKey format:privateKeyFormat encryptedRequest:encryptedRequest wrappedKey:wrappedKey error:&error]; @@ -151,7 +155,7 @@ int fetchKey(AEAContext context, ExtractionConfiguration* config) { return 1; } - DBGLOG(@"Unwrapped key: %@ (%@)", unwrappedKey, [unwrappedKey base64EncodedStringWithOptions:0]); + DBGLOG(@"Unwrapped key (cleartext): %@ (%@)", unwrappedKey, [unwrappedKey base64EncodedStringWithOptions:0]); config.key = unwrappedKey;