]> Chaos Git - corbenik/corbenik.git/commitdiff
Merge branch 'ctr9io' into ctr9io_crypto
authorchaoskagami <chaos.kagami@gmail.com>
Thu, 14 Jul 2016 09:50:14 +0000 (05:50 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Thu, 14 Jul 2016 09:50:14 +0000 (05:50 -0400)
1  2 
source/firm/firm.c

index 19abe4bb34ed84f70ed47e1077da7ec2fad85b11,0faec0cfa1485460e6336247f3f49e1ab3d241d1..9bedfa0f26340a93b4de52af0077e90bc7a5eb21
@@@ -3,11 -3,8 +3,11 @@@
  #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;
@@@ -28,72 -28,57 +31,92 @@@ static int update_96_keys = 0
  
  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
@@@ -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();
      }
  
      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();