diff --git a/source/crypto.c b/source/crypto.c index 2655f14..21968f5 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -24,6 +24,7 @@ * Crypto libs from http://github.com/b1l1s/ctr * kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 * decryptNusFirm code adapted from https://github.com/mid-kid/CakesForeveryWan/blob/master/source/firm.c +* 3ds type structs adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h */ #include "crypto.h" @@ -375,29 +376,29 @@ void set6x7xKeys(void) memset32((void *)0x01FFCD00, 0, 0x10); } -void decryptExeFs(u8 *inbuf) +void decryptExeFs(Ncch *ncch) { - u8 *exeFsOffset = inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200; - u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200; + u8 *exeFsOffset = (u8 *)ncch + ncch->exeFsOffset * 0x200; + u32 exeFsSize = ncch->exeFsSize * 0x200; u8 __attribute__((aligned(4))) ncchCtr[AES_BLOCK_SIZE] = {0}; for(u32 i = 0; i < 8; i++) - ncchCtr[7 - i] = *(inbuf + 0x108 + i); + ncchCtr[7 - i] = ncch->partitionId[i]; ncchCtr[8] = 2; - aes_setkey(0x2C, inbuf, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_setkey(0x2C, ncch, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); aes_use_keyslot(0x2C); - aes(inbuf, exeFsOffset + 0x200, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes(ncch, exeFsOffset + 0x200, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); } -void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize) +void decryptNusFirm(const Ticket *ticket, Ncch *ncch, u32 ncchSize) { const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C}; u8 __attribute__((aligned(4))) titleKey[AES_BLOCK_SIZE]; u8 __attribute__((aligned(4))) cetkIv[AES_BLOCK_SIZE] = {0}; - memcpy(titleKey, inbuf + 0x1BF, sizeof(titleKey)); - memcpy(cetkIv, inbuf + 0x1DC, 8); + memcpy(titleKey, ticket->titleKey, sizeof(titleKey)); + memcpy(cetkIv, ticket->titleId, sizeof(ticket->titleId)); aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_use_keyslot(0x3D); @@ -407,16 +408,16 @@ void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize) aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes_use_keyslot(0x16); - aes(outbuf, outbuf, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes(ncch, ncch, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); - decryptExeFs(outbuf); + decryptExeFs(ncch); } -void kernel9Loader(u8 *arm9Section) +void kernel9Loader(Arm9Bin *arm9Section) { //Determine the kernel9loader version u32 k9lVersion; - switch(arm9Section[0x53]) + switch(arm9Section->magic[3]) { case 0xFF: k9lVersion = 0; @@ -429,7 +430,7 @@ void kernel9Loader(u8 *arm9Section) break; } - u32 startOfArm9Bin = *(u32 *)(arm9Section + 0x800); + u32 startOfArm9Bin = *(u32 *)((u8 *)arm9Section + 0x800); bool needToDecrypt = startOfArm9Bin != 0x47704770 && startOfArm9Bin != 0xB0862000; if(!isDevUnit && (k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt))) @@ -452,28 +453,28 @@ void kernel9Loader(u8 *arm9Section) //Set keyX u8 __attribute__((aligned(4))) keyX[AES_BLOCK_SIZE]; aes_use_keyslot(0x11); - aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0); + aes(keyX, arm9Section->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes_setkey(0x16, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); } //Set keyY u8 __attribute__((aligned(4))) keyY[AES_BLOCK_SIZE]; - memcpy(keyY, arm9Section + 0x10, sizeof(keyY)); + memcpy(keyY, arm9Section->keyY, sizeof(keyY)); aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); //Set CTR u8 __attribute__((aligned(4))) arm9BinCtr[AES_BLOCK_SIZE]; - memcpy(arm9BinCtr, arm9Section + 0x20, sizeof(arm9BinCtr)); + memcpy(arm9BinCtr, arm9Section->ctr, sizeof(arm9BinCtr)); //Calculate the size of the ARM9 binary u32 arm9BinSize = 0; //http://stackoverflow.com/questions/12791077/atoi-implementation-in-c - for(u8 *tmp = arm9Section + 0x30; *tmp != 0; tmp++) + for(u8 *tmp = arm9Section->size; *tmp != 0; tmp++) arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0'; //Decrypt ARM9 binary aes_use_keyslot(arm9BinSlot); - aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes((u8 *)arm9Section + 0x800, (u8 *)arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); } //Set >=9.6 KeyXs diff --git a/source/crypto.h b/source/crypto.h index 931810f..78696a8 100755 --- a/source/crypto.h +++ b/source/crypto.h @@ -24,6 +24,7 @@ * Crypto libs from http://github.com/b1l1s/ctr * kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 * decryptNusFirm code adapted from https://github.com/mid-kid/CakesForeveryWan/blob/master/source/firm.c +* 3ds type structs adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h */ #pragma once @@ -101,6 +102,76 @@ #define SHA_224_HASH_SIZE (224 / 8) #define SHA_1_HASH_SIZE (160 / 8) +typedef struct Ncch { + uint8_t sig[0x100]; //RSA-2048 signature of the NCCH header, using SHA-256 + char magic[4]; //NCCH + uint32_t contentSize; //Media unit + uint8_t partitionId[8]; + uint8_t makerCode[2]; + uint16_t version; + uint8_t reserved1[4]; + uint8_t programID[8]; + uint8_t reserved2[0x10]; + uint8_t logoHash[0x20]; //Logo Region SHA-256 hash + char productCode[0x10]; + uint8_t exHeaderHash[0x20]; //Extended header SHA-256 hash + uint32_t exHeaderSize; //Extended header size + uint32_t reserved3; + uint8_t flags[8]; + uint32_t plainOffset; //Media unit + uint32_t plainSize; //Media unit + uint32_t logoOffset; //Media unit + uint32_t logoSize; //Media unit + uint32_t exeFsOffset; //Media unit + uint32_t exeFsSize; //Media unit + uint32_t exeFsHashSize; //Media unit + uint32_t reserved4; + uint32_t romFsOffset; //Media unit + uint32_t romFsSize; //Media unit + uint32_t romFsHashSize; //Media unit + uint32_t reserved5; + uint8_t exeFsHash[0x20]; //ExeFS superblock SHA-256 hash + uint8_t romFsHash[0x20]; //RomFS superblock SHA-256 hash +} Ncch; + +typedef struct Ticket +{ + char sigIssuer[0x40]; + uint8_t eccPubKey[0x3C]; + uint8_t version; + uint8_t caCrlVersion; + uint8_t signerCrlVersion; + uint8_t titleKey[0x10]; + uint8_t reserved1; + uint8_t ticketId[8]; + uint8_t consoleId[4]; + uint8_t titleId[8]; + uint8_t reserved2[2]; + uint16_t ticketTitleVersion; + uint8_t reserved3[8]; + uint8_t licenseType; + uint8_t ticketCommonKeyYIndex; //Ticket common keyY index, usually 0x1 for retail system titles. + uint8_t reserved4[0x2A]; + uint8_t unk[4]; //eShop Account ID? + uint8_t reserved5; + uint8_t audit; + uint8_t reserved6[0x42]; + uint8_t limits[0x40]; + uint8_t contentIndex[0xAC]; +} Ticket; + +typedef struct Arm9Bin { + uint8_t keyX[0x10]; + uint8_t keyY[0x10]; + uint8_t ctr[0x10]; + uint8_t size[8]; + uint8_t reserved[8]; + uint8_t ctlBlock[0x10]; + char magic[4]; + uint8_t reserved2[0xC]; + uint8_t slot0x16keyX[0x10]; +} Arm9Bin; + extern u32 emuOffset; extern bool isN3DS, isDevUnit, isA9lh; extern FirmwareSource firmSource; @@ -109,8 +180,8 @@ void ctrNandInit(void); int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf); int ctrNandWrite(u32 sector, u32 sectorCount, u8 *inbuf); void set6x7xKeys(void); -void decryptExeFs(u8 *inbuf); -void decryptNusFirm(const u8 *inbuf, u8 *outbuf, u32 ncchSize); -void kernel9Loader(u8 *arm9Section); +void decryptExeFs(Ncch *ncch); +void decryptNusFirm(const Ticket *ticket, Ncch *ncch, u32 ncchSize); +void kernel9Loader(Arm9Bin *arm9Section); void computePinHash(u8 *outbuf, const u8 *inbuf); void restoreShaHashBackup(void); \ No newline at end of file diff --git a/source/firm.c b/source/firm.c index 81e3079..051d815 100755 --- a/source/firm.c +++ b/source/firm.c @@ -331,7 +331,7 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo u8 cetk[0xA50]; if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk)) == sizeof(cetk)) - decryptNusFirm(cetk, (u8 *)firm, firmSize); + decryptNusFirm((Ticket *)&cetk[0x140], (Ncch *)firm, firmSize); else error("The firmware.bin in /luma is encrypted\nor corrupted."); } @@ -346,7 +346,7 @@ static inline u32 loadFirm(FirmwareType *firmType, FirmwareSource firmSource, bo if(firmVersion != 0xFFFFFFFF) { if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot."); - decryptExeFs((u8 *)firm); + decryptExeFs((Ncch *)firm); } return firmVersion; @@ -360,7 +360,7 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 if(isN3DS) { //Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader - kernel9Loader(arm9Section); + kernel9Loader((Arm9Bin *)arm9Section); firm->arm9Entry = (u8 *)0x801B01C; } @@ -440,7 +440,7 @@ static inline void patchLegacyFirm(FirmwareType firmType, u32 firmVersion, u32 d //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader if(isN3DS) { - kernel9Loader(arm9Section); + kernel9Loader((Arm9Bin *)arm9Section); firm->arm9Entry = (u8 *)0x801301C; } @@ -458,7 +458,7 @@ static inline void patch1x2xNativeAndSafeFirm(u32 devMode) if(isN3DS) { //Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader - kernel9Loader(arm9Section); + kernel9Loader((Arm9Bin *)arm9Section); firm->arm9Entry = (u8 *)0x801B01C; patchFirmWrites(arm9Section, section[2].size); @@ -481,7 +481,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo for(u8 *src = (u8 *)firm + section[0].offset, *srcEnd = src + section[0].size, *dst = section[0].address; src < srcEnd; src += srcModuleSize, dst += dstModuleSize) { - srcModuleSize = *(u32 *)(src + 0x104) * 0x200; + srcModuleSize = ((Ncch *)src)->contentSize * 0x200; const char *moduleName = (char *)(src + 0x200); u32 fileSize;