1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-26 20:22:17 +00:00

NPDM ACID public key replacement + NCA ACID signature recalculation.

This commit is contained in:
Pablo Curiel 2020-10-10 17:08:17 -04:00
parent 2066b11d5a
commit 9f010c4129
7 changed files with 78 additions and 12 deletions

View file

@ -143,6 +143,9 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
return false; return false;
} }
/* Calculate decrypted header hash. */
sha256CalculateHash(out->header_hash, &(out->header), sizeof(NcaHeader));
if (out->rights_id_available) if (out->rights_id_available)
{ {
/* Retrieve ticket. */ /* Retrieve ticket. */
@ -363,7 +366,6 @@ void ncaRemoveTitlekeyCrypto(NcaContext *ctx)
/* Update context flags. */ /* Update context flags. */
ctx->rights_id_available = false; ctx->rights_id_available = false;
ctx->dirty_header = true;
} }
bool ncaEncryptHeader(NcaContext *ctx) bool ncaEncryptHeader(NcaContext *ctx)
@ -375,7 +377,7 @@ bool ncaEncryptHeader(NcaContext *ctx)
} }
/* Safety check: don't encrypt the header if we don't need to. */ /* Safety check: don't encrypt the header if we don't need to. */
if (!ctx->dirty_header) return true; if (!ncaIsHeaderDirty(ctx)) return true;
size_t crypt_res = 0; size_t crypt_res = 0;
const u8 *header_key = keysGetNcaHeaderKey(); const u8 *header_key = keysGetNcaHeaderKey();
@ -1068,9 +1070,6 @@ static bool ncaGenerateHashDataPatch(NcaFsSectionContext *ctx, const void *data,
/* Recalculate FS header hash. */ /* Recalculate FS header hash. */
sha256CalculateHash(nca_ctx->header.fs_header_hash[ctx->section_num].hash, &(ctx->header), sizeof(NcaFsHeader)); sha256CalculateHash(nca_ctx->header.fs_header_hash[ctx->section_num].hash, &(ctx->header), sizeof(NcaFsHeader));
/* Enable the 'dirty_header' flag. */
nca_ctx->dirty_header = true;
/* Copy content ID. */ /* Copy content ID. */
memcpy(!is_integrity_patch ? &(hierarchical_sha256_patch->content_id) : &(hierarchical_integrity_patch->content_id), &(nca_ctx->content_id), sizeof(NcmContentId)); memcpy(!is_integrity_patch ? &(hierarchical_sha256_patch->content_id) : &(hierarchical_integrity_patch->content_id), &(nca_ctx->content_id), sizeof(NcmContentId));

View file

@ -48,6 +48,8 @@
#define NCA_AES_XTS_SECTOR_SIZE 0x200 #define NCA_AES_XTS_SECTOR_SIZE 0x200
#define NCA_ACID_SIGNATURE_AREA_SIZE 0x100 /* Signature is calculated starting at the NCA header magic word. */
typedef enum { typedef enum {
NcaDistributionType_Download = 0, NcaDistributionType_Download = 0,
NcaDistributionType_GameCard = 1 NcaDistributionType_GameCard = 1
@ -312,8 +314,8 @@ typedef struct {
bool rights_id_available; bool rights_id_available;
bool titlekey_retrieved; bool titlekey_retrieved;
u8 titlekey[AES_128_KEY_SIZE]; ///< Decrypted titlekey from the ticket. u8 titlekey[AES_128_KEY_SIZE]; ///< Decrypted titlekey from the ticket.
bool dirty_header;
NcaHeader header; ///< NCA header. NcaHeader header; ///< NCA header.
u8 header_hash[SHA256_HASH_SIZE]; ///< NCA header hash. Used to determine if it's necessary to replace the NCA header while dumping this NCA.
NcaFsSectionContext fs_contexts[NCA_FS_HEADER_COUNT]; NcaFsSectionContext fs_contexts[NCA_FS_HEADER_COUNT];
NcaDecryptedKeyArea decrypted_key_area; NcaDecryptedKeyArea decrypted_key_area;
} NcaContext; } NcaContext;
@ -368,7 +370,7 @@ void *ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const void *d
/// Generates HierarchicalSha256 FS section patch data, which can be used to seamlessly replace NCA data. /// Generates HierarchicalSha256 FS section patch data, which can be used to seamlessly replace NCA data.
/// Input offset must be relative to the start of the last HierarchicalSha256 hash region (actual underlying FS). /// Input offset must be relative to the start of the last HierarchicalSha256 hash region (actual underlying FS).
/// Bear in mind that this function recalculates both the NcaHashData block master hash and the NCA FS header hash from the NCA header, and enables the 'dirty_header' flag from the NCA context. /// Bear in mind that this function recalculates both the NcaHashData block master hash and the NCA FS header hash from the NCA header.
/// As such, this function is not designed to generate more than one patch per HierarchicalSha256 FS section. /// As such, this function is not designed to generate more than one patch per HierarchicalSha256 FS section.
bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *data, u64 data_size, u64 data_offset, NcaHierarchicalSha256Patch *out); bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *data, u64 data_size, u64 data_offset, NcaHierarchicalSha256Patch *out);
@ -378,7 +380,7 @@ void ncaWriteHierarchicalSha256PatchToMemoryBuffer(NcaContext *ctx, NcaHierarchi
/// Generates HierarchicalIntegrity FS section patch data, which can be used to seamlessly replace NCA data. /// Generates HierarchicalIntegrity FS section patch data, which can be used to seamlessly replace NCA data.
/// Input offset must be relative to the start of the last HierarchicalIntegrity hash level (actual underlying FS). /// Input offset must be relative to the start of the last HierarchicalIntegrity hash level (actual underlying FS).
/// Bear in mind that this function recalculates both the NcaHashData block master hash and the NCA FS header hash from the NCA header, and enables the 'dirty_header' flag from the NCA context. /// Bear in mind that this function recalculates both the NcaHashData block master hash and the NCA FS header hash from the NCA header.
/// As such, this function is not designed to generate more than one patch per HierarchicalIntegrity FS section. /// As such, this function is not designed to generate more than one patch per HierarchicalIntegrity FS section.
bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void *data, u64 data_size, u64 data_offset, NcaHierarchicalIntegrityPatch *out); bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void *data, u64 data_size, u64 data_offset, NcaHierarchicalIntegrityPatch *out);
@ -425,7 +427,14 @@ NX_INLINE void ncaSetDownloadDistributionType(NcaContext *ctx)
{ {
if (!ctx || ctx->header.distribution_type == NcaDistributionType_Download) return; if (!ctx || ctx->header.distribution_type == NcaDistributionType_Download) return;
ctx->header.distribution_type = NcaDistributionType_Download; ctx->header.distribution_type = NcaDistributionType_Download;
ctx->dirty_header = true; }
NX_INLINE bool ncaIsHeaderDirty(NcaContext *ctx)
{
if (!ctx) return false;
u8 tmp_hash[SHA256_HASH_SIZE] = {0};
sha256CalculateHash(tmp_hash, &(ctx->header), sizeof(NcaHeader));
return (memcmp(tmp_hash, ctx->header_hash, SHA256_HASH_SIZE) != 0);
} }
NX_INLINE bool ncaValidateHierarchicalSha256Offsets(NcaHierarchicalSha256Data *hierarchical_sha256_data, u64 section_size) NX_INLINE bool ncaValidateHierarchicalSha256Offsets(NcaHierarchicalSha256Data *hierarchical_sha256_data, u64 section_size)

View file

@ -20,6 +20,7 @@
#include "utils.h" #include "utils.h"
#include "npdm.h" #include "npdm.h"
#include "rsa.h"
bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx) bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx)
{ {
@ -259,3 +260,26 @@ end:
return success; return success;
} }
bool npdmChangeAcidPublicKeyAndNcaSignature(NpdmContext *npdm_ctx)
{
NcaContext *nca_ctx = NULL;
if (!npdmIsValidContext(npdm_ctx) || !(nca_ctx = (NcaContext*)npdm_ctx->pfs_ctx->nca_fs_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program)
{
LOGFILE("Invalid parameters!");
return false;
}
/* Update NPDM ACID public key. */
memcpy(npdm_ctx->acid_header->public_key, rsa2048GetCustomPublicKey(), RSA2048_PUBKEY_SIZE);
/* Update NCA ACID signature. */
if (!rsa2048GenerateSha256BasedPssSignature(nca_ctx->header.acid_signature, &(nca_ctx->header.magic), NCA_ACID_SIGNATURE_AREA_SIZE))
{
LOGFILE("Failed to generate RSA-2048-PSS NCA ACID signature!");
return false;
}
return true;
}

View file

@ -555,6 +555,9 @@ typedef struct {
/// Initializes a NpdmContext using a previously initialized PartitionFileSystemContext (which must belong to the ExeFS from a Program NCA). /// 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); bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx);
/// Changes the ACID public key from the NPDM in the input NpdmContext and updates the ACID signature from the NCA header in the underlying NCA context.
bool npdmChangeAcidPublicKeyAndNcaSignature(NpdmContext *npdm_ctx);
/// Helper inline functions. /// Helper inline functions.
NX_INLINE void npdmFreeContext(NpdmContext *npdm_ctx) NX_INLINE void npdmFreeContext(NpdmContext *npdm_ctx)

View file

@ -107,4 +107,36 @@ typedef struct {
char name[]; char name[];
} NsoModuleInfo; } NsoModuleInfo;
/*
typedef struct {
PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where this NSO is stored.
PartitionFileSystemEntry *pfs_entry; ///< PartitionFileSystemEntry for this NSO in the Program NCA FS section #0. Used to read NSO data.
NsoHeader nso_header; ///< Copy of the NSO header.
} NsoContext;
*/
#endif /* __NSO_H__ */ #endif /* __NSO_H__ */

View file

@ -26,6 +26,7 @@
#define __RSA_H__ #define __RSA_H__
#define RSA2048_SIG_SIZE 0x100 #define RSA2048_SIG_SIZE 0x100
#define RSA2048_PUBKEY_SIZE RSA2048_SIG_SIZE
/// Generates a RSA-2048-PSS with SHA-256 signature using a custom RSA-2048 private key. /// 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. /// Suitable to replace the ACID signature in a Program NCA header.

View file

@ -1,10 +1,8 @@
todo: todo:
nca: functions for fs section lookup? (could just let the user choose...) nca: functions for fs section lookup? (could just let the user choose...)
nca: add encrypted headers to nca context, avoid re-encrypting plaintext headers in place
nca: function to write re-encrypted nca headers / nca fs headers (don't forget nca0 please) nca: function to write re-encrypted nca headers / nca fs headers (don't forget nca0 please)
nca: function to patch the private npdm acid signature from a program nca + patch the acid signature from the nca header
nca: add encrypted header to nca context, avoid re-encrypting the plaintext header in place
nca: use hash instead of dirty_header flag?
tik: option to wipe elicense property mask tik: option to wipe elicense property mask
tik: automatically dump tickets to the SD card? tik: automatically dump tickets to the SD card?