hacks/dump-imessages/iphone-dataprotection/ramdisk_tools/AppleKeyStore.c

318 lines
10 KiB
C

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CommonCrypto/CommonCryptor.h>
#include <CommonCrypto/CommonHMAC.h>
#include "IOKit.h"
#include "IOAESAccelerator.h"
#include "AppleEffaceableStorage.h"
#include "AppleKeyStore.h"
#include "util.h"
#include "bsdcrypto/rijndael.h"
#include "bsdcrypto/key_wrap.h"
CFDictionaryRef AppleKeyStore_loadKeyBag(const char* folder, const char* filename)
{
char keybagPath[100];
struct BAG1Locker bag1_locker={0};
//unsigned char buffer_bag1[52] = {0};
snprintf(keybagPath, 99, "%s/%s.kb", folder, filename);
CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
(const UInt8*)keybagPath,
strlen(keybagPath),
0);
if (url == NULL)
return NULL;
CFReadStreamRef stream = CFReadStreamCreateWithFile (kCFAllocatorDefault, url);
if (stream == NULL)
return NULL;
if (CFReadStreamOpen(stream) != TRUE)
return NULL;
CFPropertyListRef plist = CFPropertyListCreateWithStream (kCFAllocatorDefault,
stream,
0,
kCFPropertyListImmutable,
NULL,
NULL
);
if (plist == NULL)
return NULL;
CFDataRef data = CFDictionaryGetValue(plist, CFSTR("_MKBPAYLOAD"));
if (data == NULL)
return NULL;
uint8_t* mkbpayload = valloc(CFDataGetLength(data));
CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), mkbpayload);
int length = CFDataGetLength(data);
if (length < 16)
{
free(mkbpayload);
return NULL;
}
if (AppleEffaceableStorage__getLocker(LOCKER_BAG1, (uint8_t*) &bag1_locker, sizeof(struct BAG1Locker)))
{
free(mkbpayload);
return NULL;
}
if (bag1_locker.magic != 'BAG1')
fprintf(stderr, "AppleKeyStore_loadKeyBag: bad BAG1 magic\n");
size_t decryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
bag1_locker.key,
kCCKeySizeAES256,
bag1_locker.iv,
mkbpayload,
length,
mkbpayload,
length,
&decryptedSize);
if (cryptStatus != kCCSuccess)
{
fprintf(stderr, "AppleKeyStore_loadKeyBag CCCrypt kCCDecrypt with BAG1 key failed, return code=%x\n", cryptStatus);
free(mkbpayload);
return NULL;
}
CFDataRef data2 = CFDataCreate(kCFAllocatorDefault,
mkbpayload,
decryptedSize
);
if (data2 == NULL)
{
free(mkbpayload);
return NULL;
}
CFErrorRef e=NULL;
CFPropertyListRef plist2 = CFPropertyListCreateWithData(kCFAllocatorDefault, data2, kCFPropertyListImmutable, NULL, &e);
if (plist2 == NULL)
{
fprintf(stderr, "AppleKeyStore_loadKeyBag failed to create plist, AES fail ? decryptedSize=%zx\n", decryptedSize);
CFShow(e);
}
free(mkbpayload);
CFRelease(data2);
return plist2;
}
int AppleKeyStoreKeyBagInit()
{
uint64_t out = 0;
uint32_t one = 1;
return IOKit_call("AppleKeyStore",
kAppleKeyStoreInitUserClient,
NULL,
0,
NULL,
0,
&out,
&one,
NULL,
NULL);
}
int AppleKeyStoreKeyBagCreateWithData(CFDataRef data, uint64_t* keybagId)
{
uint32_t outCnt = 1;
aes_key_wrap_ctx ctx;
uint8_t hmckkey[32] = {0};
int retcode = IOKit_call("AppleKeyStore",
kAppleKeyStoreKeyBagCreateWithData,
NULL,
0,
CFDataGetBytePtr(data),
CFDataGetLength(data),
keybagId,
&outCnt,
NULL,
NULL
);
if (retcode != 0xE00002C9)
return retcode;
//HAX to load new iOS 7 keybags on previous iOS kernels
uint32_t* kbdata = (uint32_t*) CFDataGetBytePtr(data);
if ((kbdata[2] == 'SREV') && (kbdata[4] == 0x04000000))
{
printf("Patching iOS 7 keybag VERS 4 signature for older kernels\n");
aes_key_wrap_set_key(&ctx, IOAES_key835(), 16);
assert(kbdata[0x38/4] == 'KCMH');
assert(!aes_key_unwrap(&ctx, (const uint8_t*) &kbdata[0x38/4 + 2], hmckkey, 4));
assert(kbdata[CFSwapInt32BigToHost(kbdata[1])/4 + 2] == 'NGIS');
CCHmac(kCCHmacAlgSHA1,
(const void *) &kbdata[2],
CFSwapInt32BigToHost(kbdata[1]),
hmckkey,
32,
&kbdata[CFSwapInt32BigToHost(kbdata[1])/4 + 2 + 2]);
}
outCnt = 1;
return IOKit_call("AppleKeyStore",
kAppleKeyStoreKeyBagCreateWithData,
NULL,
0,
CFDataGetBytePtr(data),
CFDataGetLength(data),
keybagId,
&outCnt,
NULL,
NULL
);
}
int AppleKeyStoreKeyBagSetSystem(uint64_t keybagId)
{
return IOKit_call("AppleKeyStore",
kAppleKeyStoreKeyBagSetSystem,
&keybagId,
1,
NULL,
0,
NULL,
NULL,
NULL,
NULL);
}
int AppleKeyStoreUnlockDevice(io_connect_t conn, CFDataRef passcode)
{
return IOConnectCallMethod(conn,
kAppleKeyStoreUnlockDevice,
NULL,
0,
CFDataGetBytePtr(passcode),
CFDataGetLength(passcode),
NULL,
NULL,
NULL,
NULL);
}
KeyBag* AppleKeyStore_parseBinaryKeyBag(CFDataRef kb)
{
const uint8_t* ptr = CFDataGetBytePtr(kb);
unsigned int len = CFDataGetLength(kb);
struct KeyBagBlobItem* p = (struct KeyBagBlobItem*) ptr;
const uint8_t* end;
if (p->tag != 'ATAD') {
printf("Keybag does not start with DATA\n");
return NULL;
}
if (8 + CFSwapInt32BigToHost(p->len) > len) {
return NULL;
}
KeyBag* keybag = malloc(sizeof(KeyBag));
if (keybag == NULL)
return NULL;
memset(keybag, 0, sizeof(KeyBag));
end = ptr + 8 + CFSwapInt32BigToHost(p->len);
p = (struct KeyBagBlobItem*) p->data.bytes;
int kbuuid=0;
int i = -1;
while ((uint8_t*)p < end) {
//printf("%x\n", p->tag);
len = CFSwapInt32BigToHost(p->len);
if (p->tag == 'SREV') {
keybag->version = CFSwapInt32BigToHost(p->data.intvalue);
}
else if (p->tag == 'TLAS') {
memcpy(keybag->salt, p->data.bytes, 20);
}
else if (p->tag == 'RETI') {
keybag->iter = CFSwapInt32BigToHost(p->data.intvalue);
}
else if (p->tag == 'DIUU') {
if (!kbuuid)
{
memcpy(keybag->uuid, p->data.bytes, 16);
kbuuid = 1;
}
else
{
i++;
if (i >= MAX_CLASS_KEYS)
break;
memcpy(keybag->keys[i].uuid, p->data.bytes, 16);
}
}
else if (p->tag == 'SALC')
{
keybag->keys[i].clas = CFSwapInt32BigToHost(p->data.intvalue);
}
else if (p->tag == 'PARW' && kbuuid)
{
keybag->keys[i].wrap = CFSwapInt32BigToHost(p->data.intvalue);
}
else if (p->tag == 'YKPW')
{
memcpy(keybag->keys[i].wpky, p->data.bytes, (len > 40) ? 40 : len);
}
p = (struct KeyBagBlobItem*) &p->data.bytes[len];
}
keybag->numKeys = i + 1;
return keybag;
}
void AppleKeyStore_printKeyBag(KeyBag* kb)
{
int i;
printf("Keybag version : %d\n", kb->version);
printf("Keybag keys : %d\n", kb->numKeys);
printf("Class\tWrap\tKey\n");
for (i=0; i < kb->numKeys; i++)
{
printf("%d\t%d\t", kb->keys[i].clas, kb->keys[i].wrap);
printBytesToHex(kb->keys[i].wpky, kb->keys[i].wrap & 2 ? 40 : 32);
printf("\n");
}
printf("\n");
}
CFMutableDictionaryRef AppleKeyStore_getClassKeys(KeyBag* kb)
{
int i;
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, kb->numKeys, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFStringRef key;
for (i=0; i < kb->numKeys; i++)
{
if(kb->keys[i].wrap == 0)
{
key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kb->keys[i].clas);
addHexaString(dict, key, kb->keys[i].wpky, 32);
CFRelease(key);
}
}
return dict;
}