From 737933f43e0402fcfcbd512f75d057a6125fda64 Mon Sep 17 00:00:00 2001 From: chaoskagami Date: Mon, 25 Jul 2016 15:13:54 -0400 Subject: [PATCH] Crypto stuff...partially working, CBC seems busted still --- include/firm/decryptor.h | 3 +- source/firm/decryptor.c | 72 ++++++++-------------------------------- source/firm/firm.c | 26 +++++++++------ 3 files changed, 30 insertions(+), 71 deletions(-) diff --git a/include/firm/decryptor.h b/include/firm/decryptor.h index fe7d703..c7f95f6 100644 --- a/include/firm/decryptor.h +++ b/include/firm/decryptor.h @@ -1,9 +1,10 @@ #ifndef __DECRYPTOR_H #define __DECRYPTOR_H -void aes(void *dst, void *src, uint32_t blockCount, void *iv, uint32_t mode); void sha256sum(void* sum, void* data, uint32_t size); +void cbc_decrypt(void *inbuf, void *outbuf, size_t size, uint32_t mode, uint8_t *iv); + typedef enum { NCCHTYPE_EXHEADER = 1, NCCHTYPE_EXEFS = 2, diff --git a/source/firm/decryptor.c b/source/firm/decryptor.c index 099ecb5..b93555d 100644 --- a/source/firm/decryptor.c +++ b/source/firm/decryptor.c @@ -36,75 +36,29 @@ ncch_getctr(const ncch_h *ncch, uint8_t *ctr, uint8_t type) } void -aes_batch(void *dst, const void *src, uint32_t blockCount) +cbc_decrypt(void *inbuf, void *outbuf, size_t size, uint32_t mode, uint8_t *iv) { - *REG_AESBLKCNT = blockCount << 16; - *REG_AESCNT |= AES_CNT_START; + size_t blocks = size; + uint8_t *in = inbuf; + uint8_t *out = outbuf; + while (blocks) { + set_ctr(iv); - const uint32_t *src32 = (const uint32_t *)src; - uint32_t *dst32 = (uint32_t *)dst; + size_t current_blocks = blocks > 0xFFFF ? 0xFFFF : blocks; - uint32_t wbc = blockCount; - uint32_t rbc = blockCount; + aes_decrypt(in, out, current_blocks, mode); - while (rbc) { - if (wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints - { - for(int i=0; i < 4; i++) - *REG_AESWRFIFO = *src32++; - wbc--; - } + memcpy(iv, out + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); - if (rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read - { - for(int i=0; i < 4; i++) - *dst32++ = *REG_AESRDFIFO; - rbc--; - } + blocks -= current_blocks; + in += AES_BLOCK_SIZE * current_blocks; + out += AES_BLOCK_SIZE * current_blocks; } } -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) +sha256sum(void* sum, void* data, uint32_t size) { - 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); diff --git a/source/firm/firm.c b/source/firm/firm.c index 0a54d64..a534738 100644 --- a/source/firm/firm.c +++ b/source/firm/firm.c @@ -60,13 +60,13 @@ void dump_firm(firm_h** buffer, uint8_t index) { 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); + ctr_decrypt(firm, firm, firm_size / AES_BLOCK_SIZE, AES_CTR_MODE|AES_CNT_INPUT_ENDIAN|AES_CNT_OUTPUT_ENDIAN|AES_CNT_INPUT_ORDER|AES_CNT_OUTPUT_ORDER, ctr); if (memcmp((char*) & firm->magic, "FIRM", 4)) abort(" Decryption failed on FIRM.\n"); + fprintf(stderr, " AES decrypted FIRM%u.\n", index); + fprintf(stderr, " Magic is intact on FIRM%u.\n", index); uint8_t detver = 0; @@ -197,18 +197,20 @@ decrypt_cetk_key(void *key, const void *cetk) return 1; if (got_cetk == 0) { + fprintf(stderr, " Retrieving 0x3D KeyY...\n"); extract_slot0x3DkeyY(); got_cetk = 1; } use_aeskey(0x3D); - memcpy(iv, ticket->titleID, sizeof(ticket->titleID)); + memcpy(iv, ticket->titleID, sizeof(ticket->titleID)); memcpy(key, ticket->titleKey, sizeof(ticket->titleKey)); - aes(key, key, 1, iv, AES_CBC_DECRYPT_MODE); + set_ctr(iv); + cbc_decrypt(key, key, 1, AES_CBC_DECRYPT_MODE|AES_CNT_INPUT_ENDIAN|AES_CNT_OUTPUT_ENDIAN|AES_CNT_INPUT_ORDER|AES_CNT_OUTPUT_ORDER, iv); - fprintf(stderr, " Extracted titlekey from cetk.\n"); + fprintf(stderr, " Extracted titlekey from cetk.\n"); return 0; } @@ -221,9 +223,11 @@ decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key) uint8_t exefs_iv[16] = { 0 }; fprintf(stderr, " Decrypting FIRM container\n"); + setup_aeskey(0x16, key); use_aeskey(0x16); - aes(ncch, ncch, *size / AES_BLOCK_SIZE, firm_iv, AES_CBC_DECRYPT_MODE); + set_ctr(firm_iv); + cbc_decrypt(ncch, ncch, *size / AES_BLOCK_SIZE, AES_CBC_DECRYPT_MODE|AES_CNT_INPUT_ENDIAN|AES_CNT_OUTPUT_ENDIAN|AES_CNT_INPUT_ORDER|AES_CNT_OUTPUT_ORDER, firm_iv); if (ncch->magic != NCCH_MAGIC) return 1; @@ -238,7 +242,7 @@ decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key) fprintf(stderr, " Decrypting ExeFs for FIRM\n"); setup_aeskeyY(0x2C, exefs_key); use_aeskey(0x2C); - aes(exefs, exefs, exefs_size / AES_BLOCK_SIZE, exefs_iv, AES_CTR_MODE); + ctr_decrypt(exefs, exefs, exefs_size / AES_BLOCK_SIZE, AES_CTR_MODE|AES_CNT_INPUT_ENDIAN|AES_CNT_OUTPUT_ENDIAN|AES_CNT_INPUT_ORDER|AES_CNT_OUTPUT_ORDER, exefs_iv); // Get the decrypted FIRM // We assume the firm.bin is always the first file @@ -266,7 +270,7 @@ decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title, uint8_t version) slot = 0x16; use_aeskey(0x11); - aes(decrypted_keyx, header->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE); + aes_decrypt(decrypted_keyx, header->slot0x16keyX, 1, AES_ECB_DECRYPT_MODE|AES_CNT_INPUT_ENDIAN|AES_CNT_OUTPUT_ENDIAN|AES_CNT_INPUT_ORDER|AES_CNT_OUTPUT_ORDER); setup_aeskeyX(slot, decrypted_keyx); } @@ -277,7 +281,7 @@ decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title, uint8_t version) int size = atoi(header->size); use_aeskey(slot); - aes(arm9bin, arm9bin, size / AES_BLOCK_SIZE, header->ctr, AES_CTR_MODE); + ctr_decrypt(arm9bin, arm9bin, size / AES_BLOCK_SIZE, AES_CTR_MODE|AES_CNT_INPUT_ENDIAN|AES_CNT_OUTPUT_ENDIAN|AES_CNT_INPUT_ORDER|AES_CNT_OUTPUT_ORDER, header->ctr); if (firm_title == NATIVE_FIRM_TITLEID) return *(uint32_t *)arm9bin != ARM9BIN_MAGIC; @@ -439,7 +443,7 @@ boot_firm() 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); + aes_decrypt(keyx, keydata, 1, AES_ECB_DECRYPT_MODE|AES_CNT_INPUT_ENDIAN|AES_CNT_OUTPUT_ENDIAN|AES_CNT_INPUT_ORDER|AES_CNT_OUTPUT_ORDER); setup_aeskeyX(slot, keyx); *(uint8_t *)(keydata + 0xF) += 1; } -- 2.39.5