int main(int argc, char **argv) { int rv; const char *what; const char *filename; const char *outname; TheImg4 *img4; unsigned type; unsigned written; unsigned char ivkey[16 + 32]; unsigned char *iv = NULL, *key = NULL; unsigned char *output = NULL; unsigned outlen = 0; int outdup = 0; DERItem item; unsigned char *data; size_t size; if (argc < 4) { fprintf(stderr, "usage: %s {-image|-extra|-keybag|-ticket} input output [ivkey]\n", argv[0]); return 1; } what = argv[1]; filename = argv[2]; outname = argv[3]; if (argc > 4) { rv = str2hex(sizeof(ivkey), ivkey, argv[4]); if (rv == sizeof(ivkey)) { iv = ivkey; key = ivkey + 16; } } data = read_file(filename, 0, &size); if (data == NULL) { fprintf(stderr, "[e] cannot read '%s'\n", filename); return -1; } img4 = parse(data, size); if (!img4) { fprintf(stderr, "[e] cannot parse '%s'\n", filename); free(data); return -1; } rv = Img4DecodeGetPayloadType(img4, &type); if (rv) { fprintf(stderr, "[e] cannot identify '%s'\n", filename); goto err; } printf("%c%c%c%c\n", FOURCC(type)); if (!strncmp(what, "-i", 2) || !strncmp(what, "-e", 2)) { int decompress; rv = Img4DecodeGetPayload(img4, &item); if (rv) { fprintf(stderr, "[e] cannot extract payload from '%s'\n", filename); goto err; } output = item.data; outlen = item.length; if (iv && key) { if (outlen & 15) { unsigned usize = (outlen + 15) & ~15; unsigned char *tmp = calloc(1, usize); if (!tmp) { fprintf(stderr, "[e] out of memory %u\n", usize); goto err; } memcpy(tmp, output, outlen); OUTSET(tmp); } rv = Img4DecodeGetPayloadKeybag(img4, &item); if (rv || item.length == 0) { fprintf(stderr, "[w] image '%s' has no keybag\n", filename); } #ifdef USE_CORECRYPTO cccbc_one_shot(ccaes_cbc_decrypt_mode(), 32, key, iv, (outlen + 15) / 16, output, output); #else AES_KEY decryptKey; AES_set_decrypt_key(key, 256, &decryptKey); AES_cbc_encrypt(output, output, (outlen + 15) & ~15, &decryptKey, iv, AES_DECRYPT); #endif } #ifdef iOS10 if (img4->payload.compression.data && img4->payload.compression.length) { DERItem tmp[2]; uint32_t deco = 0; uint64_t usize = 0; if (DERParseSequenceContent(&img4->payload.compression, 2, DERImg4PayloadItemSpecs10c, tmp, 0) || DERParseInteger(&tmp[0], &deco) || DERParseInteger64(&tmp[1], &usize)) { fprintf(stderr, "[e] cannot get decompression info\n"); goto err; } if (deco == 1 && what[1] == 'i') { size_t asize = lzfse_decode_scratch_size(); unsigned char *dec, *aux = malloc(asize); if (!aux) { fprintf(stderr, "[e] out of memory %zu\n", asize); goto err; } dec = malloc(usize + 1); if (!dec) { fprintf(stderr, "[e] out of memory %llu\n", usize + 1); free(aux); goto err; } outlen = lzfse_decode_buffer(dec, usize + 1, output, outlen, aux); free(aux); if (outlen != usize) { fprintf(stderr, "[e] decompression error\n"); free(dec); goto err; } OUTSET(dec); } } #endif decompress = (DWORD_BE(output, 0) == 'comp' && DWORD_BE(output, 4) == 'lzss'); if (decompress && what[1] == 'i') { uint32_t csize = DWORD_BE(output, 16); uint32_t usize = DWORD_BE(output, 12); uint32_t adler = DWORD_BE(output, 8); unsigned char *dec = malloc(usize); if (outlen > 0x180 + csize) { fprintf(stderr, "[i] extra 0x%x bytes after compressed chunk\n", outlen - 0x180 - csize); } if (!dec) { fprintf(stderr, "[e] out of memory %u\n", usize); goto err; } outlen = decompress_lzss(dec, output + 0x180, csize); if (adler != lzadler32(dec, outlen)) { fprintf(stderr, "[w] adler32 mismatch\n"); } OUTSET(dec); } else if (decompress) { uint32_t csize = DWORD_BE(output, 16); uint32_t usize = outlen - 0x180 - csize; if (outlen > 0x180 + csize) { unsigned char *dec = malloc(usize); if (!dec) { fprintf(stderr, "[e] out of memory %u\n", usize); goto err; } memcpy(dec, output + 0x180 + csize, usize); outlen = usize; OUTSET(dec); } else { OUTSET(NULL); } } else if (what[1] == 'e') { OUTSET(NULL); } if (!output) { fprintf(stderr, "[e] nothing to do\n"); goto err; } } if (!strncmp(what, "-k", 2)) { rv = Img4DecodeGetPayloadKeybag(img4, &item); if (rv == 0 && item.length) { output = item.data; outlen = item.length; } else { fprintf(stderr, "[e] image '%s' has no keybag\n", filename); goto err; } } if (!strncmp(what, "-t", 2)) { bool exists = false; rv = Img4DecodeManifestExists(img4, &exists); if (rv == 0 && exists) { output = img4->manifestRaw.data; outlen = img4->manifestRaw.length; } else { fprintf(stderr, "[e] image '%s' has no ticket\n", filename); goto err; } } written = write_file(outname, output, outlen); if (written != outlen) { fprintf(stderr, "[e] cannot write '%s'\n", outname); goto err; } rv = 0; out: if (outdup) { free(output); } free(img4); free(data); return rv; err: rv = -1; goto out; }
// Test the AES CBC mode static int AES_CBC_POST() { size_t key128Length = 16; size_t key192Length = 24; size_t key256Length = 32; typedef struct { size_t keyLength; int forEncryption; unsigned char* keyData; unsigned char* ivData; unsigned char* inputData; unsigned char* outputData; } testData; // AES 128 Encryption Test Data unsigned char* key128EncryptBuffer = (unsigned char*)"\x34\x49\x1b\x26\x6d\x8f\xb5\x4c\x5c\xe1\xa9\xfb\xf1\x7b\x09\x8c"; unsigned char* iv128EncryptBuffer = (unsigned char*)"\x9b\xc2\x0b\x29\x51\xff\x72\xd3\xf2\x80\xff\x3b\xd2\xdc\x3d\xcc"; unsigned char* input128EncryptBuffer = (unsigned char*)"\x06\xfe\x99\x71\x63\xcb\xcb\x55\x85\x3e\x28\x57\x74\xcc\xa8\x9d"; #ifdef FORCE_FAIL unsigned char* output128EncryptBuffer = (unsigned char*)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; #else unsigned char* output128EncryptBuffer = (unsigned char*)"\x32\x5d\xe3\x14\xe9\x29\xed\x08\x97\x87\xd0\xa2\x05\xd1\xeb\x33"; #endif // AES 128 Decryption Test Data unsigned char* key128DecryptBuffer = (unsigned char*)"\xc6\x8e\x4e\xb2\xca\x2a\xc5\xaf\xee\xac\xad\xea\xa3\x97\x11\x94"; unsigned char* iv128DecryptBuffer = (unsigned char*)"\x11\xdd\x9d\xa1\xbd\x22\x3a\xcf\x68\xc5\xa1\xe1\x96\x4c\x18\x9b"; unsigned char* input128DecryptBuffer = (unsigned char*)"\xaa\x36\x57\x9b\x0c\x72\xc5\x28\x16\x7b\x70\x12\xd7\xfa\xf0\xde"; unsigned char* output128DecryptBuffer = (unsigned char*)"\x9e\x66\x1d\xb3\x80\x39\x20\x9a\x72\xc7\xd2\x96\x40\x66\x88\xf2"; // AES 192 Encryption Test Data unsigned char* key192EncryptBuffer = (unsigned char*)"\x05\x85\xfc\xe6\xa9\x8c\x54\xd7\x2a\x4d\x7d\x53\x13\xbd\xeb\x0c\x1c\x42\xbc\xba\xf1\x68\x9b\x6b"; unsigned char* iv192EncryptBuffer = (unsigned char*)"\xf5\xc8\x5d\x21\x3c\xe2\x7e\xb2\xea\xf6\x29\x3c\xee\x44\x6f\x18"; unsigned char* input192EncryptBuffer = (unsigned char*)"\x5b\xb1\x61\xa5\x8d\xa6\x18\xfc\x55\x2d\x28\x23\x21\x4b\x8e\xee"; unsigned char* output192EncryptBuffer = (unsigned char*)"\x34\x91\xb7\xa7\x88\x67\x71\xf7\xc8\x0d\x85\x95\x4d\x6f\x7f\x28"; // AES 192 Decryption Test Data unsigned char* key192DecryptBuffer = (unsigned char*)"\x05\x8f\x89\xc4\xc9\x09\x0c\xad\x01\xd1\xa9\x37\x7f\x3f\xea\x14\x42\x24\xea\x49\x4b\x53\xc2\xd5"; unsigned char* iv192DecryptBuffer = (unsigned char*)"\xb8\xb1\x88\x69\x88\x18\x10\xdd\x4a\xb4\xd1\x19\x55\x94\x70\xc2"; unsigned char* input192DecryptBuffer = (unsigned char*)"\x12\xb9\xd4\x81\xeb\x0c\x7b\xe3\xfd\x6a\xe7\x55\xc9\xde\x3f\x6f"; unsigned char* output192DecryptBuffer = (unsigned char*)"\x7e\xb8\x86\x01\xa8\xb4\x85\x60\x5e\xbe\x7d\x88\x95\x75\xea\x94"; // AES 256 Encryption Test Data unsigned char* key256EncryptBuffer = (unsigned char*)"\xcd\x53\x9b\x65\x93\x19\x45\xb9\xe8\x65\xbc\x80\x4c\x4b\x16\x89\x24\x29\x8c\x3e\x02\xd9\xda\x79\x27\x2b\xe5\x99\x47\x92\xa0\xd4"; unsigned char* iv256EncryptBuffer = (unsigned char*)"\x0d\x52\xe3\x43\x57\x31\x4e\x28\x78\xa0\xca\x96\xc5\x32\xef\xd8"; unsigned char* input256EncryptBuffer = (unsigned char*)"\x17\x55\xb7\x73\x0b\x8c\x1c\x65\x0b\x42\x13\x70\x5b\x3e\x9c\xa2"; unsigned char* output256EncryptBuffer = (unsigned char*)"\x48\x8f\x47\x28\xa5\xac\xd5\x19\x84\x11\x0a\x23\x37\x49\x37\x30"; // AES 256 Decryption Test Data unsigned char* key256DecryptBuffer = (unsigned char*)"\x10\x42\x2a\x2a\x6c\x95\x41\xf4\x25\x63\x29\x88\xcb\x91\x83\x10\xab\xc5\xab\x8d\x96\x1c\x98\x27\xe4\x20\x04\xc1\xb9\xf4\xcd\xd1"; unsigned char* iv256DecryptBuffer = (unsigned char*)"\x0b\xf1\x8e\xba\x5e\x67\x1f\x71\x3c\x06\xd7\xc3\x15\x4c\xd4\xa9"; unsigned char* input256DecryptBuffer = (unsigned char*)"\xcc\x1b\xbc\x58\x78\xef\xf3\xde\xa7\x61\xde\x94\x5e\xf2\x50\x12"; unsigned char* output256DecryptBuffer = (unsigned char*)"\x61\xb7\x6a\x6d\xce\xaf\xc6\xae\xc1\xc3\x8d\xf3\x4a\xab\x49\x97"; testData dataToTest[] = { {key128Length, 1, key128EncryptBuffer, iv128EncryptBuffer, input128EncryptBuffer, output128EncryptBuffer}, {key128Length, 0, key128DecryptBuffer, iv128DecryptBuffer, input128DecryptBuffer, output128DecryptBuffer}, {key192Length, 1, key192EncryptBuffer, iv192EncryptBuffer, input192EncryptBuffer, output192EncryptBuffer}, {key192Length, 0, key192DecryptBuffer, iv192DecryptBuffer, input192DecryptBuffer, output192DecryptBuffer}, {key256Length, 1, key256EncryptBuffer, iv256EncryptBuffer, input256EncryptBuffer, output256EncryptBuffer}, {key256Length, 0, key256DecryptBuffer, iv256DecryptBuffer, input256DecryptBuffer, output256DecryptBuffer} }; const struct ccmode_cbc* mode_enc = ccaes_cbc_encrypt_mode(); const struct ccmode_cbc* mode_dec = ccaes_cbc_decrypt_mode(); struct { const struct ccmode_cbc* enc_mode_ptr; const struct ccmode_cbc* dec_mode_ptr; } impl[] = { {mode_enc, mode_dec}, }; int memCheckResult = 0; unsigned char outputBuffer[CCAES_BLOCK_SIZE]; int numDataToTest = 6; int numModesToTest = 1; for (int iCnt = 0; iCnt < numDataToTest; iCnt++) { for(int jCnt = 0; jCnt < numModesToTest; jCnt++) { cccbc_one_shot((dataToTest[iCnt].forEncryption ? impl[jCnt].enc_mode_ptr : impl[jCnt].dec_mode_ptr), dataToTest[iCnt].keyLength, dataToTest[iCnt].keyData, dataToTest[iCnt].ivData, 1, /* Only 1 block */ dataToTest[iCnt].inputData, outputBuffer); memCheckResult = (0 == memcmp(dataToTest[iCnt].outputData, outputBuffer, CCAES_BLOCK_SIZE)); if (!memCheckResult) { return -1; } } } return 0; }