147 lines
3.8 KiB
C
147 lines
3.8 KiB
C
#include <stdio.h>
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <hfs/hfsplus.h>
|
|
#include <openssl/aes.h>
|
|
#include "hfs/hfslib.h"
|
|
#include "emf.h"
|
|
|
|
size_t ConvertHexaCFString(CFStringRef s, uint8_t** bytes)
|
|
{
|
|
uint32_t len = CFStringGetLength(s);
|
|
uint8_t* hex = malloc(len+1);
|
|
|
|
if(hex == NULL)
|
|
return 0;
|
|
|
|
if(!CFStringGetCString(s, hex, len+1, kCFStringEncodingASCII))
|
|
{
|
|
free(hex);
|
|
return 0;
|
|
}
|
|
size_t size = 0;
|
|
hexToBytes(hex, bytes, &size);
|
|
free(hex);
|
|
return size;
|
|
}
|
|
|
|
void grabClassKey(const void *key, const void *value, void *context)
|
|
{
|
|
EMFInfo* emf = (EMFInfo*) context;
|
|
uint8_t* class_key = NULL;
|
|
|
|
if(CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFStringGetTypeID())
|
|
return;
|
|
|
|
SInt32 clas = CFStringGetIntValue((CFStringRef)key);
|
|
|
|
if(clas > 0 && clas <= MAX_CLASS_KEYS && CFStringGetLength((CFStringRef) value) == 64)
|
|
{
|
|
if(ConvertHexaCFString(value, &class_key) == 32)
|
|
{
|
|
AES_set_decrypt_key(class_key, 32*8, &(emf->classKeys[clas-1]));
|
|
free(class_key);
|
|
emf->classKeys_bitset |= 1 << clas;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
EMFInfo* EMF_init(Volume* volume, char* imagePath)
|
|
{
|
|
uint8_t* emfk = NULL;
|
|
uint8_t* dkey = NULL;
|
|
|
|
uint64_t volume_id = *((uint64_t*) (&volume->volumeHeader->finderInfo[6]));
|
|
FLIPENDIAN(volume_id);
|
|
|
|
if(imagePath == NULL)
|
|
imagePath = ".";
|
|
|
|
printf("Volume identifier : %llx\n", volume_id);
|
|
printf("Searching for %s/%llx.plist\n", imagePath, volume_id);
|
|
|
|
CFStringRef path = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s/%llx.plist"), imagePath, volume_id);
|
|
|
|
CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, FALSE);
|
|
CFRelease(path);
|
|
|
|
CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, fileURL);
|
|
CFRelease(fileURL);
|
|
|
|
if(stream == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
if(!CFReadStreamOpen(stream))
|
|
{
|
|
fprintf(stderr, "Cannot open file\n");
|
|
return NULL;
|
|
}
|
|
CFPropertyListRef dict = CFPropertyListCreateWithStream(NULL, stream, 0, kCFPropertyListImmutable, NULL, NULL);
|
|
|
|
CFRelease(stream);
|
|
|
|
if (dict == NULL || CFGetTypeID(dict) != CFDictionaryGetTypeID())
|
|
return NULL;
|
|
|
|
CFStringRef emfHex = CFDictionaryGetValue(dict, CFSTR("EMF"));
|
|
CFStringRef dkeyHex = CFDictionaryGetValue(dict, CFSTR("DKey"));
|
|
CFNumberRef dataVolumeOffset = CFDictionaryGetValue (dict, CFSTR("dataVolumeOffset"));
|
|
|
|
if (emfHex == NULL || CFGetTypeID(emfHex) != CFStringGetTypeID())
|
|
return NULL;
|
|
if (dkeyHex == NULL || CFGetTypeID(dkeyHex) != CFStringGetTypeID())
|
|
return NULL;
|
|
if (dataVolumeOffset == NULL || CFGetTypeID(dataVolumeOffset) != CFNumberGetTypeID())
|
|
return NULL;
|
|
|
|
EMFInfo* emf = malloc(sizeof(EMFInfo));
|
|
|
|
if(emf == NULL)
|
|
return NULL;
|
|
|
|
memset(emf, 0, sizeof(EMFInfo));
|
|
|
|
emf->volume = volume;
|
|
|
|
CFNumberGetValue(dataVolumeOffset, kCFNumberLongType, &emf->volume_offset);
|
|
|
|
printf("Data partition offset = %llx\n", emf->volume_offset);
|
|
|
|
if(ConvertHexaCFString(emfHex, &emfk) != 32)
|
|
{
|
|
fprintf(stderr, "Invalid EMF key\n");
|
|
free(emf);
|
|
return NULL;
|
|
}
|
|
if(ConvertHexaCFString(dkeyHex, &dkey) != 32)
|
|
{
|
|
fprintf(stderr, "Invalid DKey key\n");
|
|
free(emf);
|
|
return NULL;
|
|
}
|
|
|
|
AES_set_encrypt_key(emfk, 32*8, &(emf->emfkey));
|
|
AES_set_decrypt_key(dkey, 32*8, &(emf->classKeys[CLASS_DKEY-1]));
|
|
emf->classKeys_bitset |= 1 << CLASS_DKEY;
|
|
|
|
CFDictionaryRef classKeys = CFDictionaryGetValue(dict, CFSTR("classKeys"));
|
|
|
|
if(classKeys != NULL && CFGetTypeID(classKeys) == CFDictionaryGetTypeID())
|
|
{
|
|
printf("Reading class keys, NSProtectionComplete files should be decrypted OK\n");
|
|
CFDictionaryApplyFunction(classKeys, grabClassKey, (void*) emf);
|
|
}
|
|
else
|
|
{
|
|
printf("Only NSProtectionNone files will be decrypted\n");
|
|
}
|
|
|
|
free(emfk);
|
|
free(dkey);
|
|
return emf;
|
|
}
|