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:
parent
2066b11d5a
commit
9f010c4129
7 changed files with 78 additions and 12 deletions
|
@ -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));
|
||||||
|
|
||||||
|
|
17
source/nca.h
17
source/nca.h
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
32
source/nso.h
32
source/nso.h
|
@ -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__ */
|
||||||
|
|
|
@ -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.
|
||||||
|
|
4
todo.txt
4
todo.txt
|
@ -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?
|
||||||
|
|
Loading…
Reference in a new issue