2020-04-16 01:06:41 +01:00
/*
2020-07-03 10:31:22 +01:00
* nca . h
2020-04-16 01:06:41 +01:00
*
2020-07-03 10:31:22 +01:00
* Copyright ( c ) 2020 , 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
2020-04-16 01:06:41 +01:00
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
2020-07-03 10:31:22 +01:00
* nxdumptool is distributed in the hope it will be useful , but WITHOUT
2020-04-16 01:06:41 +01:00
* 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 < http : //www.gnu.org/licenses/>.
*/
2020-04-11 06:28:26 +01:00
# pragma once
# ifndef __NCA_H__
# define __NCA_H__
2020-04-20 11:39:41 +01:00
# include "tik.h"
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
# define NCA_FS_HEADER_COUNT 4
# define NCA_FULL_HEADER_LENGTH (sizeof(NcaHeader) + (sizeof(NcaFsHeader) * NCA_FS_HEADER_COUNT))
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
# define NCA_NCA0_MAGIC 0x4E434130 /* "NCA0". */
# define NCA_NCA2_MAGIC 0x4E434132 /* "NCA2". */
# define NCA_NCA3_MAGIC 0x4E434133 /* "NCA3". */
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
# define NCA_USED_KEY_AREA_SIZE sizeof(NcaDecryptedKeyArea) /* Four keys, 0x40 bytes. */
2020-04-26 09:35:01 +01:00
2020-07-22 09:03:28 +01:00
# define NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT 5
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
# define NCA_IVFC_MAGIC 0x49564643 /* "IVFC". */
# define NCA_IVFC_MAX_LEVEL_COUNT 7
# define NCA_IVFC_LEVEL_COUNT (NCA_IVFC_MAX_LEVEL_COUNT - 1)
# define NCA_IVFC_BLOCK_SIZE(x) (1U << (x))
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
# define NCA_BKTR_MAGIC 0x424B5452 /* "BKTR". */
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
# define NCA_FS_SECTOR_SIZE 0x200
# define NCA_FS_SECTOR_OFFSET(x) ((u64)(x) * NCA_FS_SECTOR_SIZE)
# define NCA_AES_XTS_SECTOR_SIZE 0x200
2020-04-11 06:28:26 +01:00
2020-04-15 21:50:07 +01:00
typedef enum {
NcaDistributionType_Download = 0 ,
NcaDistributionType_GameCard = 1
} NcaDistributionType ;
2020-04-11 06:28:26 +01:00
2020-04-15 21:50:07 +01:00
typedef enum {
2020-05-01 16:06:24 +01:00
NcaContentType_Program = 0 ,
NcaContentType_Meta = 1 ,
NcaContentType_Control = 2 ,
NcaContentType_Manual = 3 ,
NcaContentType_Data = 4 ,
NcaContentType_PublicData = 5
2020-04-15 21:50:07 +01:00
} NcaContentType ;
2020-04-11 06:28:26 +01:00
2020-04-15 21:50:07 +01:00
typedef enum {
NcaKeyGenerationOld_100_230 = 0 ,
NcaKeyGenerationOld_300 = 2
} NcaKeyGenerationOld ;
2020-04-11 06:28:26 +01:00
2020-04-15 21:50:07 +01:00
typedef enum {
NcaKeyAreaEncryptionKeyIndex_Application = 0 ,
NcaKeyAreaEncryptionKeyIndex_Ocean = 1 ,
NcaKeyAreaEncryptionKeyIndex_System = 2
} NcaKeyAreaEncryptionKeyIndex ;
2020-04-11 06:28:26 +01:00
2020-04-27 23:37:15 +01:00
typedef struct {
2020-07-15 23:50:34 +01:00
u32 NcaSdkAddOnVersion_Relstep : 8 ;
u32 NcaSdkAddOnVersion_Micro : 8 ;
u32 NcaSdkAddOnVersion_Minor : 8 ;
u32 NcaSdkAddOnVersion_Major : 8 ;
2020-04-27 23:37:15 +01:00
} NcaSdkAddOnVersion ;
/// 'NcaKeyGeneration_Current' will always point to the last known key generation value.
2020-04-11 06:28:26 +01:00
typedef enum {
2020-04-28 03:33:38 +01:00
NcaKeyGeneration_301_302 = 3 ,
NcaKeyGeneration_400_410 = 4 ,
NcaKeyGeneration_500_510 = 5 ,
NcaKeyGeneration_600_610 = 6 ,
NcaKeyGeneration_620 = 7 ,
NcaKeyGeneration_700_801 = 8 ,
NcaKeyGeneration_810_811 = 9 ,
NcaKeyGeneration_900_901 = 10 ,
2020-07-03 10:31:22 +01:00
NcaKeyGeneration_910_1004 = 11 ,
NcaKeyGeneration_Current = NcaKeyGeneration_910_1004
2020-04-15 21:50:07 +01:00
} NcaKeyGeneration ;
typedef struct {
2020-07-22 09:03:28 +01:00
u32 start_sector ; ///< Expressed in NCA_FS_SECTOR_SIZE sectors.
u32 end_sector ; ///< Expressed in NCA_FS_SECTOR_SIZE sectors.
u32 hash_sector ;
u8 reserved [ 0x4 ] ;
} NcaFsInfo ;
2020-04-11 06:28:26 +01:00
typedef struct {
2020-04-15 21:50:07 +01:00
u8 hash [ SHA256_HASH_SIZE ] ;
2020-07-22 09:03:28 +01:00
} NcaFsHeaderHash ;
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
/// 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.
typedef 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_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_ex [ AES_128_KEY_SIZE ] ; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtrEx crypto.
u8 aes_ctr_hw [ AES_128_KEY_SIZE ] ; ///< Unused AES-128-CTR key.
u8 reserved [ 0xB0 ] ;
} NcaEncryptedKeyArea ;
/// First 0x400 bytes from every NCA.
2020-04-11 06:28:26 +01:00
typedef struct {
2020-07-22 09:03:28 +01:00
u8 main_signature [ 0x100 ] ; ///< RSA-PSS signature over header with fixed key.
u8 acid_signature [ 0x100 ] ; ///< RSA-PSS signature over header with key in NPDM.
u32 magic ; ///< "NCA0" / "NCA2" / "NCA3".
u8 distribution_type ; ///< NcaDistributionType.
u8 content_type ; ///< NcaContentType.
u8 key_generation_old ; ///< NcaKeyGenerationOld.
u8 kaek_index ; ///< NcaKeyAreaEncryptionKeyIndex.
u64 content_size ;
u64 program_id ;
u32 content_index ;
NcaSdkAddOnVersion sdk_addon_version ;
u8 key_generation ; ///< NcaKeyGeneration.
u8 main_signature_key_generation ;
u8 reserved_1 [ 0xE ] ;
FsRightsId rights_id ; ///< Used for titlekey crypto.
NcaFsInfo fs_info [ NCA_FS_HEADER_COUNT ] ; ///< Start and end sectors for each NCA FS section.
NcaFsHeaderHash fs_header_hash [ NCA_FS_HEADER_COUNT ] ; ///< SHA-256 hashes calculated over each NCA FS section header.
NcaEncryptedKeyArea encrypted_key_area ;
} NcaHeader ;
2020-04-11 06:28:26 +01:00
2020-04-15 21:50:07 +01:00
typedef enum {
NcaFsType_RomFs = 0 ,
NcaFsType_PartitionFs = 1
} NcaFsType ;
2020-04-11 06:28:26 +01:00
2020-04-15 21:50:07 +01:00
typedef enum {
NcaHashType_Auto = 0 ,
NcaHashType_None = 1 ,
NcaHashType_HierarchicalSha256 = 2 , ///< Used by NcaFsType_PartitionFs.
NcaHashType_HierarchicalIntegrity = 3 ///< Used by NcaFsType_RomFs.
} NcaHashType ;
2020-04-11 06:28:26 +01:00
2020-04-15 21:50:07 +01:00
typedef enum {
NcaEncryptionType_Auto = 0 ,
NcaEncryptionType_None = 1 ,
NcaEncryptionType_AesXts = 2 ,
NcaEncryptionType_AesCtr = 3 ,
2020-04-29 13:59:28 +01:00
NcaEncryptionType_AesCtrEx = 4
2020-04-15 21:50:07 +01:00
} NcaEncryptionType ;
2020-04-11 06:28:26 +01:00
typedef struct {
2020-04-15 21:50:07 +01:00
u64 offset ;
u64 size ;
2020-07-22 09:03:28 +01:00
} NcaRegion ;
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
/// Used by NcaFsType_PartitionFs and NCA0 NcaFsType_RomFs.
2020-04-11 06:28:26 +01:00
typedef struct {
2020-04-15 21:50:07 +01:00
u8 master_hash [ SHA256_HASH_SIZE ] ;
u32 hash_block_size ;
2020-07-22 09:03:28 +01:00
u32 hash_region_count ;
NcaRegion hash_region [ NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT ] ;
} NcaHierarchicalSha256Data ;
2020-04-11 06:28:26 +01:00
typedef struct {
u64 offset ;
u64 size ;
2020-07-22 09:03:28 +01:00
u32 block_order ; ///< Use NCA_IVFC_BLOCK_SIZE to calculate the actual block size using this value.
2020-04-15 21:50:07 +01:00
u8 reserved [ 0x4 ] ;
2020-07-22 09:03:28 +01:00
} NcaHierarchicalIntegrityVerificationLevelInformation ;
typedef struct {
u8 value [ 0x20 ] ;
} NcaSignatureSalt ;
# pragma pack(push, 1)
typedef struct {
u32 max_level_count ; ///< Always NCA_IVFC_MAX_LEVEL_COUNT.
NcaHierarchicalIntegrityVerificationLevelInformation level_information [ NCA_IVFC_LEVEL_COUNT ] ;
NcaSignatureSalt signature_salt ;
} NcaInfoLevelHash ;
# pragma pack(pop)
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
/// Used by NcaFsType_RomFs.
2020-04-11 06:28:26 +01:00
typedef struct {
2020-07-22 09:03:28 +01:00
u32 magic ; ///< "IVFC".
2020-04-15 21:50:07 +01:00
u32 version ;
2020-07-22 09:03:28 +01:00
u32 master_hash_size ; ///< Always SHA256_HASH_SIZE.
NcaInfoLevelHash info_level_hash ;
u8 master_hash [ SHA256_HASH_SIZE ] ;
} NcaIntegrityMetaInfo ;
2020-04-11 06:28:26 +01:00
typedef struct {
union {
struct {
2020-04-20 11:39:41 +01:00
///< Used if hash_type == NcaHashType_HierarchicalSha256 (NcaFsType_PartitionFs and NCA0 NcaFsType_RomFs).
2020-07-22 09:03:28 +01:00
NcaHierarchicalSha256Data hierarchical_sha256_data ;
u8 reserved_1 [ 0x80 ] ;
2020-04-11 06:28:26 +01:00
} ;
struct {
2020-04-15 21:50:07 +01:00
///< Used if hash_type == NcaHashType_HierarchicalIntegrity (NcaFsType_RomFs).
2020-07-22 09:03:28 +01:00
NcaIntegrityMetaInfo integrity_meta_info ;
2020-04-15 21:50:07 +01:00
u8 reserved_2 [ 0x18 ] ;
2020-04-11 06:28:26 +01:00
} ;
} ;
2020-07-22 09:03:28 +01:00
} NcaHashData ;
2020-04-11 06:28:26 +01:00
typedef struct {
2020-04-15 21:50:07 +01:00
u32 magic ; ///< "BKTR".
2020-07-22 09:03:28 +01:00
u32 version ; ///< offset_count / node_count ?
2020-04-15 21:50:07 +01:00
u32 entry_count ;
u8 reserved [ 0x4 ] ;
} NcaBucketTreeHeader ;
2020-04-11 06:28:26 +01:00
typedef struct {
2020-07-22 09:03:28 +01:00
u64 offset ;
u64 size ;
NcaBucketTreeHeader header ;
} NcaBucketInfo ;
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
/// Only used for NcaEncryptionType_AesCtrEx (PatchRomFs).
2020-04-11 06:28:26 +01:00
typedef struct {
2020-07-22 09:03:28 +01:00
NcaBucketInfo indirect_bucket ;
NcaBucketInfo aes_ctr_ex_bucket ;
} NcaPatchInfo ;
2020-04-11 06:28:26 +01:00
typedef struct {
2020-04-15 21:50:07 +01:00
union {
2020-07-22 09:03:28 +01:00
u8 value [ 0x8 ] ;
2020-04-15 21:50:07 +01:00
struct {
u32 generation ;
u32 secure_value ;
} ;
} ;
2020-07-22 09:03:28 +01:00
} NcaAesCtrUpperIv ;
2020-04-15 21:50:07 +01:00
2020-07-22 09:03:28 +01:00
/// Used in NCAs with sparse storage.
2020-04-15 21:50:07 +01:00
typedef struct {
2020-07-22 09:03:28 +01:00
NcaBucketInfo sparse_bucket ;
u64 physical_offset ;
u16 generation ;
u8 reserved [ 0x6 ] ;
} NcaSparseInfo ;
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
/// Four NCA FS headers are placed right after the 0x400 byte long NCA header in NCA2 and NCA3.
/// NCA0 place the FS headers at the start sector from the NcaFsInfo entries.
typedef struct {
u16 version ;
u8 fs_type ; ///< NcaFsType.
u8 hash_type ; ///< NcaHashType.
u8 encryption_type ; ///< NcaEncryptionType.
u8 reserved_1 [ 0x3 ] ;
NcaHashData hash_data ;
NcaPatchInfo patch_info ;
NcaAesCtrUpperIv aes_ctr_upper_iv ;
NcaSparseInfo sparse_info ;
u8 reserved_2 [ 0x88 ] ;
} NcaFsHeader ;
2020-04-11 06:28:26 +01:00
2020-04-20 11:39:41 +01:00
typedef enum {
2020-04-22 21:53:20 +01:00
NcaFsSectionType_PartitionFs = 0 , ///< NcaFsType_PartitionFs + NcaHashType_HierarchicalSha256.
NcaFsSectionType_RomFs = 1 , ///< NcaFsType_RomFs + NcaHashType_HierarchicalIntegrity.
NcaFsSectionType_PatchRomFs = 2 , ///< NcaFsType_RomFs + NcaHashType_HierarchicalIntegrity + NcaEncryptionType_AesCtrEx.
NcaFsSectionType_Nca0RomFs = 3 , ///< NcaFsType_RomFs + NcaHashType_HierarchicalSha256 + NcaVersion_Nca0.
NcaFsSectionType_Invalid = 4
} NcaFsSectionType ;
2020-04-11 06:28:26 +01:00
typedef struct {
2020-07-06 01:10:07 +01:00
bool enabled ;
2020-04-22 21:53:20 +01:00
void * nca_ctx ; ///< NcaContext. Used to perform NCA reads.
2020-07-22 09:03:28 +01:00
NcaFsHeader header ; ///< NCA FS section header.
2020-04-20 11:39:41 +01:00
u8 section_num ;
2020-04-21 11:23:33 +01:00
u64 section_offset ;
u64 section_size ;
2020-04-22 21:53:20 +01:00
u8 section_type ; ///< NcaFsSectionType.
u8 encryption_type ; ///< NcaEncryptionType.
2020-07-22 09:03:28 +01:00
u8 ctr [ AES_BLOCK_SIZE ] ; ///< Used to update the AES CTR context IV based on the desired offset.
2020-04-20 11:39:41 +01:00
Aes128CtrContext ctr_ctx ;
2020-04-22 21:53:20 +01:00
Aes128XtsContext xts_decrypt_ctx ;
Aes128XtsContext xts_encrypt_ctx ;
2020-04-21 11:23:33 +01:00
} NcaFsSectionContext ;
2020-04-15 21:50:07 +01:00
2020-07-22 09:03:28 +01:00
typedef enum {
NcaVersion_Nca0 = 0 ,
NcaVersion_Nca2 = 2 ,
NcaVersion_Nca3 = 3
} NcaVersion ;
2020-04-15 21:50:07 +01:00
typedef struct {
2020-07-22 09:03:28 +01:00
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_ctr [ AES_128_KEY_SIZE ] ; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtr crypto.
u8 aes_ctr_ex [ AES_128_KEY_SIZE ] ; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtrEx crypto.
} NcaDecryptedKeyArea ;
typedef struct {
u8 storage_id ; ///< NcmStorageId.
NcmContentStorage * ncm_storage ; ///< Pointer to a NcmContentStorage instance. Used to read NCA data.
u64 gamecard_offset ; ///< Used to read NCA data from a gamecard using a FsStorage instance when storage_id == NcmStorageId_GameCard.
NcmContentId content_id ; ///< Also used to read NCA data.
2020-04-21 11:23:33 +01:00
char content_id_str [ 0x21 ] ;
2020-07-22 09:03:28 +01:00
u8 hash [ SHA256_HASH_SIZE ] ; ///< Manually calculated (if needed).
2020-04-15 21:50:07 +01:00
char hash_str [ 0x41 ] ;
2020-07-22 09:03:28 +01:00
u8 format_version ; ///< NcaVersion.
u8 content_type ; ///< NcmContentType. Retrieved from NcmContentInfo.
u64 content_size ; ///< Retrieved from NcmContentInfo.
u8 key_generation ; ///< NcaKeyGenerationOld / NcaKeyGeneration. Retrieved from the decrypted header.
u8 id_offset ; ///< Retrieved from NcmContentInfo.
2020-04-15 21:50:07 +01:00
bool rights_id_available ;
2020-07-06 01:10:07 +01:00
bool titlekey_retrieved ;
2020-07-22 09:03:28 +01:00
u8 titlekey [ AES_128_KEY_SIZE ] ; ///< Decrypted titlekey from the ticket.
2020-04-15 21:50:07 +01:00
bool dirty_header ;
2020-07-22 09:03:28 +01:00
NcaHeader header ; ///< NCA header.
NcaFsSectionContext fs_contexts [ NCA_FS_HEADER_COUNT ] ;
NcaDecryptedKeyArea decrypted_key_area ;
2020-04-15 21:50:07 +01:00
} NcaContext ;
2020-04-11 06:28:26 +01:00
2020-04-28 09:58:17 +01:00
typedef struct {
2020-07-22 09:03:28 +01:00
u64 offset ; ///< New data offset (relative to the start of the NCA content file).
u64 size ; ///< New data size.
u8 * data ; ///< New data.
} NcaHashDataPatch ;
2020-04-28 09:58:17 +01:00
typedef struct {
2020-07-22 21:35:23 +01:00
NcmContentId content_id ;
2020-07-22 09:03:28 +01:00
u32 hash_region_count ;
NcaHashDataPatch hash_region_patch [ NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT ] ;
2020-04-28 09:58:17 +01:00
} NcaHierarchicalSha256Patch ;
typedef struct {
2020-07-22 21:35:23 +01:00
NcmContentId content_id ;
2020-07-22 09:03:28 +01:00
NcaHashDataPatch hash_level_patch [ NCA_IVFC_LEVEL_COUNT ] ;
2020-04-28 09:58:17 +01:00
} NcaHierarchicalIntegrityPatch ;
2020-04-22 21:53:20 +01:00
/// Functions to control the internal heap buffer used by NCA FS section crypto operations.
2020-04-21 11:23:33 +01:00
/// Must be called at startup.
bool ncaAllocateCryptoBuffer ( void ) ;
void ncaFreeCryptoBuffer ( void ) ;
2020-04-24 10:38:13 +01:00
/// Initializes a NCA context.
2020-04-21 11:23:33 +01:00
/// If 'storage_id' != NcmStorageId_GameCard, the 'ncm_storage' argument must point to a valid NcmContentStorage instance, previously opened using the same NcmStorageId value.
/// If 'storage_id' == NcmStorageId_GameCard, the 'hfs_partition_type' argument must be a valid GameCardHashFileSystemPartitionType value.
2020-07-03 10:31:22 +01:00
/// If the NCA holds a populated Rights ID field, and if the Ticket element pointed to by 'tik' hasn't been filled, ticket data will be retrieved.
2020-07-22 09:03:28 +01:00
/// If ticket data can't be retrieved, the context will still be initialized, but anything that involves working with encrypted NCA FS section blocks won't be possible (e.g. ncaReadFsSection()).
2020-05-03 00:40:50 +01:00
bool ncaInitializeContext ( NcaContext * out , u8 storage_id , NcmContentStorage * ncm_storage , u8 hfs_partition_type , const NcmContentInfo * content_info , Ticket * tik ) ;
2020-04-21 11:23:33 +01:00
2020-04-22 21:53:20 +01:00
/// Reads raw encrypted data from a NCA using an input context, previously initialized by ncaInitializeContext().
2020-04-28 00:30:35 +01:00
/// Input offset must be relative to the start of the NCA content file.
2020-04-22 21:53:20 +01:00
bool ncaReadContentFile ( NcaContext * ctx , void * out , u64 read_size , u64 offset ) ;
2020-04-19 23:44:22 +01:00
2020-04-22 21:53:20 +01:00
/// Reads decrypted data from a NCA FS section using an input context.
2020-04-21 11:23:33 +01:00
/// Input offset must be relative to the start of the NCA FS section.
2020-04-30 09:25:03 +01:00
/// If dealing with Patch RomFS sections, this function should only be used when *not* reading BKTR AesCtrEx storage data. Use ncaReadAesCtrExStorageFromBktrSection() for that.
2020-04-21 11:23:33 +01:00
bool ncaReadFsSection ( NcaFsSectionContext * ctx , void * out , u64 read_size , u64 offset ) ;
2020-04-30 09:25:03 +01:00
/// Reads decrypted BKTR AesCtrEx storage data from a NCA Patch RomFS section using an input context and a AesCtrEx CTR value.
/// Input offset must be relative to the start of the NCA FS section.
bool ncaReadAesCtrExStorageFromBktrSection ( NcaFsSectionContext * ctx , void * out , u64 read_size , u64 offset , u32 ctr_val ) ;
2020-04-22 21:53:20 +01:00
/// Returns a pointer to a heap-allocated buffer used to encrypt the input plaintext data, based on the encryption type used by the input NCA FS section, as well as its offset and size.
/// Input offset must be relative to the start of the NCA FS section.
/// Output size and offset are guaranteed to be aligned to the AES sector size used by the encryption type from the FS section.
2020-04-29 10:54:40 +01:00
/// Output offset is relative to the start of the NCA content file, making it easier to use the output encrypted block to seamlessly replace data while dumping a NCA.
2020-04-30 09:25:03 +01:00
/// This function isn't compatible with Patch RomFS sections.
2020-04-26 09:35:01 +01:00
void * ncaGenerateEncryptedFsSectionBlock ( NcaFsSectionContext * ctx , const void * data , u64 data_size , u64 data_offset , u64 * out_block_size , u64 * out_block_offset ) ;
2020-04-21 11:23:33 +01:00
2020-07-22 09:03:28 +01:00
/// 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).
/// 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.
2020-04-29 10:54:40 +01:00
/// As such, this function is not designed to generate more than one patch per HierarchicalSha256 FS section.
2020-04-28 09:58:17 +01:00
bool ncaGenerateHierarchicalSha256Patch ( NcaFsSectionContext * ctx , const void * data , u64 data_size , u64 data_offset , NcaHierarchicalSha256Patch * out ) ;
2020-07-22 21:35:23 +01:00
/// Overwrites block(s) from a buffer holding raw NCA data using previously initialized NcaContext and NcaHierarchicalSha256Patch.
/// 'buf_offset' must hold the raw NCA offset where the data stored in 'buf' was read from.
void ncaWriteHierarchicalSha256PatchToMemoryBuffer ( NcaContext * ctx , NcaHierarchicalSha256Patch * patch , void * buf , u64 buf_size , u64 buf_offset ) ;
2020-04-28 09:58:17 +01:00
2020-07-22 09:03:28 +01:00
/// 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).
/// 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.
2020-04-29 10:54:40 +01:00
/// 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 ) ;
2020-04-28 09:58:17 +01:00
2020-07-22 21:35:23 +01:00
/// Overwrites block(s) from a buffer holding raw NCA data using a previously initialized NcaContext and NcaHierarchicalIntegrityPatch.
/// 'buf_offset' must hold the raw NCA offset where the data stored in 'buf' was read from.
void ncaWriteHierarchicalIntegrityPatchToMemoryBuffer ( NcaContext * ctx , NcaHierarchicalIntegrityPatch * patch , void * buf , u64 buf_size , u64 buf_offset ) ;
2020-04-28 09:58:17 +01:00
2020-07-22 21:35:23 +01:00
/// Removes titlekey crypto dependency from a NCA context by wiping the Rights ID from the underlying NCA header and copying the decrypted titlekey to the NCA key area.
2020-07-22 09:03:28 +01:00
void ncaRemoveTitlekeyCrypto ( NcaContext * ctx ) ;
2020-04-28 09:58:17 +01:00
2020-04-21 11:23:33 +01:00
2020-04-19 23:44:22 +01:00
2020-04-21 11:23:33 +01:00
2020-05-03 00:40:50 +01:00
/// Miscellaneous functions.
2020-04-21 11:23:33 +01:00
2020-04-26 09:35:01 +01:00
NX_INLINE void ncaConvertNcmContentSizeToU64 ( const u8 * size , u64 * out )
2020-04-15 21:50:07 +01:00
{
2020-04-24 10:38:13 +01:00
if ( ! size | | ! out ) return ;
* out = 0 ;
memcpy ( out , size , 6 ) ;
2020-04-15 21:50:07 +01:00
}
2020-04-11 06:28:26 +01:00
2020-04-26 09:35:01 +01:00
NX_INLINE void ncaConvertU64ToNcmContentSize ( const u64 * size , u8 * out )
2020-04-15 21:50:07 +01:00
{
2020-04-22 21:53:20 +01:00
if ( size & & out ) memcpy ( out , size , 6 ) ;
2020-04-15 21:50:07 +01:00
}
2020-04-11 06:28:26 +01:00
2020-04-26 09:35:01 +01:00
NX_INLINE void ncaSetDownloadDistributionType ( NcaContext * ctx )
2020-04-15 21:50:07 +01:00
{
2020-04-24 10:38:13 +01:00
if ( ! ctx | | ctx - > header . distribution_type = = NcaDistributionType_Download ) return ;
ctx - > header . distribution_type = NcaDistributionType_Download ;
ctx - > dirty_header = true ;
2020-04-15 21:50:07 +01:00
}
2020-04-11 06:28:26 +01:00
2020-07-22 09:03:28 +01:00
NX_INLINE bool ncaValidateHierarchicalSha256Offsets ( NcaHierarchicalSha256Data * hierarchical_sha256_data , u64 section_size )
2020-04-26 09:35:01 +01:00
{
2020-07-22 09:03:28 +01:00
if ( ! hierarchical_sha256_data | | ! section_size | | ! hierarchical_sha256_data - > hash_block_size | | ! hierarchical_sha256_data - > hash_region_count | | \
hierarchical_sha256_data - > hash_region_count > NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT ) return false ;
2020-04-26 09:35:01 +01:00
2020-07-22 21:35:23 +01:00
for ( u32 i = 0 ; i < hierarchical_sha256_data - > hash_region_count ; i + + )
2020-04-26 09:35:01 +01:00
{
2020-07-22 09:03:28 +01:00
if ( hierarchical_sha256_data - > hash_region [ i ] . offset > = section_size | | ! hierarchical_sha256_data - > hash_region [ i ] . size | | \
( hierarchical_sha256_data - > hash_region [ i ] . offset + hierarchical_sha256_data - > hash_region [ i ] . size ) > section_size ) return false ;
2020-04-26 09:35:01 +01:00
}
return true ;
}
2020-07-22 09:03:28 +01:00
NX_INLINE bool ncaValidateHierarchicalIntegrityOffsets ( NcaIntegrityMetaInfo * integrity_meta_info , u64 section_size )
2020-04-26 09:35:01 +01:00
{
2020-07-22 09:03:28 +01:00
if ( ! integrity_meta_info | | ! section_size | | __builtin_bswap32 ( integrity_meta_info - > magic ) ! = NCA_IVFC_MAGIC | | integrity_meta_info - > master_hash_size ! = SHA256_HASH_SIZE | | \
integrity_meta_info - > info_level_hash . max_level_count ! = NCA_IVFC_MAX_LEVEL_COUNT ) return false ;
2020-04-26 09:35:01 +01:00
2020-07-22 21:35:23 +01:00
for ( u32 i = 0 ; i < NCA_IVFC_LEVEL_COUNT ; i + + )
2020-04-26 09:35:01 +01:00
{
2020-07-22 09:03:28 +01:00
if ( integrity_meta_info - > info_level_hash . level_information [ i ] . offset > = section_size | | ! integrity_meta_info - > info_level_hash . level_information [ i ] . size | | \
! integrity_meta_info - > info_level_hash . level_information [ i ] . block_order | | \
( integrity_meta_info - > info_level_hash . level_information [ i ] . offset + integrity_meta_info - > info_level_hash . level_information [ i ] . size ) > section_size ) return false ;
2020-04-26 09:35:01 +01:00
}
return true ;
}
2020-07-22 21:35:23 +01:00
NX_INLINE void ncaFreeHierarchicalSha256Patch ( NcaHierarchicalSha256Patch * patch )
{
if ( ! patch ) return ;
for ( u32 i = 0 ; i < NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT ; i + + )
{
if ( patch - > hash_region_patch [ i ] . data ) free ( patch - > hash_region_patch [ i ] . data ) ;
}
memset ( patch , 0 , sizeof ( NcaHierarchicalSha256Patch ) ) ;
}
NX_INLINE void ncaFreeHierarchicalIntegrityPatch ( NcaHierarchicalIntegrityPatch * patch )
{
if ( ! patch ) return ;
for ( u32 i = 0 ; i < NCA_IVFC_LEVEL_COUNT ; i + + )
{
if ( patch - > hash_level_patch [ i ] . data ) free ( patch - > hash_level_patch [ i ] . data ) ;
}
memset ( patch , 0 , sizeof ( NcaHierarchicalIntegrityPatch ) ) ;
}
2020-04-15 21:50:07 +01:00
# endif /* __NCA_H__ */