#include <stdint.h>
#include <stddef.h>
+#include <ctr9/io.h>
+#include <ctr9/aes.h>
+
#include "../common.h"
- #include "../misc/sha256.h"
+ #include <ctr9/io.h>
firm_h *firm_loc = (firm_h *)FCRAM_FIRM_LOC;
uint32_t firm_size = FCRAM_SPACING;
static volatile uint32_t *const a11_entry = (volatile uint32_t *)0x1FFFFFF8;
- 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);
- }
+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;
+ }
+}
+
+ // 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
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));
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
// 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();
}
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();