diff --git a/source/godmode.c b/source/godmode.c index e1c10e9..eb6cc66 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -7,7 +7,7 @@ #include "virtual.h" #include "image.h" -#define VERSION "0.4.0" +#define VERSION "0.4.1" #define N_PANES 2 #define IMG_DRV "789I" diff --git a/source/nand/aes.c b/source/nand/aes.c index 5fe95fa..4260584 100644 --- a/source/nand/aes.c +++ b/source/nand/aes.c @@ -6,17 +6,16 @@ void setup_aeskeyX(u8 keyslot, void* keyx) u32 * _keyx = (u32*)keyx; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; if (keyslot > 3) { + *REG_AESCNT = (*REG_AESCNT | (AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); *REG_AESKEYXFIFO = _keyx[0]; *REG_AESKEYXFIFO = _keyx[1]; *REG_AESKEYXFIFO = _keyx[2]; *REG_AESKEYXFIFO = _keyx[3]; } else { - u32 old_aescnt = *REG_AESCNT; vu32* reg_aeskeyx = REG_AESKEY0123 + (((0x30*keyslot) + 0x10)/4); *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); for (u32 i = 0; i < 4; i++) reg_aeskeyx[i] = _keyx[i]; - *REG_AESCNT = old_aescnt; } } @@ -25,17 +24,16 @@ void setup_aeskeyY(u8 keyslot, void* keyy) u32 * _keyy = (u32*)keyy; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; if (keyslot > 3) { + *REG_AESCNT = (*REG_AESCNT | (AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); *REG_AESKEYYFIFO = _keyy[0]; *REG_AESKEYYFIFO = _keyy[1]; *REG_AESKEYYFIFO = _keyy[2]; *REG_AESKEYYFIFO = _keyy[3]; } else { - u32 old_aescnt = *REG_AESCNT; vu32* reg_aeskeyy = REG_AESKEY0123 + (((0x30*keyslot) + 0x20)/4); *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); for (u32 i = 0; i < 4; i++) reg_aeskeyy[i] = _keyy[i]; - *REG_AESCNT = old_aescnt; } } @@ -44,17 +42,16 @@ void setup_aeskey(u8 keyslot, void* key) u32 * _key = (u32*)key; *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80; if (keyslot > 3) { + *REG_AESCNT = (*REG_AESCNT | (AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); *REG_AESKEYFIFO = _key[0]; *REG_AESKEYFIFO = _key[1]; *REG_AESKEYFIFO = _key[2]; *REG_AESKEYFIFO = _key[3]; } else { - u32 old_aescnt = *REG_AESCNT; vu32* reg_aeskey = REG_AESKEY0123 + ((0x30*keyslot)/4); *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)); for (u32 i = 0; i < 4; i++) reg_aeskey[i] = _key[i]; - *REG_AESCNT = old_aescnt; } } diff --git a/source/nand/aes.h b/source/nand/aes.h index fae9ecf..c95f3ed 100644 --- a/source/nand/aes.h +++ b/source/nand/aes.h @@ -37,6 +37,8 @@ #define AES_CNT_TWLNAND_MODE AES_CTR_MODE #define AES_CNT_TITLEKEY_DECRYPT_MODE (AES_CBC_DECRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) #define AES_CNT_TITLEKEY_ENCRYPT_MODE (AES_CBC_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) +#define AES_CNT_ECB_DECRYPT_MODE (AES_ECB_DECRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) +#define AES_CNT_ECB_ENCRYPT_MODE (AES_ECB_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN) void setup_aeskeyX(u8 keyslot, void* keyx); diff --git a/source/nand/nand.c b/source/nand/nand.c index 423e1ad..e583171 100644 --- a/source/nand/nand.c +++ b/source/nand/nand.c @@ -36,6 +36,7 @@ static u8 nand_magic_o3ds[0x60] = { // NCSD NAND header O3DS magic static u8 CtrNandCtr[16]; static u8 TwlNandCtr[16]; +static u8 OtpSha256[32] = { 0 }; static u32 emunand_base_sector = 0x000000; @@ -108,7 +109,21 @@ bool LoadKeyFromFile(const char* folder, u8* keydata, u32 keyslot, char type, ch bool InitNandCrypto(void) { - // STEP #1: Get NAND CID, set up TWL/CTR counter + // part #0: KeyX / KeyY for secret sector 0x96 + // on a9lh this MUST be run before accessing the SHA register in any other way + if ((*(u32*) 0x101401C0) == 0) { // for a9lh + // store the current SHA256 from register + memcpy(OtpSha256, (void*)REG_SHAHASH, 32); + } else { + u8 otp[0x100]; + if ((FileGetData("0:/otp.bin", otp, 0x100, 0) == 0x100) || + (FileGetData("0:/otp0x108.bin", otp, 0x100, 0) == 0x100) || + (FileGetData("0:/Decrypt9/otp.bin", otp, 0x100, 0) == 0x100) || + (FileGetData("0:/Decrypt9/otp0x108.bin", otp, 0x100, 0) == 0x100)) + sha_quick(OtpSha256, otp, 0x90, SHA256_MODE); + } + + // part #1: Get NAND CID, set up TWL/CTR counter u8 NandCid[16]; u8 shasum[32]; @@ -206,6 +221,12 @@ bool CheckSlot0x05Crypto(void) return false; } +bool CheckSector0x96Crypto(void) +{ + const u8 zeroes[32] = { 0 }; + return !(memcmp(OtpSha256, zeroes, 32) == 0); +} + void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot) { u32 mode = (sector >= (0x0B100000 / 0x200)) ? AES_CNT_CTRNAND_MODE : AES_CNT_TWLNAND_MODE; @@ -226,6 +247,20 @@ void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot) } } +void CryptSector0x96(u8* buffer, bool encrypt) +{ + u32 mode = encrypt ? AES_CNT_ECB_ENCRYPT_MODE : AES_CNT_ECB_DECRYPT_MODE; + + // setup the key + setup_aeskeyX(0x11, OtpSha256); + setup_aeskeyY(0x11, OtpSha256 + 16); + + // decrypt the sector + use_aeskey(0x11); + for (u32 b = 0x0; b < 0x200; b += 0x10, buffer += 0x10) + aes_decrypt((void*) buffer, (void*) buffer, 1, mode); +} + int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 nand_src) { if (!count) return 0; // <--- just to be safe @@ -248,7 +283,8 @@ int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 nand_src } else { return -1; } - if (keyslot < 0x40) CryptNand(buffer, sector, count, keyslot); + if ((keyslot == 0x11) && (sector == 0x96)) CryptSector0x96(buffer, false); + else if (keyslot < 0x40) CryptNand(buffer, sector, count, keyslot); return 0; } @@ -259,7 +295,8 @@ int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 n for (u32 s = 0; s < count; s += (NAND_BUFFER_SIZE / 0x200)) { u32 pcount = min((NAND_BUFFER_SIZE/0x200), (count - s)); memcpy(NAND_BUFFER, buffer + (s*0x200), pcount * 0x200); - if (keyslot < 0x40) CryptNand(NAND_BUFFER, sector + s, pcount, keyslot); + if ((keyslot == 0x11) && (sector == 0x96)) CryptSector0x96((u8*) buffer, true); + else if (keyslot < 0x40) CryptNand(NAND_BUFFER, sector + s, pcount, keyslot); if (nand_dst == NAND_EMUNAND) { int errorcode = 0; if ((sector + s == 0) && (emunand_base_sector % 0x200000 == 0)) { // GW EmuNAND header handling diff --git a/source/nand/nand.h b/source/nand/nand.h index a49909b..9aa6159 100644 --- a/source/nand/nand.h +++ b/source/nand/nand.h @@ -12,8 +12,10 @@ bool LoadKeyFromFile(const char* folder, u8* keydata, u32 keyslot, char type, char* id); bool InitNandCrypto(void); bool CheckSlot0x05Crypto(void); +bool CheckSector0x96Crypto(void); void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot); +void CryptSector0x96(u8* buffer, bool encrypt); int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, u32 src); int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, u32 dest); diff --git a/source/nand/virtual.c b/source/nand/virtual.c index 88e9137..58672c9 100644 --- a/source/nand/virtual.c +++ b/source/nand/virtual.c @@ -7,6 +7,7 @@ #define VFLAG_ON_NO3DS NAND_TYPE_NO3DS #define VFLAG_ON_NAND (VFLAG_ON_O3DS | VFLAG_ON_N3DS | VFLAG_ON_NO3DS) #define VFLAG_ON_MEMORY VRT_MEMORY +#define VFLAG_NEEDS_OTP (1<<29) #define VFLAG_N3DS_ONLY (1<<30) #define VFLAG_NAND_SIZE (1<<31) @@ -24,10 +25,10 @@ VirtualFile virtualFileTemplates[] = { { "ctrnand_full.bin" , 0x0B930000, 0x2F5D0000, 0x04, VFLAG_ON_O3DS }, { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x05, VFLAG_ON_N3DS }, { "ctrnand_full.bin" , 0x0B930000, 0x41ED0000, 0x04, VFLAG_ON_NO3DS }, + { "sector0x96.bin" , 0x00012C00, 0x00000200, 0x11, VFLAG_ON_NAND | VFLAG_NEEDS_OTP | VFLAG_A9LH_AREA }, { "nand.bin" , 0x00000000, 0x00000000, 0xFF, VFLAG_ON_NAND | VFLAG_NAND_SIZE | VFLAG_A9LH_AREA }, { "nand_minsize.bin" , 0x00000000, 0x3AF00000, 0xFF, VFLAG_ON_O3DS | VFLAG_A9LH_AREA }, { "nand_minsize.bin" , 0x00000000, 0x4D800000, 0xFF, VFLAG_ON_N3DS | VFLAG_ON_NO3DS | VFLAG_A9LH_AREA }, - { "sector0x96.bin" , 0x00012C00, 0x00000200, 0xFF, VFLAG_ON_NAND | VFLAG_A9LH_AREA }, { "nand_hdr.bin" , 0x00000000, 0x00000200, 0xFF, VFLAG_ON_NAND | VFLAG_A9LH_AREA }, { "itcm.mem" , 0x01FF8000, 0x00008000, 0xFF, VFLAG_ON_MEMORY }, { "arm9.mem" , 0x08000000, 0x00100000, 0xFF, VFLAG_ON_MEMORY }, @@ -99,6 +100,8 @@ bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size) // process special flags if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto()) return false; // keyslot 0x05 not properly set up + if ((vfile->flags & VFLAG_NEEDS_OTP) && !CheckSector0x96Crypto()) + return false; // sector 0x96 crypto not set up if (!(virtual_src & VRT_SYSNAND) || (*(vu32*) 0x101401C0)) vfile->flags &= ~VFLAG_A9LH_AREA; // flag is meaningless outside of A9LH / SysNAND if ((vfile->flags & VFLAG_N3DS_ONLY) && (GetUnitPlatform() != PLATFORM_N3DS))