1
0
Fork 0
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:
Pablo Curiel 2023-04-08 13:34:53 +02:00
parent 7ddf1bb1fb
commit f79680184d
16 changed files with 744 additions and 660 deletions

View file

@ -28,6 +28,11 @@
extern "C" { extern "C" {
#endif #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. /// 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. /// 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. /// 'dst' and 'src' can both point to the same address.

172
include/core/key_sources.h Normal file
View 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__ */

View file

@ -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. /// Returns a pointer to the AES-128-XTS NCA header key, or NULL if keydata hasn't been loaded.
const u8 *keysGetNcaHeaderKey(void); 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. /// 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); const u8 *keysGetNcaKeyAreaEncryptionKey(u8 kaek_index, u8 key_generation);
/// Decrypts a RSA-OAEP wrapped titlekey using console-specific keydata. /// Decrypts a RSA-OAEP wrapped titlekey using console-specific keydata.

View file

@ -87,11 +87,14 @@ bool utilsCommitSdCardFileSystemChanges(void);
/// Returns a UtilsCustomFirmwareType value. /// Returns a UtilsCustomFirmwareType value.
u8 utilsGetCustomFirmwareType(void); 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. /// Returns true if the application is running under a development unit.
bool utilsIsDevelopmentUnit(void); bool utilsIsDevelopmentUnit(void);
/// Returns true if the application is running under applet mode. /// 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. /// Returns a pointer to the FsStorage object for the eMMC BIS System partition.
FsStorage *utilsGetEmmcBisSystemPartitionStorage(void); FsStorage *utilsGetEmmcBisSystemPartitionStorage(void);

View file

@ -1,7 +1,7 @@
/* /*
* sha3.h * sha3.h
* *
* Copyright (c) Atmosphère-NX * Copyright (c) Atmosphère-NX.
* Copyright (c) 2022, DarkMatterCore <pabloacurielz@gmail.com>. * Copyright (c) 2022, DarkMatterCore <pabloacurielz@gmail.com>.
* *
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).

81
include/core/smc.h Normal file
View 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__ */

View file

@ -21,6 +21,21 @@
#include "nxdt_utils.h" #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) 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) if (!ctx || !dst || !src || !size || !sector_size || (size % sector_size) != 0)

View file

@ -25,7 +25,7 @@
/* IFileSystemProxy. */ /* IFileSystemProxy. */
Result fsOpenGameCardStorage(FsStorage *out, const FsGameCardHandle *handle, u32 partition) Result fsOpenGameCardStorage(FsStorage *out, const FsGameCardHandle *handle, u32 partition)
{ {
struct { const struct {
FsGameCardHandle handle; FsGameCardHandle handle;
u32 partition; u32 partition;
} in = { *handle, partition }; } in = { *handle, partition };
@ -47,7 +47,7 @@ Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier *out)
/* IDeviceOperator. */ /* IDeviceOperator. */
Result fsDeviceOperatorUpdatePartitionInfo(FsDeviceOperator *d, const FsGameCardHandle *handle, u32 *out_title_version, u64 *out_title_id) Result fsDeviceOperatorUpdatePartitionInfo(FsDeviceOperator *d, const FsGameCardHandle *handle, u32 *out_title_version, u64 *out_title_id)
{ {
struct { const struct {
FsGameCardHandle handle; FsGameCardHandle handle;
} in = { *handle }; } in = { *handle };
@ -66,7 +66,7 @@ Result fsDeviceOperatorUpdatePartitionInfo(FsDeviceOperator *d, const FsGameCard
Result fsDeviceOperatorGetGameCardDeviceCertificate(FsDeviceOperator *d, const FsGameCardHandle *handle, FsGameCardCertificate *out) Result fsDeviceOperatorGetGameCardDeviceCertificate(FsDeviceOperator *d, const FsGameCardHandle *handle, FsGameCardCertificate *out)
{ {
struct { const struct {
FsGameCardHandle handle; FsGameCardHandle handle;
u64 buf_size; u64 buf_size;
} in = { *handle, sizeof(FsGameCardCertificate) }; } in = { *handle, sizeof(FsGameCardCertificate) };
@ -81,7 +81,7 @@ Result fsDeviceOperatorGetGameCardDeviceCertificate(FsDeviceOperator *d, const F
Result fsDeviceOperatorGetGameCardIdSet(FsDeviceOperator *d, FsGameCardIdSet *out) Result fsDeviceOperatorGetGameCardIdSet(FsDeviceOperator *d, FsGameCardIdSet *out)
{ {
struct { const struct {
u64 buf_size; u64 buf_size;
} in = { sizeof(FsGameCardIdSet) }; } in = { sizeof(FsGameCardIdSet) };

File diff suppressed because it is too large Load diff

View file

@ -34,22 +34,103 @@
static u8 *g_ncaCryptoBuffer = NULL; static u8 *g_ncaCryptoBuffer = NULL;
static Mutex g_ncaCryptoBufferMutex = 0; 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. /// Used to verify if the key area from a NCA0 is encrypted.
static const u8 g_nca0KeyAreaHash[SHA256_HASH_SIZE] = { static const u8 g_nca0KeyAreaHash[SHA256_HASH_SIZE] = {
0x9A, 0xBB, 0xD2, 0x11, 0x86, 0x00, 0x21, 0x9D, 0x7A, 0xDC, 0x5B, 0x43, 0x95, 0xF8, 0x4E, 0xFD, 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 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. */ /* Function prototypes. */
NX_INLINE bool ncaIsFsInfoEntryValid(NcaFsInfo *fs_info); NX_INLINE bool ncaIsFsInfoEntryValid(NcaFsInfo *fs_info);
static bool ncaReadDecryptedHeader(NcaContext *ctx); static bool ncaReadDecryptedHeader(NcaContext *ctx);
static bool ncaDecryptKeyArea(NcaContext *ctx); static bool ncaKeyAreaCrypt(NcaContext *ctx, bool encrypt);
static bool ncaEncryptKeyArea(NcaContext *ctx);
static bool ncaVerifyMainSignature(NcaContext *ctx); 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); memcpy(ctx->decrypted_key_area.aes_ctr, ctx->titlekey, AES_128_KEY_SIZE);
/* Encrypt NCA key area. */ /* 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); LOG_MSG_ERROR("Error encrypting %s NCA \"%s\" key area!", titleGetNcmContentTypeName(ctx->content_type), ctx->content_id_str);
return false; return false;
@ -541,7 +622,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
ctx->valid_main_signature = ncaVerifyMainSignature(ctx); ctx->valid_main_signature = ncaVerifyMainSignature(ctx);
/* Decrypt NCA key area (if needed). */ /* 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); LOG_MSG_ERROR("Error decrypting NCA \"%s\" key area!", ctx->content_id_str);
return false; return false;
@ -586,7 +667,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
return true; return true;
} }
static bool ncaDecryptKeyArea(NcaContext *ctx) static bool ncaKeyAreaCrypt(NcaContext *ctx, bool encrypt)
{ {
if (!ctx) if (!ctx)
{ {
@ -594,59 +675,19 @@ static bool ncaDecryptKeyArea(NcaContext *ctx)
return false; return false;
} }
const u8 null_key[AES_128_KEY_SIZE] = {0}; 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)));
u8 key_count = NCA_KEY_AREA_USED_KEY_COUNT; size_t dst_key_area_size = (encrypt ? sizeof(NcaEncryptedKeyArea) : sizeof(NcaDecryptedKeyArea));
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;
}
u8 key_count = NCA_KEY_AREA_USED_KEY_COUNT; u8 key_count = NCA_KEY_AREA_USED_KEY_COUNT;
if (ctx->format_version == NcaVersion_Nca0) key_count--; if (ctx->format_version == NcaVersion_Nca0) key_count--;
const u8 *kaek = NULL, null_key[AES_128_KEY_SIZE] = {0}; 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. */ /* Check if we're dealing with a NCA0 with a plaintext key area. */
if (ncaIsVersion0KeyAreaEncrypted(ctx)) 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; return true;
} }
@ -654,27 +695,24 @@ static bool ncaEncryptKeyArea(NcaContext *ctx)
kaek = keysGetNcaKeyAreaEncryptionKey(ctx->header.kaek_index, ctx->key_generation); kaek = keysGetNcaKeyAreaEncryptionKey(ctx->header.kaek_index, ctx->key_generation);
if (!kaek) 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; return false;
} }
/* Clear encrypted key area. */ /* Clear destination key area. */
memset(&(ctx->header.encrypted_key_area), 0, sizeof(NcaEncryptedKeyArea)); memset(dst_key_area, 0, dst_key_area_size);
/* Initialize AES-128-ECB encryption context using the retrieved KAEK. */ /* Process source key area. */
aes128ContextCreate(&key_area_ctx, kaek, true);
/* Process key area. */
for(u8 i = 0; i < key_count; i++) for(u8 i = 0; i < key_count; i++)
{ {
const u8 *src_key = ctx->decrypted_key_area.keys[i]; const u8 *src_key = (src_key_area + (i * AES_128_KEY_SIZE));
u8 *dst_key = ctx->header.encrypted_key_area.keys[i]; u8 *dst_key = (dst_key_area + (i * AES_128_KEY_SIZE));
/* Don't proceed if we're dealing with a null key. */ /* Don't proceed if we're dealing with a null key. */
if (!memcmp(src_key, null_key, AES_128_KEY_SIZE)) continue; if (!memcmp(src_key, null_key, AES_128_KEY_SIZE)) continue;
/* Encrypt current key area entry. */ /* Process current key area entry. */
aes128EncryptBlock(&key_area_ctx, dst_key, src_key); aes128EcbCrypt(dst_key, src_key, kaek, encrypt);
} }
return true; return true;
@ -688,9 +726,15 @@ static bool ncaVerifyMainSignature(NcaContext *ctx)
return false; 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. */ /* Retrieve modulus for the NCA main signature. */
const u8 *modulus = keysGetNcaMainSignatureModulus(ctx->header.main_signature_key_generation); const u8 *modulus = (utilsIsDevelopmentUnit() ? g_ncaHeaderMainSignatureModuliDev[key_generation] : g_ncaHeaderMainSignatureModuliProd[key_generation]);
if (!modulus) return false;
/* Verify NCA signature. */ /* Verify NCA signature. */
bool ret = rsa2048VerifySha256BasedPssSignature(&(ctx->header.magic), NCA_SIGNATURE_AREA_SIZE, ctx->header.main_signature, modulus, g_ncaHeaderMainSignaturePublicExponent, \ bool ret = rsa2048VerifySha256BasedPssSignature(&(ctx->header.magic), NCA_SIGNATURE_AREA_SIZE, ctx->header.main_signature, modulus, g_ncaHeaderMainSignaturePublicExponent, \

View file

@ -57,6 +57,8 @@ static int g_nxLinkSocketFd = -1;
static u8 g_customFirmwareType = UtilsCustomFirmwareType_Unknown; static u8 g_customFirmwareType = UtilsCustomFirmwareType_Unknown;
static u8 g_productModel = SetSysProductModel_Invalid;
static bool g_isDevUnit = false; static bool g_isDevUnit = false;
static AppletType g_programAppletType = AppletType_None; 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 void _utilsGetCustomFirmwareType(void);
static bool _utilsIsDevelopmentUnit(void); static bool _utilsGetProductModel(void);
static bool _utilsAppletModeCheck(void); static bool _utilsIsDevelopmentUnit(void);
static bool utilsMountEmmcBisSystemPartitionStorage(void); static bool utilsMountEmmcBisSystemPartitionStorage(void);
static void utilsUnmountEmmcBisSystemPartitionStorage(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" : \ if (g_customFirmwareType != UtilsCustomFirmwareType_Unknown) LOG_MSG_INFO("Detected %s CFW.", (g_customFirmwareType == UtilsCustomFirmwareType_Atmosphere ? "Atmosphère" : \
(g_customFirmwareType == UtilsCustomFirmwareType_SXOS ? "SX OS" : "ReiNX"))); (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; if (!_utilsIsDevelopmentUnit()) break;
LOG_MSG_INFO("Running under %s unit.", g_isDevUnit ? "development" : "retail");
/* Get applet type. */ /* Get applet type. */
g_programAppletType = appletGetAppletType(); 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). */ /* Create output directories (SD card only). */
/* TODO: remove the APP_TITLE check whenever we're ready for a release. */ /* 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. */ /* Initialize HTTP interface. */
/* CURL must be initialized before starting any other threads. */ /* cURL must be initialized before starting any other threads. */
if (!httpInitialize()) break; if (!httpInitialize()) break;
/* Initialize USB interface. */ /* Initialize USB interface. */
@ -235,7 +240,7 @@ bool utilsInitializeResources(const int program_argc, const char **program_argv)
appletHook(&g_systemOverclockCookie, utilsOverclockSystemAppletHook, NULL); appletHook(&g_systemOverclockCookie, utilsOverclockSystemAppletHook, NULL);
/* Enable video recording if we're running under title override mode. */ /* Enable video recording if we're running under title override mode. */
if (!_utilsAppletModeCheck()) if (!utilsIsAppletMode())
{ {
bool flag = false; bool flag = false;
rc = appletIsGamePlayRecordingSupported(&flag); rc = appletIsGamePlayRecordingSupported(&flag);
@ -369,14 +374,19 @@ u8 utilsGetCustomFirmwareType(void)
return g_customFirmwareType; return g_customFirmwareType;
} }
bool utilsIsMarikoUnit(void)
{
return (g_productModel > SetSysProductModel_Copper);
}
bool utilsIsDevelopmentUnit(void) bool utilsIsDevelopmentUnit(void)
{ {
return g_isDevUnit; return g_isDevUnit;
} }
bool utilsAppletModeCheck(void) bool utilsIsAppletMode(void)
{ {
return _utilsAppletModeCheck(); return (g_programAppletType > AppletType_Application && g_programAppletType < AppletType_SystemApplication);
} }
FsStorage *utilsGetEmmcBisSystemPartitionStorage(void) FsStorage *utilsGetEmmcBisSystemPartitionStorage(void)
@ -1050,6 +1060,24 @@ static void _utilsGetCustomFirmwareType(void)
g_customFirmwareType = (rnx_srv ? UtilsCustomFirmwareType_ReiNX : (tx_srv ? UtilsCustomFirmwareType_SXOS : UtilsCustomFirmwareType_Atmosphere)); 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) static bool _utilsIsDevelopmentUnit(void)
{ {
Result rc = 0; Result rc = 0;
@ -1066,11 +1094,6 @@ static bool _utilsIsDevelopmentUnit(void)
return R_SUCCEEDED(rc); return R_SUCCEEDED(rc);
} }
static bool _utilsAppletModeCheck(void)
{
return (g_programAppletType > AppletType_Application && g_programAppletType < AppletType_SystemApplication);
}
static bool utilsMountEmmcBisSystemPartitionStorage(void) static bool utilsMountEmmcBisSystemPartitionStorage(void)
{ {
Result rc = 0; Result rc = 0;
@ -1137,7 +1160,7 @@ static void utilsOverclockSystemAppletHook(AppletHookType hook, void *param)
static void utilsChangeHomeButtonBlockStatus(bool block) static void utilsChangeHomeButtonBlockStatus(bool block)
{ {
/* Only change HOME button blocking status if we're running as a regular application or a system application. */ /* 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) if (block)
{ {

View file

@ -46,7 +46,6 @@ static Result servicesGetExosphereApiVersion(u32 *out);
static Result servicesNifmUserInitialize(void); static Result servicesNifmUserInitialize(void);
static bool servicesClkGetServiceType(void *arg); static bool servicesClkGetServiceType(void *arg);
static bool servicesSplCryptoCheckAvailability(void *arg);
/* Global variables. */ /* Global variables. */
@ -55,16 +54,15 @@ static ServiceInfo g_serviceInfo[] = {
{ false, "ns", NULL, &nsInitialize, &nsExit }, { false, "ns", NULL, &nsInitialize, &nsExit },
{ false, "csrng", NULL, &csrngInitialize, &csrngExit }, { false, "csrng", NULL, &csrngInitialize, &csrngExit },
{ false, "spl:", NULL, &splInitialize, &splExit }, { 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, "pm:dmnt", NULL, &pmdmntInitialize, &pmdmntExit },
{ false, "psm", NULL, &psmInitialize, &psmExit }, { false, "psm", NULL, &psmInitialize, &psmExit },
{ false, "nifm:u", NULL, &servicesNifmUserInitialize, &nifmExit }, { false, "nifm:u", NULL, &servicesNifmUserInitialize, &nifmExit },
{ false, "clk", &servicesClkGetServiceType, NULL, NULL }, /* Placeholder for pcv / clkrst. */ { false, "clk", &servicesClkGetServiceType, NULL, NULL }, /* Placeholder for pcv / clkrst. */
{ false, "es", NULL, &esInitialize, &esExit }, { false, "es", NULL, &esInitialize, &esExit },
{ false, "set", NULL, &setInitialize, &setExit }, { false, "set", NULL, &setInitialize, &setExit },
{ false, "set:sys", NULL, &setsysInitialize, &setsysExit }, { false, "set:sys", NULL, &setsysInitialize, &setsysExit },
{ false, "set:cal", NULL, &setcalInitialize, &setcalExit }, { false, "set:cal", NULL, &setcalInitialize, &setcalExit },
{ false, "bsd:u", NULL, &socketInitializeDefault, &socketExit } /* socketInitialize*() functions take care of initializing bsd:* too. */ { false, "bsd:u", NULL, &socketInitializeDefault, &socketExit } /* socketInitialize*() functions take care of initializing bsd:* too. */
}; };
static const u32 g_serviceInfoCount = MAX_ELEMENTS(g_serviceInfo); static const u32 g_serviceInfoCount = MAX_ELEMENTS(g_serviceInfo);
@ -331,14 +329,3 @@ static bool servicesClkGetServiceType(void *arg)
return true; 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);
}

View file

@ -1,7 +1,7 @@
/* /*
* sha3.c * sha3.c
* *
* Copyright (c) Atmosphère-NX * Copyright (c) Atmosphère-NX.
* Copyright (c) 2022, DarkMatterCore <pabloacurielz@gmail.com>. * Copyright (c) 2022, DarkMatterCore <pabloacurielz@gmail.com>.
* *
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).

View file

@ -387,7 +387,6 @@ static bool tikGetDecryptedTitleKey(void *dst, const void *src, u8 key_generatio
} }
const u8 *ticket_common_key = NULL; const u8 *ticket_common_key = NULL;
Aes128Context titlekey_aes_ctx = {0};
ticket_common_key = keysGetTicketCommonKey(key_generation); ticket_common_key = keysGetTicketCommonKey(key_generation);
if (!ticket_common_key) if (!ticket_common_key)
@ -396,8 +395,7 @@ static bool tikGetDecryptedTitleKey(void *dst, const void *src, u8 key_generatio
return false; return false;
} }
aes128ContextCreate(&titlekey_aes_ctx, ticket_common_key, false); aes128EcbCrypt(dst, src, ticket_common_key, false);
aes128DecryptBlock(&titlekey_aes_ctx, dst, src);
return true; return true;
} }

View file

@ -48,7 +48,7 @@ int main(int argc, char *argv[])
try { try {
/* Check if we're running under applet mode. */ /* Check if we're running under applet mode. */
if (utilsAppletModeCheck()) if (utilsIsAppletMode())
{ {
/* Push crash frame with the applet mode warning. */ /* Push crash frame with the applet mode warning. */
brls::Application::pushView(new brls::CrashFrame("generic/applet_mode_warning"_i18n, [](brls::View *view) { brls::Application::pushView(new brls::CrashFrame("generic/applet_mode_warning"_i18n, [](brls::View *view) {

View file

@ -40,7 +40,7 @@ namespace nxdt::views
this->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg")); this->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg"));
/* Check if we're running under applet mode. */ /* Check if we're running under applet mode. */
this->applet_mode = utilsAppletModeCheck(); this->applet_mode = utilsIsAppletMode();
/* Create labels. */ /* Create labels. */
this->applet_mode_lbl = new brls::Label(brls::LabelStyle::HINT, "root_view/applet_mode"_i18n); this->applet_mode_lbl = new brls::Label(brls::LabelStyle::HINT, "root_view/applet_mode"_i18n);