forked from SciresM/hactool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nca.h
191 lines (171 loc) · 5.35 KB
/
nca.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#ifndef HACTOOL_NCA_H
#define HACTOOL_NCA_H
#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"
#include "bktr.h"
#define MAGIC_NCA3 0x3341434E /* "NCA3" */
#define MAGIC_NCA2 0x3241434E /* "NCA2" */
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;
uint8_t _0xE0[0x18];
bktr_header_t relocation_header;
bktr_header_t subsection_header;
} bktr_superblock_t;
typedef struct {
bktr_superblock_t *superblock;
FILE *file;
validity_t superblock_hash_validity;
bktr_relocation_block_t *relocation_block;
bktr_subsection_block_t *subsection_block;
ivfc_level_ctx_t ivfc_levels[IVFC_MAX_LEVEL];
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;
} 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,
CRYPT_BKTR = 4
} 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;
bktr_superblock_t bktr_superblock;
};
union {
uint8_t section_ctr[0x8];
struct {
uint32_t section_ctr_low;
uint32_t section_ctr_high;
};
};
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,
INVALID
};
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;
aes_ctx_t *aes; /* AES context for the section. */
hactool_ctx_t *tool_ctx;
union {
pfs0_ctx_t pfs0_ctx;
romfs_ctx_t romfs_ctx;
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;
int physical_reads; /* Should reads be forced physical? */
} nca_section_ctx_t;
typedef struct nca_ctx {
FILE *file; /* File for this NCA. */
size_t file_size;
unsigned char crypto_type;
int has_rights_id;
int is_decrypted;
validity_t fixed_sig_validity;
validity_t npdm_sig_validity;
hactool_ctx_t *tool_ctx;
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);
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);
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);
void nca_save_bktr_section(nca_section_ctx_t *ctx);
#endif