diff --git a/source/common/common.h b/source/common/common.h index b295531..7062b67 100644 --- a/source/common/common.h +++ b/source/common/common.h @@ -49,7 +49,7 @@ #endif // GodMode9 version -#define VERSION "1.2.7" +#define VERSION "1.2.9" // input / output paths #define SUPPORT_PATHS "0:/gm9/support", "0:", "0:/files9" // legacy paths diff --git a/source/crypto/keydb.c b/source/crypto/keydb.c index 953c0b2..474b42a 100644 --- a/source/crypto/keydb.c +++ b/source/crypto/keydb.c @@ -61,52 +61,6 @@ void CryptAesKeyInfo(AesKeyInfo* info) { info->isEncrypted = !info->isEncrypted; } -u32 CheckAesKeyInfo(u8* key, u32 keyslot, char type, char* id) -{ - static const AesKeyHashInfo keyHashes[] = { - { { 0x05, 'Y', "" }, KEYS_RETAIL, // Retail N3DS CTRNAND key SHA256 - { 0x98, 0x24, 0x27, 0x14, 0x22, 0xB0, 0x6B, 0xF2, 0x10, 0x96, 0x9C, 0x36, 0x42, 0x53, 0x7C, 0x86, - 0x62, 0x22, 0x5C, 0xFD, 0x6F, 0xAE, 0x9B, 0x0A, 0x85, 0xA5, 0xCE, 0x21, 0xAA, 0xB6, 0xC8, 0x4D } - }, - { { 0x18, 'X', "" }, KEYS_RETAIL, // Retail NCCH Secure3 key SHA256 - { 0x76, 0xC7, 0x6B, 0x65, 0x5D, 0xB8, 0x52, 0x19, 0xC5, 0xD3, 0x5D, 0x51, 0x7F, 0xFA, 0xF7, 0xA4, - 0x3E, 0xBA, 0xD6, 0x6E, 0x31, 0xFB, 0xDD, 0x57, 0x43, 0x92, 0x59, 0x37, 0xA8, 0x93, 0xCC, 0xFC } - }, - { { 0x1B, 'X', "" }, KEYS_RETAIL, // Retail NCCH Secure4 key SHA256 - { 0x9A, 0x20, 0x1E, 0x7C, 0x37, 0x37, 0xF3, 0x72, 0x2E, 0x5B, 0x57, 0x8D, 0x11, 0x83, 0x7F, 0x19, - 0x7C, 0xA6, 0x5B, 0xF5, 0x26, 0x25, 0xB2, 0x69, 0x06, 0x93, 0xE4, 0x16, 0x53, 0x52, 0xC6, 0xBB } - }, - { { 0x25, 'X', "" }, KEYS_RETAIL, // Retail NCCH 7x key SHA256 - { 0x7E, 0x87, 0x8D, 0xDE, 0x92, 0x93, 0x8E, 0x4C, 0x71, 0x7D, 0xD5, 0x3D, 0x1E, 0xA3, 0x5A, 0x75, - 0x63, 0x3F, 0x51, 0x30, 0xD8, 0xCF, 0xD7, 0xC7, 0x6C, 0x8F, 0x4A, 0x8F, 0xB8, 0x70, 0x50, 0xCD } - }/*, - { { 0x18, 'X', "" }, KEYS_DEVKIT, // DevKit NCCH Secure3 key SHA256 - { 0x08, 0xE1, 0x09, 0x62, 0xF6, 0x5A, 0x09, 0xAA, 0x12, 0x2C, 0x7C, 0xBE, 0xDE, 0xA1, 0x9C, 0x4B, - 0x5C, 0x9A, 0x8A, 0xC3, 0xD9, 0x8E, 0xA1, 0x62, 0x04, 0x11, 0xD7, 0xE8, 0x55, 0x70, 0xA6, 0xC2 } - }, - { { 0x1B, 'X', "" }, KEYS_DEVKIT, // DevKit NCCH Secure4 key SHA256 - { 0xA5, 0x3C, 0x3E, 0x5D, 0x09, 0x5C, 0x73, 0x35, 0x21, 0x79, 0x3F, 0x2E, 0x4C, 0x10, 0xCA, 0xAE, - 0x87, 0x83, 0x51, 0x53, 0x46, 0x0B, 0x52, 0x39, 0x9B, 0x00, 0x62, 0xF6, 0x39, 0xCB, 0x62, 0x16 } - }*/ - }; - - u8 keySha256[32]; - sha_quick(keySha256, key, 16, SHA256_MODE); - for (u32 p = 0; p < sizeof(keyHashes) / sizeof(AesKeyHashInfo); p++) { - if ((keyHashes[p].desc.slot != keyslot) || (keyHashes[p].desc.type != type)) - continue; - if ((!id && keyHashes[p].desc.id[0]) || (id && strncmp(id, keyHashes[p].desc.id, 10) != 0)) - continue; - if (keyHashes[p].keyUnitType && (keyHashes[p].keyUnitType != GetUnitKeysType())) - continue; - if (memcmp(keySha256, keyHashes[p].keySha256, 32) == 0) { - return 0; - } - } - - return 1; -} - u32 CheckKeySlot(u32 keyslot, char type) { static const AesNcchSampleInfo keyNcchSamples[] = { @@ -146,7 +100,7 @@ u32 CheckKeySlot(u32 keyslot, char type) set_ctr(zeroes); aes_decrypt(sample, sample, 1, AES_CNT_CTRNAND_MODE); if (memcmp(keyNcchSamples[p].sample, sample, 16) == 0) { - keyXState |= (u64) 1 << keyslot; + keyXState |= 1ull << keyslot; return 0; } } @@ -155,21 +109,22 @@ u32 CheckKeySlot(u32 keyslot, char type) return 1; } -u32 LoadKeyFromFile(u8* key, u32 keyslot, char type, char* id) +u32 LoadKeyFromFile(void* key, u32 keyslot, char type, char* id) { const char* base[] = { SUPPORT_PATHS }; u8 keystore[16] __attribute__((aligned(32))) = {0}; bool found = false; - // use keystore if key == NULL - if (!key) key = keystore; - // checking the obvious if ((keyslot >= 0x40) || ((type != 'X') && (type != 'Y') && (type != 'N') && (type != 'I'))) return 1; // check if already loaded - if (!id && (CheckKeySlot(keyslot, type) == 0)) return 0; + if (!key && !id && (CheckKeySlot(keyslot, type) == 0)) return 0; + + // use keystore if key == NULL + if (!key) key = keystore; + // try to get key from 'aeskeydb.bin' file for (u32 i = 0; !found && (i < (sizeof(base)/sizeof(char*))); i++) { FIL fp; @@ -213,23 +168,78 @@ u32 LoadKeyFromFile(u8* key, u32 keyslot, char type, char* id) // done if this is an IV if (type == 'I') return 0; - // verify key (verification is disabled) - // if (CheckAesKeyInfo(key, keyslot, type, id) != 0) return 1; - // now, setup the key if (type == 'X') { setup_aeskeyX(keyslot, key); - keyXState |= (u64) 1 << keyslot; + keyXState |= 1ull << keyslot; } else if (type == 'Y') { setup_aeskeyY(keyslot, key); - keyYState |= (u64) 1 << keyslot; + keyYState |= 1ull << keyslot; } else { // normalKey includes keyX & keyY setup_aeskey(keyslot, key); - keyState |= (u64) 1 << keyslot; - keyXState |= (u64) 1 << keyslot; - keyYState |= (u64) 1 << keyslot; + keyState |= 1ull << keyslot; + keyXState |= 1ull << keyslot; + keyYState |= 1ull << keyslot; } use_aeskey(keyslot); return 0; } + +u32 InitKeyDb( void ) +{ + // use this to quickly initialize all applicable keys in aeskeydb.bin + static const u64 keyslot_whitelist = (1ull<<0x02)|(1ull<<0x03)|(1ull<<0x05)|(1ull<<0x18)|(1ull<<0x19)|(1ull<<0x1A)|(1ull<<0x1B)| + (1ull<<0x1C)|(1ull<<0x1D)|(1ull<<0x1E)|(1ull<<0x1F)|(1ull<<0x24)|(1ull<<0x25)|(1ull<<0x2F); + AesKeyInfo* keydb = (AesKeyInfo*) (void*) TEMP_BUFFER; + u32 nkeys = 0; + + // try to load aeskeydb.bin file + const char* base[] = { SUPPORT_PATHS }; + for (u32 i = 0; !nkeys && (i < (sizeof(base)/sizeof(char*))); i++) { + FIL fp; + UINT btr; + char path[64]; + snprintf(path, 64, "%s/%s", base[i], KEYDB_NAME); + if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) continue; + if ((f_read(&fp, keydb, TEMP_BUFFER_SIZE, &btr) == FR_OK) && + (btr > 0) && (btr < TEMP_BUFFER_SIZE) && !(btr % sizeof(AesKeyInfo))) + nkeys = btr / sizeof(AesKeyInfo); + f_close(&fp); + } + + // failed if arriving here with empty hands + if (!nkeys) return 1; + + // apply all applicable keys + for (u32 i = 0; i < nkeys; i++) { + AesKeyInfo* info = &(keydb[i]); + if ((info->slot >= 0x40) || ((info->type != 'X') && (info->type != 'Y') && (info->type != 'N') && (info->type != 'I'))) + return 1; // looks faulty, better stop right here + if (!((1ull<slot)&keyslot_whitelist)) continue; // not in keyslot whitelist + if ((info->type == 'I') || (*(info->id)) || (info->keyUnitType && (info->keyUnitType != GetUnitKeysType())) || + (CheckKeySlot(info->slot, info->type) == 0)) continue; // most likely valid, but not applicable or already set + if (info->isEncrypted) CryptAesKeyInfo(info); // decrypt key + + // apply key + u8 key[16] __attribute__((aligned(32))) = {0}; + char type = info->type; + u32 keyslot = info->slot; + memcpy(key, info->key, 16); + if (type == 'X') { + setup_aeskeyX(keyslot, key); + keyXState |= 1ull << keyslot; + } else if (type == 'Y') { + setup_aeskeyY(keyslot, key); + keyYState |= 1ull << keyslot; + } else { // normalKey includes keyX & keyY + setup_aeskey(keyslot, key); + keyState |= 1ull << keyslot; + keyXState |= 1ull << keyslot; + keyYState |= 1ull << keyslot; + } + use_aeskey(keyslot); + } + + return 0; +} diff --git a/source/crypto/keydb.h b/source/crypto/keydb.h index 1fb4bd9..44ab194 100644 --- a/source/crypto/keydb.h +++ b/source/crypto/keydb.h @@ -20,4 +20,5 @@ typedef struct { u32 GetUnitKeysType(void); void CryptAesKeyInfo(AesKeyInfo* info); -u32 LoadKeyFromFile(u8* key, u32 keyslot, char type, char* id); +u32 LoadKeyFromFile(void* key, u32 keyslot, char type, char* id); +u32 InitKeyDb(void); diff --git a/source/godmode.c b/source/godmode.c index 5e53f3c..02ed288 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -1412,7 +1412,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur (ValidateFirm(TEMP_BUFFER, firm_size) != 0)) { // fix the boot path first ("sdmc"/"nand" for Luma et al, hacky af) const char* bootpath = curr_entry->path; - char fixpath[256] = { 0 }; // for Luma et al, hacky as fuck + char fixpath[256] = { 0 }; if ((*bootpath != '0') && (*bootpath != '1')) { optionstr[0] = "Make a copy at " OUTPUT_PATH "/temp.firm"; optionstr[1] = "Try to boot anyways"; @@ -1605,7 +1605,7 @@ u32 GodMode() { InitSDCardFS(); AutoEmuNandBase(true); - InitNandCrypto(); + InitNandCrypto(true); InitExtFS(); // this takes long - do it while splash is displayed diff --git a/source/nand/nand.c b/source/nand/nand.c index 508a643..9da817a 100644 --- a/source/nand/nand.c +++ b/source/nand/nand.c @@ -31,16 +31,6 @@ static const u8 slot0x05KeyY_sha256[0x20] = { // hash for slot0x05KeyY (16 byte) 0x62, 0x22, 0x5C, 0xFD, 0x6F, 0xAE, 0x9B, 0x0A, 0x85, 0xA5, 0xCE, 0x21, 0xAA, 0xB6, 0xC8, 0x4D }; -static const u8 slot0x24KeyY_sha256[0x20] = { // hash for slot0x24KeyY (16 byte) - 0x5F, 0x04, 0x01, 0x22, 0x95, 0xB2, 0x23, 0x70, 0x12, 0x40, 0x53, 0x30, 0xC0, 0xA7, 0xBF, 0x7C, - 0xD4, 0x40, 0x92, 0x25, 0xD1, 0x9D, 0xA2, 0xDE, 0xCD, 0xC7, 0x12, 0x97, 0x08, 0x46, 0x54, 0xB7 -}; - -static const u8 slot0x03KeyYdev_sha256[0x20] = { // slot0x03KeyY hash for devkits only (16 byte) - 0x4D, 0xBB, 0xDD, 0x08, 0x2B, 0xE3, 0xDF, 0x48, 0x51, 0x2D, 0xBD, 0xF9, 0xED, 0xDA, 0x0C, 0x52, - 0x8F, 0x6D, 0x94, 0xB8, 0xED, 0xE4, 0x4D, 0x3A, 0xFA, 0x2A, 0x63, 0x57, 0xE4, 0xFA, 0x65, 0x69 -}; - static const u8 slot0x11Key95_sha256[0x20] = { // slot0x11Key95 hash (first 16 byte of sector0x96) 0xBA, 0xC1, 0x40, 0x9C, 0x6E, 0xE4, 0x1F, 0x04, 0xAA, 0xC4, 0xE2, 0x09, 0x5C, 0xE9, 0x4F, 0x78, 0x6C, 0x78, 0x5F, 0xAC, 0xEC, 0x7E, 0xC0, 0x11, 0x26, 0x9D, 0x4E, 0x47, 0xB3, 0x64, 0xC4, 0xA5 @@ -70,44 +60,28 @@ static u8 OtpSha256[32] = { 0 }; static u32 emunand_base_sector = 0x000000; -u32 LoadKeyYFromP9(u8* key, const u8* keyhash, u32 offset, u32 keyslot) +bool GetOtp0x90(void* otp0x90, u32 len) { - static const u32 offsetA9l = 0x066A00; // fixed offset, this only has to work for FIRM90 / FIRM81 - static const u32 sector_firm0 = 0x058980; // standard firm0 sector (this only has to work in A9LH anyways) - u8 ctr0x15[16] __attribute__((aligned(32))); - u8 keyY0x15[16] __attribute__((aligned(32))); - u8 keyY[16] __attribute__((aligned(32))); - u8 header[0x200]; + // a short helper function for crypto setup outside of sighax + u8 __attribute__((aligned(32))) otp_key[0x10]; + u8 __attribute__((aligned(32))) otp_iv[0x10]; - // check arm9loaderhax - if (!IS_A9LH || IS_SIGHAX || (offset < (offsetA9l + 0x0800))) return 1; - - // section 2 (arm9loader) header of FIRM - // this is @0x066A00 in FIRM90 & FIRM81 - ReadNandBytes(header, (sector_firm0 * 0x200) + offsetA9l, 0x200, 0x06, NAND_SYSNAND); - memcpy(keyY0x15, header + 0x10, 0x10); // 0x15 keyY - memcpy(ctr0x15, header + 0x20, 0x10); // 0x15 counter - - // read and decrypt the encrypted keyY - ReadNandBytes(keyY, (sector_firm0 * 0x200) + offset, 0x10, 0x06, NAND_SYSNAND); - setup_aeskeyY(0x15, keyY0x15); - use_aeskey(0x15); - ctr_decrypt_byte(keyY, keyY, 0x10, offset - (offsetA9l + 0x800), AES_CNT_CTRNAND_MODE, ctr0x15); - if (key) memcpy(key, keyY, 0x10); - - // check the key - u8 shasum[0x32]; - sha_quick(shasum, keyY, 16, SHA256_MODE); - if (memcmp(shasum, keyhash, 32) == 0) { - setup_aeskeyY(keyslot, keyY); - use_aeskey(keyslot); - return 0; + len = len - (len % 0x10); + if (len > 0x90) len = 0x90; + memcpy(otp0x90, (u8*) 0x01FFB800, len); + if ((LoadKeyFromFile(otp_key, 0x11, 'N', "OTP") == 0) && + ((LoadKeyFromFile(otp_iv, 0x11, 'I', "IVOTP") == 0) || + (LoadKeyFromFile(otp_iv, 0x11, 'I', "OTP") == 0))) { + setup_aeskey(0x11, otp_key); + use_aeskey(0x11); + cbc_encrypt(otp0x90, otp0x90, len / 0x10, AES_CNT_TITLEKEY_ENCRYPT_MODE, otp_iv); + return true; } - return 1; + return false; } -bool InitNandCrypto(void) +bool InitNandCrypto(bool init_full) { // part #0: KeyX / KeyY for secret sector 0x96 // on a9lh this MUST be run before accessing the SHA register in any other way @@ -120,17 +94,8 @@ bool InitNandCrypto(void) } if (!CheckSector0x96Crypto()) { // if all else fails... u8 __attribute__((aligned(32))) otp0x90[0x90]; - u8 __attribute__((aligned(32))) otp_key[0x10]; - u8 __attribute__((aligned(32))) otp_iv[0x10]; - memcpy(otp0x90, (u8*) 0x01FFB800, 0x90); - if ((LoadKeyFromFile(otp_key, 0x11, 'N', "OTP") == 0) && - ((LoadKeyFromFile(otp_iv, 0x11, 'I', "IVOTP") == 0) || - (LoadKeyFromFile(otp_iv, 0x11, 'I', "OTP") == 0))) { - setup_aeskey(0x11, otp_key); - use_aeskey(0x11); - cbc_encrypt(otp0x90, otp0x90, 0x90 / 0x10, AES_CNT_TITLEKEY_ENCRYPT_MODE, otp_iv); + if (GetOtp0x90(otp0x90, 0x90)) sha_quick(OtpSha256, otp0x90, 0x90, SHA256_MODE); - } } // part #1: Get NAND CID, set up TWL/CTR counter @@ -145,63 +110,68 @@ bool InitNandCrypto(void) for(u32 i = 0; i < 16; i++) // little endian and reversed order TwlNandCtr[i] = shasum[15-i]; - // part #2: TWL KEY (if not already set up + // part #2: TWL KEY (if not already set up) // see: https://www.3dbrew.org/wiki/Memory_layout#ARM9_ITCM if (GetNandPartitionInfo(NULL, NP_TYPE_FAT, NP_SUBTYPE_TWL, 0, NAND_SYSNAND) != 0) { - u8 TwlKeyY[16] __attribute__((aligned(32))); - - // k9l already did the part of the init that required the OTP registers - if(IS_DEVKIT) { - vu32 *RegKey0x03X = ®_AESKEY0123[((0x30u * 0x03) + 0x10u)/4u]; - - // this is dfferent from key setup on retail - RegKey0x03X[1] = 0xEE7A4B1E; - RegKey0x03X[2] = 0xAF42C08B; - - LoadKeyYFromP9(TwlKeyY, slot0x03KeyYdev_sha256, 0x0EC0D8, 0x03); - } else { - // see: https://www.3dbrew.org/wiki/Memory_layout#ARM9_ITCM - u64 TwlCustId = 0x80000000ULL | (*(vu64 *)0x01FFB808 ^ 0x8C267B7B358A6AFULL); - u8 TwlKeyX[16] __attribute__((aligned(32))); - u32* TwlKeyXW = (u32*) (void*) TwlKeyX; - - TwlKeyXW[0] = (u32) (TwlCustId>>0); - TwlKeyXW[1] = *(vu32*)0x01FFD3A8; // "NINT" - TwlKeyXW[2] = *(vu32*)0x01FFD3AC; // "ENDO" - TwlKeyXW[3] = (u32) (TwlCustId>>32); - setup_aeskeyX(0x03, TwlKeyX); - - memcpy(TwlKeyY, (u8*) 0x01FFD3C8, 16); + u64 TwlCustId = 0; // TWL customer ID (different for devkits) + if (!IS_DEVKIT) TwlCustId = 0x80000000ULL | (*(vu64 *)0x01FFB808 ^ 0x8C267B7B358A6AFULL); + else if (IS_UNLOCKED) TwlCustId = (*(vu64*)0x10012000); + if (!TwlCustId && IS_DEVKIT) { + u64 __attribute__((aligned(32))) otp0x10[2]; + if (GetOtp0x90(otp0x10, 0x10)) TwlCustId = *otp0x10; + } + + if (TwlCustId) { // give up if TwlCustId not found + u32 TwlKey0x03Y[4] __attribute__((aligned(32))); + u32 TwlKey0x03X[4] __attribute__((aligned(32))); + + if (IS_DEVKIT) { + TwlKey0x03X[1] = 0xEE7A4B1E; + TwlKey0x03X[2] = 0xAF42C08B; + LoadKeyFromFile(TwlKey0x03Y, 0x03, 'Y', NULL); + } else { + TwlKey0x03X[1] = *(vu32*)0x01FFD3A8; // "NINT" + TwlKey0x03X[2] = *(vu32*)0x01FFD3AC; // "ENDO" + memcpy(TwlKey0x03Y, (u8*) 0x01FFD3C8, 16); + } + + TwlKey0x03X[0] = (u32) (TwlCustId>>0); + TwlKey0x03X[3] = (u32) (TwlCustId>>32); + TwlKey0x03Y[3] = 0xE1A00005; + + setup_aeskeyX(0x03, TwlKey0x03X); + setup_aeskeyY(0x03, TwlKey0x03Y); + use_aeskey(0x03); + + if (init_full) { // full init + vu32 *RegKey0x01X = ®_AESKEY0123[((0x30u * 0x01) + 0x10u)/4u]; + RegKey0x01X[2] = (u32) (TwlCustId>>32); + RegKey0x01X[3] = (u32) (TwlCustId>>0); + + setup_aeskeyX(0x02, (u8*)0x01FFD398); + if (IS_DEVKIT) { + u32 TwlKey0x02Y[4] __attribute__((aligned(32))); + LoadKeyFromFile(TwlKey0x02Y, 0x02, 'Y', NULL); + setup_aeskeyY(0x02, TwlKey0x02Y); + } else setup_aeskeyY(0x02, (u8*)0x01FFD220); + use_aeskey(0x02); + + if (IS_UNLOCKED) + (*(vu64*)0x10012100) = TwlCustId; + } } - - static const u32 TwlKeyYW3 = 0xE1A00005; - memcpy(TwlKeyY + 12, &TwlKeyYW3, 4); - - setup_aeskeyY(0x03, TwlKeyY); - use_aeskey(0x03); } // part #3: CTRNAND N3DS KEY (if not set up) - // thanks AuroraWright and Gelex for advice on this - // see: https://github.com/AuroraWright/Luma3DS/blob/master/source/crypto.c#L347 - if (GetNandPartitionInfo(NULL, NP_TYPE_FAT, NP_SUBTYPE_CTR, 0, NAND_SYSNAND) != 0) { - if (IS_A9LH && !IS_SIGHAX) { // only on A9LH - // keyY 0x05 is encrypted @0x0EB014 in the FIRM90 - // keyY 0x05 is encrypted @0x0EB24C in the FIRM81 - if ((LoadKeyYFromP9(slot0x05KeyY, slot0x05KeyY_sha256, 0x0EB014, 0x05) != 0) && - (LoadKeyYFromP9(slot0x05KeyY, slot0x05KeyY_sha256, 0x0EB24C, 0x05) != 0)) - LoadKeyFromFile(slot0x05KeyY, 0x05, 'Y', NULL); - } else LoadKeyFromFile(slot0x05KeyY, 0x05, 'Y', NULL); - } + if (GetNandPartitionInfo(NULL, NP_TYPE_FAT, NP_SUBTYPE_CTR, 0, NAND_SYSNAND) != 0) + LoadKeyFromFile(slot0x05KeyY, 0x05, 'Y', NULL); - // part #4: AGBSAVE CMAC KEY (source see above) - if (IS_A9LH && !IS_SIGHAX) { // only on A9LH - // keyY 0x24 is encrypted @0x0E62DC in the FIRM90 - // keyY 0x24 is encrypted @0x0E6514 in the FIRM81 - if ((LoadKeyYFromP9(NULL, slot0x24KeyY_sha256, 0x0E62DC, 0x24) != 0) && - (LoadKeyYFromP9(NULL, slot0x24KeyY_sha256, 0x0E6514, 0x24) != 0)) - LoadKeyFromFile(NULL, 0x24, 'Y', NULL); - } else LoadKeyFromFile(NULL, 0x24, 'Y', NULL); + // part #4: AGBSAVE CMAC KEY (set up on A9LH and SigHax) + if (IS_A9LH || IS_SIGHAX) + LoadKeyFromFile(NULL, 0x24, 'Y', NULL); + + // part #5: FULL INIT + if (init_full) InitKeyDb(); return true; } diff --git a/source/nand/nand.h b/source/nand/nand.h index e6289c3..8171a6e 100644 --- a/source/nand/nand.h +++ b/source/nand/nand.h @@ -56,7 +56,7 @@ typedef struct { } __attribute__((packed)) NandNcsdHeader; -bool InitNandCrypto(void); +bool InitNandCrypto(bool init_full); bool CheckSlot0x05Crypto(void); bool CheckSector0x96Crypto(void); bool CheckGenuineNandNcsd(void);