Merge pull request #82 from SciresM/save_dev

Implement savefile reading, output, file listing, and verification
This commit is contained in:
hexkyz 2019-10-18 19:20:10 +01:00 committed by GitHub
commit 21b84a3be3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 1522 additions and 3 deletions

View file

@ -13,7 +13,7 @@ all:
.c.o:
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
hactool: sha.o aes.o extkeys.o rsa.o npdm.o bktr.o kip.o packages.o pki.o pfs0.o hfs0.o nca0_romfs.o romfs.o utils.o nax0.o nso.o lz4.o nca.o xci.o main.o filepath.o ConvertUTF.o cJSON.o
hactool: save.o sha.o aes.o extkeys.o rsa.o npdm.o bktr.o kip.o packages.o pki.o pfs0.o hfs0.o nca0_romfs.o romfs.o utils.o nax0.o nso.o lz4.o nca.o xci.o main.o filepath.o ConvertUTF.o cJSON.o
$(CC) -o $@ $^ $(LDFLAGS) -L $(LIBDIR)
aes.o: aes.h types.h
@ -52,6 +52,8 @@ nca0_romfs.o: nca0_romfs.h ivfc.h types.h
rsa.o: rsa.h sha.h types.h
save.o: save.h ivfc.h aes.h sha.h filepath.h types.h
sha.o: sha.h types.h
utils.o: utils.h types.h

View file

@ -84,6 +84,9 @@ INI1 options:
NAX0 options:
--sdseed=seed Set console unique seed for SD card NAX0 encryption.
--sdpath=path Set relative path for NAX0 key derivation (ex: /registered/000000FF/cafebabecafebabecafebabecafebabe.nca).
Save data options:
--outdir=dir Specify save directory path.
--listfiles List files in save file.
Key Derivation options:
--sbk=key Set console unique Secure Boot Key for key derivation.
--tseckey=key Set console unique TSEC Key for key derivation.```

View file

@ -251,6 +251,9 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
} else if (strcmp(key, "package2_key_source") == 0) {
parse_hex_key(keyset->package2_key_source, value, sizeof(keyset->package2_key_source));
matched_key = 1;
} else if (strcmp(key, "per_console_key_source") == 0) {
parse_hex_key(keyset->per_console_key_source, value, sizeof(keyset->per_console_key_source));
matched_key = 1;
} else if (strcmp(key, "sd_card_kek_source") == 0) {
parse_hex_key(keyset->sd_card_kek_source, value, sizeof(keyset->sd_card_kek_source));
matched_key = 1;

9
ivfc.h
View file

@ -37,6 +37,15 @@ typedef struct {
uint8_t master_hash[0x20];
} ivfc_hdr_t;
typedef struct {
uint32_t magic;
uint32_t id;
uint32_t master_hash_size;
uint32_t num_levels;
ivfc_level_hdr_t level_headers[IVFC_MAX_LEVEL];
uint8_t salt_source[0x20];
} ivfc_save_hdr_t;
/* RomFS structs. */
#define ROMFS_HEADER_SIZE 0x00000050

21
main.c
View file

@ -13,6 +13,7 @@
#include "extkeys.h"
#include "packages.h"
#include "nso.h"
#include "save.h"
static const char *prog_name = "hactool";
@ -97,6 +98,9 @@ static void usage(void) {
"NAX0 options:\n"
" --sdseed=seed Set console unique seed for SD card NAX0 encryption.\n"
" --sdpath=path Set relative path for NAX0 key derivation (ex: /registered/000000FF/cafebabecafebabecafebabecafebabe.nca).\n"
"Save data options:\n"
" --outdir=dir Specify save directory path.\n"
" --listfiles List files in save file.\n"
"Key Derivation options:\n"
" --sbk=key Set console unique Secure Boot Key for key derivation.\n"
" --tseckey=key Set console unique TSEC Key for key derivation.\n"
@ -110,7 +114,7 @@ int main(int argc, char **argv) {
nca_ctx_t nca_ctx;
char input_name[0x200];
filepath_t keypath;
prog_name = (argc < 1) ? "hactool" : argv[0];
nca_init(&nca_ctx);
@ -180,6 +184,7 @@ int main(int argc, char **argv) {
{"saveini1json", 0, NULL, 38},
{"uncompressed", 1, NULL, 39},
{"disablekeywarns", 0, NULL, 40},
{"listfiles", 0, NULL, 41},
{NULL, 0, NULL, 0},
};
@ -237,6 +242,8 @@ int main(int argc, char **argv) {
nca_ctx.tool_ctx->file_type = FILETYPE_NAX0;
} else if (!strcmp(optarg, "keygen") || !strcmp(optarg, "keys") || !strcmp(optarg, "boot0") || !strcmp(optarg, "boot")) {
nca_ctx.tool_ctx->file_type = FILETYPE_BOOT0;
} else if (!strcmp(optarg, "save")) {
nca_ctx.tool_ctx->file_type = FILETYPE_SAVE;
}
break;
case 0: filepath_set(&nca_ctx.tool_ctx->settings.section_paths[0], optarg); break;
@ -390,6 +397,9 @@ int main(int argc, char **argv) {
case 40:
nca_ctx.tool_ctx->settings.skip_key_warnings = 1;
break;
case 41:
nca_ctx.tool_ctx->action |= ACTION_LISTFILES;
break;
default:
usage();
return EXIT_FAILURE;
@ -675,6 +685,15 @@ int main(int argc, char **argv) {
pki_print_keys(&new_keyset);
break;
}
case FILETYPE_SAVE: {
save_ctx_t save_ctx;
memset(&save_ctx, 0, sizeof(save_ctx));
save_ctx.file = tool_ctx.file;
save_ctx.tool_ctx = &tool_ctx;
save_process(&save_ctx);
save_free_contexts(&save_ctx);
break;
}
default: {
fprintf(stderr, "Unknown File Type!\n\n");
usage();

12
pki.c
View file

@ -229,6 +229,10 @@ void pki_derive_keys(nca_keyset_t *keyset) {
}
aes_ctx_t *mac_gen_ctx = new_aes_ctx(&keyset->keyblob_keys[i], 0x10, AES_MODE_ECB);
aes_decrypt(mac_gen_ctx, &keyset->keyblob_mac_keys[i], keyset->keyblob_mac_key_source, 0x10);
/* Derive Device key */
if (i == 0 && memcmp(keyset->per_console_key_source, zeroes, 0x10) != 0) {
aes_decrypt(mac_gen_ctx, keyset->device_key, keyset->per_console_key_source, 0x10);
}
free_aes_ctx(mac_gen_ctx);
}
for (unsigned int i = 0; i < 0x6; i++) {
@ -368,6 +372,11 @@ void pki_derive_keys(nca_keyset_t *keyset) {
free_aes_ctx(sd_ctx);
}
/* Derive Save MAC Key */
if (i == 0 && memcmp(keyset->save_mac_kek_source, zeroes, 0x10) != 0 && memcmp(keyset->save_mac_key_source, zeroes, 0x10) != 0 && memcmp(keyset->device_key, zeroes, 0x10) != 0) {
generate_kek(keyset->save_mac_key, keyset->save_mac_kek_source, keyset->device_key, keyset->aes_kek_generation_source, keyset->save_mac_key_source);
}
free_aes_ctx(master_ctx);
}
@ -381,6 +390,7 @@ void pki_print_keys(nca_keyset_t *keyset) {
PRINT_KEY_WITH_NAME(keyset->secure_boot_key, secure_boot_key);
PRINT_KEY_WITH_NAME(keyset->tsec_key, tsec_key);
PRINT_KEY_WITH_NAME(keyset->device_key, device_key);
PRINT_KEY_WITH_NAME(keyset->tsec_root_kek, tsec_root_kek);
PRINT_KEY_WITH_NAME(keyset->package1_mac_kek, package1_mac_kek);
PRINT_KEY_WITH_NAME(keyset->package1_kek, package1_kek);
@ -442,6 +452,7 @@ void pki_print_keys(nca_keyset_t *keyset) {
PRINT_KEY_WITH_NAME_IDX(keyset->package2_keys[i], package2_key, i);
}
printf("\n");
PRINT_KEY_WITH_NAME(keyset->per_console_key_source, per_console_key_source);
PRINT_KEY_WITH_NAME(keyset->aes_kek_generation_source, aes_kek_generation_source);
PRINT_KEY_WITH_NAME(keyset->aes_key_generation_source, aes_key_generation_source);
PRINT_KEY_WITH_NAME(keyset->titlekek_source, titlekek_source);
@ -458,6 +469,7 @@ void pki_print_keys(nca_keyset_t *keyset) {
PRINT_KEY_WITH_NAME(keyset->sd_card_key_sources[1], sd_card_nca_key_source);
PRINT_KEY_WITH_NAME(keyset->save_mac_kek_source, save_mac_kek_source);
PRINT_KEY_WITH_NAME(keyset->save_mac_key_source, save_mac_key_source);
PRINT_KEY_WITH_NAME(keyset->save_mac_key, save_mac_key);
printf("\n");
PRINT_KEY_WITH_NAME(keyset->header_key_source, header_key_source);
PRINT_KEY_WITH_NAME(keyset->header_key, header_key);

1018
save.c Normal file

File diff suppressed because it is too large Load diff

448
save.h Normal file
View file

@ -0,0 +1,448 @@
#ifndef HACTOOL_SAVE_H
#define HACTOOL_SAVE_H
#include "types.h"
#include "settings.h"
#include "ivfc.h"
#define SAVE_HEADER_SIZE 0x4000
#define SAVE_FAT_ENTRY_SIZE 8
#define SAVE_FS_LIST_MAX_NAME_LENGTH 0x40
#define SAVE_FS_LIST_ENTRY_SIZE 0x60
#define MAGIC_DISF 0x46534944
#define MAGIC_DPFS 0x53465044
#define MAGIC_JNGL 0x4C474E4A
#define MAGIC_SAVE 0x45564153
#define MAGIC_RMAP 0x50414D52
typedef struct save_ctx_t save_ctx_t;
typedef struct {
uint32_t magic; /* DISF */
uint32_t version;
uint8_t hash[0x20];
uint64_t file_map_entry_offset;
uint64_t file_map_entry_size;
uint64_t meta_map_entry_offset;
uint64_t meta_map_entry_size;
uint64_t file_map_data_offset;
uint64_t file_map_data_size;
uint64_t duplex_l1_offset_a;
uint64_t duplex_l1_offset_b;
uint64_t duplex_l1_size;
uint64_t duplex_data_offset_a;
uint64_t duplex_data_offset_b;
uint64_t duplex_data_size;
uint64_t journal_data_offset;
uint64_t journal_data_size_a;
uint64_t journal_data_size_b;
uint64_t journal_size;
uint64_t duplex_master_offset_a;
uint64_t duplex_master_offset_b;
uint64_t duplex_master_size;
uint64_t ivfc_master_hash_offset_a;
uint64_t ivfc_master_hash_offset_b;
uint64_t ivfc_master_hash_size;
uint64_t journal_map_table_offset;
uint64_t journal_map_table_size;
uint64_t journal_physical_bitmap_offset;
uint64_t journal_physical_bitmap_size;
uint64_t journal_virtual_bitmap_offset;
uint64_t journal_virtual_bitmap_size;
uint64_t journal_free_bitmap_offset;
uint64_t journal_free_bitmap_size;
uint64_t ivfc_l1_offset;
uint64_t ivfc_l1_size;
uint64_t ivfc_l2_offset;
uint64_t ivfc_l2_size;
uint64_t ivfc_l3_offset;
uint64_t ivfc_l3_size;
uint64_t fat_offset;
uint64_t fat_size;
uint64_t duplex_index;
uint64_t fat_ivfc_master_hash_a;
uint64_t fat_ivfc_master_hash_b;
uint64_t fat_ivfc_l1_offset;
uint64_t fat_ivfc_l1_size;
uint64_t fat_ivfc_l2_offset;
uint64_t fat_ivfc_l2_size;
uint8_t _0x190[0x70];
} fs_layout_t;
#pragma pack(push, 1)
typedef struct {
uint64_t offset;
uint64_t length;
uint32_t block_size_power;
} duplex_info_t;
#pragma pack(pop)
typedef struct {
uint32_t magic; /* DPFS */
uint32_t version;
duplex_info_t layers[3];
} duplex_header_t;
typedef struct {
uint32_t version;
uint32_t main_data_block_count;
uint32_t journal_block_count;
uint32_t _0x0C;
} journal_map_header_t;
typedef struct {
uint32_t magic; /* JNGL */
uint32_t version;
uint64_t total_size;
uint64_t journal_size;
uint64_t block_size;
} journal_header_t;
typedef struct {
uint32_t magic; /* SAVE */
uint32_t version;
uint64_t block_count;
uint64_t block_size;
} save_fs_header_t;
typedef struct {
uint64_t block_size;
uint64_t allocation_table_offset;
uint32_t allocation_table_block_count;
uint32_t _0x14;
uint64_t data_offset;
uint32_t data_block_count;
uint32_t _0x24;
uint32_t directory_table_block;
uint32_t file_table_block;
} fat_header_t;
typedef struct {
uint32_t magic; /* RMAP */
uint32_t version;
uint32_t map_entry_count;
uint32_t map_segment_count;
uint32_t segment_bits;
uint8_t _0x14[0x2C];
} remap_header_t;
typedef struct remap_segment_ctx_t remap_segment_ctx_t;
typedef struct remap_entry_ctx_t remap_entry_ctx_t;
#pragma pack(push, 1)
struct remap_entry_ctx_t {
uint64_t virtual_offset;
uint64_t physical_offset;
uint64_t size;
uint32_t alignment;
uint32_t _0x1C;
uint64_t virtual_offset_end;
uint64_t physical_offset_end;
remap_segment_ctx_t *segment;
remap_entry_ctx_t *next;
};
#pragma pack(pop)
struct remap_segment_ctx_t{
uint64_t offset;
uint64_t length;
remap_entry_ctx_t *entries;
uint64_t entry_count;
};
typedef struct {
uint8_t *data;
uint8_t *bitmap;
} duplex_bitmap_t;
typedef struct {
uint32_t block_size;
uint8_t *bitmap_storage;
uint8_t *data_a;
uint8_t *data_b;
duplex_bitmap_t bitmap;
uint64_t _length;
} duplex_storage_ctx_t;
enum base_storage_type {
STORAGE_BYTES = 0,
STORAGE_DUPLEX = 1,
STORAGE_REMAP = 2,
STORAGE_JOURNAL = 3
};
typedef struct {
remap_header_t *header;
remap_entry_ctx_t *map_entries;
remap_segment_ctx_t *segments;
enum base_storage_type type;
uint64_t base_storage_offset;
duplex_storage_ctx_t *duplex;
FILE *file;
} remap_storage_ctx_t;
typedef struct {
uint64_t title_id;
uint8_t user_id[0x10];
uint64_t save_id;
uint8_t save_data_type;
uint8_t _0x21[0x1F];
uint64_t save_owner_id;
uint64_t timestamp;
uint64_t _0x50;
uint64_t data_size;
uint64_t journal_size;
uint64_t commit_id;
} extra_data_t;
#pragma pack(push, 1)
typedef struct {
uint8_t cmac[0x10];
uint8_t _0x10[0xF0];
fs_layout_t layout;
duplex_header_t duplex_header;
ivfc_save_hdr_t data_ivfc_header;
uint32_t _0x404;
journal_header_t journal_header;
journal_map_header_t map_header;
uint8_t _0x438[0x1D0];
save_fs_header_t save_header;
fat_header_t fat_header;
remap_header_t main_remap_header, meta_remap_header;
uint64_t _0x6D0;
extra_data_t extra_data;
uint8_t _0x748[0x390];
ivfc_save_hdr_t fat_ivfc_header;
uint8_t _0xB98[0x3468];
} save_header_t;
#pragma pack(pop)
typedef struct {
duplex_storage_ctx_t layers[2];
duplex_storage_ctx_t data_layer;
uint64_t _length;
} hierarchical_duplex_storage_ctx_t;
typedef struct {
uint8_t *data_a;
uint8_t *data_b;
duplex_info_t info;
} duplex_fs_layer_info_t;
typedef struct {
uint8_t *map_storage;
uint8_t *physical_block_bitmap;
uint8_t *virtual_block_bitmap;
uint8_t *free_block_bitmap;
} journal_map_params_t;
typedef struct {
uint32_t physical_index;
uint32_t virtual_index;
} journal_map_entry_t;
typedef struct {
journal_map_header_t *header;
journal_map_entry_t *entries;
uint8_t *map_storage;
} journal_map_ctx_t;
typedef struct {
journal_map_ctx_t map;
journal_header_t *header;
uint32_t block_size;
uint64_t journal_data_offset;
uint64_t _length;
FILE *file;
} journal_storage_ctx_t;
typedef struct {
uint64_t data_offset;
uint64_t data_size;
uint64_t hash_offset;
uint32_t hash_block_size;
validity_t hash_validity;
enum base_storage_type type;
save_ctx_t *save_ctx;
} ivfc_level_save_ctx_t;
typedef struct {
ivfc_level_save_ctx_t *data;
uint32_t block_size;
uint8_t salt[0x20];
} integrity_verification_info_ctx_t;
typedef struct integrity_verification_storage_ctx_t integrity_verification_storage_ctx_t;
struct integrity_verification_storage_ctx_t {
ivfc_level_save_ctx_t *hash_storage;
ivfc_level_save_ctx_t *base_storage;
validity_t *block_validities;
uint8_t salt[0x20];
uint32_t sector_size;
uint32_t sector_count;
uint64_t _length;
integrity_verification_storage_ctx_t *next_level;
};
typedef struct {
ivfc_level_save_ctx_t levels[5];
ivfc_level_save_ctx_t *data_level;
validity_t **level_validities;
uint64_t _length;
integrity_verification_storage_ctx_t integrity_storages[4];
} hierarchical_integrity_verification_storage_ctx_t;
typedef struct {
uint32_t prev;
uint32_t next;
} allocation_table_entry_t;
typedef struct {
uint32_t free_list_entry_index;
void *base_storage;
fat_header_t *header;
} allocation_table_ctx_t;
typedef struct {
hierarchical_integrity_verification_storage_ctx_t *base_storage;
uint32_t block_size;
uint32_t initial_block;
allocation_table_ctx_t *fat;
uint64_t _length;
} allocation_table_storage_ctx_t;
typedef struct {
allocation_table_ctx_t *fat;
uint32_t virtual_block;
uint32_t physical_block;
uint32_t current_segment_size;
uint32_t next_block;
uint32_t prev_block;
} allocation_table_iterator_ctx_t;
typedef struct {
char name[SAVE_FS_LIST_MAX_NAME_LENGTH];
uint32_t parent;
} save_entry_key_t;
#pragma pack(push, 1)
typedef struct {
uint32_t start_block;
uint64_t length;
uint32_t _0xC[2];
} save_file_info_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct {
uint32_t next_directory;
uint32_t next_file;
uint32_t _0x8[3];
} save_find_position_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct {
uint32_t next_sibling;
union { /* Save table entry type. Size = 0x14. */
save_file_info_t save_file_info;
save_find_position_t save_find_position;
};
} save_table_entry_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct {
uint32_t parent;
char name[SAVE_FS_LIST_MAX_NAME_LENGTH];
save_table_entry_t value;
uint32_t next;
} save_fs_list_entry_t;
#pragma pack(pop)
typedef struct {
uint32_t free_list_head_index;
uint32_t used_list_head_index;
allocation_table_storage_ctx_t storage;
} save_filesystem_list_ctx_t;
typedef struct {
save_filesystem_list_ctx_t file_table;
save_filesystem_list_ctx_t directory_table;
} hierarchical_save_file_table_ctx_t;
typedef struct {
hierarchical_integrity_verification_storage_ctx_t *base_storage;
allocation_table_ctx_t allocation_table;
save_fs_header_t *header;
hierarchical_save_file_table_ctx_t file_table;
} save_filesystem_ctx_t;
struct save_ctx_t {
FILE *file;
hactool_ctx_t *tool_ctx;
save_header_t header;
validity_t header_cmac_validity;
validity_t header_hash_validity;
uint8_t *data_ivfc_master;
uint8_t *fat_ivfc_master;
remap_storage_ctx_t data_remap_storage;
remap_storage_ctx_t meta_remap_storage;
duplex_fs_layer_info_t duplex_layers[3];
hierarchical_duplex_storage_ctx_t duplex_storage;
journal_storage_ctx_t journal_storage;
journal_map_params_t journal_map_info;
hierarchical_integrity_verification_storage_ctx_t core_data_ivfc_storage;
hierarchical_integrity_verification_storage_ctx_t fat_ivfc_storage;
uint8_t *fat_storage;
save_filesystem_ctx_t save_filesystem_core;
};
static inline uint32_t allocation_table_entry_index_to_block(uint32_t entry_index) {
return entry_index - 1;
}
static inline uint32_t allocation_table_block_to_entry_index(uint32_t block_index) {
return block_index + 1;
}
static inline int allocation_table_is_list_end(allocation_table_entry_t *entry) {
return (entry->next & 0x7FFFFFFF) == 0;
}
static inline int allocation_table_is_list_start(allocation_table_entry_t *entry) {
return entry->prev == 0x80000000;
}
static inline int allocation_table_get_next(allocation_table_entry_t *entry) {
return entry->next & 0x7FFFFFFF;
}
static inline int allocation_table_get_prev(allocation_table_entry_t *entry) {
return entry->prev & 0x7FFFFFFF;
}
static inline allocation_table_entry_t *save_allocation_table_read_entry(allocation_table_ctx_t *ctx, uint32_t entry_index) {
return (allocation_table_entry_t *)((uint8_t *)ctx->base_storage + entry_index * SAVE_FAT_ENTRY_SIZE);
}
static inline uint32_t save_allocation_table_get_free_list_entry_index(allocation_table_ctx_t *ctx) {
return allocation_table_get_next(save_allocation_table_read_entry(ctx, ctx->free_list_entry_index));
}
static inline uint32_t save_allocation_table_get_free_list_block_index(allocation_table_ctx_t *ctx) {
return allocation_table_entry_index_to_block(save_allocation_table_get_free_list_entry_index(ctx));
}
void save_process(save_ctx_t *ctx);
void save_process_header(save_ctx_t *ctx);
void save_save(save_ctx_t *ctx);
void save_print(save_ctx_t *ctx);
void save_free_contexts(save_ctx_t *ctx);
#endif

View file

@ -18,6 +18,7 @@ typedef enum {
typedef struct {
unsigned char secure_boot_key[0x10]; /* Secure boot key for use in key derivation. NOTE: CONSOLE UNIQUE. */
unsigned char tsec_key[0x10]; /* TSEC key for use in key derivation. NOTE: CONSOLE UNIQUE. */
unsigned char device_key[0x10]; /* Device key used to derive some FS keys. NOTE: CONSOLE UNIQUE. */
unsigned char keyblob_keys[0x20][0x10]; /* Actual keys used to decrypt keyblobs. NOTE: CONSOLE UNIQUE.*/
unsigned char keyblob_mac_keys[0x20][0x10]; /* Keys used to validate keyblobs. NOTE: CONSOLE UNIQUE. */
unsigned char encrypted_keyblobs[0x20][0xB0]; /* Actual encrypted keyblobs (EKS). NOTE: CONSOLE UNIQUE. */
@ -37,6 +38,7 @@ typedef struct {
unsigned char package1_keys[0x20][0x10]; /* Package1 keys. */
unsigned char package2_keys[0x20][0x10]; /* Package2 keys. */
unsigned char package2_key_source[0x10]; /* Seed for Package2 key. */
unsigned char per_console_key_source[0x10]; /* Seed for Device key. */
unsigned char aes_kek_generation_source[0x10]; /* Seed for GenerateAesKek, usecase + generation 0. */
unsigned char aes_key_generation_source[0x10]; /* Seed for GenerateAesKey. */
unsigned char key_area_key_application_source[0x10]; /* Seed for kaek 0. */
@ -52,6 +54,7 @@ typedef struct {
unsigned char header_key[0x20]; /* NCA header key. */
unsigned char titlekeks[0x20][0x10]; /* Title key encryption keys. */
unsigned char key_area_keys[0x20][3][0x10]; /* Key area encryption keys. */
unsigned char save_mac_key[0x10]; /* Key used to sign savedata. */
unsigned char sd_card_keys[2][0x20];
unsigned char nca_hdr_fixed_key_modulus[0x100]; /* NCA header fixed key RSA pubk. */
unsigned char acid_fixed_key_modulus[0x100]; /* ACID fixed key RSA pubk. */
@ -127,7 +130,8 @@ enum hactool_file_type
FILETYPE_KIP1,
FILETYPE_NSO0,
FILETYPE_NAX0,
FILETYPE_BOOT0
FILETYPE_BOOT0,
FILETYPE_SAVE
};
#define ACTION_INFO (1<<0)
@ -139,6 +143,7 @@ enum hactool_file_type
#define ACTION_EXTRACTINI1 (1<<6)
#define ACTION_ONLYUPDATEDROMFS (1<<7)
#define ACTION_SAVEINIJSON (1<<8)
#define ACTION_LISTFILES (1<<9)
struct nca_ctx; /* This will get re-defined by nca.h. */