mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-26 12:12:02 +00:00
More NCA changes.
This commit is contained in:
parent
9e337a5d0a
commit
8ce253d13d
4 changed files with 74 additions and 61 deletions
|
@ -37,7 +37,11 @@ extern "C" {
|
||||||
#define NCA_NCA2_MAGIC 0x4E434132 /* "NCA2". */
|
#define NCA_NCA2_MAGIC 0x4E434132 /* "NCA2". */
|
||||||
#define NCA_NCA3_MAGIC 0x4E434133 /* "NCA3". */
|
#define NCA_NCA3_MAGIC 0x4E434133 /* "NCA3". */
|
||||||
|
|
||||||
#define NCA_USED_KEY_AREA_SIZE sizeof(NcaDecryptedKeyArea) /* Four keys, 0x40 bytes. */
|
#define NCA_KEY_AREA_KEY_COUNT 0x10
|
||||||
|
#define NCA_KEY_AREA_SIZE (NCA_KEY_AREA_KEY_COUNT * AES_128_KEY_SIZE)
|
||||||
|
|
||||||
|
#define NCA_KEY_AREA_USED_KEY_COUNT 3
|
||||||
|
#define NCA_KEY_AREA_USED_SIZE (NCA_KEY_AREA_USED_KEY_COUNT * AES_128_KEY_SIZE)
|
||||||
|
|
||||||
#define NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT 5
|
#define NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT 5
|
||||||
|
|
||||||
|
@ -121,18 +125,22 @@ typedef struct {
|
||||||
NXDT_ASSERT(NcaFsHeaderHash, 0x20);
|
NXDT_ASSERT(NcaFsHeaderHash, 0x20);
|
||||||
|
|
||||||
/// Encrypted NCA key area used to hold NCA FS section encryption keys. Zeroed out if the NCA uses titlekey crypto.
|
/// Encrypted NCA key area used to hold NCA FS section encryption keys. Zeroed out if the NCA uses titlekey crypto.
|
||||||
/// Only the first 4 key entries are encrypted.
|
|
||||||
/// If a particular key entry is unused, it is zeroed out before this area is encrypted.
|
/// If a particular key entry is unused, it is zeroed out before this area is encrypted.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
union {
|
||||||
|
u8 keys[NCA_KEY_AREA_KEY_COUNT][AES_128_KEY_SIZE];
|
||||||
|
struct {
|
||||||
u8 aes_xts_1[AES_128_KEY_SIZE]; ///< AES-128-XTS key 0 used for NCA FS sections with NcaEncryptionType_AesXts crypto.
|
u8 aes_xts_1[AES_128_KEY_SIZE]; ///< AES-128-XTS key 0 used for NCA FS sections with NcaEncryptionType_AesXts crypto.
|
||||||
u8 aes_xts_2[AES_128_KEY_SIZE]; ///< AES-128-XTS key 1 used for NCA FS sections with NcaEncryptionType_AesXts crypto.
|
u8 aes_xts_2[AES_128_KEY_SIZE]; ///< AES-128-XTS key 1 used for NCA FS sections with NcaEncryptionType_AesXts crypto.
|
||||||
u8 aes_ctr[AES_128_KEY_SIZE]; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtr crypto.
|
u8 aes_ctr[AES_128_KEY_SIZE]; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtr* and NcaEncryptionType_AesCtrEx* crypto.
|
||||||
u8 aes_ctr_ex[AES_128_KEY_SIZE]; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtrEx crypto.
|
u8 aes_ctr_ex[AES_128_KEY_SIZE]; ///< Unused AES-128-CTR key.
|
||||||
u8 aes_ctr_hw[AES_128_KEY_SIZE]; ///< Unused AES-128-CTR key.
|
u8 aes_ctr_hw[AES_128_KEY_SIZE]; ///< Unused AES-128-CTR key.
|
||||||
u8 reserved[0xB0];
|
u8 reserved[0xB0];
|
||||||
|
};
|
||||||
|
};
|
||||||
} NcaEncryptedKeyArea;
|
} NcaEncryptedKeyArea;
|
||||||
|
|
||||||
NXDT_ASSERT(NcaEncryptedKeyArea, 0x100);
|
NXDT_ASSERT(NcaEncryptedKeyArea, NCA_KEY_AREA_SIZE);
|
||||||
|
|
||||||
/// First 0x400 bytes from every NCA.
|
/// First 0x400 bytes from every NCA.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -183,6 +191,12 @@ typedef enum {
|
||||||
NcaEncryptionType_AesCtrExSkipLayerHash = 6
|
NcaEncryptionType_AesCtrExSkipLayerHash = 6
|
||||||
} NcaEncryptionType;
|
} NcaEncryptionType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NcaMetaDataHashType_None = 0,
|
||||||
|
NcaMetaDataHashType_HierarchicalIntegrity = 1,
|
||||||
|
NcaMetaDataHashType_HierarchicalIntegritySha3 = 2
|
||||||
|
} NcaMetaDataHashType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u64 size;
|
u64 size;
|
||||||
|
@ -270,7 +284,7 @@ typedef struct {
|
||||||
|
|
||||||
NXDT_ASSERT(NcaBucketInfo, 0x20);
|
NXDT_ASSERT(NcaBucketInfo, 0x20);
|
||||||
|
|
||||||
/// Only used for NcaEncryptionType_AesCtrEx (PatchRomFs).
|
/// Only used for NcaEncryptionType_AesCtrEx and NcaEncryptionType_AesCtrExSkipLayerHash (PatchRomFs).
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NcaBucketInfo indirect_bucket;
|
NcaBucketInfo indirect_bucket;
|
||||||
NcaBucketInfo aes_ctr_ex_bucket;
|
NcaBucketInfo aes_ctr_ex_bucket;
|
||||||
|
@ -323,13 +337,14 @@ typedef struct {
|
||||||
u8 fs_type; ///< NcaFsType.
|
u8 fs_type; ///< NcaFsType.
|
||||||
u8 hash_type; ///< NcaHashType.
|
u8 hash_type; ///< NcaHashType.
|
||||||
u8 encryption_type; ///< NcaEncryptionType.
|
u8 encryption_type; ///< NcaEncryptionType.
|
||||||
u8 reserved_1[0x3];
|
u8 metadata_hash_type; ///< NcaMetaDataHashType.
|
||||||
|
u8 reserved_1[0x2];
|
||||||
NcaHashData hash_data;
|
NcaHashData hash_data;
|
||||||
NcaPatchInfo patch_info;
|
NcaPatchInfo patch_info;
|
||||||
NcaAesCtrUpperIv aes_ctr_upper_iv;
|
NcaAesCtrUpperIv aes_ctr_upper_iv;
|
||||||
NcaSparseInfo sparse_info;
|
NcaSparseInfo sparse_info;
|
||||||
NcaCompressionInfo compression_info;
|
NcaCompressionInfo compression_info;
|
||||||
NcaMetaDataHashDataInfo hash_data_info;
|
NcaMetaDataHashDataInfo metadata_hash_info;
|
||||||
u8 reserved_2[0x30];
|
u8 reserved_2[0x30];
|
||||||
} NcaFsHeader;
|
} NcaFsHeader;
|
||||||
|
|
||||||
|
@ -378,13 +393,17 @@ typedef enum {
|
||||||
} NcaVersion;
|
} NcaVersion;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
union {
|
||||||
|
u8 keys[NCA_KEY_AREA_USED_KEY_COUNT][AES_128_KEY_SIZE];
|
||||||
|
struct {
|
||||||
u8 aes_xts_1[AES_128_KEY_SIZE]; ///< AES-128-XTS key 0 used for NCA FS sections with NcaEncryptionType_AesXts crypto.
|
u8 aes_xts_1[AES_128_KEY_SIZE]; ///< AES-128-XTS key 0 used for NCA FS sections with NcaEncryptionType_AesXts crypto.
|
||||||
u8 aes_xts_2[AES_128_KEY_SIZE]; ///< AES-128-XTS key 1 used for NCA FS sections with NcaEncryptionType_AesXts crypto.
|
u8 aes_xts_2[AES_128_KEY_SIZE]; ///< AES-128-XTS key 1 used for NCA FS sections with NcaEncryptionType_AesXts crypto.
|
||||||
u8 aes_ctr[AES_128_KEY_SIZE]; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtr crypto.
|
u8 aes_ctr[AES_128_KEY_SIZE]; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtr and NcaEncryptionType_AesCtrSkipLayerHash crypto.
|
||||||
u8 aes_ctr_ex[AES_128_KEY_SIZE]; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtrEx crypto.
|
};
|
||||||
|
};
|
||||||
} NcaDecryptedKeyArea;
|
} NcaDecryptedKeyArea;
|
||||||
|
|
||||||
NXDT_ASSERT(NcaDecryptedKeyArea, 0x40);
|
NXDT_ASSERT(NcaDecryptedKeyArea, NCA_KEY_AREA_USED_SIZE);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 storage_id; ///< NcmStorageId.
|
u8 storage_id; ///< NcmStorageId.
|
||||||
|
|
|
@ -103,8 +103,8 @@ typedef enum {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 production : 1;
|
u32 production : 1;
|
||||||
u32 unqualified_approval : 1;
|
u32 unqualified_approval : 1;
|
||||||
u32 memory_region : 5; ///< NpdmMemoryRegion.
|
u32 memory_region : 4; ///< NpdmMemoryRegion.
|
||||||
u32 reserved : 25;
|
u32 reserved : 26;
|
||||||
} NpdmAcidFlags;
|
} NpdmAcidFlags;
|
||||||
|
|
||||||
NXDT_ASSERT(NpdmAcidFlags, 0x4);
|
NXDT_ASSERT(NpdmAcidFlags, 0x4);
|
||||||
|
|
|
@ -40,8 +40,9 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
||||||
|
|
||||||
if (!out || !base_nca_fs_ctx || !(base_nca_ctx = (NcaContext*)base_nca_fs_ctx->nca_ctx) || \
|
if (!out || !base_nca_fs_ctx || !(base_nca_ctx = (NcaContext*)base_nca_fs_ctx->nca_ctx) || \
|
||||||
!update_nca_fs_ctx || !update_nca_fs_ctx->enabled || !(update_nca_ctx = (NcaContext*)update_nca_fs_ctx->nca_ctx) || \
|
!update_nca_fs_ctx || !update_nca_fs_ctx->enabled || !(update_nca_ctx = (NcaContext*)update_nca_fs_ctx->nca_ctx) || \
|
||||||
update_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || update_nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx || \
|
update_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || (update_nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx && \
|
||||||
base_nca_ctx->header.program_id != update_nca_ctx->header.program_id || base_nca_ctx->header.content_type != update_nca_ctx->header.content_type || \
|
update_nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrExSkipLayerHash) || base_nca_ctx->header.program_id != update_nca_ctx->header.program_id || \
|
||||||
|
base_nca_ctx->header.content_type != update_nca_ctx->header.content_type || \
|
||||||
__builtin_bswap32(update_nca_fs_ctx->header.patch_info.indirect_bucket.header.magic) != NCA_BKTR_MAGIC || \
|
__builtin_bswap32(update_nca_fs_ctx->header.patch_info.indirect_bucket.header.magic) != NCA_BKTR_MAGIC || \
|
||||||
update_nca_fs_ctx->header.patch_info.indirect_bucket.header.version != NCA_BKTR_VERSION || \
|
update_nca_fs_ctx->header.patch_info.indirect_bucket.header.version != NCA_BKTR_VERSION || \
|
||||||
__builtin_bswap32(update_nca_fs_ctx->header.patch_info.aes_ctr_ex_bucket.header.magic) != NCA_BKTR_MAGIC || \
|
__builtin_bswap32(update_nca_fs_ctx->header.patch_info.aes_ctr_ex_bucket.header.magic) != NCA_BKTR_MAGIC || \
|
||||||
|
@ -58,7 +59,8 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
||||||
bktrFreeContext(out);
|
bktrFreeContext(out);
|
||||||
|
|
||||||
/* Update missing base NCA RomFS status. */
|
/* Update missing base NCA RomFS status. */
|
||||||
out->missing_base_romfs = (!base_nca_fs_ctx->enabled || base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || base_nca_fs_ctx->encryption_type == NcaEncryptionType_AesCtrEx);
|
out->missing_base_romfs = (!base_nca_fs_ctx->enabled || base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || \
|
||||||
|
(base_nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtr && base_nca_fs_ctx->encryption_type != NcaEncryptionType_AesCtrSkipLayerHash));
|
||||||
|
|
||||||
/* Initialize base NCA RomFS context. */
|
/* Initialize base NCA RomFS context. */
|
||||||
if (!out->missing_base_romfs && !romfsInitializeContext(&(out->base_romfs_ctx), base_nca_fs_ctx))
|
if (!out->missing_base_romfs && !romfsInitializeContext(&(out->base_romfs_ctx), base_nca_fs_ctx))
|
||||||
|
|
|
@ -278,7 +278,7 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
||||||
|
|
||||||
/* Initialize crypto data. */
|
/* Initialize crypto data. */
|
||||||
if ((!out->rights_id_available || (out->rights_id_available && out->titlekey_retrieved)) && fs_ctx->encryption_type > NcaEncryptionType_None && \
|
if ((!out->rights_id_available || (out->rights_id_available && out->titlekey_retrieved)) && fs_ctx->encryption_type > NcaEncryptionType_None && \
|
||||||
fs_ctx->encryption_type <= NcaEncryptionType_AesCtrEx)
|
fs_ctx->encryption_type <= NcaEncryptionType_AesCtrExSkipLayerHash)
|
||||||
{
|
{
|
||||||
/* Initialize the partial AES counter for this section. */
|
/* Initialize the partial AES counter for this section. */
|
||||||
aes128CtrInitializePartialCtr(fs_ctx->ctr, fs_ctx->header.aes_ctr_upper_iv.value, fs_ctx->section_offset);
|
aes128CtrInitializePartialCtr(fs_ctx->ctr, fs_ctx->header.aes_ctr_upper_iv.value, fs_ctx->section_offset);
|
||||||
|
@ -306,18 +306,12 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
||||||
aes128XtsContextCreate(&(fs_ctx->xts_decrypt_ctx), out->decrypted_key_area.aes_xts_1, out->decrypted_key_area.aes_xts_2, false);
|
aes128XtsContextCreate(&(fs_ctx->xts_decrypt_ctx), out->decrypted_key_area.aes_xts_1, out->decrypted_key_area.aes_xts_2, false);
|
||||||
aes128XtsContextCreate(&(fs_ctx->xts_encrypt_ctx), out->decrypted_key_area.aes_xts_1, out->decrypted_key_area.aes_xts_2, true);
|
aes128XtsContextCreate(&(fs_ctx->xts_encrypt_ctx), out->decrypted_key_area.aes_xts_1, out->decrypted_key_area.aes_xts_2, true);
|
||||||
} else
|
} else
|
||||||
if (fs_ctx->encryption_type == NcaEncryptionType_AesCtr || fs_ctx->encryption_type == NcaEncryptionType_AesCtrEx)
|
if (fs_ctx->encryption_type >= NcaEncryptionType_AesCtr && fs_ctx->encryption_type <= NcaEncryptionType_AesCtrExSkipLayerHash)
|
||||||
{
|
{
|
||||||
/* Patch RomFS sections also use the AES-128-CTR key from the decrypted NCA key area, for some reason. */
|
/* Patch RomFS sections also use the AES-128-CTR key from the decrypted NCA key area, for some reason. */
|
||||||
aes128CtrContextCreate(&(fs_ctx->ctr_ctx), out->decrypted_key_area.aes_ctr, fs_ctx->ctr);
|
aes128CtrContextCreate(&(fs_ctx->ctr_ctx), out->decrypted_key_area.aes_ctr, fs_ctx->ctr);
|
||||||
if (fs_ctx->has_sparse_layer) aes128CtrContextCreate(&(fs_ctx->sparse_ctr_ctx), out->decrypted_key_area.aes_ctr, fs_ctx->sparse_ctr);
|
if (fs_ctx->has_sparse_layer) aes128CtrContextCreate(&(fs_ctx->sparse_ctr_ctx), out->decrypted_key_area.aes_ctr, fs_ctx->sparse_ctr);
|
||||||
} /***else
|
}
|
||||||
if (fs_ctx->encryption_type == NcaEncryptionType_AesCtr)
|
|
||||||
{
|
|
||||||
aes128CtrContextCreate(&(fs_ctx->ctr_ctx), out->decrypted_key_area.aes_ctr, fs_ctx->ctr);
|
|
||||||
} else {
|
|
||||||
aes128CtrContextCreate(&(fs_ctx->ctr_ctx), out->decrypted_key_area.aes_ctr_ex, fs_ctx->ctr);
|
|
||||||
}***/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,15 +449,6 @@ bool ncaRemoveTitleKeyCrypto(NcaContext *ctx)
|
||||||
/* Patch RomFS sections also use the AES-128-CTR key from the decrypted NCA key area, for some reason. */
|
/* Patch RomFS sections also use the AES-128-CTR key from the decrypted NCA key area, for some reason. */
|
||||||
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);
|
||||||
|
|
||||||
/***for(u8 i = 0; i < NCA_FS_HEADER_COUNT; i++)
|
|
||||||
{
|
|
||||||
NcaFsSectionContext *fs_ctx = &(ctx->fs_ctx[i]);
|
|
||||||
if (!fs_ctx->enabled || (fs_ctx->encryption_type != NcaEncryptionType_AesCtr && fs_ctx->encryption_type != NcaEncryptionType_AesCtrEx)) continue;
|
|
||||||
|
|
||||||
u8 *key_ptr = (fs_ctx->encryption_type == NcaEncryptionType_AesCtr ? ctx->decrypted_key_area.aes_ctr : ctx->decrypted_key_area.aes_ctr_ex);
|
|
||||||
memcpy(key_ptr, ctx->titlekey, AES_128_KEY_SIZE);
|
|
||||||
}***/
|
|
||||||
|
|
||||||
/* Encrypt NCA key area. */
|
/* Encrypt NCA key area. */
|
||||||
if (!ncaEncryptKeyArea(ctx))
|
if (!ncaEncryptKeyArea(ctx))
|
||||||
{
|
{
|
||||||
|
@ -719,23 +704,25 @@ static bool ncaDecryptKeyArea(NcaContext *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 null_key[AES_128_KEY_SIZE] = {0};
|
const u8 null_key[AES_128_KEY_SIZE] = {0};
|
||||||
u8 key_count = (ctx->format_version == NcaVersion_Nca0 ? 2 : 4);
|
|
||||||
|
u8 key_count = NCA_KEY_AREA_USED_KEY_COUNT;
|
||||||
|
if (ctx->format_version == NcaVersion_Nca0) key_count--;
|
||||||
|
|
||||||
/* Check if we're dealing with a NCA0 with a plaintext key area. */
|
/* Check if we're dealing with a NCA0 with a plaintext key area. */
|
||||||
if (ncaIsVersion0KeyAreaEncrypted(ctx))
|
if (ncaIsVersion0KeyAreaEncrypted(ctx))
|
||||||
{
|
{
|
||||||
memcpy(&(ctx->decrypted_key_area), &(ctx->header.encrypted_key_area), NCA_USED_KEY_AREA_SIZE);
|
memcpy(&(ctx->decrypted_key_area), &(ctx->header.encrypted_key_area), sizeof(NcaDecryptedKeyArea));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear decrypted key area. */
|
/* Clear decrypted key area. */
|
||||||
memset(&(ctx->decrypted_key_area), 0, NCA_USED_KEY_AREA_SIZE);
|
memset(&(ctx->decrypted_key_area), 0, sizeof(NcaDecryptedKeyArea));
|
||||||
|
|
||||||
/* Process key area. */
|
/* Process key area. */
|
||||||
for(u8 i = 0; i < key_count; i++)
|
for(u8 i = 0; i < key_count; i++)
|
||||||
{
|
{
|
||||||
const u8 *src_key = ((u8*)&(ctx->header.encrypted_key_area) + (i * AES_128_KEY_SIZE));
|
const u8 *src_key = ctx->header.encrypted_key_area.keys[i];
|
||||||
u8 *dst_key = ((u8*)&(ctx->decrypted_key_area) + (i * AES_128_KEY_SIZE));
|
u8 *dst_key = ctx->decrypted_key_area.keys[i];
|
||||||
|
|
||||||
/* 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;
|
||||||
|
@ -759,14 +746,16 @@ static bool ncaEncryptKeyArea(NcaContext *ctx)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 key_count = (ctx->format_version == NcaVersion_Nca0 ? 2 : 4);
|
u8 key_count = NCA_KEY_AREA_USED_KEY_COUNT;
|
||||||
|
if (ctx->format_version == NcaVersion_Nca0) key_count--;
|
||||||
|
|
||||||
const u8 *kaek = NULL, null_key[AES_128_KEY_SIZE] = {0};
|
const u8 *kaek = NULL, null_key[AES_128_KEY_SIZE] = {0};
|
||||||
Aes128Context key_area_ctx = {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), NCA_USED_KEY_AREA_SIZE);
|
memcpy(&(ctx->header.encrypted_key_area), &(ctx->decrypted_key_area), sizeof(NcaDecryptedKeyArea));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,8 +776,8 @@ static bool ncaEncryptKeyArea(NcaContext *ctx)
|
||||||
/* Process key area. */
|
/* Process key area. */
|
||||||
for(u8 i = 0; i < key_count; i++)
|
for(u8 i = 0; i < key_count; i++)
|
||||||
{
|
{
|
||||||
const u8 *src_key = ((u8*)&(ctx->decrypted_key_area) + (i * AES_128_KEY_SIZE));
|
const u8 *src_key = ctx->decrypted_key_area.keys[i];
|
||||||
u8 *dst_key = ((u8*)&(ctx->header.encrypted_key_area) + (i * AES_128_KEY_SIZE));
|
u8 *dst_key = ctx->header.encrypted_key_area.keys[i];
|
||||||
|
|
||||||
/* 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;
|
||||||
|
@ -822,7 +811,7 @@ NX_INLINE bool ncaIsVersion0KeyAreaEncrypted(NcaContext *ctx)
|
||||||
if (!ctx || ctx->format_version != NcaVersion_Nca0) return false;
|
if (!ctx || ctx->format_version != NcaVersion_Nca0) return false;
|
||||||
|
|
||||||
u8 nca0_key_area_hash[SHA256_HASH_SIZE] = {0};
|
u8 nca0_key_area_hash[SHA256_HASH_SIZE] = {0};
|
||||||
sha256CalculateHash(nca0_key_area_hash, &(ctx->header.encrypted_key_area), NCA_USED_KEY_AREA_SIZE);
|
sha256CalculateHash(nca0_key_area_hash, &(ctx->header.encrypted_key_area), 4 * AES_128_KEY_SIZE);
|
||||||
return (memcmp(nca0_key_area_hash, g_nca0KeyAreaHash, SHA256_HASH_SIZE) != 0);
|
return (memcmp(nca0_key_area_hash, g_nca0KeyAreaHash, SHA256_HASH_SIZE) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -847,8 +836,8 @@ NX_INLINE bool ncaCheckRightsIdAvailability(NcaContext *ctx)
|
||||||
static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size, u64 offset)
|
static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size, u64 offset)
|
||||||
{
|
{
|
||||||
if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || !ctx->nca_ctx || ctx->section_num >= NCA_FS_HEADER_COUNT || ctx->section_offset < sizeof(NcaHeader) || \
|
if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || !ctx->nca_ctx || ctx->section_num >= NCA_FS_HEADER_COUNT || ctx->section_offset < sizeof(NcaHeader) || \
|
||||||
ctx->section_type >= NcaFsSectionType_Invalid || ctx->encryption_type == NcaEncryptionType_Auto || ctx->encryption_type > NcaEncryptionType_AesCtrEx || !out || !read_size || \
|
ctx->section_type >= NcaFsSectionType_Invalid || ctx->encryption_type == NcaEncryptionType_Auto || ctx->encryption_type > NcaEncryptionType_AesCtrExSkipLayerHash || \
|
||||||
(offset + read_size) > ctx->section_size)
|
!out || !read_size || (offset + read_size) > ctx->section_size)
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid NCA FS section header parameters!");
|
LOG_MSG("Invalid NCA FS section header parameters!");
|
||||||
return false;
|
return false;
|
||||||
|
@ -875,7 +864,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
||||||
/* Optimization for reads from plaintext FS sections or reads that are aligned to the AES-CTR / AES-XTS sector size. */
|
/* Optimization for reads from plaintext FS sections or reads that are aligned to the AES-CTR / AES-XTS sector size. */
|
||||||
if (ctx->encryption_type == NcaEncryptionType_None || \
|
if (ctx->encryption_type == NcaEncryptionType_None || \
|
||||||
(ctx->encryption_type == NcaEncryptionType_AesXts && !(content_offset % NCA_AES_XTS_SECTOR_SIZE) && !(read_size % NCA_AES_XTS_SECTOR_SIZE)) || \
|
(ctx->encryption_type == NcaEncryptionType_AesXts && !(content_offset % NCA_AES_XTS_SECTOR_SIZE) && !(read_size % NCA_AES_XTS_SECTOR_SIZE)) || \
|
||||||
((ctx->encryption_type == NcaEncryptionType_AesCtr || ctx->encryption_type == NcaEncryptionType_AesCtrEx) && !(content_offset % AES_BLOCK_SIZE) && !(read_size % AES_BLOCK_SIZE)))
|
(ctx->encryption_type >= NcaEncryptionType_AesCtr && ctx->encryption_type <= NcaEncryptionType_AesCtrExSkipLayerHash && !(content_offset % AES_BLOCK_SIZE) && !(read_size % AES_BLOCK_SIZE)))
|
||||||
{
|
{
|
||||||
/* Read data. */
|
/* Read data. */
|
||||||
if (!ncaReadContentFile(nca_ctx, out, read_size, content_offset))
|
if (!ncaReadContentFile(nca_ctx, out, read_size, content_offset))
|
||||||
|
@ -904,7 +893,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
if (ctx->encryption_type == NcaEncryptionType_AesCtr || ctx->encryption_type == NcaEncryptionType_AesCtrEx)
|
if (ctx->encryption_type >= NcaEncryptionType_AesCtr && ctx->encryption_type <= NcaEncryptionType_AesCtrExSkipLayerHash)
|
||||||
{
|
{
|
||||||
aes128CtrUpdatePartialCtr(ctx->ctr, content_offset);
|
aes128CtrUpdatePartialCtr(ctx->ctr, content_offset);
|
||||||
aes128CtrContextResetCtr(&(ctx->ctr_ctx), ctx->ctr);
|
aes128CtrContextResetCtr(&(ctx->ctr_ctx), ctx->ctr);
|
||||||
|
@ -945,7 +934,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
if (ctx->encryption_type == NcaEncryptionType_AesCtr || ctx->encryption_type == NcaEncryptionType_AesCtrEx)
|
if (ctx->encryption_type >= NcaEncryptionType_AesCtr && ctx->encryption_type <= NcaEncryptionType_AesCtrExSkipLayerHash)
|
||||||
{
|
{
|
||||||
aes128CtrUpdatePartialCtr(ctx->ctr, block_start_offset);
|
aes128CtrUpdatePartialCtr(ctx->ctr, block_start_offset);
|
||||||
aes128CtrContextResetCtr(&(ctx->ctr_ctx), ctx->ctr);
|
aes128CtrContextResetCtr(&(ctx->ctr_ctx), ctx->ctr);
|
||||||
|
@ -964,7 +953,8 @@ end:
|
||||||
static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, void *out, u64 read_size, u64 offset, u32 ctr_val)
|
static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, void *out, u64 read_size, u64 offset, u32 ctr_val)
|
||||||
{
|
{
|
||||||
if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || !ctx->nca_ctx || ctx->section_num >= NCA_FS_HEADER_COUNT || ctx->section_offset < sizeof(NcaHeader) || \
|
if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || !ctx->nca_ctx || ctx->section_num >= NCA_FS_HEADER_COUNT || ctx->section_offset < sizeof(NcaHeader) || \
|
||||||
ctx->section_type != NcaFsSectionType_PatchRomFs || ctx->encryption_type != NcaEncryptionType_AesCtrEx || !out || !read_size || (offset + read_size) > ctx->section_size)
|
ctx->section_type != NcaFsSectionType_PatchRomFs || (ctx->encryption_type != NcaEncryptionType_AesCtrEx && ctx->encryption_type != NcaEncryptionType_AesCtrExSkipLayerHash) || \
|
||||||
|
!out || !read_size || (offset + read_size) > ctx->section_size)
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid NCA FS section header parameters!");
|
LOG_MSG("Invalid NCA FS section header parameters!");
|
||||||
return false;
|
return false;
|
||||||
|
@ -1277,9 +1267,11 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
||||||
u8 *out = NULL;
|
u8 *out = NULL;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
|
// TODO: add support for Sha3 layers and SkipLayer crypto types.
|
||||||
if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || ctx->has_sparse_layer || !ctx->nca_ctx || ctx->section_num >= NCA_FS_HEADER_COUNT || ctx->section_offset < sizeof(NcaHeader) || \
|
if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || ctx->has_sparse_layer || !ctx->nca_ctx || ctx->section_num >= NCA_FS_HEADER_COUNT || ctx->section_offset < sizeof(NcaHeader) || \
|
||||||
ctx->section_type >= NcaFsSectionType_Invalid || ctx->encryption_type == NcaEncryptionType_Auto || ctx->encryption_type >= NcaEncryptionType_AesCtrEx || !data || !data_size || \
|
ctx->hash_type < NcaHashType_HierarchicalSha256 || ctx->hash_type > NcaHashType_HierarchicalIntegrity || ctx->encryption_type == NcaEncryptionType_Auto || \
|
||||||
(data_offset + data_size) > ctx->section_size || !out_block_size || !out_block_offset)
|
ctx->encryption_type >= NcaEncryptionType_AesCtrEx || ctx->section_type >= NcaFsSectionType_Invalid || !data || !data_size || (data_offset + data_size) > ctx->section_size || \
|
||||||
|
!out_block_size || !out_block_offset)
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid NCA FS section header parameters!");
|
LOG_MSG("Invalid NCA FS section header parameters!");
|
||||||
goto end;
|
goto end;
|
||||||
|
|
Loading…
Reference in a new issue