From: chaoskagami Date: Thu, 14 Jul 2016 09:50:14 +0000 (-0400) Subject: Merge branch 'ctr9io' into ctr9io_crypto X-Git-Tag: v0.2.0~24 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=66fec02646696fe2c5719f01fd5c01896bccd0f9;p=corbenik%2Fcorbenik.git Merge branch 'ctr9io' into ctr9io_crypto --- 66fec02646696fe2c5719f01fd5c01896bccd0f9 diff --cc source/firm/firm.c index 19abe4b,0faec0c..9bedfa0 --- a/source/firm/firm.c +++ b/source/firm/firm.c @@@ -3,11 -3,8 +3,11 @@@ #include #include +#include +#include + #include "../common.h" - #include "../misc/sha256.h" + #include firm_h *firm_loc = (firm_h *)FCRAM_FIRM_LOC; uint32_t firm_size = FCRAM_SPACING; @@@ -28,72 -28,57 +31,92 @@@ static int update_96_keys = 0 static volatile uint32_t *const a11_entry = (volatile uint32_t *)0x1FFFFFF8; +typedef enum { + NCCHTYPE_EXHEADER = 1, + NCCHTYPE_EXEFS = 2, + NCCHTYPE_ROMFS = 3, +} ctr_ncchtypes; + +void +ncch_getctr(const ncch_h *ncch, uint8_t *ctr, uint8_t type) +{ + uint32_t version = ncch->version; + const uint8_t *partitionID = ncch->partitionID; + int i; + + for (i = 0; i < 16; i++) + ctr[i] = 0x00; + + if (version == 2 || version == 0) { + for (i = 0; i < 8; i++) + ctr[i] = partitionID[7 - i]; // Convert to big endian & normal input + ctr[8] = type; + } else if (version == 1) { + int x = 0; + if (type == NCCHTYPE_EXHEADER) + x = MEDIA_UNITS; + else if (type == NCCHTYPE_EXEFS) + x = ncch->exeFSOffset * MEDIA_UNITS; + else if (type == NCCHTYPE_ROMFS) + x = ncch->exeFSOffset * MEDIA_UNITS; + for (i = 0; i < 8; i++) + ctr[i] = partitionID[i]; + for (i = 0; i < 4; i++) + ctr[i + 12] = (x >> ((3 - i) * 8)) & 0xFF; + } +} + - void - aes(void *dst, const void *src, uint32_t blockCount, void *iv, uint32_t mode, uint32_t ivMode) - { - aes_setmode(mode); - uint32_t blocks; - while (blockCount != 0) { - if ((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE && (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE) - aes_setiv(iv, ivMode); - blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount; - - // Save the last block for the next decryption CBC batch's iv - if ((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE) { - memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); - aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); - } + // Fwd decl + int decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title, uint8_t version); - // Process the current batch - aes_batch(dst, src, blocks); + #define SECTOR_SIZE 0x200 - // Save the last block for the next encryption CBC batch's iv - if ((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE) { - memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); - aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); - } else if ((mode & AES_ALL_MODES) == AES_CTR_MODE) { // Advance counter for CTR mode - aes_advctr(iv, blocks, ivMode); - } + // 0x0B130000 = start of FIRM0 partition, 0x400000 = size of FIRM partition (4MB) + void dump_firm(firm_h** buffer, uint8_t index) { + if (*buffer != NULL) return; + + uint32_t firm_offset = 0x0B130000 + (index % 2) * 0x400000, + firm_size = 0x00100000; // 1MB, because + + buffer[0] = static_allocate(firm_size); + + uint8_t ctr[0x10], + cid[0x10], + sha_t[0x20]; + + firm_h* firm = buffer[0]; + + if (sdmmc_nand_readsectors(firm_offset / SECTOR_SIZE, firm_size / SECTOR_SIZE, (uint8_t*)firm)) + abort(" Failed to read NAND!\n"); - src += blocks * AES_BLOCK_SIZE; - dst += blocks * AES_BLOCK_SIZE; - blockCount -= blocks; + fprintf(stderr, " Read FIRM%u off NAND.\n", index); + + sdmmc_get_cid(1, (uint32_t*)cid); + sha(sha_t, cid, 0x10, SHA_256_MODE); + memcpy(ctr, sha_t, 0x10); + aes_advctr(ctr, firm_offset / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); + + aes_use_keyslot(0x06); + aes_setiv(ctr, AES_INPUT_BE|AES_INPUT_NORMAL); + aes((uint8_t*)firm, (uint8_t*)firm, firm_size / AES_BLOCK_SIZE, ctr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + + fprintf(stderr, " AES decrypted FIRM%u.\n", index); + + if (memcmp((char*) & firm->magic, "FIRM", 4)) + abort(" Decryption failed on FIRM.\n"); + + fprintf(stderr, " Magic is intact on FIRM%u.\n", index); + + uint8_t detver = 0; + + if(index == 1) + detver = 0x10; + + if(decrypt_arm9bin((arm9bin_h*)((uint8_t*)firm + firm->section[2].offset), NATIVE_FIRM_TITLEID, detver)) { + abort(" Failed to decrypt FIRM%u arm9loader.\n", index); } + + fprintf(stderr, " Decrypted FIRM%u arm9loader.\n", index); } void @@@ -130,28 -197,12 +235,12 @@@ decrypt_cetk_key(void *key, const void if (ticket->ticketCommonKeyYIndex != 1) return 1; - if (!common_key_y_init) { - uint8_t common_key_y[AES_BLOCK_SIZE] = { 0 }; - uint8_t *p9_base = (uint8_t *)0x08028000; - uint8_t *i; - for (i = p9_base + 0x70000 - AES_BLOCK_SIZE; i >= p9_base; i--) { - if (i[0] == 0xD0 && i[4] == 0x9C && i[8] == 0x32 && i[12] == 0x23) { - // At i, there's 7 keys with 4 bytes padding between them. - // We only need the 2nd. - memcpy(common_key_y, i + AES_BLOCK_SIZE + 4, sizeof(common_key_y)); - fprintf(stderr, "y"); - break; - } - } - - if (i < p9_base) - return 1; - - setup_aeskeyY(0x3D, common_key_y); - common_key_y_init = 1; + if (got_cetk == 0) { + extract_slot0x3DkeyY(); + got_cetk = 1; } - aes_use_keyslot(0x3D); + use_aeskey(0x3D); memcpy(iv, ticket->titleID, sizeof(ticket->titleID)); memcpy(key, ticket->titleKey, sizeof(ticket->titleKey)); @@@ -181,12 -232,12 +270,12 @@@ decrypt_firm_title(firm_h *dest, ncch_ ncch_getctr(ncch, exefs_iv, NCCHTYPE_EXEFS); // Get the exefs offset and size from the NCCH - exefs_h *exefs = (exefs_h *)((void *)ncch + ncch->exeFSOffset * MEDIA_UNITS); + exefs_h *exefs = (exefs_h *)((uint8_t *)ncch + ncch->exeFSOffset * MEDIA_UNITS); uint32_t exefs_size = ncch->exeFSSize * MEDIA_UNITS; - fprintf(BOTTOM_SCREEN, "e"); - setup_aeskeyY(0x2C, exefs_key); - use_aeskey(0x2C); + fprintf(stderr, " Decrypting ExeFs for FIRM\n"); + aes_setkey(0x2C, exefs_key, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x2C); aes(exefs, exefs, exefs_size / AES_BLOCK_SIZE, exefs_iv, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); // Get the decrypted FIRM @@@ -408,9 -429,9 +467,9 @@@ boot_firm( // depending on which firmware you're booting from. // TODO: Don't use the hardcoded offset. if (update_96_keys && fsig->console == console_n3ds && fsig->version > 0x0F) { - void *keydata = find_section_key(); + uint8_t *keydata = find_section_key(); if (!keydata) { - abort("Couldn't find key!\n"); + abort("Couldn't find section key.\n"); } wait(); @@@ -427,9 -448,9 +486,9 @@@ } for (firm_section_h *section = firm_loc->section; section < firm_loc->section + 4 && section->address != 0; section++) { - memcpy((void *)section->address, (void *)firm_loc + section->offset, section->size); + memcpy((void *)section->address, (void *)((uint8_t*)firm_loc + section->offset), section->size); } - fprintf(BOTTOM_SCREEN, "Copied FIRM\n"); + fprintf(stderr, "Copied FIRM.\n"); wait();