uint8_t* decryptFirmTitleNcch(uint8_t* title, unsigned int size){ ctr_ncchheader NCCH; uint8_t CTR[16]; PartitionInfo INFO; NCCH = *((ctr_ncchheader*)title); if(memcmp(NCCH.magic, "NCCH", 4) != 0) return NULL; ncch_get_counter(NCCH, CTR, 2); INFO.ctr = CTR; INFO.buffer = title + getle32(NCCH.exefsoffset)*0x200; INFO.keyY = NCCH.signature; INFO.size = size; INFO.keyslot = 0x2C; DecryptPartition(&INFO); uint8_t* firm = (uint8_t*)(INFO.buffer + 0x200); return firm; }
int VerifyNCCHSection(USER_CONTEXT *ctx, u8 cxi_key[0x10], u32 offset, FILE *ncch) { NCCH_STRUCT *cxi_ctx = malloc(sizeof(NCCH_STRUCT)); if(cxi_ctx == NULL){ printf("[!] Memory Allocation Failure\n"); return Fail; } memset(cxi_ctx,0x0,sizeof(NCCH_STRUCT)); GetCXIStruct(cxi_ctx,offset,ncch); u8 HeaderSignature[0x100]; u8 Header[0x100]; u8 HeaderSHAHash[0x20]; u8 ExHeader[0x800]; memset(&HeaderSignature,0x0,0x100); memset(&Header,0x0,0x100); memset(&HeaderSHAHash,0x0,0x20); fseek(ncch,offset+0x0,SEEK_SET); fread(HeaderSignature,0x100,1,ncch); fread(Header,0x100,1,ncch); ctr_sha(&Header,0x100,HeaderSHAHash,CTR_SHA_256); RSA_2048_KEY HeaderRSA; memset(&HeaderRSA,0x0,sizeof(RSA_2048_KEY)); u8 Exponent[0x3] = {0x01,0x00,0x01}; memcpy(HeaderRSA.e,Exponent,0x3); if(cxi_ctx->is_cfa == True) memcpy(HeaderRSA.n,ctx->keys.NcsdCfa.n,0x100); else{ memset(&ExHeader,0x0,0x800); fseek(ncch,offset+cxi_ctx->exheader_offset,SEEK_SET); fread(&ExHeader,0x800,1,ncch); if(cxi_ctx->encrypted == True){ u8 counter[0x10]; ncch_get_counter(cxi_ctx,counter,NCCHTYPE_EXHEADER); ctr_aes_context aes_ctx; memset(&aes_ctx,0x0,sizeof(ctr_aes_context)); ctr_init_counter(&aes_ctx, cxi_key, counter); ctr_crypt_counter(&aes_ctx, ExHeader, ExHeader, 0x800); if(memcmp((ExHeader+0x200),cxi_ctx->programID,8) != 0){ printf("[!] CXI decryption failed\n"); return Fail; } } memcpy(HeaderRSA.n,ExHeader+0x500,0x100); } return ctr_rsa(HeaderSHAHash,HeaderSignature,HeaderRSA.n,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); }
uint8_t* decryptFirmTitleNcch(uint8_t* title, size_t *size) { const size_t sector = 512; const size_t header = 512; ctr_ncchheader NCCH; uint8_t CTR[16]; PartitionInfo INFO; NCCH = *((ctr_ncchheader*)title); if(memcmp(NCCH.magic, "NCCH", 4) != 0) return NULL; ncch_get_counter(NCCH, CTR, 2); INFO.ctr = CTR; INFO.buffer = title + getle32(NCCH.exefsoffset)*sector; INFO.keyY = NCCH.signature; INFO.size = getle32(NCCH.exefssize)*sector; INFO.keyslot = 0x2C; DecryptPartition(&INFO); if (size != NULL) *size = INFO.size - header; uint8_t* firm = (uint8_t*)(INFO.buffer + header); if (getMpInfo() == MPINFO_KTR) if (decryptFirmKtrArm9(firm)) return NULL; return firm; }
int ProcessCTR(char* path){ PartitionInfo myInfo; File myFile; char myString[256]; //In case it is needed... if(FileOpen(&myFile, path, 0)){ ConsoleInit(); ConsoleAddText(TITLE); unsigned int ncch_base = 0x100; unsigned char magic[] = { 0, 0, 0, 0, 0}; FileRead(&myFile, magic, 4, ncch_base); if(magic[0] == 'N' && magic[1] == 'C' && magic[2] == 'S' && magic[3] == 'D'){ ncch_base = 0x4000; FileRead(&myFile, magic, 4, ncch_base+0x100); if(!(magic[0] == 'N' && magic[1] == 'C' && magic[2] == 'C' && magic[3] == 'H')){ FileClose(&myFile); return 2; } }else if(magic[0] == 'N' && magic[1] == 'C' && magic[2] == 'C' && magic[3] == 'H'){ ncch_base = 0x0; }else{ FileClose(&myFile); return 2; } ctr_ncchheader NCCH; unsigned int mediaunitsize = 0x200; FileRead(&myFile, &NCCH, 0x200, ncch_base); //ConsoleAddText(path); ConsoleAddText(NCCH.productcode); unsigned int NEWCRYPTO = 0, CRYPTO = 1; if(NCCH.flags[3] != 0) NEWCRYPTO = 1; if(NCCH.flags[7] & 4) CRYPTO = 0; if(NEWCRYPTO){ ConsoleAddText("\nCryptoType : 7.X Key security"); }else if(CRYPTO){ ConsoleAddText("\nCryptoType : Secure"); }else{ ConsoleAddText("\nCryptoType : None"); ConsoleAddText("Decryption completed!"); FileClose(&myFile); ConsoleShow(); return 3; } ConsoleShow(); u8 CTR[16]; if(getle32(NCCH.extendedheadersize) > 0){ ConsoleAddText("Decrypting ExHeader..."); ConsoleShow(); ncch_get_counter(NCCH, CTR, 1); FileRead(&myFile, BUFFER_ADDR, 0x800, ncch_base + 0x200); myInfo.buffer = BUFFER_ADDR; myInfo.size = 0x800; myInfo.keyslot = 0x2C; myInfo.ctr = CTR; myInfo.keyY = NCCH.signature; DecryptPartition(&myInfo); FileWrite(&myFile, BUFFER_ADDR, 0x800, ncch_base + 0x200); } if(getle32(NCCH.exefssize) > 0){ ConsoleAddText("Decrypting ExeFS..."); ConsoleShow(); ncch_get_counter(NCCH, CTR, 2); myInfo.buffer = BUFFER_ADDR; myInfo.keyslot = NEWCRYPTO ? 0x25 : 0x2C; myInfo.ctr = CTR; myInfo.keyY = NCCH.signature; size_t bytesRead = FileRead(&myFile, BUFFER_ADDR, getle32(NCCH.exefssize) * mediaunitsize, ncch_base + getle32(NCCH.exefsoffset) * mediaunitsize); myInfo.size = bytesRead; ProcessExeFS(&myInfo); //Explanation at function definition FileWrite(&myFile, BUFFER_ADDR, getle32(NCCH.exefssize) * mediaunitsize, ncch_base + getle32(NCCH.exefsoffset) * mediaunitsize); } if(getle32(NCCH.romfssize) > 0){ ConsoleAddText("Decrypting RomFS..."); ConsoleShow(); ncch_get_counter(NCCH, CTR, 3); myInfo.buffer = BUFFER_ADDR; myInfo.keyslot = NEWCRYPTO ? 0x25 : 0x2C; myInfo.ctr = CTR; myInfo.keyY = NCCH.signature; for(int i = 0; i < getle32(NCCH.romfssize) * mediaunitsize / BLOCK_SIZE; i++){ sprintf(myString, "%i%%", (int)((i*BLOCK_SIZE)/(getle32(NCCH.romfssize) * mediaunitsize/ 100))); int x, y; ConsoleGetXY(&x, &y); y += CHAR_WIDTH * 4; x += CHAR_WIDTH*22; DrawString(TOP_SCREEN, myString, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); size_t bytesRead = FileRead(&myFile, BUFFER_ADDR, BLOCK_SIZE, ncch_base + getle32(NCCH.romfsoffset) * mediaunitsize + i*BLOCK_SIZE); myInfo.size = bytesRead; DecryptPartition(&myInfo); add_ctr(myInfo.ctr, bytesRead/16); FileWrite(&myFile, BUFFER_ADDR, BLOCK_SIZE, ncch_base + getle32(NCCH.romfsoffset) * mediaunitsize + i*BLOCK_SIZE); } } NCCH.flags[7] |= 4; //Disable encryption NCCH.flags[3] = 0; //Disable 7.XKey usage FileWrite(&myFile, &NCCH, 0x200, ncch_base); if(ncch_base == 0x4000) FileWrite(&myFile, ((u8*)&NCCH) + 0x100, 0x100, 0x1100); //Only for NCSD FileClose(&myFile); ConsoleAddText("Decryption completed!"); ConsoleShow(); return 0; }else return 1; }