}
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);
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;
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;
}
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;
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
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);
}
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;
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;
}