2018-02-03 05:35:43 +00:00
|
|
|
#ifndef HACTOOL_NCA_H
|
|
|
|
#define HACTOOL_NCA_H
|
2018-01-24 17:52:25 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "types.h"
|
|
|
|
#include "settings.h"
|
|
|
|
#include "aes.h"
|
|
|
|
#include "npdm.h"
|
|
|
|
#include "pfs0.h"
|
|
|
|
#include "ivfc.h"
|
2018-07-20 09:57:28 +00:00
|
|
|
#include "nca0_romfs.h"
|
2018-01-27 05:31:55 +00:00
|
|
|
#include "bktr.h"
|
2018-01-24 17:52:25 +00:00
|
|
|
|
|
|
|
#define MAGIC_NCA3 0x3341434E /* "NCA3" */
|
2018-03-15 05:42:02 +00:00
|
|
|
#define MAGIC_NCA2 0x3241434E /* "NCA2" */
|
2018-07-20 09:57:28 +00:00
|
|
|
#define MAGIC_NCA0 0x3041434E /* "NCA0" */
|
2018-01-24 17:52:25 +00:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t media_start_offset;
|
|
|
|
uint32_t media_end_offset;
|
|
|
|
uint8_t _0x8[0x8]; /* Padding. */
|
|
|
|
} nca_section_entry_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
ivfc_hdr_t ivfc_header;
|
2018-01-27 05:31:55 +00:00
|
|
|
uint8_t _0xE0[0x18];
|
|
|
|
bktr_header_t relocation_header;
|
|
|
|
bktr_header_t subsection_header;
|
2018-01-24 17:52:25 +00:00
|
|
|
} bktr_superblock_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
bktr_superblock_t *superblock;
|
2018-02-03 01:06:33 +00:00
|
|
|
FILE *file;
|
2018-01-24 17:52:25 +00:00
|
|
|
validity_t superblock_hash_validity;
|
2018-01-27 05:31:55 +00:00
|
|
|
bktr_relocation_block_t *relocation_block;
|
|
|
|
bktr_subsection_block_t *subsection_block;
|
2018-01-24 17:52:25 +00:00
|
|
|
ivfc_level_ctx_t ivfc_levels[IVFC_MAX_LEVEL];
|
2018-01-27 05:31:55 +00:00
|
|
|
uint64_t romfs_offset;
|
|
|
|
romfs_hdr_t header;
|
|
|
|
romfs_direntry_t *directories;
|
|
|
|
romfs_fentry_t *files;
|
|
|
|
uint64_t virtual_seek;
|
|
|
|
uint64_t bktr_seek;
|
|
|
|
uint64_t base_seek;
|
2018-01-24 17:52:25 +00:00
|
|
|
} bktr_section_ctx_t;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
PARTITION_ROMFS = 0,
|
|
|
|
PARTITION_PFS0 = 1
|
|
|
|
} section_partition_type_t;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
FS_TYPE_PFS0 = 2,
|
|
|
|
FS_TYPE_ROMFS = 3
|
|
|
|
} section_fs_type_t;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
CRYPT_NONE = 1,
|
|
|
|
CRYPT_XTS = 2,
|
|
|
|
CRYPT_CTR = 3,
|
2018-07-20 09:57:28 +00:00
|
|
|
CRYPT_BKTR = 4,
|
|
|
|
CRYPT_NCA0 = MAGIC_NCA0
|
2018-01-24 17:52:25 +00:00
|
|
|
} section_crypt_type_t;
|
|
|
|
|
|
|
|
/* NCA FS header. */
|
|
|
|
typedef struct {
|
|
|
|
uint8_t _0x0;
|
|
|
|
uint8_t _0x1;
|
|
|
|
uint8_t partition_type;
|
|
|
|
uint8_t fs_type;
|
|
|
|
uint8_t crypt_type;
|
|
|
|
uint8_t _0x5[0x3];
|
|
|
|
union { /* FS-specific superblock. Size = 0x138. */
|
|
|
|
pfs0_superblock_t pfs0_superblock;
|
|
|
|
romfs_superblock_t romfs_superblock;
|
2018-07-20 09:57:28 +00:00
|
|
|
nca0_romfs_superblock_t nca0_romfs_superblock;
|
2018-01-24 17:52:25 +00:00
|
|
|
bktr_superblock_t bktr_superblock;
|
|
|
|
};
|
2018-01-27 05:31:55 +00:00
|
|
|
union {
|
|
|
|
uint8_t section_ctr[0x8];
|
|
|
|
struct {
|
|
|
|
uint32_t section_ctr_low;
|
|
|
|
uint32_t section_ctr_high;
|
|
|
|
};
|
|
|
|
};
|
2018-01-24 17:52:25 +00:00
|
|
|
uint8_t _0x148[0xB8]; /* Padding. */
|
|
|
|
} nca_fs_header_t;
|
|
|
|
|
|
|
|
/* Nintendo content archive header. */
|
|
|
|
typedef struct {
|
|
|
|
uint8_t fixed_key_sig[0x100]; /* RSA-PSS signature over header with fixed key. */
|
|
|
|
uint8_t npdm_key_sig[0x100]; /* RSA-PSS signature over header with key in NPDM. */
|
|
|
|
uint32_t magic;
|
|
|
|
uint8_t distribution; /* System vs gamecard. */
|
|
|
|
uint8_t content_type;
|
|
|
|
uint8_t crypto_type; /* Which keyblob (field 1) */
|
|
|
|
uint8_t kaek_ind; /* Which kaek index? */
|
|
|
|
uint64_t nca_size; /* Entire archive size. */
|
|
|
|
uint64_t title_id;
|
|
|
|
uint8_t _0x218[0x4]; /* Padding. */
|
|
|
|
union {
|
|
|
|
uint32_t sdk_version; /* What SDK was this built with? */
|
|
|
|
struct {
|
|
|
|
uint8_t sdk_revision;
|
|
|
|
uint8_t sdk_micro;
|
|
|
|
uint8_t sdk_minor;
|
|
|
|
uint8_t sdk_major;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
uint8_t crypto_type2; /* Which keyblob (field 2) */
|
|
|
|
uint8_t _0x221[0xF]; /* Padding. */
|
|
|
|
uint8_t rights_id[0x10]; /* Rights ID (for titlekey crypto). */
|
|
|
|
nca_section_entry_t section_entries[4]; /* Section entry metadata. */
|
|
|
|
uint8_t section_hashes[4][0x20]; /* SHA-256 hashes for each section header. */
|
|
|
|
uint8_t encrypted_keys[4][0x10]; /* Encrypted key area. */
|
|
|
|
uint8_t _0x340[0xC0]; /* Padding. */
|
|
|
|
nca_fs_header_t fs_headers[4]; /* FS section headers. */
|
|
|
|
} nca_header_t;
|
|
|
|
|
|
|
|
enum nca_section_type {
|
|
|
|
PFS0,
|
|
|
|
ROMFS,
|
|
|
|
BKTR,
|
2018-07-20 09:57:28 +00:00
|
|
|
NCA0_ROMFS,
|
2018-01-24 17:52:25 +00:00
|
|
|
INVALID
|
|
|
|
};
|
|
|
|
|
2018-07-20 09:57:28 +00:00
|
|
|
enum nca_version {
|
|
|
|
NCAVERSION_UNKNOWN = 0,
|
|
|
|
NCAVERSION_NCA0_BETA,
|
|
|
|
NCAVERSION_NCA0,
|
|
|
|
/* NCAVERSION_NCA1, // Does this exist? */
|
|
|
|
NCAVERSION_NCA2,
|
|
|
|
NCAVERSION_NCA3
|
|
|
|
};
|
|
|
|
|
2020-01-15 11:01:22 +00:00
|
|
|
enum nca_content_type {
|
|
|
|
NCACONTENTTYPE_PROGRAM = 0,
|
|
|
|
NCACONTENTTYPE_META = 1,
|
|
|
|
NCACONTENTTYPE_CONTROL = 2,
|
|
|
|
NCACONTENTTYPE_MANUAL = 3,
|
|
|
|
NCACONTENTTYPE_DATA = 4,
|
|
|
|
NCACONTENTTPYE_PUBLICDATA = 5,
|
|
|
|
};
|
|
|
|
|
2018-01-24 17:52:25 +00:00
|
|
|
typedef struct {
|
|
|
|
int is_present;
|
|
|
|
enum nca_section_type type;
|
|
|
|
FILE *file; /* Pointer to file. */
|
|
|
|
uint64_t offset;
|
|
|
|
uint64_t size;
|
|
|
|
uint32_t section_num;
|
|
|
|
nca_fs_header_t *header;
|
|
|
|
int is_decrypted;
|
2018-07-20 09:57:28 +00:00
|
|
|
uint64_t sector_size;
|
|
|
|
uint64_t sector_mask;
|
2018-01-24 17:52:25 +00:00
|
|
|
aes_ctx_t *aes; /* AES context for the section. */
|
2018-02-03 05:35:43 +00:00
|
|
|
hactool_ctx_t *tool_ctx;
|
2018-01-24 17:52:25 +00:00
|
|
|
union {
|
2018-02-03 01:06:33 +00:00
|
|
|
pfs0_ctx_t pfs0_ctx;
|
|
|
|
romfs_ctx_t romfs_ctx;
|
2018-07-20 09:57:28 +00:00
|
|
|
nca0_romfs_ctx_t nca0_romfs_ctx;
|
2018-01-24 17:52:25 +00:00
|
|
|
bktr_section_ctx_t bktr_ctx;
|
|
|
|
};
|
|
|
|
validity_t superblock_hash_validity;
|
|
|
|
unsigned char ctr[0x10];
|
|
|
|
uint64_t cur_seek;
|
|
|
|
size_t sector_num;
|
|
|
|
uint32_t sector_ofs;
|
2018-02-03 19:28:08 +00:00
|
|
|
int physical_reads; /* Should reads be forced physical? */
|
2018-07-20 09:57:28 +00:00
|
|
|
section_crypt_type_t crypt_type;
|
2018-01-24 17:52:25 +00:00
|
|
|
} nca_section_ctx_t;
|
|
|
|
|
2018-01-27 11:22:09 +00:00
|
|
|
typedef struct nca_ctx {
|
2018-01-24 17:52:25 +00:00
|
|
|
FILE *file; /* File for this NCA. */
|
2020-01-15 10:07:22 +00:00
|
|
|
size_t file_size;
|
2018-01-24 17:52:25 +00:00
|
|
|
unsigned char crypto_type;
|
|
|
|
int has_rights_id;
|
|
|
|
int is_decrypted;
|
2018-07-24 05:16:26 +00:00
|
|
|
int is_cli_target;
|
2018-07-20 09:57:28 +00:00
|
|
|
enum nca_version format_version;
|
2018-01-24 17:52:25 +00:00
|
|
|
validity_t fixed_sig_validity;
|
|
|
|
validity_t npdm_sig_validity;
|
2018-02-03 05:35:43 +00:00
|
|
|
hactool_ctx_t *tool_ctx;
|
2018-01-24 17:52:25 +00:00
|
|
|
unsigned char decrypted_keys[4][0x10];
|
|
|
|
unsigned char title_key[0x10];
|
|
|
|
nca_section_ctx_t section_contexts[4];
|
|
|
|
npdm_t *npdm;
|
|
|
|
nca_header_t header;
|
|
|
|
} nca_ctx_t;
|
|
|
|
|
|
|
|
void nca_init(nca_ctx_t *ctx);
|
|
|
|
void nca_process(nca_ctx_t *ctx);
|
|
|
|
int nca_decrypt_header(nca_ctx_t *ctx);
|
|
|
|
void nca_decrypt_key_area(nca_ctx_t *ctx);
|
|
|
|
void nca_print(nca_ctx_t *ctx);
|
|
|
|
|
|
|
|
void nca_free_section_contexts(nca_ctx_t *ctx);
|
|
|
|
|
|
|
|
void nca_section_fseek(nca_section_ctx_t *ctx, uint64_t offset);
|
|
|
|
size_t nca_section_fread(nca_section_ctx_t *ctx, void *buffer, size_t count);
|
|
|
|
|
|
|
|
void nca_save_section_file(nca_section_ctx_t *ctx, uint64_t ofs, uint64_t total_size, filepath_t *filepath);
|
|
|
|
|
|
|
|
/* These have to be in nca.c, sadly... */
|
|
|
|
void nca_process_pfs0_section(nca_section_ctx_t *ctx);
|
|
|
|
void nca_process_ivfc_section(nca_section_ctx_t *ctx);
|
2018-07-20 09:57:28 +00:00
|
|
|
void nca_process_nca0_romfs_section(nca_section_ctx_t *ctx);
|
2018-01-24 17:52:25 +00:00
|
|
|
void nca_process_bktr_section(nca_section_ctx_t *ctx);
|
|
|
|
void nca_print_pfs0_section(nca_section_ctx_t *ctx);
|
|
|
|
void nca_print_ivfc_section(nca_section_ctx_t *ctx);
|
2018-07-20 09:57:28 +00:00
|
|
|
void nca_print_nca0_romfs_section(nca_section_ctx_t *ctx);
|
2018-01-24 17:52:25 +00:00
|
|
|
void nca_print_bktr_section(nca_section_ctx_t *ctx);
|
|
|
|
|
|
|
|
|
|
|
|
void nca_save_section(nca_section_ctx_t *ctx);
|
|
|
|
void nca_save_pfs0_section(nca_section_ctx_t *ctx);
|
|
|
|
void nca_save_ivfc_section(nca_section_ctx_t *ctx);
|
2018-07-20 09:57:28 +00:00
|
|
|
void nca_save_nca0_romfs_section(nca_section_ctx_t *ctx);
|
2018-01-24 17:52:25 +00:00
|
|
|
void nca_save_bktr_section(nca_section_ctx_t *ctx);
|
|
|
|
|
2018-01-24 22:18:27 +00:00
|
|
|
#endif
|