--- /dev/null
+/*
+ This is all fairly minimal and based on @d0k3's decrypt9 code.
+*/
+
+#include "../std/memory.h"
+#include <ctr9/aes.h>
+#include <ctr9/sha.h>
+
+#include "firm.h"
+#include "decryptor.h"
+
+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_batch(void *dst, const void *src, uint32_t blockCount)
+{
+ *REG_AESBLKCNT = blockCount << 16;
+ *REG_AESCNT |= AES_CNT_START;
+
+ const uint32_t *src32 = (const uint32_t *)src;
+ uint32_t *dst32 = (uint32_t *)dst;
+
+ uint32_t wbc = blockCount;
+ uint32_t rbc = blockCount;
+
+ while (rbc) {
+ if (wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
+ {
+ *REG_AESWRFIFO = *src32++;
+ *REG_AESWRFIFO = *src32++;
+ *REG_AESWRFIFO = *src32++;
+ *REG_AESWRFIFO = *src32++;
+ wbc--;
+ }
+
+ if (rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
+ {
+ *dst32++ = *REG_AESRDFIFO;
+ *dst32++ = *REG_AESRDFIFO;
+ *dst32++ = *REG_AESRDFIFO;
+ *dst32++ = *REG_AESRDFIFO;
+ rbc--;
+ }
+ }
+}
+
+inline void
+aes_setmode(uint32_t mode)
+{
+ *REG_AESCNT = mode | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN | AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
+}
+
+void
+aes(void *dst, void *src, uint32_t blockCount, void *iv, uint32_t mode)
+{
+ aes_setmode(mode);
+
+ uint32_t blocks;
+ while (blockCount != 0) {
+ if ((mode & (7u << 27)) != AES_ECB_ENCRYPT_MODE && (mode & (7u << 27)) != AES_ECB_DECRYPT_MODE)
+ set_ctr(iv);
+
+ blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
+
+ // Save the last block for the next decryption CBC batch's iv
+ if ((mode & (7u << 27)) == AES_CBC_DECRYPT_MODE)
+ memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+ // Process the current batch
+ aes_batch(dst, src, blocks);
+
+ // Save the last block for the next encryption CBC batch's iv
+ if ((mode & (7u << 27)) == AES_CBC_ENCRYPT_MODE)
+ memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+
+ // Advance counter for CTR mode
+ else if ((mode & (7u << 27)) == AES_CTR_MODE)
+ add_ctr(iv, blocks);
+
+ src += blocks * AES_BLOCK_SIZE;
+ dst += blocks * AES_BLOCK_SIZE;
+ blockCount -= blocks;
+ }
+}
+
+void
+sha256sum(void* sum, void* data, uint32_t size) {
+ sha_init(SHA256_MODE);
+ sha_update(data, size);
+ sha_get(sum);
+}
#include <ctr9/io.h>
#include <ctr9/aes.h>
+#include <ctr9/sha.h>
#include "../common.h"
#include <ctr9/io.h>
+#include "decryptor.h"
+
firm_h *firm_loc = (firm_h *)FCRAM_FIRM_LOC;
uint32_t firm_size = FCRAM_SPACING;
firm_section_h firm_proc9;
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;
- }
-}
-
// Fwd decl
int decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title, uint8_t version);
fprintf(stderr, " Read FIRM%u off NAND.\n", index);
sdmmc_get_cid(1, (uint32_t*)cid);
- sha(sha_t, cid, 0x10, SHA_256_MODE);
+ sha256sum(sha_t, cid, 0x10);
memcpy(ctr, sha_t, 0x10);
- aes_advctr(ctr, firm_offset / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
+ add_ctr(ctr, firm_offset / AES_BLOCK_SIZE);
- 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);
+ use_aeskey(0x06);
+ set_ctr(ctr);
+ aes(firm, firm, firm_size / AES_BLOCK_SIZE, ctr, AES_CTR_MODE);
fprintf(stderr, " AES decrypted FIRM%u.\n", index);
// Is candidate?
if (mem[j] == byte) {
// Yes. Check hash.
- sha(hash, &mem[j], 0x10, SHA_256_MODE);
+ sha256sum(hash, &mem[j], 0x10);
if(!memcmp(sha256, hash, 0x20)) {
return &mem[j];
memcpy(mem, key_data, 16);
- aes_setkey(0x05, mem, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
+ setup_aeskeyY(0x05, mem);
}
void extract_slot0x3DkeyY() {
memcpy(mem, key_data, 16);
- aes_setkey(0x3D, mem, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
+ setup_aeskeyY(0x3D, mem);
}
void* find_section_key() {
int
decrypt_cetk_key(void *key, const void *cetk)
{
- static int got_cetk = 0;
- uint8_t iv[AES_BLOCK_SIZE] = { 0 };
- uint32_t sigtype = __builtin_bswap32(*(uint32_t *)cetk);
+ static int got_cetk = 0;
+ uint8_t iv[AES_BLOCK_SIZE] = { 0 };
+ uint32_t sigtype = __builtin_bswap32(*(uint32_t *)cetk);
- if (sigtype != SIG_TYPE_RSA2048_SHA256)
- return 1;
+ if (sigtype != SIG_TYPE_RSA2048_SHA256)
+ return 1;
- ticket_h *ticket = (ticket_h *)((uint8_t*)cetk + sizeof(sigtype) + 0x13C);
+ ticket_h *ticket = (ticket_h *)(cetk + sizeof(sigtype) + 0x13C);
+ if (ticket->ticketCommonKeyYIndex != 1)
+ return 1;
- if (ticket->ticketCommonKeyYIndex != 1)
- return 1;
+ if (got_cetk == 0) {
+ extract_slot0x3DkeyY();
+ got_cetk = 1;
+ }
- if (got_cetk == 0) {
- extract_slot0x3DkeyY();
- got_cetk = 1;
- }
+ use_aeskey(0x3D);
- use_aeskey(0x3D);
- memcpy(iv, ticket->titleID, sizeof(ticket->titleID));
+ memcpy(iv, ticket->titleID, sizeof(ticket->titleID));
+ memcpy(key, ticket->titleKey, sizeof(ticket->titleKey));
- memcpy(key, ticket->titleKey, sizeof(ticket->titleKey));
- aes(key, key, 1, iv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+ aes(key, key, 1, iv, AES_CBC_DECRYPT_MODE);
- fprintf(stderr, " Extracted titlekey from cetk.\n");
+ fprintf(stderr, " Extracted titlekey from cetk.\n");
- return 0;
+ return 0;
}
int
uint8_t exefs_iv[16] = { 0 };
fprintf(stderr, " Decrypting FIRM container\n");
- aes_setkey(0x16, key, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
- aes_use_keyslot(0x16);
- aes(ncch, ncch, *size / AES_BLOCK_SIZE, firm_iv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+ setup_aeskey(0x16, key);
+ use_aeskey(0x16);
+ aes(ncch, ncch, *size / AES_BLOCK_SIZE, firm_iv, AES_CBC_DECRYPT_MODE);
if (ncch->magic != NCCH_MAGIC)
return 1;
uint32_t exefs_size = ncch->exeFSSize * MEDIA_UNITS;
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);
+ setup_aeskeyY(0x2C, exefs_key);
+ use_aeskey(0x2C);
+ aes(exefs, exefs, exefs_size / AES_BLOCK_SIZE, exefs_iv, AES_CTR_MODE);
// Get the decrypted FIRM
// We assume the firm.bin is always the first file
slot = 0x16;
use_aeskey(0x11);
- aes(decrypted_keyx, header->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
+ aes(decrypted_keyx, header->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE);
setup_aeskeyX(slot, decrypted_keyx);
}
int size = atoi(header->size);
use_aeskey(slot);
- aes(arm9bin, arm9bin, size / AES_BLOCK_SIZE, header->ctr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+ aes(arm9bin, arm9bin, size / AES_BLOCK_SIZE, header->ctr, AES_CTR_MODE);
if (firm_title == NATIVE_FIRM_TITLEID)
return *(uint32_t *)arm9bin != ARM9BIN_MAGIC;
use_aeskey(0x11);
uint8_t keyx[AES_BLOCK_SIZE];
for (int slot = 0x19; slot < 0x20; slot++) {
- aes(keyx, keydata, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
+ aes(keyx, keydata, 1, NULL, AES_ECB_DECRYPT_MODE);
setup_aeskeyX(slot, keyx);
*(uint8_t *)(keydata + 0xF) += 1;
}