mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-26 04:02:11 +00:00
Remove support for NPDM patching.
This commit is contained in:
parent
d3b007d9af
commit
ce4034852c
10 changed files with 24 additions and 278 deletions
|
@ -53,7 +53,6 @@ static options_t options[] = {
|
|||
{ "set download distribution type", 0 },
|
||||
{ "remove console specific data", 1 },
|
||||
{ "remove titlekey crypto (overrides previous option)", 0 },
|
||||
{ "change acid rsa key/sig", 0 },
|
||||
{ "disable linked account requirement", 0 },
|
||||
{ "enable screenshots", 0 },
|
||||
{ "enable video capture", 0 },
|
||||
|
@ -135,13 +134,12 @@ static void nspDump(TitleInfo *title_info, u64 free_space)
|
|||
bool set_download_type = (options[0].val == 1);
|
||||
bool remove_console_data = (options[1].val == 1);
|
||||
bool remove_titlekey_crypto = (options[2].val == 1);
|
||||
bool change_acid_rsa = (options[3].val == 1);
|
||||
bool patch_sua = (options[4].val == 1);
|
||||
bool patch_screenshot = (options[5].val == 1);
|
||||
bool patch_video_capture = (options[6].val == 1);
|
||||
bool patch_hdcp = (options[7].val == 1);
|
||||
bool append_authoringtool_data = (options[8].val == 1);
|
||||
UsbHsFsDevice *ums_device = (options[9].val == 0 ? NULL : &(ums_devices[options[8].val - 1]));
|
||||
bool patch_sua = (options[3].val == 1);
|
||||
bool patch_screenshot = (options[4].val == 1);
|
||||
bool patch_video_capture = (options[5].val == 1);
|
||||
bool patch_hdcp = (options[6].val == 1);
|
||||
bool append_authoringtool_data = (options[7].val == 1);
|
||||
UsbHsFsDevice *ums_device = (options[8].val == 0 ? NULL : &(ums_devices[options[8].val - 1]));
|
||||
bool success = false;
|
||||
|
||||
if (ums_device && ums_device->write_protect)
|
||||
|
@ -211,7 +209,7 @@ static void nspDump(TitleInfo *title_info, u64 free_space)
|
|||
}
|
||||
|
||||
// determine if we should initialize programinfo ctx
|
||||
if (change_acid_rsa || append_authoringtool_data)
|
||||
if (append_authoringtool_data)
|
||||
{
|
||||
program_count = titleGetContentCountByType(title_info, NcmContentType_Program);
|
||||
if (program_count && !(program_info_ctx = calloc(program_count, sizeof(ProgramInfoContext))))
|
||||
|
@ -317,12 +315,6 @@ static void nspDump(TitleInfo *title_info, u64 free_space)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (change_acid_rsa && !programInfoGenerateNcaPatch(cur_program_info_ctx))
|
||||
{
|
||||
consolePrint("program info nca patch failed (%s)\n", cur_nca_ctx->content_id_str);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (append_authoringtool_data && !programInfoGenerateAuthoringToolXml(cur_program_info_ctx))
|
||||
{
|
||||
consolePrint("program info xml failed (%s)\n", cur_nca_ctx->content_id_str);
|
||||
|
@ -615,9 +607,6 @@ static void nspDump(TitleInfo *title_info, u64 free_space)
|
|||
case NcmContentType_Meta:
|
||||
cnmtWriteNcaPatch(&cnmt_ctx, buf, blksize, offset);
|
||||
break;
|
||||
case NcmContentType_Program:
|
||||
programInfoWriteNcaPatch((ProgramInfoContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset);
|
||||
break;
|
||||
case NcmContentType_Control:
|
||||
nacpWriteNcaPatch((NacpContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset);
|
||||
break;
|
||||
|
|
|
@ -61,7 +61,6 @@ static options_t options[] = {
|
|||
{ "set download distribution type", false },
|
||||
{ "remove console specific data", true },
|
||||
{ "remove titlekey crypto (overrides previous option)", false },
|
||||
{ "change acid rsa key/sig", false },
|
||||
{ "disable linked account requirement", false },
|
||||
{ "enable screenshots", false },
|
||||
{ "enable video capture", false },
|
||||
|
@ -127,12 +126,11 @@ static void dump_thread_func(void *arg)
|
|||
bool set_download_type = options[0].val;
|
||||
bool remove_console_data = options[1].val;
|
||||
bool remove_titlekey_crypto = options[2].val;
|
||||
bool change_acid_rsa = options[3].val;
|
||||
bool patch_sua = options[4].val;
|
||||
bool patch_screenshot = options[5].val;
|
||||
bool patch_video_capture = options[6].val;
|
||||
bool patch_hdcp = options[7].val;
|
||||
bool append_authoringtool_data = options[8].val;
|
||||
bool patch_sua = options[3].val;
|
||||
bool patch_screenshot = options[4].val;
|
||||
bool patch_video_capture = options[5].val;
|
||||
bool patch_hdcp = options[6].val;
|
||||
bool append_authoringtool_data = options[7].val;
|
||||
bool success = false;
|
||||
|
||||
u8 *buf = NULL;
|
||||
|
@ -197,7 +195,7 @@ static void dump_thread_func(void *arg)
|
|||
}
|
||||
|
||||
// determine if we should initialize programinfo ctx
|
||||
if (change_acid_rsa || append_authoringtool_data)
|
||||
if (append_authoringtool_data)
|
||||
{
|
||||
program_count = titleGetContentCountByType(title_info, NcmContentType_Program);
|
||||
if (program_count && !(program_info_ctx = calloc(program_count, sizeof(ProgramInfoContext))))
|
||||
|
@ -303,12 +301,6 @@ static void dump_thread_func(void *arg)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (change_acid_rsa && !programInfoGenerateNcaPatch(cur_program_info_ctx))
|
||||
{
|
||||
consolePrint("program info nca patch failed (%s)\n", cur_nca_ctx->content_id_str);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (append_authoringtool_data && !programInfoGenerateAuthoringToolXml(cur_program_info_ctx))
|
||||
{
|
||||
consolePrint("program info xml failed (%s)\n", cur_nca_ctx->content_id_str);
|
||||
|
@ -592,9 +584,6 @@ static void dump_thread_func(void *arg)
|
|||
case NcmContentType_Meta:
|
||||
cnmtWriteNcaPatch(&cnmt_ctx, buf, blksize, offset);
|
||||
break;
|
||||
case NcmContentType_Program:
|
||||
programInfoWriteNcaPatch((ProgramInfoContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset);
|
||||
break;
|
||||
case NcmContentType_Control:
|
||||
nacpWriteNcaPatch((NacpContext*)cur_nca_ctx->content_type_ctx, buf, blksize, offset);
|
||||
break;
|
||||
|
|
|
@ -599,13 +599,8 @@ typedef struct {
|
|||
NXDT_ASSERT(NpdmKernelCapabilityDescriptorEntry, 0x4);
|
||||
|
||||
typedef struct {
|
||||
NcaContext *nca_ctx; ///< Pointer to the NCA context for the Program NCA from which NPDM data is retrieved.
|
||||
PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where the NPDM is stored.
|
||||
PartitionFileSystemEntry *pfs_entry; ///< PartitionFileSystemEntry for the NPDM in the Program NCA FS section #0. Used to generate a NcaHierarchicalSha256Patch if needed.
|
||||
NcaHierarchicalSha256Patch nca_patch; ///< NcaHierarchicalSha256Patch generated if NPDM modifications are needed. Used to seamlessly replace Program NCA data while writing it.
|
||||
///< Bear in mind that generating a patch modifies the NCA context.
|
||||
u8 *raw_data; ///< Pointer to a dynamically allocated buffer that holds the raw NPDM.
|
||||
u64 raw_data_size; ///< Raw NPDM size. Kept here for convenience - this is part of 'pfs_entry'.
|
||||
u64 raw_data_size; ///< Raw NPDM size.
|
||||
NpdmMetaHeader *meta_header; ///< Pointer to the NpdmMetaHeader within 'raw_data'.
|
||||
NpdmAcidHeader *acid_header; ///< Pointer to the NpdmAcidHeader within 'raw_data'.
|
||||
NpdmFsAccessControlDescriptor *acid_fac_descriptor; ///< Pointer to the NpdmFsAccessControlDescriptor within the NPDM ACID section.
|
||||
|
@ -620,26 +615,18 @@ typedef struct {
|
|||
/// Initializes a NpdmContext using a previously initialized PartitionFileSystemContext (which must belong to the ExeFS from a Program NCA).
|
||||
bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx);
|
||||
|
||||
/// Changes the ACID public key from the NPDM in the input NpdmContext, updates the ACID signature from the NCA header in the underlying NCA context and generates a Partition FS entry patch.
|
||||
bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx);
|
||||
|
||||
/// Writes data from the Partition FS entry patch in the input NpdmContext to the provided buffer.
|
||||
void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_offset);
|
||||
|
||||
/// Helper inline functions.
|
||||
|
||||
NX_INLINE void npdmFreeContext(NpdmContext *npdm_ctx)
|
||||
{
|
||||
if (!npdm_ctx) return;
|
||||
pfsFreeEntryPatch(&(npdm_ctx->nca_patch));
|
||||
if (npdm_ctx->raw_data) free(npdm_ctx->raw_data);
|
||||
memset(npdm_ctx, 0, sizeof(NpdmContext));
|
||||
}
|
||||
|
||||
NX_INLINE bool npdmIsValidContext(NpdmContext *npdm_ctx)
|
||||
{
|
||||
return (npdm_ctx && npdm_ctx->nca_ctx && npdm_ctx->pfs_ctx && npdm_ctx->pfs_entry && npdm_ctx->raw_data && npdm_ctx->raw_data_size && npdm_ctx->meta_header && npdm_ctx->acid_header && \
|
||||
npdm_ctx->acid_fac_descriptor && \
|
||||
return (npdm_ctx && npdm_ctx->raw_data && npdm_ctx->raw_data_size && npdm_ctx->meta_header && npdm_ctx->acid_header && npdm_ctx->acid_fac_descriptor && \
|
||||
((npdm_ctx->acid_header->srv_access_control_size && npdm_ctx->acid_sac_descriptor) || (!npdm_ctx->acid_header->srv_access_control_size && !npdm_ctx->acid_sac_descriptor)) && \
|
||||
((npdm_ctx->acid_header->kernel_capability_size && npdm_ctx->acid_kc_descriptor) || (!npdm_ctx->acid_header->kernel_capability_size && !npdm_ctx->acid_kc_descriptor)) && \
|
||||
npdm_ctx->aci_header && npdm_ctx->aci_fac_data && \
|
||||
|
|
|
@ -34,7 +34,7 @@ extern "C" {
|
|||
typedef struct {
|
||||
NcaContext *nca_ctx; ///< Pointer to the NCA context for the Program NCA from which program data (NPDM / NSO) is retrieved.
|
||||
PartitionFileSystemContext pfs_ctx; ///< PartitionFileSystemContext for the Program NCA ExeFS, which is where program data (NPDM / NSO) is stored.
|
||||
NpdmContext npdm_ctx; ///< NpdmContext for the NPDM stored in Program NCA ExeFS. Holds its own NcaHierarchicalSha256Patch that may be applied to the Program NCA if needed.
|
||||
NpdmContext npdm_ctx; ///< NpdmContext for the NPDM stored in Program NCA ExeFS.
|
||||
u32 nso_count; ///< Number of NSOs stored in Program NCA FS section #0.
|
||||
NsoContext *nso_ctx; ///< Pointer to a dynamically allocated buffer that holds 'nso_count' NSO contexts.
|
||||
char *authoring_tool_xml; ///< Pointer to a dynamically allocated, NULL-terminated buffer that holds AuthoringTool-like XML data.
|
||||
|
@ -71,18 +71,7 @@ NX_INLINE void programInfoFreeContext(ProgramInfoContext *program_info_ctx)
|
|||
|
||||
NX_INLINE bool programInfoIsValidContext(ProgramInfoContext *program_info_ctx)
|
||||
{
|
||||
return (program_info_ctx && program_info_ctx->nca_ctx && npdmIsValidContext(&(program_info_ctx->npdm_ctx)) && program_info_ctx->npdm_ctx.pfs_ctx == &(program_info_ctx->pfs_ctx) && \
|
||||
program_info_ctx->nso_count && program_info_ctx->nso_ctx);
|
||||
}
|
||||
|
||||
NX_INLINE bool programInfoGenerateNcaPatch(ProgramInfoContext *program_info_ctx)
|
||||
{
|
||||
return (programInfoIsValidContext(program_info_ctx) && npdmGenerateNcaPatch(&(program_info_ctx->npdm_ctx)));
|
||||
}
|
||||
|
||||
NX_INLINE void programInfoWriteNcaPatch(ProgramInfoContext *program_info_ctx, void *buf, u64 buf_size, u64 buf_offset)
|
||||
{
|
||||
if (program_info_ctx) npdmWriteNcaPatch(&(program_info_ctx->npdm_ctx), buf, buf_size, buf_offset);
|
||||
return (program_info_ctx && program_info_ctx->nca_ctx && npdmIsValidContext(&(program_info_ctx->npdm_ctx)) && program_info_ctx->nso_count && program_info_ctx->nso_ctx);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
* rsa.c
|
||||
*
|
||||
* Copyright (c) 2018-2019, SciresM.
|
||||
* Copyright (c) 2018-2019, The-4n.
|
||||
* Copyright (c) 2020-2022, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
|
@ -36,19 +35,10 @@ extern "C" {
|
|||
#define RSA2048_SIG_SIZE RSA2048_BYTES
|
||||
#define RSA2048_PUBKEY_SIZE RSA2048_BYTES
|
||||
|
||||
/// Returns a pointer to the RSA-2048 public key that can be used to verify signatures generated by rsa2048GenerateSha256BasedPssSignature().
|
||||
/// Suitable to replace the ACID public key in a NPDM.
|
||||
const u8 *rsa2048GetCustomPublicKey(void);
|
||||
|
||||
/// Verifies a RSA-2048-PSS with SHA-256 signature.
|
||||
/// The provided signature and modulus should have sizes of at least RSA2048_SIG_SIZE and RSA2048_PUBKEY_SIZE, respectively.
|
||||
bool rsa2048VerifySha256BasedPssSignature(const void *data, size_t data_size, const void *signature, const void *modulus, const void *public_exponent, size_t public_exponent_size);
|
||||
|
||||
/// Generates a RSA-2048-PSS with SHA-256 signature using a custom RSA-2048 private key.
|
||||
/// Suitable to replace the ACID signature in a Program NCA header.
|
||||
/// Destination buffer size should be at least RSA2048_SIG_SIZE.
|
||||
bool rsa2048GenerateSha256BasedPssSignature(void *dst, const void *src, size_t size);
|
||||
|
||||
/// Performs RSA-2048-OAEP decryption.
|
||||
/// Suitable to decrypt the titlekey block from tickets with personalized crypto.
|
||||
/// The provided signature and modulus should have sizes of at least RSA2048_SIG_SIZE and RSA2048_PUBKEY_SIZE, respectively.
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
"set_download_distribution": false,
|
||||
"remove_console_data": true,
|
||||
"remove_titlekey_crypto": false,
|
||||
"replace_acid_key_sig": false,
|
||||
"disable_linked_account_requirement": false,
|
||||
"enable_screenshots": false,
|
||||
"enable_video_capture": false,
|
||||
|
|
|
@ -216,7 +216,7 @@ end:
|
|||
|
||||
static bool configValidateJsonNspObject(const struct json_object *obj)
|
||||
{
|
||||
bool ret = false, set_download_distribution_found = false, remove_console_data_found = false, remove_titlekey_crypto_found = false, replace_acid_key_sig_found = false;
|
||||
bool ret = false, set_download_distribution_found = false, remove_console_data_found = false, remove_titlekey_crypto_found = false;
|
||||
bool disable_linked_account_requirement_found = false, enable_screenshots_found = false, enable_video_capture_found = false, disable_hdcp_found = false, append_authoringtool_data_found = false, lookup_checksum_found = false;
|
||||
|
||||
if (!jsonValidateObject(obj)) goto end;
|
||||
|
@ -226,7 +226,6 @@ static bool configValidateJsonNspObject(const struct json_object *obj)
|
|||
CONFIG_VALIDATE_FIELD(Boolean, set_download_distribution);
|
||||
CONFIG_VALIDATE_FIELD(Boolean, remove_console_data);
|
||||
CONFIG_VALIDATE_FIELD(Boolean, remove_titlekey_crypto);
|
||||
CONFIG_VALIDATE_FIELD(Boolean, replace_acid_key_sig);
|
||||
CONFIG_VALIDATE_FIELD(Boolean, disable_linked_account_requirement);
|
||||
CONFIG_VALIDATE_FIELD(Boolean, enable_screenshots);
|
||||
CONFIG_VALIDATE_FIELD(Boolean, enable_video_capture);
|
||||
|
@ -236,7 +235,7 @@ static bool configValidateJsonNspObject(const struct json_object *obj)
|
|||
goto end;
|
||||
}
|
||||
|
||||
ret = (set_download_distribution_found && remove_console_data_found && remove_titlekey_crypto_found && replace_acid_key_sig_found && disable_linked_account_requirement_found && \
|
||||
ret = (set_download_distribution_found && remove_console_data_found && remove_titlekey_crypto_found && disable_linked_account_requirement_found && \
|
||||
enable_screenshots_found && enable_video_capture_found && disable_hdcp_found && append_authoringtool_data_found && lookup_checksum_found);
|
||||
|
||||
end:
|
||||
|
|
|
@ -28,6 +28,7 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
NcaContext *nca_ctx = NULL;
|
||||
u64 cur_offset = 0;
|
||||
bool success = false, dump_meta_header = false, dump_acid_header = false, dump_aci_header = false;
|
||||
PartitionFileSystemEntry *pfs_entry = NULL;
|
||||
|
||||
if (!out || !pfs_ctx || !pfs_ctx->nca_fs_ctx || !(nca_ctx = (NcaContext*)pfs_ctx->nca_fs_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program || !pfs_ctx->offset || !pfs_ctx->size || \
|
||||
!pfs_ctx->is_exefs || pfs_ctx->header_size <= sizeof(PartitionFileSystemHeader) || !pfs_ctx->header)
|
||||
|
@ -40,9 +41,7 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
npdmFreeContext(out);
|
||||
|
||||
/* Get 'main.npdm' file entry. */
|
||||
out->nca_ctx = nca_ctx;
|
||||
out->pfs_ctx = pfs_ctx;
|
||||
if (!(out->pfs_entry = pfsGetEntryByName(out->pfs_ctx, "main.npdm")))
|
||||
if (!(pfs_entry = pfsGetEntryByName(pfs_ctx, "main.npdm")))
|
||||
{
|
||||
LOG_MSG("'main.npdm' entry unavailable in ExeFS!");
|
||||
goto end;
|
||||
|
@ -51,14 +50,14 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
//LOG_MSG("Found 'main.npdm' entry in Program NCA \"%s\".", nca_ctx->content_id_str);
|
||||
|
||||
/* Check raw NPDM size. */
|
||||
if (!out->pfs_entry->size)
|
||||
if (!pfs_entry->size)
|
||||
{
|
||||
LOG_MSG("Invalid raw NPDM size!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate memory for the raw NPDM data. */
|
||||
out->raw_data_size = out->pfs_entry->size;
|
||||
out->raw_data_size = pfs_entry->size;
|
||||
if (!(out->raw_data = malloc(out->raw_data_size)))
|
||||
{
|
||||
LOG_MSG("Failed to allocate memory for the raw NPDM data!");
|
||||
|
@ -66,7 +65,7 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
}
|
||||
|
||||
/* Read raw NPDM data into memory buffer. */
|
||||
if (!pfsReadEntryData(out->pfs_ctx, out->pfs_entry, out->raw_data, out->raw_data_size, 0))
|
||||
if (!pfsReadEntryData(pfs_ctx, pfs_entry, out->raw_data, out->raw_data_size, 0))
|
||||
{
|
||||
LOG_MSG("Failed to read raw NPDM data!");
|
||||
goto end;
|
||||
|
@ -287,62 +286,3 @@ end:
|
|||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx)
|
||||
{
|
||||
if (!npdmIsValidContext(npdm_ctx) || npdm_ctx->nca_ctx->content_type != NcmContentType_Program)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
NcaContext *nca_ctx = npdm_ctx->nca_ctx;
|
||||
|
||||
/* Check if we really need to generate this patch. */
|
||||
if (!ncaIsHeaderDirty(nca_ctx))
|
||||
{
|
||||
LOG_MSG("Skipping NPDM patching - NCA header hasn't been modified.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Update NPDM ACID public key. */
|
||||
memcpy(npdm_ctx->acid_header->public_key, rsa2048GetCustomPublicKey(), RSA2048_PUBKEY_SIZE);
|
||||
|
||||
/* Generate Partition FS entry patch. */
|
||||
if (!pfsGenerateEntryPatch(npdm_ctx->pfs_ctx, npdm_ctx->pfs_entry, npdm_ctx->raw_data, npdm_ctx->raw_data_size, 0, &(npdm_ctx->nca_patch)))
|
||||
{
|
||||
LOG_MSG("Failed to generate Partition FS entry patch!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Update NCA ACID signature. */
|
||||
if (!rsa2048GenerateSha256BasedPssSignature(nca_ctx->header.acid_signature, &(nca_ctx->header.magic), NCA_SIGNATURE_AREA_SIZE))
|
||||
{
|
||||
LOG_MSG("Failed to generate RSA-2048-PSS NCA ACID signature!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Update NCA content type context patch status. */
|
||||
nca_ctx->content_type_ctx_patch = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_offset)
|
||||
{
|
||||
NcaContext *nca_ctx = NULL;
|
||||
NcaHierarchicalSha256Patch *nca_patch = (npdm_ctx ? &(npdm_ctx->nca_patch) : NULL);
|
||||
|
||||
/* Using npdmIsValidContext() here would probably take up precious CPU cycles. */
|
||||
if (!nca_patch || nca_patch->written || !(nca_ctx = npdm_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program || !nca_ctx->content_type_ctx_patch) return;
|
||||
|
||||
/* Attempt to write Partition FS entry patch. */
|
||||
pfsWriteEntryPatchToMemoryBuffer(npdm_ctx->pfs_ctx, nca_patch, buf, buf_size, buf_offset);
|
||||
|
||||
/* Check if we need to update the NCA content type context patch status. */
|
||||
if (nca_patch->written)
|
||||
{
|
||||
nca_ctx->content_type_ctx_patch = false;
|
||||
LOG_MSG("NPDM Partition FS entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
* rsa.c
|
||||
*
|
||||
* Copyright (c) 2018-2019, SciresM.
|
||||
* Copyright (c) 2018-2019, The-4n.
|
||||
* Copyright (c) 2020-2022, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
|
@ -29,65 +28,6 @@
|
|||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/pk.h>
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
/// Self-generated private key.
|
||||
static const char g_rsa2048CustomPrivateKey[] = "-----BEGIN RSA PRIVATE KEY-----\r\n"
|
||||
"MIIEowIBAAKCAQEAvVRzt+8mE7oE4RkmSh3ws4CGlBj7uhHkfwCpPFsn4TNVdLRo\r\n"
|
||||
"YYY17jQYWTtcOYPMcHxwUpgJyspGN8QGXEkJqY8jILv2eO0jBGtg7Br2afUBp6/x\r\n"
|
||||
"BOMT2RlYVX6H4a1UA19Hzmcn+T1hdDwS6oBYpi8rJSm0+q+yB34dueNkVsk4eKbj\r\n"
|
||||
"CNNKFi+XgyNBi41d57SPCrkcm/9tkagRorE8vLcFPcXcYOjdXH3L4XTXq7sxxytA\r\n"
|
||||
"I66erfSc4XunkoLifcbfMOB3gjGCoQs6GfaiAU3TwxewQ7hdoqvj5Gm9VyHqzeDF\r\n"
|
||||
"5mUTlmed2I6m4ELxbV1b0lUguR5ZEzwXwiVWxwIDAQABAoIBADvLYkijFOmCBGx7\r\n"
|
||||
"HualkhF+9AHt6gKYCAw8Tzaqq2uqZMDZAWZblsjGVzJHVxcrEvQruOW88srDG24d\r\n"
|
||||
"UMzwnEaa2ENMWclTS43nw9KNqWlJYd5t6LbcaLZWFNnbflq9/RybiPgdCDjlM9Qb\r\n"
|
||||
"7PV214iUuRGhnHDX8GgBYq4ErPnjQ7+Gv1ducpMYjZencLWCl4fFX86U0/MU0+Qf\r\n"
|
||||
"jKGegQTnk52aaeScbDOjjx5h+m0hkDNSfsmXTlvJt2c8wy/Yx+leVgCPjMC1nbft\r\n"
|
||||
"Ob1TlpjuEAKBOGt4+DkWwVmIlxilmx9wCTZnwvPKd7A0e0FGsdHnQienPrMqlgbl\r\n"
|
||||
"JPYwJuECgYEA6yLZHTfX3ebpzcdQQqmuHZtbOcs+EGRy24gAzd+9vCGKf0VtKSl9\r\n"
|
||||
"3oA3XBOe2C2TgSgbWFZ7v/2efWRjgwJta0BQlpkzkh6NUQa2LI2M3zgZwHCZ7Ihr\r\n"
|
||||
"skG73qZsMHOOv7VQz/wDp6AZNasfz21Mcyh4uFzpkb3NKLXqsJ9LeG8CgYEAziEb\r\n"
|
||||
"yBCuhCKq7YZt/cHlbCbi7HbCYbub0isOCUtV0qPsX+kVZdPS+oGLPq1905JKdAe9\r\n"
|
||||
"O+4SltCw6qn9RgYnCCVQ47SGHg7KO8Z5vdcNUiDvsQ+jNFlmM5QBuf1UV/Y+DV/Q\r\n"
|
||||
"fZdA06OeYxkfPuBMtjdS9qMKwm3OsCkiQasWQykCgYAqALieAoq6JfSgALmyntLu\r\n"
|
||||
"kQDzyv2UOg1Wb+4M2KnxAGDYKVO9pZ7Jb0f0V8DpRwLxcHOqDRDgE/MK3TL1hSp8\r\n"
|
||||
"nSmILWfL8081KSjDvqlqeoAHI1YrrZbnadyggkQTR6E5V69O5+rTN8MpFh+Bkzmz\r\n"
|
||||
"3IfsDxTeJvSOECkTUfFOWwKBgQDG/id3yMLxRRaGH5TnuNvmwNOpPC0DdL5E8tOm\r\n"
|
||||
"HVhI9X8oSDgkCY5Pz+fBJnOmYEAIK8B/rqG7ftSMdnbPtvjPYFbqvEgNlHGfq0e0\r\n"
|
||||
"AXwWoT1ETbhcvUFw4Z2ZE/rswAe/mZQI6o/mwLoTKRmE9byY3Gf3OgcVFDTI060C\r\n"
|
||||
"gEwJoQKBgHpOmtGum3JuLpPc+PTXZOe29tdWndkFWktjPoow60d+NO2jpTFuEpmW\r\n"
|
||||
"XRW35vXI8PqMCmHOQ8YU59aMN9juAnsJmPUxbAW5fZfvVwWUo0cTOenfT6syrEYO\r\n"
|
||||
"n5NEG+mY4WZaOFRNiZu8+4aJI1yycXMyA22iKcU8+nN/sMAJs3Nx\r\n"
|
||||
"-----END RSA PRIVATE KEY-----\r\n";
|
||||
|
||||
/// Self-generated public key.
|
||||
/// Used to verify signatures generated with g_rsa2048CustomPrivateKey.
|
||||
static const u8 g_rsa2048CustomPublicKey[] = {
|
||||
0xBD, 0x54, 0x73, 0xB7, 0xEF, 0x26, 0x13, 0xBA, 0x04, 0xE1, 0x19, 0x26, 0x4A, 0x1D, 0xF0, 0xB3,
|
||||
0x80, 0x86, 0x94, 0x18, 0xFB, 0xBA, 0x11, 0xE4, 0x7F, 0x00, 0xA9, 0x3C, 0x5B, 0x27, 0xE1, 0x33,
|
||||
0x55, 0x74, 0xB4, 0x68, 0x61, 0x86, 0x35, 0xEE, 0x34, 0x18, 0x59, 0x3B, 0x5C, 0x39, 0x83, 0xCC,
|
||||
0x70, 0x7C, 0x70, 0x52, 0x98, 0x09, 0xCA, 0xCA, 0x46, 0x37, 0xC4, 0x06, 0x5C, 0x49, 0x09, 0xA9,
|
||||
0x8F, 0x23, 0x20, 0xBB, 0xF6, 0x78, 0xED, 0x23, 0x04, 0x6B, 0x60, 0xEC, 0x1A, 0xF6, 0x69, 0xF5,
|
||||
0x01, 0xA7, 0xAF, 0xF1, 0x04, 0xE3, 0x13, 0xD9, 0x19, 0x58, 0x55, 0x7E, 0x87, 0xE1, 0xAD, 0x54,
|
||||
0x03, 0x5F, 0x47, 0xCE, 0x67, 0x27, 0xF9, 0x3D, 0x61, 0x74, 0x3C, 0x12, 0xEA, 0x80, 0x58, 0xA6,
|
||||
0x2F, 0x2B, 0x25, 0x29, 0xB4, 0xFA, 0xAF, 0xB2, 0x07, 0x7E, 0x1D, 0xB9, 0xE3, 0x64, 0x56, 0xC9,
|
||||
0x38, 0x78, 0xA6, 0xE3, 0x08, 0xD3, 0x4A, 0x16, 0x2F, 0x97, 0x83, 0x23, 0x41, 0x8B, 0x8D, 0x5D,
|
||||
0xE7, 0xB4, 0x8F, 0x0A, 0xB9, 0x1C, 0x9B, 0xFF, 0x6D, 0x91, 0xA8, 0x11, 0xA2, 0xB1, 0x3C, 0xBC,
|
||||
0xB7, 0x05, 0x3D, 0xC5, 0xDC, 0x60, 0xE8, 0xDD, 0x5C, 0x7D, 0xCB, 0xE1, 0x74, 0xD7, 0xAB, 0xBB,
|
||||
0x31, 0xC7, 0x2B, 0x40, 0x23, 0xAE, 0x9E, 0xAD, 0xF4, 0x9C, 0xE1, 0x7B, 0xA7, 0x92, 0x82, 0xE2,
|
||||
0x7D, 0xC6, 0xDF, 0x30, 0xE0, 0x77, 0x82, 0x31, 0x82, 0xA1, 0x0B, 0x3A, 0x19, 0xF6, 0xA2, 0x01,
|
||||
0x4D, 0xD3, 0xC3, 0x17, 0xB0, 0x43, 0xB8, 0x5D, 0xA2, 0xAB, 0xE3, 0xE4, 0x69, 0xBD, 0x57, 0x21,
|
||||
0xEA, 0xCD, 0xE0, 0xC5, 0xE6, 0x65, 0x13, 0x96, 0x67, 0x9D, 0xD8, 0x8E, 0xA6, 0xE0, 0x42, 0xF1,
|
||||
0x6D, 0x5D, 0x5B, 0xD2, 0x55, 0x20, 0xB9, 0x1E, 0x59, 0x13, 0x3C, 0x17, 0xC2, 0x25, 0x56, 0xC7
|
||||
};
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
const u8 *rsa2048GetCustomPublicKey(void)
|
||||
{
|
||||
return g_rsa2048CustomPublicKey;
|
||||
}
|
||||
|
||||
bool rsa2048VerifySha256BasedPssSignature(const void *data, size_t data_size, const void *signature, const void *modulus, const void *public_exponent, size_t public_exponent_size)
|
||||
{
|
||||
if (!data || !data_size || !signature || !modulus || !public_exponent || !public_exponent_size)
|
||||
|
@ -131,72 +71,6 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool rsa2048GenerateSha256BasedPssSignature(void *dst, const void *src, size_t size)
|
||||
{
|
||||
if (!dst || !src || !size)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_pk_context pk;
|
||||
|
||||
size_t olen = 0;
|
||||
int mbedtls_ret = 0;
|
||||
const char *pers = __func__;
|
||||
u8 hash[SHA256_HASH_SIZE] = {0}, buf[MBEDTLS_MPI_MAX_SIZE] = {0};
|
||||
|
||||
bool ret = false;
|
||||
|
||||
/* Initialize contexts. */
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
mbedtls_pk_init(&pk);
|
||||
|
||||
/* Calculate SHA-256 checksum for the input data. */
|
||||
sha256CalculateHash(hash, src, size);
|
||||
|
||||
/* Seed the random number generator. */
|
||||
mbedtls_ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const u8*)pers, strlen(pers));
|
||||
if (mbedtls_ret != 0)
|
||||
{
|
||||
LOG_MSG("mbedtls_ctr_drbg_seed failed! (%d).", mbedtls_ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Parse private key. */
|
||||
mbedtls_ret = mbedtls_pk_parse_key(&pk, (const u8*)g_rsa2048CustomPrivateKey, strlen(g_rsa2048CustomPrivateKey) + 1, NULL, 0);
|
||||
if (mbedtls_ret != 0)
|
||||
{
|
||||
LOG_MSG("mbedtls_pk_parse_key failed! (%d).", mbedtls_ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Set RSA padding. */
|
||||
mbedtls_rsa_set_padding(mbedtls_pk_rsa(pk), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
|
||||
|
||||
/* Calculate hash signature. */
|
||||
mbedtls_ret = mbedtls_pk_sign(&pk, MBEDTLS_MD_SHA256, hash, 0, buf, &olen, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
if (mbedtls_ret != 0 || olen < RSA2048_SIG_SIZE)
|
||||
{
|
||||
LOG_MSG("mbedtls_pk_sign failed! (%d, %lu).", mbedtls_ret, olen);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Copy signature to output buffer. */
|
||||
memcpy(dst, buf, RSA2048_SIG_SIZE);
|
||||
ret = true;
|
||||
|
||||
end:
|
||||
mbedtls_pk_free(&pk);
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool rsa2048OaepDecrypt(void *dst, size_t dst_size, const void *signature, const void *modulus, const void *public_exponent, size_t public_exponent_size, const void *private_exponent, \
|
||||
size_t private_exponent_size, const void *label, size_t label_size, size_t *out_size)
|
||||
{
|
||||
|
|
10
todo.txt
10
todo.txt
|
@ -36,11 +36,6 @@ list of top level functions designed to alter nca data in order of (possible) us
|
|||
|
||||
* ncaRemoveTitlekeyCrypto (can be used with digital titles + game updates in gamecards)
|
||||
|
||||
* programInfoGenerateNcaPatch (Program)
|
||||
* calls npdmGenerateNcaPatch
|
||||
* calls pfsGenerateEntryPatch
|
||||
* calls ncaGenerateHierarchicalSha256Patch
|
||||
|
||||
* nacpGenerateNcaPatch (Control)
|
||||
* calls romfsGenerateFileEntryPatch
|
||||
* calls ncaGenerateHierarchicalSha256Patch / ncaGenerateHierarchicalIntegrityPatch
|
||||
|
@ -62,11 +57,6 @@ list of top level functions designed to alter nca data in order of (possible) us
|
|||
* calls pfsWriteEntryPatchToMemoryBuffer
|
||||
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer
|
||||
|
||||
* programInfoWriteNcaPatch (writes ndpm patch)
|
||||
* calls npdmWriteNcaPatch
|
||||
* calls pfsWriteEntryPatchToMemoryBuffer
|
||||
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer
|
||||
|
||||
* nacpWriteNcaPatch (writes nacp patch)
|
||||
* calls romfsWriteFileEntryPatchToMemoryBuffer
|
||||
* calls ncaWriteHierarchicalSha256PatchToMemoryBuffer / ncaWriteHierarchicalIntegrityPatchToMemoryBuffer
|
||||
|
|
Loading…
Reference in a new issue