mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Runtime key derivation with hardcoded key sources
* aes: add aes128EcbCrypt() as a one-shot function to perform AES-128-ECB crypto. The rest of the codebase now calls this function whenever suitable. * fs_ext: add const keyword to IPC input structs wherever suitable. * key_sources: add hardcoded master key vectors (prod, dev); master KEK sources (Erista, Mariko); master key source; ticket common key source; SMC key type sources; SMC seal key masks; AES key generation source; NCA header KEK source; NCA header key source and NCA KAEK sources. Also fixed the hardcoded gamecard CardInfo key source for dev units (it was previously generated using retail keydata, my bad). * keys: remove keysGetNcaMainSignatureModulus(); remove keysDecryptNcaKeyAreaEntry(); repurpose keyset struct to only hold keys that can actually be used for the current hardware type; remove KeysGameCardKeyset; remove keysIsXXModulusYYMandatory() helpers; remove keysRetrieveKeysFromProgramMemory(); remove keysDeriveSealedNcaKeyAreaEncryptionKeys(); add keysDeriveMasterKeys() and keysDerivePerGenerationKeys(); rename keysDeriveGameCardKeys() -> keysDeriveGcCardInfoKey(); add small reimplementations of GenerateAesKek, LoadAesKey and GenerateAesKey; add keysLoadAesKeyFromAesKek() and keysGenerateAesKeyFromAesKek() wrappers. Furthermore, master key derivation is now carried out manually using hardcoded key sources and the last known master key, which is loaded from the Lockpick_RCM keys file -- if the last known master key is unavailable, the key derivation algorithm will then fallback to TSEC root key / Mariko KEK based key derivation, depending on the hardware type. * nca: add hardcoded NCA man signature moduli (prod, dev); merge ncaDecryptKeyArea() and ncaEncryptKeyArea() into ncaKeyAreaCrypt(). * nxdt_utils: add utilsIsMarikoUnit(); remove _utilsAppletModeCheck(); rename utilsAppletModeCheck() -> utilsIsAppletMode(). * services: remove spl:mig dependency (yay). * smc: add SmcKeyType enum; add SmcSealKey enum; add SmcGenerateAesKekOption struct; add smcPrepareGenerateAesKekOption().
This commit is contained in:
parent
7ddf1bb1fb
commit
f79680184d
16 changed files with 744 additions and 660 deletions
|
@ -28,6 +28,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// One-shot function to perform AES-128-ECB crypto.
|
||||
/// 'dst', 'src' and 'key' must all have a size of at least AES_BLOCK_SIZE bytes.
|
||||
/// 'dst' and 'src' can both point to the same address.
|
||||
void aes128EcbCrypt(void *dst, const void *src, const void *key, bool encrypt);
|
||||
|
||||
/// Performs an AES-128-XTS crypto operation using the non-standard Nintendo XTS tweak.
|
||||
/// The Aes128XtsContext element should have been previously initialized with aes128XtsContextCreate(). 'encrypt' should match the value of 'is_encryptor' used with that call.
|
||||
/// 'dst' and 'src' can both point to the same address.
|
||||
|
|
172
include/core/key_sources.h
Normal file
172
include/core/key_sources.h
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* key_sources.h
|
||||
*
|
||||
* Copyright (c) 2019-2023, shchmue.
|
||||
* Copyright (c) 2020-2023, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* nxdumptool is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Last updated on: 2023-04-08. */
|
||||
/* Current key generation: NcaKeyGeneration_Since1600NUP (16 / 0F). */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __KEY_SOURCES_H__
|
||||
#define __KEY_SOURCES_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* TODO: update on TSEC root key changes. */
|
||||
#define TSEC_ROOT_KEY_VERSION 2
|
||||
|
||||
/* Used to derive all previous master keys using the latest master key on retail units. */
|
||||
/* TODO: update on master key changes. */
|
||||
static const u8 g_masterKeyVectorsProd[NcaKeyGeneration_Current][AES_128_KEY_SIZE] = {
|
||||
{ 0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D }, ///< Zeroes encrypted with master key 00.
|
||||
{ 0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD }, ///< Master key 00 encrypted with master key 01.
|
||||
{ 0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72 }, ///< Master key 01 encrypted with master key 02.
|
||||
{ 0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07 }, ///< Master key 02 encrypted with master key 03.
|
||||
{ 0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9 }, ///< Master key 03 encrypted with master key 04.
|
||||
{ 0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE }, ///< Master key 04 encrypted with master key 05.
|
||||
{ 0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57 }, ///< Master key 05 encrypted with master key 06.
|
||||
{ 0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F }, ///< Master key 06 encrypted with master key 07.
|
||||
{ 0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29 }, ///< Master key 07 encrypted with master key 08.
|
||||
{ 0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80 }, ///< Master key 08 encrypted with master key 09.
|
||||
{ 0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A }, ///< Master key 09 encrypted with master key 0A.
|
||||
{ 0xC1, 0x8D, 0x16, 0xBB, 0x2A, 0xE4, 0x1D, 0xD4, 0xC2, 0xC1, 0xB6, 0x40, 0x94, 0x35, 0x63, 0x98 }, ///< Master key 0A encrypted with master key 0B.
|
||||
{ 0xA3, 0x24, 0x65, 0x75, 0xEA, 0xCC, 0x6E, 0x8D, 0xFB, 0x5A, 0x16, 0x50, 0x74, 0xD2, 0x15, 0x06 }, ///< Master key 0B encrypted with master key 0C.
|
||||
{ 0x83, 0x67, 0xAF, 0x01, 0xCF, 0x93, 0xA1, 0xAB, 0x80, 0x45, 0xF7, 0x3F, 0x72, 0xFD, 0x3B, 0x38 }, ///< Master key 0C encrypted with master key 0D.
|
||||
{ 0xB1, 0x81, 0xA6, 0x0D, 0x72, 0xC7, 0xEE, 0x15, 0x21, 0xF3, 0xC0, 0xB5, 0x6B, 0x61, 0x6D, 0xE7 }, ///< Master key 0D encrypted with master key 0E.
|
||||
{ 0xAF, 0x11, 0x4C, 0x67, 0x17, 0x7A, 0x52, 0x43, 0xF7, 0x70, 0x2F, 0xC7, 0xEF, 0x81, 0x72, 0x16 }, ///< Master key 0E encrypted with master key 0F.
|
||||
};
|
||||
|
||||
/* Used to derive all previous master keys using the latest master key on development units. */
|
||||
/* TODO: update on master key changes. */
|
||||
static const u8 g_masterKeyVectorsDev[NcaKeyGeneration_Current][AES_128_KEY_SIZE] = {
|
||||
{ 0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE }, ///< Zeroes encrypted with master key 00.
|
||||
{ 0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23 }, ///< Master key 00 encrypted with master key 01.
|
||||
{ 0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D }, ///< Master key 01 encrypted with master key 02.
|
||||
{ 0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3 }, ///< Master key 02 encrypted with master key 03.
|
||||
{ 0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA }, ///< Master key 03 encrypted with master key 04.
|
||||
{ 0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC }, ///< Master key 04 encrypted with master key 05.
|
||||
{ 0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E }, ///< Master key 05 encrypted with master key 06.
|
||||
{ 0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19 }, ///< Master key 06 encrypted with master key 07.
|
||||
{ 0xEC, 0xE1, 0x46, 0x89, 0x37, 0xFD, 0xD2, 0x15, 0x8C, 0x3F, 0x24, 0x82, 0xEF, 0x49, 0x68, 0x04 }, ///< Master key 07 encrypted with master key 08.
|
||||
{ 0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE }, ///< Master key 08 encrypted with master key 09.
|
||||
{ 0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4 }, ///< Master key 09 encrypted with master key 0A.
|
||||
{ 0x21, 0x88, 0x6B, 0x10, 0x9E, 0x83, 0xD6, 0x52, 0xAB, 0x08, 0xDB, 0x6D, 0x39, 0xFF, 0x1C, 0x9C }, ///< Master key 0A encrypted with master key 0B.
|
||||
{ 0x8A, 0xCE, 0xC4, 0x7F, 0xBE, 0x08, 0x61, 0x88, 0xD3, 0x73, 0x64, 0x51, 0xE2, 0xB6, 0x53, 0x15 }, ///< Master key 0B encrypted with master key 0C.
|
||||
{ 0x08, 0xE0, 0xF4, 0xBE, 0xAA, 0x6E, 0x5A, 0xC3, 0xA6, 0xBC, 0xFE, 0xB9, 0xE2, 0xA3, 0x24, 0x12 }, ///< Master key 0C encrypted with master key 0D.
|
||||
{ 0xD6, 0x80, 0x98, 0xC0, 0xFA, 0xC7, 0x13, 0xCB, 0x93, 0xD2, 0x0B, 0x82, 0x4C, 0xA1, 0x7B, 0x8D }, ///< Master key 0D encrypted with master key 0E.
|
||||
{ 0x78, 0x66, 0x19, 0xBD, 0x86, 0xE7, 0xC1, 0x09, 0x9B, 0x6F, 0x92, 0xB2, 0x58, 0x7D, 0xCF, 0x26 }, ///< Master key 0E encrypted with master key 0F.
|
||||
};
|
||||
|
||||
/* Used to derive a master KEK using the TSEC root key on Erista units. */
|
||||
/* TODO: update on master key changes. */
|
||||
static const u8 g_eristaMasterKekSource[AES_128_KEY_SIZE] = {
|
||||
0x99, 0x22, 0x09, 0x57, 0xA7, 0xF9, 0x5E, 0x94, 0xFE, 0x78, 0x7F, 0x41, 0xD6, 0xE7, 0x56, 0xE6
|
||||
};
|
||||
|
||||
/* Used to derive a master KEK on retail Mariko units. */
|
||||
/* TODO: update on master key changes. */
|
||||
static const u8 g_marikoMasterKekSourceProd[AES_128_KEY_SIZE] = {
|
||||
0xA5, 0xEC, 0x16, 0x39, 0x1A, 0x30, 0x16, 0x08, 0x2E, 0xCF, 0x09, 0x6F, 0x5E, 0x7C, 0xEE, 0xA9
|
||||
};
|
||||
|
||||
/* Used to derive a master KEK on development Mariko units. */
|
||||
/* TODO: update on master key changes. */
|
||||
static const u8 g_marikoMasterKekSourceDev[AES_128_KEY_SIZE] = {
|
||||
0x3A, 0x9C, 0xF0, 0x39, 0x70, 0x23, 0xF6, 0xAF, 0x71, 0x44, 0x60, 0xF4, 0x6D, 0xED, 0xA1, 0xD6
|
||||
};
|
||||
|
||||
/* Used to derive master keys from master KEKs. Found in TrustZone / Secure Monitor. */
|
||||
static const u8 g_masterKeySource[AES_128_KEY_SIZE] = {
|
||||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
|
||||
};
|
||||
|
||||
/* Randomly generated KEK source used to derive official CardInfo area keys. */
|
||||
static const u8 g_gcCardInfoKekSource[AES_128_KEY_SIZE] = {
|
||||
0xDE, 0xC6, 0x3F, 0x6A, 0xBF, 0x37, 0x72, 0x0B, 0x7E, 0x54, 0x67, 0x6A, 0x2D, 0xEF, 0xDD, 0x97
|
||||
};
|
||||
|
||||
/* CardInfo area key used in retail units. Obfuscated using g_gcCardInfoKekSource and SMC AES engine keydata. */
|
||||
/* Hardcoded because it can only be retrieved in plaintext form from FS program memory under HOS 9.0.0+ -- and we wish to use it under previous HOS versions as well. */
|
||||
static const u8 g_gcCardInfoKeySourceProd[AES_128_KEY_SIZE] = {
|
||||
0xF4, 0x92, 0x06, 0x52, 0xD6, 0x37, 0x70, 0xAF, 0xB1, 0x9C, 0x6F, 0x63, 0x09, 0x01, 0xF6, 0x29
|
||||
};
|
||||
|
||||
/* CardInfo area key used in development units. Obfuscated using g_gcCardInfoKekSource and SMC AES engine keydata. */
|
||||
/* Hardcoded because it can only be retrieved in plaintext form from FS program memory under HOS 9.0.0+ -- and we wish to use it under previous HOS versions as well. */
|
||||
static const u8 g_gcCardInfoKeySourceDev[AES_128_KEY_SIZE] = {
|
||||
0x54, 0xC3, 0xE1, 0xF2, 0x5B, 0x3A, 0x5E, 0xC0, 0x4C, 0xA7, 0xCF, 0xFB, 0xE1, 0xAE, 0x16, 0xCA
|
||||
};
|
||||
|
||||
/* KEK source used to generate ticket common keys, which in turn are used to decrypt titlekeys from tickets. Also known as "titlekek_source". */
|
||||
/* Found in TrustZone / Secure Monitor. */
|
||||
static const u8 g_ticketCommonKeySource[AES_128_KEY_SIZE] = {
|
||||
0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B
|
||||
};
|
||||
|
||||
/* Used by GenerateAesKek to derive keys. Found in TrustZone / Secure Monitor. */
|
||||
static const u8 g_smcKeyTypeSources[SmcKeyType_Count][AES_128_KEY_SIZE] = {
|
||||
[SmcKeyType_Default] = { 0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9 }, ///< Also known as "aes_kek_generation_source".
|
||||
[SmcKeyType_NormalOnly] = { 0x25, 0x03, 0x31, 0xFB, 0x25, 0x26, 0x0B, 0x79, 0x8C, 0x80, 0xD2, 0x69, 0x98, 0xE2, 0x22, 0x77 },
|
||||
[SmcKeyType_RecoveryOnly] = { 0x76, 0x14, 0x1D, 0x34, 0x93, 0x2D, 0xE1, 0x84, 0x24, 0x7B, 0x66, 0x65, 0x55, 0x04, 0x65, 0x81 },
|
||||
[SmcKeyType_NormalAndRecovery] = { 0xAF, 0x3D, 0xB7, 0xF3, 0x08, 0xA2, 0xD8, 0xA2, 0x08, 0xCA, 0x18, 0xA8, 0x69, 0x46, 0xC9, 0x0B },
|
||||
};
|
||||
|
||||
/* Used by GenerateAesKek to derive keys. Found in TrustZone / Secure Monitor. */
|
||||
static const u8 g_smcSealKeyMasks[SmcSealKey_Count][AES_128_KEY_SIZE] = {
|
||||
[SmcSealKey_LoadAesKey] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
[SmcSealKey_DecryptDeviceUniqueData] = { 0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74 },
|
||||
[SmcSealKey_ImportLotusKey] = { 0x57, 0xE2, 0xD9, 0x45, 0xE4, 0x92, 0xF4, 0xFD, 0xC3, 0xF9, 0x86, 0x38, 0x89, 0x78, 0x9F, 0x3C },
|
||||
[SmcSealKey_ImportEsDeviceKey] = { 0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB },
|
||||
[SmcSealKey_ReencryptDeviceUniqueData] = { 0x59, 0xD9, 0x31, 0xF4, 0xA7, 0x97, 0xB8, 0x14, 0x40, 0xD6, 0xA2, 0x60, 0x2B, 0xED, 0x15, 0x31 },
|
||||
[SmcSealKey_ImportSslKey] = { 0xFD, 0x6A, 0x25, 0xE5, 0xD8, 0x38, 0x7F, 0x91, 0x49, 0xDA, 0xF8, 0x59, 0xA8, 0x28, 0xE6, 0x75 },
|
||||
[SmcSealKey_ImportEsClientCertKey] = { 0x89, 0x96, 0x43, 0x9A, 0x7C, 0xD5, 0x59, 0x55, 0x24, 0xD5, 0x24, 0x18, 0xAB, 0x6C, 0x04, 0x61 }
|
||||
};
|
||||
|
||||
/* Used by GenerateAesKey. Found in SPL. */
|
||||
static const u8 g_aesKeyGenerationSource[AES_128_KEY_SIZE] = {
|
||||
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8
|
||||
};
|
||||
|
||||
/* Used to derive the NCA header key. Found in the .rodata segment from the FS sysmodule. */
|
||||
static const u8 g_ncaHeaderKekSource[AES_128_KEY_SIZE] = {
|
||||
0x1F, 0x12, 0x91, 0x3A, 0x4A, 0xCB, 0xF0, 0x0D, 0x4C, 0xDE, 0x3A, 0xF6, 0xD5, 0x23, 0x88, 0x2A
|
||||
};
|
||||
|
||||
/* Used to derive the NCA header key. Found in the .data segment from the FS sysmodule. */
|
||||
static const u8 g_ncaHeaderKeySource[AES_128_KEY_SIZE * 2] = {
|
||||
0x5A, 0x3E, 0xD8, 0x4F, 0xDE, 0xC0, 0xD8, 0x26, 0x31, 0xF7, 0xE2, 0x5D, 0x19, 0x7B, 0xF5, 0xD0,
|
||||
0x1C, 0x9B, 0x7B, 0xFA, 0xF6, 0x28, 0x18, 0x3D, 0x71, 0xF6, 0x4D, 0x73, 0xF1, 0x50, 0xB9, 0xD2
|
||||
};
|
||||
|
||||
/* Key sources used to derive NCA key area encryption keys required to handle key areas from NCA headers. Found in the .rodata segment from the FS sysmodule. */
|
||||
static const u8 g_ncaKeyAreaEncryptionKeySources[NcaKeyAreaEncryptionKeyIndex_Count][AES_128_KEY_SIZE] = {
|
||||
{ 0x7F, 0x59, 0x97, 0x1E, 0x62, 0x9F, 0x36, 0xA1, 0x30, 0x98, 0x06, 0x6F, 0x21, 0x44, 0xC3, 0x0D }, ///< Application.
|
||||
{ 0x32, 0x7D, 0x36, 0x08, 0x5A, 0xD1, 0x75, 0x8D, 0xAB, 0x4E, 0x6F, 0xBA, 0xA5, 0x55, 0xD8, 0x82 }, ///< Ocean.
|
||||
{ 0x87, 0x45, 0xF1, 0xBB, 0xA6, 0xBE, 0x79, 0x64, 0x7D, 0x04, 0x8B, 0xA6, 0x7B, 0x5F, 0xDA, 0x4A } ///< System.
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __KEY_SOURCES_H__ */
|
|
@ -37,16 +37,7 @@ bool keysLoadKeyset(void);
|
|||
/// Returns a pointer to the AES-128-XTS NCA header key, or NULL if keydata hasn't been loaded.
|
||||
const u8 *keysGetNcaHeaderKey(void);
|
||||
|
||||
/// Returns a pointer to the RSA-2048-PSS modulus for the NCA header main signature, using the provided key generation value.
|
||||
const u8 *keysGetNcaMainSignatureModulus(u8 key_generation);
|
||||
|
||||
/// Decrypts 'src' into 'dst' using the provided key area encryption key index and key generation values. Runtime sealed keydata from the SMC AES engine is used to achieve this.
|
||||
/// Both 'dst' and 'src' buffers must have a size of at least AES_128_KEY_SIZE.
|
||||
/// Returns false if an error occurs or if keydata hasn't been loaded.
|
||||
bool keysDecryptNcaKeyAreaEntry(u8 kaek_index, u8 key_generation, void *dst, const void *src);
|
||||
|
||||
/// Returns a pointer to an AES-128-ECB NCA key area encryption key using the provided key area encryption key index and key generation values, or NULL if keydata hasn't been loaded.
|
||||
/// This data is loaded from the Lockpick_RCM keys file.
|
||||
const u8 *keysGetNcaKeyAreaEncryptionKey(u8 kaek_index, u8 key_generation);
|
||||
|
||||
/// Decrypts a RSA-OAEP wrapped titlekey using console-specific keydata.
|
||||
|
|
|
@ -87,11 +87,14 @@ bool utilsCommitSdCardFileSystemChanges(void);
|
|||
/// Returns a UtilsCustomFirmwareType value.
|
||||
u8 utilsGetCustomFirmwareType(void);
|
||||
|
||||
/// Returns true if the application is running under a Mariko unit.
|
||||
bool utilsIsMarikoUnit(void);
|
||||
|
||||
/// Returns true if the application is running under a development unit.
|
||||
bool utilsIsDevelopmentUnit(void);
|
||||
|
||||
/// Returns true if the application is running under applet mode.
|
||||
bool utilsAppletModeCheck(void);
|
||||
bool utilsIsAppletMode(void);
|
||||
|
||||
/// Returns a pointer to the FsStorage object for the eMMC BIS System partition.
|
||||
FsStorage *utilsGetEmmcBisSystemPartitionStorage(void);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* sha3.h
|
||||
*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
* Copyright (c) Atmosphère-NX.
|
||||
* Copyright (c) 2022, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
|
|
81
include/core/smc.h
Normal file
81
include/core/smc.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* smc.h
|
||||
*
|
||||
* Copyright (c) Atmosphère-NX.
|
||||
* Copyright (c) 2020-2023, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* nxdumptool is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __SMC_H__
|
||||
#define __SMC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
SmcKeyType_Default = 0, ///< Also known as "aes_kek_generation_source".
|
||||
SmcKeyType_NormalOnly = 1,
|
||||
SmcKeyType_RecoveryOnly = 2,
|
||||
SmcKeyType_NormalAndRecovery = 3,
|
||||
SmcKeyType_Count = 4
|
||||
} SmcKeyType;
|
||||
|
||||
typedef enum {
|
||||
SmcSealKey_LoadAesKey = 0,
|
||||
SmcSealKey_DecryptDeviceUniqueData = 1,
|
||||
SmcSealKey_ImportLotusKey = 2,
|
||||
SmcSealKey_ImportEsDeviceKey = 3,
|
||||
SmcSealKey_ReencryptDeviceUniqueData = 4,
|
||||
SmcSealKey_ImportSslKey = 5,
|
||||
SmcSealKey_ImportEsClientCertKey = 6,
|
||||
SmcSealKey_Count = 7
|
||||
} SmcSealKey;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
u32 value; ///< Can be used with spl calls.
|
||||
struct {
|
||||
u32 is_device_unique : 1;
|
||||
u32 key_type_idx : 4; ///< SmcKeyType.
|
||||
u32 seal_key_idx : 3; ///< SmcSealKey.
|
||||
u32 reserved : 24;
|
||||
} fields;
|
||||
};
|
||||
} SmcGenerateAesKekOption;
|
||||
|
||||
/// Helper inline functions.
|
||||
|
||||
NX_INLINE bool smcPrepareGenerateAesKekOption(bool is_device_unique, u32 key_type_idx, u32 seal_key_idx, SmcGenerateAesKekOption *out)
|
||||
{
|
||||
if (key_type_idx >= SmcKeyType_Count || seal_key_idx >= SmcSealKey_Count) return false;
|
||||
|
||||
out->fields.is_device_unique = (u32)(is_device_unique & 1);
|
||||
out->fields.key_type_idx = key_type_idx;
|
||||
out->fields.seal_key_idx = seal_key_idx;
|
||||
out->fields.reserved = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SMC_H__ */
|
|
@ -21,6 +21,21 @@
|
|||
|
||||
#include "nxdt_utils.h"
|
||||
|
||||
void aes128EcbCrypt(void *dst, const void *src, const void *key, bool encrypt)
|
||||
{
|
||||
if (!dst || !src || !key) return;
|
||||
|
||||
Aes128Context ctx = {0};
|
||||
aes128ContextCreate(&ctx, key, encrypt);
|
||||
|
||||
if (encrypt)
|
||||
{
|
||||
aes128EncryptBlock(&ctx, dst, src);
|
||||
} else {
|
||||
aes128DecryptBlock(&ctx, dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
size_t aes128XtsNintendoCrypt(Aes128XtsContext *ctx, void *dst, const void *src, size_t size, u64 sector, size_t sector_size, bool encrypt)
|
||||
{
|
||||
if (!ctx || !dst || !src || !size || !sector_size || (size % sector_size) != 0)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
/* IFileSystemProxy. */
|
||||
Result fsOpenGameCardStorage(FsStorage *out, const FsGameCardHandle *handle, u32 partition)
|
||||
{
|
||||
struct {
|
||||
const struct {
|
||||
FsGameCardHandle handle;
|
||||
u32 partition;
|
||||
} in = { *handle, partition };
|
||||
|
@ -47,7 +47,7 @@ Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier *out)
|
|||
/* IDeviceOperator. */
|
||||
Result fsDeviceOperatorUpdatePartitionInfo(FsDeviceOperator *d, const FsGameCardHandle *handle, u32 *out_title_version, u64 *out_title_id)
|
||||
{
|
||||
struct {
|
||||
const struct {
|
||||
FsGameCardHandle handle;
|
||||
} in = { *handle };
|
||||
|
||||
|
@ -66,7 +66,7 @@ Result fsDeviceOperatorUpdatePartitionInfo(FsDeviceOperator *d, const FsGameCard
|
|||
|
||||
Result fsDeviceOperatorGetGameCardDeviceCertificate(FsDeviceOperator *d, const FsGameCardHandle *handle, FsGameCardCertificate *out)
|
||||
{
|
||||
struct {
|
||||
const struct {
|
||||
FsGameCardHandle handle;
|
||||
u64 buf_size;
|
||||
} in = { *handle, sizeof(FsGameCardCertificate) };
|
||||
|
@ -81,7 +81,7 @@ Result fsDeviceOperatorGetGameCardDeviceCertificate(FsDeviceOperator *d, const F
|
|||
|
||||
Result fsDeviceOperatorGetGameCardIdSet(FsDeviceOperator *d, FsGameCardIdSet *out)
|
||||
{
|
||||
struct {
|
||||
const struct {
|
||||
u64 buf_size;
|
||||
} in = { sizeof(FsGameCardIdSet) };
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -34,22 +34,103 @@
|
|||
static u8 *g_ncaCryptoBuffer = NULL;
|
||||
static Mutex g_ncaCryptoBufferMutex = 0;
|
||||
|
||||
/// Used to verify the NCA header main signature.
|
||||
static const u8 g_ncaHeaderMainSignaturePublicExponent[3] = { 0x01, 0x00, 0x01 };
|
||||
|
||||
/// RSA-2048-PSS moduli used to verify the main signature from NCA headers with retail crypto. Found in the .rodata segment from the FS sysmodule.
|
||||
/// TODO: update on signature keygen changes.
|
||||
static const u8 g_ncaHeaderMainSignatureModuliProd[NcaSignatureKeyGeneration_Max][RSA2048_PUBKEY_SIZE] = {
|
||||
{
|
||||
0xBF, 0xBE, 0x40, 0x6C, 0xF4, 0xA7, 0x80, 0xE9, 0xF0, 0x7D, 0x0C, 0x99, 0x61, 0x1D, 0x77, 0x2F,
|
||||
0x96, 0xBC, 0x4B, 0x9E, 0x58, 0x38, 0x1B, 0x03, 0xAB, 0xB1, 0x75, 0x49, 0x9F, 0x2B, 0x4D, 0x58,
|
||||
0x34, 0xB0, 0x05, 0xA3, 0x75, 0x22, 0xBE, 0x1A, 0x3F, 0x03, 0x73, 0xAC, 0x70, 0x68, 0xD1, 0x16,
|
||||
0xB9, 0x04, 0x46, 0x5E, 0xB7, 0x07, 0x91, 0x2F, 0x07, 0x8B, 0x26, 0xDE, 0xF6, 0x00, 0x07, 0xB2,
|
||||
0xB4, 0x51, 0xF8, 0x0D, 0x0A, 0x5E, 0x58, 0xAD, 0xEB, 0xBC, 0x9A, 0xD6, 0x49, 0xB9, 0x64, 0xEF,
|
||||
0xA7, 0x82, 0xB5, 0xCF, 0x6D, 0x70, 0x13, 0xB0, 0x0F, 0x85, 0xF6, 0xA9, 0x08, 0xAA, 0x4D, 0x67,
|
||||
0x66, 0x87, 0xFA, 0x89, 0xFF, 0x75, 0x90, 0x18, 0x1E, 0x6B, 0x3D, 0xE9, 0x8A, 0x68, 0xC9, 0x26,
|
||||
0x04, 0xD9, 0x80, 0xCE, 0x3F, 0x5E, 0x92, 0xCE, 0x01, 0xFF, 0x06, 0x3B, 0xF2, 0xC1, 0xA9, 0x0C,
|
||||
0xCE, 0x02, 0x6F, 0x16, 0xBC, 0x92, 0x42, 0x0A, 0x41, 0x64, 0xCD, 0x52, 0xB6, 0x34, 0x4D, 0xAE,
|
||||
0xC0, 0x2E, 0xDE, 0xA4, 0xDF, 0x27, 0x68, 0x3C, 0xC1, 0xA0, 0x60, 0xAD, 0x43, 0xF3, 0xFC, 0x86,
|
||||
0xC1, 0x3E, 0x6C, 0x46, 0xF7, 0x7C, 0x29, 0x9F, 0xFA, 0xFD, 0xF0, 0xE3, 0xCE, 0x64, 0xE7, 0x35,
|
||||
0xF2, 0xF6, 0x56, 0x56, 0x6F, 0x6D, 0xF1, 0xE2, 0x42, 0xB0, 0x83, 0x40, 0xA5, 0xC3, 0x20, 0x2B,
|
||||
0xCC, 0x9A, 0xAE, 0xCA, 0xED, 0x4D, 0x70, 0x30, 0xA8, 0x70, 0x1C, 0x70, 0xFD, 0x13, 0x63, 0x29,
|
||||
0x02, 0x79, 0xEA, 0xD2, 0xA7, 0xAF, 0x35, 0x28, 0x32, 0x1C, 0x7B, 0xE6, 0x2F, 0x1A, 0xAA, 0x40,
|
||||
0x7E, 0x32, 0x8C, 0x27, 0x42, 0xFE, 0x82, 0x78, 0xEC, 0x0D, 0xEB, 0xE6, 0x83, 0x4B, 0x6D, 0x81,
|
||||
0x04, 0x40, 0x1A, 0x9E, 0x9A, 0x67, 0xF6, 0x72, 0x29, 0xFA, 0x04, 0xF0, 0x9D, 0xE4, 0xF4, 0x03
|
||||
},
|
||||
{
|
||||
0xAD, 0xE3, 0xE1, 0xFA, 0x04, 0x35, 0xE5, 0xB6, 0xDD, 0x49, 0xEA, 0x89, 0x29, 0xB1, 0xFF, 0xB6,
|
||||
0x43, 0xDF, 0xCA, 0x96, 0xA0, 0x4A, 0x13, 0xDF, 0x43, 0xD9, 0x94, 0x97, 0x96, 0x43, 0x65, 0x48,
|
||||
0x70, 0x58, 0x33, 0xA2, 0x7D, 0x35, 0x7B, 0x96, 0x74, 0x5E, 0x0B, 0x5C, 0x32, 0x18, 0x14, 0x24,
|
||||
0xC2, 0x58, 0xB3, 0x6C, 0x22, 0x7A, 0xA1, 0xB7, 0xCB, 0x90, 0xA7, 0xA3, 0xF9, 0x7D, 0x45, 0x16,
|
||||
0xA5, 0xC8, 0xED, 0x8F, 0xAD, 0x39, 0x5E, 0x9E, 0x4B, 0x51, 0x68, 0x7D, 0xF8, 0x0C, 0x35, 0xC6,
|
||||
0x3F, 0x91, 0xAE, 0x44, 0xA5, 0x92, 0x30, 0x0D, 0x46, 0xF8, 0x40, 0xFF, 0xD0, 0xFF, 0x06, 0xD2,
|
||||
0x1C, 0x7F, 0x96, 0x18, 0xDC, 0xB7, 0x1D, 0x66, 0x3E, 0xD1, 0x73, 0xBC, 0x15, 0x8A, 0x2F, 0x94,
|
||||
0xF3, 0x00, 0xC1, 0x83, 0xF1, 0xCD, 0xD7, 0x81, 0x88, 0xAB, 0xDF, 0x8C, 0xEF, 0x97, 0xDD, 0x1B,
|
||||
0x17, 0x5F, 0x58, 0xF6, 0x9A, 0xE9, 0xE8, 0xC2, 0x2F, 0x38, 0x15, 0xF5, 0x21, 0x07, 0xF8, 0x37,
|
||||
0x90, 0x5D, 0x2E, 0x02, 0x40, 0x24, 0x15, 0x0D, 0x25, 0xB7, 0x26, 0x5D, 0x09, 0xCC, 0x4C, 0xF4,
|
||||
0xF2, 0x1B, 0x94, 0x70, 0x5A, 0x9E, 0xEE, 0xED, 0x77, 0x77, 0xD4, 0x51, 0x99, 0xF5, 0xDC, 0x76,
|
||||
0x1E, 0xE3, 0x6C, 0x8C, 0xD1, 0x12, 0xD4, 0x57, 0xD1, 0xB6, 0x83, 0xE4, 0xE4, 0xFE, 0xDA, 0xE9,
|
||||
0xB4, 0x3B, 0x33, 0xE5, 0x37, 0x8A, 0xDF, 0xB5, 0x7F, 0x89, 0xF1, 0x9B, 0x9E, 0xB0, 0x15, 0xB2,
|
||||
0x3A, 0xFE, 0xEA, 0x61, 0x84, 0x5B, 0x7D, 0x4B, 0x23, 0x12, 0x0B, 0x83, 0x12, 0xF2, 0x22, 0x6B,
|
||||
0xB9, 0x22, 0x96, 0x4B, 0x26, 0x0B, 0x63, 0x5E, 0x96, 0x57, 0x52, 0xA3, 0x67, 0x64, 0x22, 0xCA,
|
||||
0xD0, 0x56, 0x3E, 0x74, 0xB5, 0x98, 0x1F, 0x0D, 0xF8, 0xB3, 0x34, 0xE6, 0x98, 0x68, 0x5A, 0xAD
|
||||
}
|
||||
};
|
||||
|
||||
/// RSA-2048-PSS moduli used to verify the main signature from NCA headers with development crypto. Found in the .rodata segment from the FS sysmodule.
|
||||
/// TODO: update on signature keygen changes.
|
||||
static const u8 g_ncaHeaderMainSignatureModuliDev[NcaSignatureKeyGeneration_Max][RSA2048_PUBKEY_SIZE] = {
|
||||
{
|
||||
0xD8, 0xF1, 0x18, 0xEF, 0x32, 0x72, 0x4C, 0xA7, 0x47, 0x4C, 0xB9, 0xEA, 0xB3, 0x04, 0xA8, 0xA4,
|
||||
0xAC, 0x99, 0x08, 0x08, 0x04, 0xBF, 0x68, 0x57, 0xB8, 0x43, 0x94, 0x2B, 0xC7, 0xB9, 0x66, 0x49,
|
||||
0x85, 0xE5, 0x8A, 0x9B, 0xC1, 0x00, 0x9A, 0x6A, 0x8D, 0xD0, 0xEF, 0xCE, 0xFF, 0x86, 0xC8, 0x5C,
|
||||
0x5D, 0xE9, 0x53, 0x7B, 0x19, 0x2A, 0xA8, 0xC0, 0x22, 0xD1, 0xF3, 0x22, 0x0A, 0x50, 0xF2, 0x2B,
|
||||
0x65, 0x05, 0x1B, 0x9E, 0xEC, 0x61, 0xB5, 0x63, 0xA3, 0x6F, 0x3B, 0xBA, 0x63, 0x3A, 0x53, 0xF4,
|
||||
0x49, 0x2F, 0xCF, 0x03, 0xCC, 0xD7, 0x50, 0x82, 0x1B, 0x29, 0x4F, 0x08, 0xDE, 0x1B, 0x6D, 0x47,
|
||||
0x4F, 0xA8, 0xB6, 0x6A, 0x26, 0xA0, 0x83, 0x3F, 0x1A, 0xAF, 0x83, 0x8F, 0x0E, 0x17, 0x3F, 0xFE,
|
||||
0x44, 0x1C, 0x56, 0x94, 0x2E, 0x49, 0x83, 0x83, 0x03, 0xE9, 0xB6, 0xAD, 0xD5, 0xDE, 0xE3, 0x2D,
|
||||
0xA1, 0xD9, 0x66, 0x20, 0x5D, 0x1F, 0x5E, 0x96, 0x5D, 0x5B, 0x55, 0x0D, 0xD4, 0xB4, 0x77, 0x6E,
|
||||
0xAE, 0x1B, 0x69, 0xF3, 0xA6, 0x61, 0x0E, 0x51, 0x62, 0x39, 0x28, 0x63, 0x75, 0x76, 0xBF, 0xB0,
|
||||
0xD2, 0x22, 0xEF, 0x98, 0x25, 0x02, 0x05, 0xC0, 0xD7, 0x6A, 0x06, 0x2C, 0xA5, 0xD8, 0x5A, 0x9D,
|
||||
0x7A, 0xA4, 0x21, 0x55, 0x9F, 0xF9, 0x3E, 0xBF, 0x16, 0xF6, 0x07, 0xC2, 0xB9, 0x6E, 0x87, 0x9E,
|
||||
0xB5, 0x1C, 0xBE, 0x97, 0xFA, 0x82, 0x7E, 0xED, 0x30, 0xD4, 0x66, 0x3F, 0xDE, 0xD8, 0x1B, 0x4B,
|
||||
0x15, 0xD9, 0xFB, 0x2F, 0x50, 0xF0, 0x9D, 0x1D, 0x52, 0x4C, 0x1C, 0x4D, 0x8D, 0xAE, 0x85, 0x1E,
|
||||
0xEA, 0x7F, 0x86, 0xF3, 0x0B, 0x7B, 0x87, 0x81, 0x98, 0x23, 0x80, 0x63, 0x4F, 0x2F, 0xB0, 0x62,
|
||||
0xCC, 0x6E, 0xD2, 0x46, 0x13, 0x65, 0x2B, 0xD6, 0x44, 0x33, 0x59, 0xB5, 0x8F, 0xB9, 0x4A, 0xA9
|
||||
},
|
||||
{
|
||||
0x9A, 0xBC, 0x88, 0xBD, 0x0A, 0xBE, 0xD7, 0x0C, 0x9B, 0x42, 0x75, 0x65, 0x38, 0x5E, 0xD1, 0x01,
|
||||
0xCD, 0x12, 0xAE, 0xEA, 0xE9, 0x4B, 0xDB, 0xB4, 0x5E, 0x36, 0x10, 0x96, 0xDA, 0x3D, 0x2E, 0x66,
|
||||
0xD3, 0x99, 0x13, 0x8A, 0xBE, 0x67, 0x41, 0xC8, 0x93, 0xD9, 0x3E, 0x42, 0xCE, 0x34, 0xCE, 0x96,
|
||||
0xFA, 0x0B, 0x23, 0xCC, 0x2C, 0xDF, 0x07, 0x3F, 0x3B, 0x24, 0x4B, 0x12, 0x67, 0x3A, 0x29, 0x36,
|
||||
0xA3, 0xAA, 0x06, 0xF0, 0x65, 0xA5, 0x85, 0xBA, 0xFD, 0x12, 0xEC, 0xF1, 0x60, 0x67, 0xF0, 0x8F,
|
||||
0xD3, 0x5B, 0x01, 0x1B, 0x1E, 0x84, 0xA3, 0x5C, 0x65, 0x36, 0xF9, 0x23, 0x7E, 0xF3, 0x26, 0x38,
|
||||
0x64, 0x98, 0xBA, 0xE4, 0x19, 0x91, 0x4C, 0x02, 0xCF, 0xC9, 0x6D, 0x86, 0xEC, 0x1D, 0x41, 0x69,
|
||||
0xDD, 0x56, 0xEA, 0x5C, 0xA3, 0x2A, 0x58, 0xB4, 0x39, 0xCC, 0x40, 0x31, 0xFD, 0xFB, 0x42, 0x74,
|
||||
0xF8, 0xEC, 0xEA, 0x00, 0xF0, 0xD9, 0x28, 0xEA, 0xFA, 0x2D, 0x00, 0xE1, 0x43, 0x53, 0xC6, 0x32,
|
||||
0xF4, 0xA2, 0x07, 0xD4, 0x5F, 0xD4, 0xCB, 0xAC, 0xCA, 0xFF, 0xDF, 0x84, 0xD2, 0x86, 0x14, 0x3C,
|
||||
0xDE, 0x22, 0x75, 0xA5, 0x73, 0xFF, 0x68, 0x07, 0x4A, 0xF9, 0x7C, 0x2C, 0xCC, 0xDE, 0x45, 0xB6,
|
||||
0x54, 0x82, 0x90, 0x36, 0x1F, 0x2C, 0x51, 0x96, 0xC5, 0x0A, 0x53, 0x5B, 0xF0, 0x8B, 0x4A, 0xAA,
|
||||
0x3B, 0x68, 0x97, 0x19, 0x17, 0x1F, 0x01, 0xB8, 0xED, 0xB9, 0x9A, 0x5E, 0x08, 0xC5, 0x20, 0x1E,
|
||||
0x6A, 0x09, 0xF0, 0xE9, 0x73, 0xA3, 0xBE, 0x10, 0x06, 0x02, 0xE9, 0xFB, 0x85, 0xFA, 0x5F, 0x01,
|
||||
0xAC, 0x60, 0xE0, 0xED, 0x7D, 0xB9, 0x49, 0xA8, 0x9E, 0x98, 0x7D, 0x91, 0x40, 0x05, 0xCF, 0xF9,
|
||||
0x1A, 0xFC, 0x40, 0x22, 0xA8, 0x96, 0x5B, 0xB0, 0xDC, 0x7A, 0xF5, 0xB7, 0xE9, 0x91, 0x4C, 0x49
|
||||
}
|
||||
};
|
||||
|
||||
/// Used to verify if the key area from a NCA0 is encrypted.
|
||||
static const u8 g_nca0KeyAreaHash[SHA256_HASH_SIZE] = {
|
||||
0x9A, 0xBB, 0xD2, 0x11, 0x86, 0x00, 0x21, 0x9D, 0x7A, 0xDC, 0x5B, 0x43, 0x95, 0xF8, 0x4E, 0xFD,
|
||||
0xFF, 0x6B, 0x25, 0xEF, 0x9F, 0x96, 0x85, 0x28, 0x18, 0x9E, 0x76, 0xB0, 0x92, 0xF0, 0x6A, 0xCB
|
||||
};
|
||||
|
||||
/// Used to verify the NCA header main signature.
|
||||
static const u8 g_ncaHeaderMainSignaturePublicExponent[3] = { 0x01, 0x00, 0x01 };
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
NX_INLINE bool ncaIsFsInfoEntryValid(NcaFsInfo *fs_info);
|
||||
|
||||
static bool ncaReadDecryptedHeader(NcaContext *ctx);
|
||||
static bool ncaDecryptKeyArea(NcaContext *ctx);
|
||||
static bool ncaEncryptKeyArea(NcaContext *ctx);
|
||||
static bool ncaKeyAreaCrypt(NcaContext *ctx, bool encrypt);
|
||||
|
||||
static bool ncaVerifyMainSignature(NcaContext *ctx);
|
||||
|
||||
|
@ -338,7 +419,7 @@ bool ncaRemoveTitleKeyCrypto(NcaContext *ctx)
|
|||
memcpy(ctx->decrypted_key_area.aes_ctr, ctx->titlekey, AES_128_KEY_SIZE);
|
||||
|
||||
/* Encrypt NCA key area. */
|
||||
if (!ncaEncryptKeyArea(ctx))
|
||||
if (!ncaKeyAreaCrypt(ctx, true))
|
||||
{
|
||||
LOG_MSG_ERROR("Error encrypting %s NCA \"%s\" key area!", titleGetNcmContentTypeName(ctx->content_type), ctx->content_id_str);
|
||||
return false;
|
||||
|
@ -541,7 +622,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
|
|||
ctx->valid_main_signature = ncaVerifyMainSignature(ctx);
|
||||
|
||||
/* Decrypt NCA key area (if needed). */
|
||||
if (!ctx->rights_id_available && !ncaDecryptKeyArea(ctx))
|
||||
if (!ctx->rights_id_available && !ncaKeyAreaCrypt(ctx, false))
|
||||
{
|
||||
LOG_MSG_ERROR("Error decrypting NCA \"%s\" key area!", ctx->content_id_str);
|
||||
return false;
|
||||
|
@ -586,7 +667,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool ncaDecryptKeyArea(NcaContext *ctx)
|
||||
static bool ncaKeyAreaCrypt(NcaContext *ctx, bool encrypt)
|
||||
{
|
||||
if (!ctx)
|
||||
{
|
||||
|
@ -594,59 +675,19 @@ static bool ncaDecryptKeyArea(NcaContext *ctx)
|
|||
return false;
|
||||
}
|
||||
|
||||
const u8 null_key[AES_128_KEY_SIZE] = {0};
|
||||
|
||||
u8 key_count = NCA_KEY_AREA_USED_KEY_COUNT;
|
||||
if (ctx->format_version == NcaVersion_Nca0) key_count--;
|
||||
|
||||
/* Check if we're dealing with a NCA0 with a plaintext key area. */
|
||||
if (ncaIsVersion0KeyAreaEncrypted(ctx))
|
||||
{
|
||||
memcpy(&(ctx->decrypted_key_area), &(ctx->header.encrypted_key_area), sizeof(NcaDecryptedKeyArea));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Clear decrypted key area. */
|
||||
memset(&(ctx->decrypted_key_area), 0, sizeof(NcaDecryptedKeyArea));
|
||||
|
||||
/* Process key area. */
|
||||
for(u8 i = 0; i < key_count; i++)
|
||||
{
|
||||
const u8 *src_key = ctx->header.encrypted_key_area.keys[i];
|
||||
u8 *dst_key = ctx->decrypted_key_area.keys[i];
|
||||
|
||||
/* Don't proceed if we're dealing with a null key. */
|
||||
if (!memcmp(src_key, null_key, AES_128_KEY_SIZE)) continue;
|
||||
|
||||
/* Decrypt current key area entry. */
|
||||
if (!keysDecryptNcaKeyAreaEntry(ctx->header.kaek_index, ctx->key_generation, dst_key, src_key))
|
||||
{
|
||||
LOG_MSG_ERROR("Failed to decrypt NCA key area entry #%u!", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ncaEncryptKeyArea(NcaContext *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
{
|
||||
LOG_MSG_ERROR("Invalid NCA context!");
|
||||
return false;
|
||||
}
|
||||
const u8 *src_key_area = (encrypt ? ((const u8*)&(ctx->decrypted_key_area)) : ((const u8*)&(ctx->header.encrypted_key_area)));
|
||||
u8 *dst_key_area = (encrypt ? ((u8*)&(ctx->header.encrypted_key_area)) : ((u8*)&(ctx->decrypted_key_area)));
|
||||
size_t dst_key_area_size = (encrypt ? sizeof(NcaEncryptedKeyArea) : sizeof(NcaDecryptedKeyArea));
|
||||
|
||||
u8 key_count = NCA_KEY_AREA_USED_KEY_COUNT;
|
||||
if (ctx->format_version == NcaVersion_Nca0) key_count--;
|
||||
|
||||
const u8 *kaek = NULL, null_key[AES_128_KEY_SIZE] = {0};
|
||||
Aes128Context key_area_ctx = {0};
|
||||
|
||||
/* Check if we're dealing with a NCA0 with a plaintext key area. */
|
||||
if (ncaIsVersion0KeyAreaEncrypted(ctx))
|
||||
{
|
||||
memcpy(&(ctx->header.encrypted_key_area), &(ctx->decrypted_key_area), sizeof(NcaDecryptedKeyArea));
|
||||
memcpy(dst_key_area, src_key_area, sizeof(NcaDecryptedKeyArea));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -654,27 +695,24 @@ static bool ncaEncryptKeyArea(NcaContext *ctx)
|
|||
kaek = keysGetNcaKeyAreaEncryptionKey(ctx->header.kaek_index, ctx->key_generation);
|
||||
if (!kaek)
|
||||
{
|
||||
LOG_MSG_ERROR("Unable to retrieve KAEK for KAEK index 0x%02X and key generation 0x%02X!", ctx->header.kaek_index, ctx->key_generation);
|
||||
LOG_MSG_ERROR("Unable to retrieve KAEK for type %u and generation %u!", ctx->header.kaek_index, ctx->key_generation);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Clear encrypted key area. */
|
||||
memset(&(ctx->header.encrypted_key_area), 0, sizeof(NcaEncryptedKeyArea));
|
||||
/* Clear destination key area. */
|
||||
memset(dst_key_area, 0, dst_key_area_size);
|
||||
|
||||
/* Initialize AES-128-ECB encryption context using the retrieved KAEK. */
|
||||
aes128ContextCreate(&key_area_ctx, kaek, true);
|
||||
|
||||
/* Process key area. */
|
||||
/* Process source key area. */
|
||||
for(u8 i = 0; i < key_count; i++)
|
||||
{
|
||||
const u8 *src_key = ctx->decrypted_key_area.keys[i];
|
||||
u8 *dst_key = ctx->header.encrypted_key_area.keys[i];
|
||||
const u8 *src_key = (src_key_area + (i * AES_128_KEY_SIZE));
|
||||
u8 *dst_key = (dst_key_area + (i * AES_128_KEY_SIZE));
|
||||
|
||||
/* Don't proceed if we're dealing with a null key. */
|
||||
if (!memcmp(src_key, null_key, AES_128_KEY_SIZE)) continue;
|
||||
|
||||
/* Encrypt current key area entry. */
|
||||
aes128EncryptBlock(&key_area_ctx, dst_key, src_key);
|
||||
/* Process current key area entry. */
|
||||
aes128EcbCrypt(dst_key, src_key, kaek, encrypt);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -688,9 +726,15 @@ static bool ncaVerifyMainSignature(NcaContext *ctx)
|
|||
return false;
|
||||
}
|
||||
|
||||
u8 key_generation = ctx->header.main_signature_key_generation;
|
||||
if (key_generation > NcaSignatureKeyGeneration_Current)
|
||||
{
|
||||
LOG_MSG_ERROR("Unsupported key generation value! (0x%02X).", key_generation);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Retrieve modulus for the NCA main signature. */
|
||||
const u8 *modulus = keysGetNcaMainSignatureModulus(ctx->header.main_signature_key_generation);
|
||||
if (!modulus) return false;
|
||||
const u8 *modulus = (utilsIsDevelopmentUnit() ? g_ncaHeaderMainSignatureModuliDev[key_generation] : g_ncaHeaderMainSignatureModuliProd[key_generation]);
|
||||
|
||||
/* Verify NCA signature. */
|
||||
bool ret = rsa2048VerifySha256BasedPssSignature(&(ctx->header.magic), NCA_SIGNATURE_AREA_SIZE, ctx->header.main_signature, modulus, g_ncaHeaderMainSignaturePublicExponent, \
|
||||
|
|
|
@ -57,6 +57,8 @@ static int g_nxLinkSocketFd = -1;
|
|||
|
||||
static u8 g_customFirmwareType = UtilsCustomFirmwareType_Unknown;
|
||||
|
||||
static u8 g_productModel = SetSysProductModel_Invalid;
|
||||
|
||||
static bool g_isDevUnit = false;
|
||||
|
||||
static AppletType g_programAppletType = AppletType_None;
|
||||
|
@ -96,9 +98,9 @@ static void _utilsGetLaunchPath(int program_argc, const char **program_argv);
|
|||
|
||||
static void _utilsGetCustomFirmwareType(void);
|
||||
|
||||
static bool _utilsIsDevelopmentUnit(void);
|
||||
static bool _utilsGetProductModel(void);
|
||||
|
||||
static bool _utilsAppletModeCheck(void);
|
||||
static bool _utilsIsDevelopmentUnit(void);
|
||||
|
||||
static bool utilsMountEmmcBisSystemPartitionStorage(void);
|
||||
static void utilsUnmountEmmcBisSystemPartitionStorage(void);
|
||||
|
@ -153,13 +155,16 @@ bool utilsInitializeResources(const int program_argc, const char **program_argv)
|
|||
if (g_customFirmwareType != UtilsCustomFirmwareType_Unknown) LOG_MSG_INFO("Detected %s CFW.", (g_customFirmwareType == UtilsCustomFirmwareType_Atmosphere ? "Atmosphère" : \
|
||||
(g_customFirmwareType == UtilsCustomFirmwareType_SXOS ? "SX OS" : "ReiNX")));
|
||||
|
||||
/* Check if we're not running under a development unit. */
|
||||
/* Get product model. */
|
||||
if (!_utilsGetProductModel()) break;
|
||||
|
||||
/* Get development unit flag. */
|
||||
if (!_utilsIsDevelopmentUnit()) break;
|
||||
LOG_MSG_INFO("Running under %s unit.", g_isDevUnit ? "development" : "retail");
|
||||
|
||||
/* Get applet type. */
|
||||
g_programAppletType = appletGetAppletType();
|
||||
LOG_MSG_INFO("Running under %s mode.", _utilsAppletModeCheck() ? "applet" : "title override");
|
||||
|
||||
LOG_MSG_INFO("Running under %s %s unit in %s mode.", g_isDevUnit ? "development" : "retail", utilsIsMarikoUnit() ? "Mariko" : "Erista", utilsIsAppletMode() ? "applet" : "title override");
|
||||
|
||||
/* Create output directories (SD card only). */
|
||||
/* TODO: remove the APP_TITLE check whenever we're ready for a release. */
|
||||
|
@ -182,7 +187,7 @@ bool utilsInitializeResources(const int program_argc, const char **program_argv)
|
|||
}
|
||||
|
||||
/* Initialize HTTP interface. */
|
||||
/* CURL must be initialized before starting any other threads. */
|
||||
/* cURL must be initialized before starting any other threads. */
|
||||
if (!httpInitialize()) break;
|
||||
|
||||
/* Initialize USB interface. */
|
||||
|
@ -235,7 +240,7 @@ bool utilsInitializeResources(const int program_argc, const char **program_argv)
|
|||
appletHook(&g_systemOverclockCookie, utilsOverclockSystemAppletHook, NULL);
|
||||
|
||||
/* Enable video recording if we're running under title override mode. */
|
||||
if (!_utilsAppletModeCheck())
|
||||
if (!utilsIsAppletMode())
|
||||
{
|
||||
bool flag = false;
|
||||
rc = appletIsGamePlayRecordingSupported(&flag);
|
||||
|
@ -369,14 +374,19 @@ u8 utilsGetCustomFirmwareType(void)
|
|||
return g_customFirmwareType;
|
||||
}
|
||||
|
||||
bool utilsIsMarikoUnit(void)
|
||||
{
|
||||
return (g_productModel > SetSysProductModel_Copper);
|
||||
}
|
||||
|
||||
bool utilsIsDevelopmentUnit(void)
|
||||
{
|
||||
return g_isDevUnit;
|
||||
}
|
||||
|
||||
bool utilsAppletModeCheck(void)
|
||||
bool utilsIsAppletMode(void)
|
||||
{
|
||||
return _utilsAppletModeCheck();
|
||||
return (g_programAppletType > AppletType_Application && g_programAppletType < AppletType_SystemApplication);
|
||||
}
|
||||
|
||||
FsStorage *utilsGetEmmcBisSystemPartitionStorage(void)
|
||||
|
@ -1050,6 +1060,24 @@ static void _utilsGetCustomFirmwareType(void)
|
|||
g_customFirmwareType = (rnx_srv ? UtilsCustomFirmwareType_ReiNX : (tx_srv ? UtilsCustomFirmwareType_SXOS : UtilsCustomFirmwareType_Atmosphere));
|
||||
}
|
||||
|
||||
static bool _utilsGetProductModel(void)
|
||||
{
|
||||
Result rc = 0;
|
||||
bool ret = false;
|
||||
SetSysProductModel model = SetSysProductModel_Invalid;
|
||||
|
||||
rc = setsysGetProductModel(&model);
|
||||
if (R_SUCCEEDED(rc) && model != SetSysProductModel_Invalid)
|
||||
{
|
||||
g_productModel = model;
|
||||
ret = true;
|
||||
} else {
|
||||
LOG_MSG_ERROR("setsysGetProductModel failed! (0x%X) (%d).", rc, model);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool _utilsIsDevelopmentUnit(void)
|
||||
{
|
||||
Result rc = 0;
|
||||
|
@ -1066,11 +1094,6 @@ static bool _utilsIsDevelopmentUnit(void)
|
|||
return R_SUCCEEDED(rc);
|
||||
}
|
||||
|
||||
static bool _utilsAppletModeCheck(void)
|
||||
{
|
||||
return (g_programAppletType > AppletType_Application && g_programAppletType < AppletType_SystemApplication);
|
||||
}
|
||||
|
||||
static bool utilsMountEmmcBisSystemPartitionStorage(void)
|
||||
{
|
||||
Result rc = 0;
|
||||
|
@ -1137,7 +1160,7 @@ static void utilsOverclockSystemAppletHook(AppletHookType hook, void *param)
|
|||
static void utilsChangeHomeButtonBlockStatus(bool block)
|
||||
{
|
||||
/* Only change HOME button blocking status if we're running as a regular application or a system application. */
|
||||
if (_utilsAppletModeCheck()) return;
|
||||
if (utilsIsAppletMode()) return;
|
||||
|
||||
if (block)
|
||||
{
|
||||
|
|
|
@ -46,7 +46,6 @@ static Result servicesGetExosphereApiVersion(u32 *out);
|
|||
|
||||
static Result servicesNifmUserInitialize(void);
|
||||
static bool servicesClkGetServiceType(void *arg);
|
||||
static bool servicesSplCryptoCheckAvailability(void *arg);
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
|
@ -55,7 +54,6 @@ static ServiceInfo g_serviceInfo[] = {
|
|||
{ false, "ns", NULL, &nsInitialize, &nsExit },
|
||||
{ false, "csrng", NULL, &csrngInitialize, &csrngExit },
|
||||
{ false, "spl:", NULL, &splInitialize, &splExit },
|
||||
{ false, "spl:mig", &servicesSplCryptoCheckAvailability, &splCryptoInitialize, &splCryptoExit }, /* Checks if spl:mig is really available (e.g. avoid calling splInitialize twice). */
|
||||
{ false, "pm:dmnt", NULL, &pmdmntInitialize, &pmdmntExit },
|
||||
{ false, "psm", NULL, &psmInitialize, &psmExit },
|
||||
{ false, "nifm:u", NULL, &servicesNifmUserInitialize, &nifmExit },
|
||||
|
@ -331,14 +329,3 @@ static bool servicesClkGetServiceType(void *arg)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool servicesSplCryptoCheckAvailability(void *arg)
|
||||
{
|
||||
if (!arg) return false;
|
||||
|
||||
ServiceInfo *info = (ServiceInfo*)arg;
|
||||
if (strcmp(info->name, "spl:mig") != 0 || info->init_func == NULL || info->close_func == NULL) return false;
|
||||
|
||||
/* Check if spl:mig is available (sysver equal to or greater than 4.0.0). */
|
||||
return hosversionAtLeast(4, 0, 0);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* sha3.c
|
||||
*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
* Copyright (c) Atmosphère-NX.
|
||||
* Copyright (c) 2022, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
|
|
|
@ -387,7 +387,6 @@ static bool tikGetDecryptedTitleKey(void *dst, const void *src, u8 key_generatio
|
|||
}
|
||||
|
||||
const u8 *ticket_common_key = NULL;
|
||||
Aes128Context titlekey_aes_ctx = {0};
|
||||
|
||||
ticket_common_key = keysGetTicketCommonKey(key_generation);
|
||||
if (!ticket_common_key)
|
||||
|
@ -396,8 +395,7 @@ static bool tikGetDecryptedTitleKey(void *dst, const void *src, u8 key_generatio
|
|||
return false;
|
||||
}
|
||||
|
||||
aes128ContextCreate(&titlekey_aes_ctx, ticket_common_key, false);
|
||||
aes128DecryptBlock(&titlekey_aes_ctx, dst, src);
|
||||
aes128EcbCrypt(dst, src, ticket_common_key, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
try {
|
||||
/* Check if we're running under applet mode. */
|
||||
if (utilsAppletModeCheck())
|
||||
if (utilsIsAppletMode())
|
||||
{
|
||||
/* Push crash frame with the applet mode warning. */
|
||||
brls::Application::pushView(new brls::CrashFrame("generic/applet_mode_warning"_i18n, [](brls::View *view) {
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace nxdt::views
|
|||
this->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg"));
|
||||
|
||||
/* Check if we're running under applet mode. */
|
||||
this->applet_mode = utilsAppletModeCheck();
|
||||
this->applet_mode = utilsIsAppletMode();
|
||||
|
||||
/* Create labels. */
|
||||
this->applet_mode_lbl = new brls::Label(brls::LabelStyle::HINT, "root_view/applet_mode"_i18n);
|
||||
|
|
Loading…
Reference in a new issue