Fix trailing spaces

This commit is contained in:
Michael Scire 2020-01-15 02:07:22 -08:00
parent 55e625d67d
commit e37d4d2da2
19 changed files with 264 additions and 264 deletions

30
aes.c
View file

@ -8,24 +8,24 @@
/* Allocate a new context. */
aes_ctx_t *new_aes_ctx(const void *key, unsigned int key_size, aes_mode_t mode) {
aes_ctx_t *ctx;
if ((ctx = malloc(sizeof(*ctx))) == NULL) {
FATAL_ERROR("Failed to allocate aes_ctx_t!");
}
mbedtls_cipher_init(&ctx->cipher_dec);
mbedtls_cipher_init(&ctx->cipher_enc);
if (mbedtls_cipher_setup(&ctx->cipher_dec, mbedtls_cipher_info_from_type(mode))
|| mbedtls_cipher_setup(&ctx->cipher_enc, mbedtls_cipher_info_from_type(mode))) {
FATAL_ERROR("Failed to set up AES context!");
}
if (mbedtls_cipher_setkey(&ctx->cipher_dec, key, key_size * 8, AES_DECRYPT)
|| mbedtls_cipher_setkey(&ctx->cipher_enc, key, key_size * 8, AES_ENCRYPT)) {
FATAL_ERROR("Failed to set key for AES context!");
}
return ctx;
}
@ -35,7 +35,7 @@ void free_aes_ctx(aes_ctx_t *ctx) {
if (ctx == NULL) {
return;
}
mbedtls_cipher_free(&ctx->cipher_dec);
mbedtls_cipher_free(&ctx->cipher_enc);
free(ctx);
@ -65,17 +65,17 @@ void aes_calculate_cmac(void *dst, void *src, size_t size, const void *key) {
/* Encrypt with context. */
void aes_encrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) {
size_t out_len = 0;
/* Prepare context */
mbedtls_cipher_reset(&ctx->cipher_enc);
/* XTS doesn't need per-block updating */
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_XTS)
mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
else
{
unsigned int blk_size = mbedtls_cipher_get_block_size(&ctx->cipher_enc);
/* Do per-block updating */
for (int offset = 0; (unsigned int)offset < l; offset += blk_size)
{
@ -83,15 +83,15 @@ void aes_encrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) {
mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src + offset, len, (unsigned char *)dst + offset, &out_len);
}
}
/* Flush all data */
mbedtls_cipher_finish(&ctx->cipher_enc, NULL, NULL);
}
/* Decrypt with context. */
void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l)
void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l)
{
bool src_equals_dst = false;
bool src_equals_dst = false;
if (src == dst)
{
@ -105,17 +105,17 @@ void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l)
}
size_t out_len = 0;
/* Prepare context */
mbedtls_cipher_reset(&ctx->cipher_dec);
/* XTS doesn't need per-block updating */
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_dec) == MBEDTLS_MODE_XTS)
mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
else
{
unsigned int blk_size = mbedtls_cipher_get_block_size(&ctx->cipher_dec);
/* Do per-block updating */
for (int offset = 0; (unsigned int)offset < l; offset += blk_size)
{
@ -123,7 +123,7 @@ void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l)
mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src + offset, len, (unsigned char *)dst + offset, &out_len);
}
}
/* Flush all data */
mbedtls_cipher_finish(&ctx->cipher_dec, NULL, NULL);

16
bktr.c
View file

@ -12,20 +12,20 @@ bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uin
fprintf(stderr, "Too big offset looked up in BKTR relocation table!\n");
exit(EXIT_FAILURE);
}
uint32_t bucket_num = 0;
for (unsigned int i = 1; i < block->num_buckets; i++) {
if (block->bucket_virtual_offsets[i] <= offset) {
bucket_num++;
}
}
bktr_relocation_bucket_t *bucket = bktr_get_relocation_bucket(block, bucket_num);
if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */
return &bucket->entries[0];
}
/* Binary search. */
uint32_t low = 0, high = bucket->num_entries - 1;
while (low <= high) {
@ -55,20 +55,20 @@ bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uin
if (offset >= last_bucket->entries[last_bucket->num_entries].offset) {
return &last_bucket->entries[last_bucket->num_entries];
}
uint32_t bucket_num = 0;
for (unsigned int i = 1; i < block->num_buckets; i++) {
if (block->bucket_physical_offsets[i] <= offset) {
bucket_num++;
}
}
bktr_subsection_bucket_t *bucket = bktr_get_subsection_bucket(block, bucket_num);
if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */
return &bucket->entries[0];
}
/* Binary search. */
uint32_t low = 0, high = bucket->num_entries - 1;
while (low <= high) {

View file

@ -178,7 +178,7 @@ void parse_hex_key(unsigned char *key, const char *hex, unsigned int len) {
void extkeys_parse_titlekeys(hactool_settings_t *settings, FILE *f) {
char *key, *value;
int ret;
while ((ret = get_kv(f, &key, &value)) != 1 && ret != -2) {
if (ret == 0) {
if (key == NULL || value == NULL) {
@ -186,7 +186,7 @@ void extkeys_parse_titlekeys(hactool_settings_t *settings, FILE *f) {
}
unsigned char rights_id[0x10];
unsigned char titlekey[0x10];
bool should_ignore_key = false;
if (strlen(key) != 0x20) {
should_ignore_key = true;
@ -214,7 +214,7 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
char *key, *value;
int ret;
nca_keyset_t *keyset = &settings->keyset;
while ((ret = get_kv(f, &key, &value)) != 1 && ret != -2) {
if (ret == 0) {
if (key == NULL || value == NULL) {
@ -225,7 +225,7 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
parse_hex_key(keyset->aes_kek_generation_source, value, sizeof(keyset->aes_kek_generation_source));
matched_key = 1;
} else if (strcmp(key, "aes_key_generation_source") == 0) {
parse_hex_key(keyset->aes_key_generation_source, value, sizeof(keyset->aes_key_generation_source));
parse_hex_key(keyset->aes_key_generation_source, value, sizeof(keyset->aes_key_generation_source));
matched_key = 1;
} else if (strcmp(key, "key_area_key_application_source") == 0) {
parse_hex_key(keyset->key_area_key_application_source, value, sizeof(keyset->key_area_key_application_source));
@ -307,28 +307,28 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "keyblob_key_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->keyblob_keys[i], value, sizeof(keyset->keyblob_keys[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "keyblob_mac_key_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->keyblob_mac_keys[i], value, sizeof(keyset->keyblob_mac_keys[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "encrypted_keyblob_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->encrypted_keyblobs[i], value, sizeof(keyset->encrypted_keyblobs[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "keyblob_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->keyblobs[i], value, sizeof(keyset->keyblobs[i]));
@ -343,21 +343,21 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "tsec_root_key_%02"PRIx32, i - 6);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->tsec_root_keys[i - 6], value, sizeof(keyset->tsec_root_keys[i - 6]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "master_kek_source_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->master_kek_sources[i], value, sizeof(keyset->master_kek_sources[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "package1_mac_key_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->package1_mac_keys[i], value, sizeof(keyset->package1_mac_keys[i]));
@ -365,56 +365,56 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
break;
}
}
for (unsigned int i = 0; i < 0x20 && !matched_key; i++) {
for (unsigned int i = 0; i < 0x20 && !matched_key; i++) {
snprintf(test_name, sizeof(test_name), "master_kek_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->master_keks[i], value, sizeof(keyset->master_keks[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "master_key_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->master_keys[i], value, sizeof(keyset->master_keys[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "package1_key_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->package1_keys[i], value, sizeof(keyset->package1_keys[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "package2_key_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->package2_keys[i], value, sizeof(keyset->package2_keys[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "titlekek_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->titlekeks[i], value, sizeof(keyset->titlekeks[i]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "key_area_key_application_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->key_area_keys[i][0], value, sizeof(keyset->key_area_keys[i][0]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "key_area_key_ocean_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->key_area_keys[i][1], value, sizeof(keyset->key_area_keys[i][1]));
matched_key = 1;
break;
}
snprintf(test_name, sizeof(test_name), "key_area_key_system_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->key_area_keys[i][2], value, sizeof(keyset->key_area_keys[i][2]));
@ -444,7 +444,7 @@ void settings_add_titlekey(hactool_settings_t *settings, const unsigned char *ri
fprintf(stderr, " already has a corresponding titlekey!\n");
exit(EXIT_FAILURE);
}
/* Ensure enough space for keys. */
if (settings->known_titlekeys.count == 0) {
settings->known_titlekeys.titlekeys = malloc(1 * sizeof(titlekey_entry_t));
@ -456,9 +456,9 @@ void settings_add_titlekey(hactool_settings_t *settings, const unsigned char *ri
fprintf(stderr, "Failed to allocate titlekey list!\n");
exit(EXIT_FAILURE);
}
titlekey_entry_t *new_key = &settings->known_titlekeys.titlekeys[settings->known_titlekeys.count++];
memcpy(new_key->rights_id, rights_id, 0x10);
memcpy(new_key->titlekey, titlekey, 0x10);
}
@ -469,7 +469,7 @@ titlekey_entry_t *settings_get_titlekey(hactool_settings_t *settings, const unsi
return &settings->known_titlekeys.titlekeys[i];
}
}
return NULL;
}

14
hfs0.c
View file

@ -3,13 +3,13 @@
void hfs0_process(hfs0_ctx_t *ctx) {
/* Read *just* safe amount. */
hfs0_header_t raw_header;
hfs0_header_t raw_header;
fseeko64(ctx->file, ctx->offset, SEEK_SET);
if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) {
fprintf(stderr, "Failed to read HFS0 header!\n");
exit(EXIT_FAILURE);
}
if (raw_header.magic != MAGIC_HFS0) {
memdump(stdout, "Sanity: ", &raw_header, sizeof(raw_header));
printf("Error: HFS0 is corrupt!\n");
@ -22,16 +22,16 @@ void hfs0_process(hfs0_ctx_t *ctx) {
fprintf(stderr, "Failed to allocate HFS0 header!\n");
exit(EXIT_FAILURE);
}
fseeko64(ctx->file, ctx->offset, SEEK_SET);
if (fread(ctx->header, 1, header_size, ctx->file) != header_size) {
fprintf(stderr, "Failed to read HFS0 header!\n");
exit(EXIT_FAILURE);
}
/* Weak file validation. */
uint64_t max_size = 0x1ULL;
max_size <<= 48; /* Switch file sizes are capped at 48 bits. */
max_size <<= 48; /* Switch file sizes are capped at 48 bits. */
uint64_t cur_ofs = 0;
for (unsigned int i = 0; i < ctx->header->num_files; i++) {
hfs0_file_entry_t *cur_file = hfs0_get_file_entry(ctx->header, i);
@ -41,11 +41,11 @@ void hfs0_process(hfs0_ctx_t *ctx) {
}
cur_ofs += cur_file->size;
}
if (ctx->tool_ctx->action & ACTION_INFO) {
hfs0_print(ctx);
}
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
hfs0_save(ctx);
}

42
kip.c
View file

@ -6,13 +6,13 @@
void ini1_process(ini1_ctx_t *ctx) {
/* Read *just* safe amount. */
ini1_header_t raw_header;
ini1_header_t raw_header;
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) {
fprintf(stderr, "Failed to read INI1 header!\n");
exit(EXIT_FAILURE);
}
if (raw_header.magic != MAGIC_INI1 || raw_header.num_processes > INI1_MAX_KIPS) {
printf("Error: INI1 is corrupt!\n");
exit(EXIT_FAILURE);
@ -23,13 +23,13 @@ void ini1_process(ini1_ctx_t *ctx) {
fprintf(stderr, "Failed to allocate INI1 header!\n");
exit(EXIT_FAILURE);
}
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(ctx->header, 1, raw_header.size, ctx->file) != raw_header.size) {
fprintf(stderr, "Failed to read INI1!\n");
exit(EXIT_FAILURE);
}
uint64_t offset = 0;
for (unsigned int i = 0; i < ctx->header->num_processes; i++) {
ctx->kips[i].tool_ctx = ctx->tool_ctx;
@ -40,11 +40,11 @@ void ini1_process(ini1_ctx_t *ctx) {
}
offset += kip1_get_size(&ctx->kips[i]);
}
if (ctx->tool_ctx->action & ACTION_INFO) {
ini1_print(ctx);
}
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
ini1_save(ctx);
}
@ -109,7 +109,7 @@ char *kip1_get_json(kip1_ctx_t *ctx) {
cJSON *kip_json = cJSON_CreateObject();
char *output_str = NULL;
char work_buffer[0x300] = {0};
/* Add KIP1 header fields. */
strcpy(work_buffer, ctx->header->name);
cJSON_AddStringToObject(kip_json, "name", work_buffer);
@ -118,13 +118,13 @@ char *kip1_get_json(kip1_ctx_t *ctx) {
cJSON_AddNumberToObject(kip_json, "main_thread_priority", ctx->header->main_thread_priority);
cJSON_AddNumberToObject(kip_json, "default_cpu_id", ctx->header->default_core);
cJSON_AddNumberToObject(kip_json, "process_category", ctx->header->process_category);
/* Add KAC. */
cJSON *kac_json = kac_get_json(ctx->header->capabilities, sizeof(ctx->header->capabilities) / sizeof(uint32_t));
cJSON_AddItemToObject(kip_json, "kernel_capabilities", kac_json);
output_str = cJSON_Print(kip_json);
cJSON_Delete(kip_json);
return output_str;
}
@ -133,11 +133,11 @@ static void kip1_blz_uncompress(void *hdr_end) {
uint32_t addl_size = ((uint32_t *)hdr_end)[-1];
uint32_t header_size = ((uint32_t *)hdr_end)[-2];
uint32_t cmp_and_hdr_size = ((uint32_t *)hdr_end)[-3];
unsigned char *cmp_start = (unsigned char *)(((uintptr_t)hdr_end) - cmp_and_hdr_size);
uint32_t cmp_ofs = cmp_and_hdr_size - header_size;
uint32_t out_ofs = cmp_and_hdr_size + addl_size;
while (out_ofs) {
unsigned char control = cmp_start[--cmp_ofs];
for (unsigned int i = 0; i < 8; i++) {
@ -155,7 +155,7 @@ static void kip1_blz_uncompress(void *hdr_end) {
seg_size = out_ofs;
}
out_ofs -= seg_size;
for (unsigned int j = 0; j < seg_size; j++) {
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
}
@ -182,7 +182,7 @@ static void *kip1_uncompress(kip1_ctx_t *ctx, uint64_t *size) {
new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size;
}
new_header.flags &= 0xF8;
*size = kip1_get_size_from_header(&new_header);
unsigned char *new_kip = calloc(1, *size);
if (new_kip == NULL) {
@ -190,7 +190,7 @@ static void *kip1_uncompress(kip1_ctx_t *ctx, uint64_t *size) {
exit(EXIT_FAILURE);
}
*((kip1_header_t *)new_kip) = new_header;
uint64_t new_offset = 0x100;
uint64_t old_offset = 0x100;
for (unsigned int i = 0; i < 3; i++) {
@ -200,19 +200,19 @@ static void *kip1_uncompress(kip1_ctx_t *ctx, uint64_t *size) {
new_offset += ctx->header->section_headers[i].out_size;
old_offset += ctx->header->section_headers[i].compressed_size;
}
return new_kip;
}
void kip1_process(kip1_ctx_t *ctx) {
/* Read *just* safe amount. */
kip1_header_t raw_header;
kip1_header_t raw_header;
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) {
fprintf(stderr, "Failed to read KIP1 header!\n");
exit(EXIT_FAILURE);
}
if (raw_header.magic != MAGIC_KIP1) {
printf("Error: KIP1 is corrupt!\n");
exit(EXIT_FAILURE);
@ -224,17 +224,17 @@ void kip1_process(kip1_ctx_t *ctx) {
fprintf(stderr, "Failed to allocate KIP1!\n");
exit(EXIT_FAILURE);
}
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(ctx->header, 1, size, ctx->file) != size) {
fprintf(stderr, "Failed to read KIP1!\n");
exit(EXIT_FAILURE);
}
if (ctx->tool_ctx->action & ACTION_INFO) {
kip1_print(ctx, 0);
}
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
kip1_save(ctx);
}

76
main.c
View file

@ -19,7 +19,7 @@ static const char *prog_name = "hactool";
/* Print usage. Taken largely from ctrtool. */
static void usage(void) {
fprintf(stderr,
fprintf(stderr,
"hactool (c) SciresM.\n"
"Built: %s %s\n"
"\n"
@ -56,7 +56,7 @@ static void usage(void) {
" --baseromfs Set Base RomFS to use with update partitions.\n"
" --basenca Set Base NCA to use with update partitions.\n"
" --basefake Use a fake Base RomFS with update partitions (all reads will return 0xCC).\n"
" --onlyupdated Ignore non-updated files in update partitions.\n"
" --onlyupdated Ignore non-updated files in update partitions.\n"
"NPDM options:\n"
" --json=file Specify file path for saving JSON representation of program permissions to.\n"
"KIP1 options:\n"
@ -124,7 +124,7 @@ int main(int argc, char **argv) {
filepath_init(&keypath);
nca_ctx.tool_ctx = &tool_ctx;
nca_ctx.is_cli_target = true;
nca_ctx.tool_ctx->file_type = FILETYPE_NCA;
base_ctx.file_type = FILETYPE_NCA;
@ -134,7 +134,7 @@ int main(int argc, char **argv) {
while (1) {
int option_index;
int c;
static struct option long_options[] =
static struct option long_options[] =
{
{"extract", 0, NULL, 'x'},
{"info", 0, NULL, 'i'},
@ -192,7 +192,7 @@ int main(int argc, char **argv) {
if (c == -1)
break;
switch (c)
switch (c)
{
case 'i':
nca_ctx.tool_ctx->action |= ACTION_INFO;
@ -219,9 +219,9 @@ int main(int argc, char **argv) {
} else if (!strcmp(optarg, "pfs0") || !strcmp(optarg, "exefs")) {
nca_ctx.tool_ctx->file_type = FILETYPE_PFS0;
} else if (!strcmp(optarg, "romfs")) {
nca_ctx.tool_ctx->file_type = FILETYPE_ROMFS;
nca_ctx.tool_ctx->file_type = FILETYPE_ROMFS;
} else if (!strcmp(optarg, "nca0_romfs") || !strcmp(optarg, "nca0romfs") || !strcmp(optarg, "betaromfs") || !strcmp(optarg, "beta_romfs")) {
nca_ctx.tool_ctx->file_type = FILETYPE_NCA0_ROMFS;
nca_ctx.tool_ctx->file_type = FILETYPE_NCA0_ROMFS;
} else if (!strcmp(optarg, "hfs0")) {
nca_ctx.tool_ctx->file_type = FILETYPE_HFS0;
} else if (!strcmp(optarg, "xci") || !strcmp(optarg, "gamecard") || !strcmp(optarg, "gc")) {
@ -256,19 +256,19 @@ int main(int argc, char **argv) {
case 7: filepath_set(&nca_ctx.tool_ctx->settings.section_dir_paths[3], optarg); break;
case 8:
nca_ctx.tool_ctx->settings.exefs_path.enabled = 1;
filepath_set(&nca_ctx.tool_ctx->settings.exefs_path.path, optarg);
filepath_set(&nca_ctx.tool_ctx->settings.exefs_path.path, optarg);
break;
case 9:
nca_ctx.tool_ctx->settings.romfs_path.enabled = 1;
filepath_set(&nca_ctx.tool_ctx->settings.romfs_path.path, optarg);
filepath_set(&nca_ctx.tool_ctx->settings.romfs_path.path, optarg);
break;
case 10:
nca_ctx.tool_ctx->settings.exefs_dir_path.enabled = 1;
filepath_set(&nca_ctx.tool_ctx->settings.exefs_dir_path.path, optarg);
filepath_set(&nca_ctx.tool_ctx->settings.exefs_dir_path.path, optarg);
break;
case 11:
nca_ctx.tool_ctx->settings.romfs_dir_path.enabled = 1;
filepath_set(&nca_ctx.tool_ctx->settings.romfs_dir_path.path, optarg);
filepath_set(&nca_ctx.tool_ctx->settings.romfs_dir_path.path, optarg);
break;
case 12:
parse_hex_key(nca_ctx.tool_ctx->settings.cli_titlekey, optarg, 16);
@ -314,43 +314,43 @@ int main(int argc, char **argv) {
break;
case 17:
tool_ctx.settings.out_dir_path.enabled = 1;
filepath_set(&tool_ctx.settings.out_dir_path.path, optarg);
filepath_set(&tool_ctx.settings.out_dir_path.path, optarg);
break;
case 18:
filepath_set(&nca_ctx.tool_ctx->settings.plaintext_path, optarg);
filepath_set(&nca_ctx.tool_ctx->settings.plaintext_path, optarg);
break;
case 19:
filepath_set(&nca_ctx.tool_ctx->settings.header_path, optarg);
filepath_set(&nca_ctx.tool_ctx->settings.header_path, optarg);
break;
case 20:
filepath_set(&tool_ctx.settings.pfs0_dir_path, optarg);
filepath_set(&tool_ctx.settings.pfs0_dir_path, optarg);
break;
case 21:
filepath_set(&tool_ctx.settings.hfs0_dir_path, optarg);
filepath_set(&tool_ctx.settings.hfs0_dir_path, optarg);
break;
case 22:
filepath_set(&tool_ctx.settings.rootpt_dir_path, optarg);
filepath_set(&tool_ctx.settings.rootpt_dir_path, optarg);
break;
case 23:
filepath_set(&tool_ctx.settings.update_dir_path, optarg);
filepath_set(&tool_ctx.settings.update_dir_path, optarg);
break;
case 24:
filepath_set(&tool_ctx.settings.normal_dir_path, optarg);
filepath_set(&tool_ctx.settings.normal_dir_path, optarg);
break;
case 25:
filepath_set(&tool_ctx.settings.secure_dir_path, optarg);
filepath_set(&tool_ctx.settings.secure_dir_path, optarg);
break;
case 26:
filepath_set(&tool_ctx.settings.logo_dir_path, optarg);
filepath_set(&tool_ctx.settings.logo_dir_path, optarg);
break;
case 27:
filepath_set(&tool_ctx.settings.pk11_dir_path, optarg);
filepath_set(&tool_ctx.settings.pk11_dir_path, optarg);
break;
case 28:
filepath_set(&tool_ctx.settings.pk21_dir_path, optarg);
filepath_set(&tool_ctx.settings.pk21_dir_path, optarg);
break;
case 29:
filepath_set(&tool_ctx.settings.ini1_dir_path, optarg);
filepath_set(&tool_ctx.settings.ini1_dir_path, optarg);
break;
case 30:
tool_ctx.action |= ACTION_EXTRACTINI1;
@ -386,13 +386,13 @@ int main(int argc, char **argv) {
parse_hex_key(nca_ctx.tool_ctx->settings.keygen_tsec, optarg, 16);
break;
case 37:
filepath_set(&tool_ctx.settings.npdm_json_path, optarg);
filepath_set(&tool_ctx.settings.npdm_json_path, optarg);
break;
case 38:
tool_ctx.action |= ACTION_SAVEINIJSON;
break;
case 39:
filepath_set(&nca_ctx.tool_ctx->settings.uncompressed_path, optarg);
filepath_set(&nca_ctx.tool_ctx->settings.uncompressed_path, optarg);
break;
case 40:
nca_ctx.tool_ctx->settings.skip_key_warnings = 1;
@ -405,7 +405,7 @@ int main(int argc, char **argv) {
return EXIT_FAILURE;
}
}
/* Try to populate default keyfile. */
FILE *keyfile = NULL;
if (keypath.valid == VALIDITY_VALID) {
@ -432,7 +432,7 @@ int main(int argc, char **argv) {
pki_derive_keys(&tool_ctx.settings.keyset);
fclose(keyfile);
}
/* Try to load titlekeys. */
FILE *titlekeyfile = open_key_file("title");
if (titlekeyfile != NULL) {
@ -445,7 +445,7 @@ int main(int argc, char **argv) {
} else if (tool_ctx.file_type != FILETYPE_BOOT0 && ((optind < argc) || (argc == 1))) {
usage();
}
/* Special case NAX0. */
if (tool_ctx.file_type == FILETYPE_NAX0) {
nax0_ctx_t nax_ctx;
@ -453,10 +453,10 @@ int main(int argc, char **argv) {
filepath_set(&nax_ctx.base_path, input_name);
nax_ctx.tool_ctx = &tool_ctx;
nax0_process(&nax_ctx);
if (nax_ctx.aes_ctx) {
free_aes_ctx(nax_ctx.aes_ctx);
}
}
if (nax_ctx.num_files) {
for (unsigned int i = 0; i < nax_ctx.num_files; i++) {
fclose(nax_ctx.files[i]);
@ -467,13 +467,13 @@ int main(int argc, char **argv) {
}
printf("Done!\n");
return EXIT_SUCCESS;
}
}
if ((tool_ctx.file = fopen(input_name, "rb")) == NULL && tool_ctx.file_type != FILETYPE_BOOT0) {
fprintf(stderr, "unable to open %s: %s\n", input_name, strerror(errno));
return EXIT_FAILURE;
}
switch (tool_ctx.file_type) {
case FILETYPE_NCA: {
if (nca_ctx.tool_ctx->base_nca_ctx != NULL) {
@ -497,18 +497,18 @@ int main(int argc, char **argv) {
nca_ctx.file = tool_ctx.file;
nca_process(&nca_ctx);
nca_free_section_contexts(&nca_ctx);
if (nca_ctx.tool_ctx->base_file_type == BASEFILE_FAKE) {
nca_ctx.tool_ctx->base_file = NULL;
}
if (nca_ctx.tool_ctx->base_file != NULL) {
fclose(nca_ctx.tool_ctx->base_file);
if (nca_ctx.tool_ctx->base_file_type == BASEFILE_NCA) {
nca_free_section_contexts(nca_ctx.tool_ctx->base_nca_ctx);
free(nca_ctx.tool_ctx->base_nca_ctx);
}
}
}
break;
}
case FILETYPE_PFS0: {
@ -699,7 +699,7 @@ int main(int argc, char **argv) {
usage();
}
}
if (tool_ctx.settings.known_titlekeys.titlekeys != NULL) {
free(tool_ctx.settings.known_titlekeys.titlekeys);
}

18
nax0.c
View file

@ -8,7 +8,7 @@ static size_t nax0_read(nax0_ctx_t *ctx, uint64_t offset, void *dst, size_t size
fseeko64(ctx->files[0], offset, SEEK_SET);
return fread(dst, 1, size, ctx->files[0]);
}
FILE *which = ctx->files[offset / 0xFFFF0000ULL];
uint64_t offset_in_file = offset % 0xFFFF0000ULL;
fseeko64(which, offset_in_file, SEEK_SET);
@ -61,15 +61,15 @@ void nax0_process(nax0_ctx_t *ctx) {
}
}
}
nax0_read(ctx, 0, &ctx->header, sizeof(ctx->header));
if (ctx->header.magic != MAGIC_NAX0) {
printf("Error: File has invalid NAX0 magic!\n");
return;
}
memcpy(ctx->encrypted_keys, ctx->header.keys, sizeof(ctx->header.keys));
int found = 0;
for (ctx->k = 0; ctx->k < 2; ctx->k++) {
unsigned char nax_specific_keys[2][0x10];
@ -79,7 +79,7 @@ void nax0_process(nax0_ctx_t *ctx) {
aes_decrypt(nax_k_ctx, ctx->header.keys[i], ctx->encrypted_keys[i], 0x10);
free_aes_ctx(nax_k_ctx);
}
unsigned char validation_mac[0x20];
sha256_get_buffer_hmac(validation_mac, &ctx->header.magic, 0x60, ctx->tool_ctx->settings.keyset.sd_card_keys[ctx->k] + 0x10, 0x10);
if (memcmp(ctx->header.hmac_header, validation_mac, 0x20) == 0) {
@ -87,18 +87,18 @@ void nax0_process(nax0_ctx_t *ctx) {
break;
}
}
if (!found) {
printf("Error: NAX0 key derivation failed. Check SD card seed and relative path?\n");
return;
}
ctx->aes_ctx = new_aes_ctx(ctx->header.keys, 0x20, AES_MODE_XTS);
if (ctx->tool_ctx->action & ACTION_INFO) {
nax0_print(ctx);
}
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
nax0_save(ctx);
}

2
nca.h
View file

@ -165,7 +165,7 @@ typedef struct {
typedef struct nca_ctx {
FILE *file; /* File for this NCA. */
size_t file_size;
size_t file_size;
unsigned char crypto_type;
int has_rights_id;
int is_decrypted;

View file

@ -16,7 +16,7 @@ static void nca0_romfs_visit_file(nca0_romfs_ctx_t *ctx, uint32_t file_offset, f
if (entry->name_size) {
filepath_append_n(cur_path, entry->name_size, "%s", entry->name);
}
/* If we're extracting... */
if ((ctx->tool_ctx->action & ACTION_LISTROMFS) == 0) {
printf("Saving %s...\n", cur_path->char_path);
@ -99,14 +99,14 @@ void nca0_romfs_process(nca0_romfs_ctx_t *ctx) {
fprintf(stderr, "NCA0 RomFS is corrupt?\n");
return;
}
/* If there's ever anything meaningful to print about RomFS, uncomment and implement.
*
* if (ctx->tool_ctx->action & ACTION_INFO) {
* nca0_romfs_print(ctx);
* }
*/
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
nca0_romfs_save(ctx);
}

View file

@ -27,7 +27,7 @@ typedef struct {
uint32_t block_size; /* In bytes. */
uint32_t always_2;
uint64_t hash_table_offset; /* Normally zero. */
uint64_t hash_table_size;
uint64_t hash_table_size;
uint64_t romfs_offset;
uint64_t romfs_size;
uint8_t _0x48[0xF0];

20
nso.c
View file

@ -15,7 +15,7 @@ static void *nso_uncompress(nso0_ctx_t *ctx) {
new_header.segments[1].align_or_total_size = 0;
/* Clear compression flags. */
new_header.flags &= 0xF8;
uint64_t size = nso_get_size(&new_header);
nso0_header_t *new_nso = calloc(1, size);
if (new_nso == NULL) {
@ -23,7 +23,7 @@ static void *nso_uncompress(nso0_ctx_t *ctx) {
exit(EXIT_FAILURE);
}
*((nso0_header_t *)new_nso) = new_header;
for (unsigned int segment = 0; segment < 3; segment++) {
char *src = (char *)ctx->header + ctx->header->segments[segment].file_off;
char *dst = (char *)new_nso + new_header.segments[segment].file_off;
@ -45,19 +45,19 @@ static void *nso_uncompress(nso0_ctx_t *ctx) {
}
}
}
return new_nso;
}
void nso0_process(nso0_ctx_t *ctx) {
/* Read *just* safe amount. */
nso0_header_t raw_header;
nso0_header_t raw_header;
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) {
fprintf(stderr, "Failed to read NSO0 header!\n");
exit(EXIT_FAILURE);
}
if (raw_header.magic != MAGIC_NSO0) {
printf("Error: NSO0 is corrupt!\n");
exit(EXIT_FAILURE);
@ -69,19 +69,19 @@ void nso0_process(nso0_ctx_t *ctx) {
fprintf(stderr, "Failed to allocate NSO0!\n");
exit(EXIT_FAILURE);
}
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(ctx->header, 1, size, ctx->file) != size) {
fprintf(stderr, "Failed to read NSO0!\n");
exit(EXIT_FAILURE);
}
ctx->uncompressed_header = nso_uncompress(ctx);
if (ctx->tool_ctx->action & ACTION_INFO) {
nso0_print(ctx);
}
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
nso0_save(ctx);
}
@ -111,7 +111,7 @@ void nso0_print(nso0_ctx_t *ctx) {
void nso0_save(nso0_ctx_t *ctx) {
filepath_t *uncmp_path = &ctx->tool_ctx->settings.uncompressed_path;
if (ctx->tool_ctx->file_type == FILETYPE_NSO0 && uncmp_path->valid == VALIDITY_VALID) {
if (ctx->tool_ctx->file_type == FILETYPE_NSO0 && uncmp_path->valid == VALIDITY_VALID) {
FILE *f_uncmp = os_fopen(uncmp_path->os_path, OS_MODE_WRITE);
if (f_uncmp == NULL) {
fprintf(stderr, "Failed to open %s!\n", uncmp_path->char_path);

View file

@ -11,7 +11,7 @@ void pk11_process(pk11_ctx_t *ctx) {
fprintf(stderr, "Failed to read PK11 Stage 1!\n");
exit(EXIT_FAILURE);
}
/* Check if PK11 was built in 2016. */
/* This is a heuristic to detect an older layout for the PK11 binary. */
if (ctx->stage1.build_date[0] == '2' && ctx->stage1.build_date[1] == '0' && ctx->stage1.build_date[2] == '1' && ctx->stage1.build_date[3] == '6') {
@ -19,18 +19,18 @@ void pk11_process(pk11_ctx_t *ctx) {
} else {
ctx->is_pilot = 0;
}
ctx->pk11 = malloc(ctx->stage1.pk11_size);
if (ctx->pk11 == NULL) {
fprintf(stderr, "Failed to allocate PK11!\n");
exit(EXIT_FAILURE);
}
if (fread(ctx->pk11, 1, ctx->stage1.pk11_size, ctx->file) != ctx->stage1.pk11_size) {
fprintf(stderr, "Failed to read PK11!\n");
exit(EXIT_FAILURE);
}
aes_ctx_t *crypt_ctx = NULL;
pk11_t dec_header;
for (unsigned int i = 0; i < 0x20; i++) {
@ -44,26 +44,26 @@ void pk11_process(pk11_ctx_t *ctx) {
free_aes_ctx(crypt_ctx);
crypt_ctx = NULL;
}
if (crypt_ctx == NULL) {
fprintf(stderr, "Failed to decrypt PK11! Is correct key present?\n");
exit(EXIT_FAILURE);
}
aes_setiv(crypt_ctx, ctx->stage1.ctr, 0x10);
aes_decrypt(crypt_ctx, ctx->pk11, ctx->pk11, ctx->stage1.pk11_size);
uint64_t pk11_size = 0x20 + ctx->pk11->warmboot_size + ctx->pk11->nx_bootloader_size + ctx->pk11->secmon_size;
pk11_size = align64(pk11_size, 0x10);
if (pk11_size != ctx->stage1.pk11_size) {
fprintf(stderr, "PK11 seems corrupt!\n");
exit(EXIT_FAILURE);
}
if (ctx->tool_ctx->action & ACTION_INFO) {
pk11_print(ctx);
}
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
pk11_save(ctx);
}
@ -92,7 +92,7 @@ void pk11_save(pk11_ctx_t *ctx) {
}
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
os_makedir(dirpath->os_path);
/* Save Decrypted.bin */
printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path);
char *decrypted_bin = malloc(sizeof(ctx->stage1) + ctx->stage1.pk11_size);
@ -104,28 +104,28 @@ void pk11_save(pk11_ctx_t *ctx) {
memcpy(decrypted_bin + sizeof(ctx->stage1), ctx->pk11, ctx->stage1.pk11_size);
save_buffer_to_directory_file(decrypted_bin, sizeof(ctx->stage1) + ctx->stage1.pk11_size, dirpath, "Decrypted.bin");
free(decrypted_bin);
/* Save Warmboot.bin */
printf("Saving Warmboot.bin to %s/Warmboot.bin...\n", dirpath->char_path);
save_buffer_to_directory_file(pk11_get_warmboot_bin(ctx), ctx->pk11->warmboot_size, dirpath, "Warmboot.bin");
/* Save NX_Bootloader.bin */
printf("Saving NX_Bootloader.bin to %s/NX_Bootloader.bin...\n", dirpath->char_path);
save_buffer_to_directory_file(pk11_get_nx_bootloader(ctx), ctx->pk11->nx_bootloader_size, dirpath, "NX_Bootloader.bin");
/* Save Secure_Monitor.bin */
printf("Saving Secure_Monitor.bin to %s/Secure_Monitor.bin...\n", dirpath->char_path);
save_buffer_to_directory_file(pk11_get_secmon(ctx), ctx->pk11->secmon_size, dirpath, "Secure_Monitor.bin");
}
}
void pk21_process(pk21_ctx_t *ctx) {
void pk21_process(pk21_ctx_t *ctx) {
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(&ctx->header, 1, sizeof(ctx->header), ctx->file) != sizeof(ctx->header)) {
fprintf(stderr, "Failed to read PK21 Header!\n");
exit(EXIT_FAILURE);
}
bool is_encrypted = false;
for (unsigned int i = 0; i < 0x100; i++) {
if (ctx->header.signature[i] != 0) {
@ -133,7 +133,7 @@ void pk21_process(pk21_ctx_t *ctx) {
}
}
is_encrypted &= ctx->header.magic != MAGIC_PK21;
if (is_encrypted) {
if (rsa2048_pss_verify(&ctx->header.ctr, 0x100, ctx->header.signature, ctx->tool_ctx->settings.keyset.package2_fixed_key_modulus)) {
ctx->signature_validity = VALIDITY_VALID;
@ -143,21 +143,21 @@ void pk21_process(pk21_ctx_t *ctx) {
} else {
ctx->signature_validity = VALIDITY_UNCHECKED;
}
/* Nintendo, what the fuck? */
ctx->package_size = ctx->header.ctr_dwords[0] ^ ctx->header.ctr_dwords[2] ^ ctx->header.ctr_dwords[3];
if (ctx->package_size > 0x7FC000) {
fprintf(stderr, "Error: Package2 Header is corrupt!\n");
exit(EXIT_FAILURE);
}
aes_ctx_t *crypt_ctx = NULL;
if (is_encrypted) {
unsigned char ctr[0x10];
pk21_header_t temp_header;
memcpy(ctr, ctx->header.ctr, sizeof(ctr));
for (unsigned int i = 0; i < 0x20; i++) {
ctx->key_rev = i;
memcpy(&temp_header, &ctx->header, sizeof(temp_header));
@ -172,29 +172,29 @@ void pk21_process(pk21_ctx_t *ctx) {
free_aes_ctx(crypt_ctx);
crypt_ctx = NULL;
}
if (crypt_ctx == NULL) {
fprintf(stderr, "Failed to decrypt PK21! Is correct key present?\n");
exit(EXIT_FAILURE);
}
}
if (ctx->package_size != 0x200 + ctx->header.section_sizes[0] + ctx->header.section_sizes[1] + ctx->header.section_sizes[2]) {
fprintf(stderr, "Error: Package2 Header is corrupt!\n");
exit(EXIT_FAILURE);
}
ctx->sections = malloc(ctx->package_size);
if (ctx->sections == NULL) {
fprintf(stderr, "Failed to allocate sections!\n");
exit(EXIT_FAILURE);
}
if (fread(ctx->sections, 1, ctx->package_size - 0x200, ctx->file) != ctx->package_size - 0x200) {
fprintf(stderr, "Failed to read PK21 Sections!\n");
exit(EXIT_FAILURE);
}
uint64_t offset = 0;
for (unsigned int i = 0; i < 3; i++) {
unsigned char calc_hash[0x20];
@ -206,11 +206,11 @@ void pk21_process(pk21_ctx_t *ctx) {
}
if (is_encrypted) {
aes_setiv(crypt_ctx, ctx->header.section_ctrs[i], 0x10);
aes_decrypt(crypt_ctx, ctx->sections + offset, ctx->sections + offset, ctx->header.section_sizes[i]);
aes_decrypt(crypt_ctx, ctx->sections + offset, ctx->sections + offset, ctx->header.section_sizes[i]);
}
offset += ctx->header.section_sizes[i];
}
ctx->ini1_ctx.tool_ctx = ctx->tool_ctx;
/* Support 8.0.0 INI1 embedded in Kernel */
if (ctx->header.section_sizes[1] > 0) {
@ -237,11 +237,11 @@ void pk21_process(pk21_ctx_t *ctx) {
offset += kip1_get_size(&ctx->ini1_ctx.kips[i]);
}
}
if (ctx->tool_ctx->action & ACTION_INFO) {
pk21_print(ctx);
}
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
pk21_save(ctx);
}
@ -271,10 +271,10 @@ void pk21_print(pk21_ctx_t *ctx) {
} else {
memdump(stdout, " Signature: ", &ctx->header.signature, 0x100);
}
/* What the fuck? */
printf(" Header Version: %02"PRIx32"\n", (ctx->header.ctr_dwords[1] ^ (ctx->header.ctr_dwords[1] >> 16) ^ (ctx->header.ctr_dwords[1] >> 24)) & 0xFF);
bool is_ini1_embedded = ctx->header.section_sizes[1] == 0;
for (unsigned int i = 0; i < 3; i++) {
printf(" Section %"PRId32" (%s):\n", i, pk21_get_section_name(i, is_ini1_embedded));
@ -291,7 +291,7 @@ void pk21_print(pk21_ctx_t *ctx) {
printf(" Load Address: %08"PRIx32"\n", ctx->header.section_offsets[i] + 0x80000000);
printf(" Size: %08"PRIx32"\n", ctx->header.section_sizes[i]);
}
printf("\n");
ini1_print(&ctx->ini1_ctx);
}
@ -307,7 +307,7 @@ void pk21_save(pk21_ctx_t *ctx) {
}
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
os_makedir(dirpath->os_path);
/* Save Decrypted.bin */
printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path);
char *decrypted_bin = malloc(ctx->package_size);
@ -319,11 +319,11 @@ void pk21_save(pk21_ctx_t *ctx) {
memcpy(decrypted_bin + sizeof(ctx->header), ctx->sections, ctx->package_size - 0x200);
save_buffer_to_directory_file(decrypted_bin, ctx->package_size, dirpath, "Decrypted.bin");
free(decrypted_bin);
/* Save Kernel.bin */
printf("Saving Kernel.bin to %s/Kernel.bin...\n", dirpath->char_path);
save_buffer_to_directory_file(ctx->sections, ctx->header.section_sizes[0], dirpath, "Kernel.bin");
/* Save INI1.bin */
printf("Saving INI1.bin to %s/INI1.bin...\n", dirpath->char_path);
if (ctx->header.section_sizes[1] > 0)

14
pfs0.c
View file

@ -3,13 +3,13 @@
void pfs0_process(pfs0_ctx_t *ctx) {
/* Read *just* safe amount. */
pfs0_header_t raw_header;
pfs0_header_t raw_header;
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) {
fprintf(stderr, "Failed to read PFS0 header!\n");
exit(EXIT_FAILURE);
}
if (raw_header.magic != MAGIC_PFS0) {
printf("Error: PFS0 is corrupt!\n");
exit(EXIT_FAILURE);
@ -21,16 +21,16 @@ void pfs0_process(pfs0_ctx_t *ctx) {
fprintf(stderr, "Failed to allocate PFS0 header!\n");
exit(EXIT_FAILURE);
}
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(ctx->header, 1, header_size, ctx->file) != header_size) {
fprintf(stderr, "Failed to read PFS0 header!\n");
exit(EXIT_FAILURE);
}
/* Weak file validation. */
uint64_t max_size = 0x1ULL;
max_size <<= 48; /* Switch file sizes are capped at 48 bits. */
max_size <<= 48; /* Switch file sizes are capped at 48 bits. */
uint64_t cur_ofs = 0;
for (unsigned int i = 0; i < ctx->header->num_files; i++) {
pfs0_file_entry_t *cur_file = pfs0_get_file_entry(ctx->header, i);
@ -58,11 +58,11 @@ void pfs0_process(pfs0_ctx_t *ctx) {
}
}
}
if (ctx->tool_ctx->action & ACTION_INFO) {
pfs0_print(ctx);
}
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
pfs0_save(ctx);
}

2
pfs0.h
View file

@ -26,7 +26,7 @@ typedef struct {
uint32_t block_size; /* In bytes. */
uint32_t always_2;
uint64_t hash_table_offset; /* Normally zero. */
uint64_t hash_table_size;
uint64_t hash_table_size;
uint64_t pfs0_offset;
uint64_t pfs0_size;
uint8_t _0x48[0xF0];

View file

@ -96,14 +96,14 @@ void romfs_process(romfs_ctx_t *ctx) {
exit(EXIT_FAILURE);
}
}
/* If there's ever anything meaningful to print about RomFS, uncomment and implement.
*
* if (ctx->tool_ctx->action & ACTION_INFO) {
* romfs_print(ctx);
* }
*/
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
romfs_save(ctx);
}

52
rsa.c
View file

@ -11,7 +11,7 @@
static void calculate_mgf1_and_xor(unsigned char *data, size_t data_size, const void *h_src, size_t h_src_size) {
unsigned char h_buf[RSA_2048_BYTES] = {0};
memcpy(h_buf, h_src, h_src_size);
unsigned char mgf1_buf[0x20];
size_t ofs = 0;
unsigned int seed = 0;
@ -34,7 +34,7 @@ int rsa2048_pss_verify(const void *data, size_t len, const unsigned char *signat
mbedtls_mpi modulus_mpi;
mbedtls_mpi e_mpi;
mbedtls_mpi message_mpi;
mbedtls_mpi_init(&signature_mpi);
mbedtls_mpi_init(&modulus_mpi);
mbedtls_mpi_init(&e_mpi);
@ -44,7 +44,7 @@ int rsa2048_pss_verify(const void *data, size_t len, const unsigned char *signat
unsigned char m_buf[RSA_2048_BYTES];
unsigned char h_buf[0x24];
const unsigned char E[3] = {1, 0, 1};
mbedtls_mpi_read_binary(&e_mpi, E, 3);
mbedtls_mpi_read_binary(&signature_mpi, signature, RSA_2048_BYTES);
mbedtls_mpi_read_binary(&modulus_mpi, modulus, RSA_2048_BYTES);
@ -77,7 +77,7 @@ int rsa2048_pss_verify(const void *data, size_t len, const unsigned char *signat
if (m_buf[i] != 0) {
return false;
}
}
}
if (m_buf[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) {
return false;
}
@ -98,7 +98,7 @@ int rsa2048_pkcs1_verify(const void *data, size_t len, const unsigned char *sign
mbedtls_mpi modulus_mpi;
mbedtls_mpi e_mpi;
mbedtls_mpi message_mpi;
mbedtls_mpi_init(&signature_mpi);
mbedtls_mpi_init(&modulus_mpi);
mbedtls_mpi_init(&e_mpi);
@ -108,7 +108,7 @@ int rsa2048_pkcs1_verify(const void *data, size_t len, const unsigned char *sign
unsigned char m_buf[RSA_2048_BYTES];
unsigned char h_buf[0x20];
const unsigned char E[3] = {1, 0, 1};
mbedtls_mpi_read_binary(&e_mpi, E, 3);
mbedtls_mpi_read_binary(&signature_mpi, signature, RSA_2048_BYTES);
mbedtls_mpi_read_binary(&modulus_mpi, modulus, RSA_2048_BYTES);
@ -122,27 +122,27 @@ int rsa2048_pkcs1_verify(const void *data, size_t len, const unsigned char *sign
mbedtls_mpi_free(&modulus_mpi);
mbedtls_mpi_free(&e_mpi);
mbedtls_mpi_free(&message_mpi);
/* For RSA-2048, this prefix is just a constant. */
const unsigned char pkcs1_hash_prefix[0xE0] = {
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x31, 0x30,
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x31, 0x30,
0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
};
sha256_hash_buffer(h_buf, data, len);
return memcmp(pkcs1_hash_prefix, m_buf, 0xE0) == 0 && memcmp(&m_buf[0xE0], h_buf, 0x20) == 0;
}
@ -152,7 +152,7 @@ int rsa2048_oaep_decrypt_verify(void *out, size_t max_out_len, const unsigned ch
mbedtls_mpi modulus_mpi;
mbedtls_mpi exp_mpi;
mbedtls_mpi message_mpi;
mbedtls_mpi_init(&signature_mpi);
mbedtls_mpi_init(&modulus_mpi);
mbedtls_mpi_init(&exp_mpi);
@ -160,7 +160,7 @@ int rsa2048_oaep_decrypt_verify(void *out, size_t max_out_len, const unsigned ch
mbedtls_mpi_lset(&message_mpi, RSA_2048_BITS);
unsigned char m_buf[RSA_2048_BYTES];
mbedtls_mpi_read_binary(&exp_mpi, exponent, exponent_len);
mbedtls_mpi_read_binary(&signature_mpi, signature, RSA_2048_BYTES);
mbedtls_mpi_read_binary(&modulus_mpi, modulus, RSA_2048_BYTES);
@ -174,7 +174,7 @@ int rsa2048_oaep_decrypt_verify(void *out, size_t max_out_len, const unsigned ch
mbedtls_mpi_free(&modulus_mpi);
mbedtls_mpi_free(&exp_mpi);
mbedtls_mpi_free(&message_mpi);
/* There's no automated PSS verification as far as I can tell. */
if (m_buf[0] != 0x00) {
return false;
@ -190,7 +190,7 @@ int rsa2048_oaep_decrypt_verify(void *out, size_t max_out_len, const unsigned ch
if (memcmp(db, label_hash, 0x20) != 0) {
return false;
}
/* Validate message prefix. */
const unsigned char *data = db + 0x20;
size_t remaining = RSA_2048_BYTES - 0x20 - 1 - 0x20;

View file

@ -20,9 +20,9 @@ typedef struct {
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. */
unsigned char keyblobs[0x20][0x90]; /* Actual decrypted keyblobs (EKS). */
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. */
unsigned char keyblobs[0x20][0x90]; /* Actual decrypted keyblobs (EKS). */
unsigned char keyblob_key_sources[0x20][0x10]; /* Seeds for keyblob keys. */
unsigned char keyblob_mac_key_source[0x10]; /* Seed for keyblob MAC key derivation. */
unsigned char tsec_root_kek[0x10]; /* Used to generate TSEC root keys. */

26
sha.c
View file

@ -7,21 +7,21 @@
/* Allocate new context. */
sha_ctx_t *new_sha_ctx(hash_type_t type, int hmac) {
sha_ctx_t *ctx;
if ((ctx = malloc(sizeof(*ctx))) == NULL) {
FATAL_ERROR("Failed to allocate sha_ctx_t!");
}
mbedtls_md_init(&ctx->digest);
if (mbedtls_md_setup(&ctx->digest, mbedtls_md_info_from_type(type), hmac)) {
FATAL_ERROR("Failed to set up hash context!");
}
if (mbedtls_md_starts(&ctx->digest)) {
FATAL_ERROR("Failed to start hash context!");
}
return ctx;
}
@ -31,7 +31,7 @@ void free_sha_ctx(sha_ctx_t *ctx) {
if (ctx == NULL) {
return;
}
mbedtls_md_free(&ctx->digest);
free(ctx);
}
@ -57,29 +57,29 @@ void sha256_hash_buffer(unsigned char *digest, const void *data, size_t l) {
/* SHA256-HMAC digest. */
void sha256_get_buffer_hmac(void *digest, const void *secret, size_t s_l, const void *data, size_t d_l) {
sha_ctx_t *ctx;
if ((ctx = malloc(sizeof(*ctx))) == NULL) {
FATAL_ERROR("Failed to allocate sha_ctx_t!");
}
mbedtls_md_init(&ctx->digest);
if (mbedtls_md_setup(&ctx->digest, mbedtls_md_info_from_type(HASH_TYPE_SHA256), 1)) {
FATAL_ERROR("Failed to set up hash context!");
}
if (mbedtls_md_hmac_starts(&ctx->digest, secret, s_l)) {
FATAL_ERROR("Failed to set up HMAC secret context!");
}
if (mbedtls_md_hmac_update(&ctx->digest, data, d_l)) {
FATAL_ERROR("Failed processing HMAC input!");
}
if (mbedtls_md_hmac_finish(&ctx->digest, digest)) {
FATAL_ERROR("Failed getting HMAC output!");
}
mbedtls_md_free(&ctx->digest);
free(ctx);
}

82
xci.c
View file

@ -7,21 +7,21 @@
/* However, it (and other XCI keys) can be dumped with a GCD attack on two signatures. */
/* Contact SciresM for details, if curious. */
static const unsigned char xci_header_pubk[0x100] = {
0x98, 0xC7, 0x26, 0xB6, 0x0D, 0x0A, 0x50, 0xA7, 0x39, 0x21, 0x0A, 0xE3, 0x2F, 0xE4, 0x3E, 0x2E,
0x5B, 0xA2, 0x86, 0x75, 0xAA, 0x5C, 0xEE, 0x34, 0xF1, 0xA3, 0x3A, 0x7E, 0xBD, 0x90, 0x4E, 0xF7,
0x8D, 0xFA, 0x17, 0xAA, 0x6B, 0xC6, 0x36, 0x6D, 0x4C, 0x9A, 0x6D, 0x57, 0x2F, 0x80, 0xA2, 0xBC,
0x38, 0x4D, 0xDA, 0x99, 0xA1, 0xD8, 0xC3, 0xE2, 0x99, 0x79, 0x36, 0x71, 0x90, 0x20, 0x25, 0x9D,
0x4D, 0x11, 0xB8, 0x2E, 0x63, 0x6B, 0x5A, 0xFA, 0x1E, 0x9C, 0x04, 0xD1, 0xC5, 0xF0, 0x9C, 0xB1,
0x0F, 0xB8, 0xC1, 0x7B, 0xBF, 0xE8, 0xB0, 0xD2, 0x2B, 0x47, 0x01, 0x22, 0x6B, 0x23, 0xC9, 0xD0,
0xBC, 0xEB, 0x75, 0x6E, 0x41, 0x7D, 0x4C, 0x26, 0xA4, 0x73, 0x21, 0xB4, 0xF0, 0x14, 0xE5, 0xD9,
0x8D, 0xB3, 0x64, 0xEE, 0xA8, 0xFA, 0x84, 0x1B, 0xB8, 0xB8, 0x7C, 0x88, 0x6B, 0xEF, 0xCC, 0x97,
0x04, 0x04, 0x9A, 0x67, 0x2F, 0xDF, 0xEC, 0x0D, 0xB2, 0x5F, 0xB5, 0xB2, 0xBD, 0xB5, 0x4B, 0xDE,
0x0E, 0x88, 0xA3, 0xBA, 0xD1, 0xB4, 0xE0, 0x91, 0x81, 0xA7, 0x84, 0xEB, 0x77, 0x85, 0x8B, 0xEF,
0xA5, 0xE3, 0x27, 0xB2, 0xF2, 0x82, 0x2B, 0x29, 0xF1, 0x75, 0x2D, 0xCE, 0xCC, 0xAE, 0x9B, 0x8D,
0xED, 0x5C, 0xF1, 0x8E, 0xDB, 0x9A, 0xD7, 0xAF, 0x42, 0x14, 0x52, 0xCD, 0xE3, 0xC5, 0xDD, 0xCE,
0x08, 0x12, 0x17, 0xD0, 0x7F, 0x1A, 0xAA, 0x1F, 0x7D, 0xE0, 0x93, 0x54, 0xC8, 0xBC, 0x73, 0x8A,
0xCB, 0xAD, 0x6E, 0x93, 0xE2, 0x19, 0x72, 0x6B, 0xD3, 0x45, 0xF8, 0x73, 0x3D, 0x2B, 0x6A, 0x55,
0xD2, 0x3A, 0x8B, 0xB0, 0x8A, 0x42, 0xE3, 0x3D, 0xF1, 0x92, 0x23, 0x42, 0x2E, 0xBA, 0xCC, 0x9C,
0x98, 0xC7, 0x26, 0xB6, 0x0D, 0x0A, 0x50, 0xA7, 0x39, 0x21, 0x0A, 0xE3, 0x2F, 0xE4, 0x3E, 0x2E,
0x5B, 0xA2, 0x86, 0x75, 0xAA, 0x5C, 0xEE, 0x34, 0xF1, 0xA3, 0x3A, 0x7E, 0xBD, 0x90, 0x4E, 0xF7,
0x8D, 0xFA, 0x17, 0xAA, 0x6B, 0xC6, 0x36, 0x6D, 0x4C, 0x9A, 0x6D, 0x57, 0x2F, 0x80, 0xA2, 0xBC,
0x38, 0x4D, 0xDA, 0x99, 0xA1, 0xD8, 0xC3, 0xE2, 0x99, 0x79, 0x36, 0x71, 0x90, 0x20, 0x25, 0x9D,
0x4D, 0x11, 0xB8, 0x2E, 0x63, 0x6B, 0x5A, 0xFA, 0x1E, 0x9C, 0x04, 0xD1, 0xC5, 0xF0, 0x9C, 0xB1,
0x0F, 0xB8, 0xC1, 0x7B, 0xBF, 0xE8, 0xB0, 0xD2, 0x2B, 0x47, 0x01, 0x22, 0x6B, 0x23, 0xC9, 0xD0,
0xBC, 0xEB, 0x75, 0x6E, 0x41, 0x7D, 0x4C, 0x26, 0xA4, 0x73, 0x21, 0xB4, 0xF0, 0x14, 0xE5, 0xD9,
0x8D, 0xB3, 0x64, 0xEE, 0xA8, 0xFA, 0x84, 0x1B, 0xB8, 0xB8, 0x7C, 0x88, 0x6B, 0xEF, 0xCC, 0x97,
0x04, 0x04, 0x9A, 0x67, 0x2F, 0xDF, 0xEC, 0x0D, 0xB2, 0x5F, 0xB5, 0xB2, 0xBD, 0xB5, 0x4B, 0xDE,
0x0E, 0x88, 0xA3, 0xBA, 0xD1, 0xB4, 0xE0, 0x91, 0x81, 0xA7, 0x84, 0xEB, 0x77, 0x85, 0x8B, 0xEF,
0xA5, 0xE3, 0x27, 0xB2, 0xF2, 0x82, 0x2B, 0x29, 0xF1, 0x75, 0x2D, 0xCE, 0xCC, 0xAE, 0x9B, 0x8D,
0xED, 0x5C, 0xF1, 0x8E, 0xDB, 0x9A, 0xD7, 0xAF, 0x42, 0x14, 0x52, 0xCD, 0xE3, 0xC5, 0xDD, 0xCE,
0x08, 0x12, 0x17, 0xD0, 0x7F, 0x1A, 0xAA, 0x1F, 0x7D, 0xE0, 0x93, 0x54, 0xC8, 0xBC, 0x73, 0x8A,
0xCB, 0xAD, 0x6E, 0x93, 0xE2, 0x19, 0x72, 0x6B, 0xD3, 0x45, 0xF8, 0x73, 0x3D, 0x2B, 0x6A, 0x55,
0xD2, 0x3A, 0x8B, 0xB0, 0x8A, 0x42, 0xE3, 0x3D, 0xF1, 0x92, 0x23, 0x42, 0x2E, 0xBA, 0xCC, 0x9C,
0x9A, 0xC1, 0xDD, 0x62, 0x86, 0x9C, 0x2E, 0xE1, 0x2D, 0x6F, 0x62, 0x67, 0x51, 0x08, 0x0E, 0xCF
};
@ -31,12 +31,12 @@ void xci_process(xci_ctx_t *ctx) {
fprintf(stderr, "Failed to read XCI header!\n");
return;
}
if (ctx->header.magic != MAGIC_HEAD) {
fprintf(stderr, "Error: XCI header is corrupt!\n");
exit(EXIT_FAILURE);
}
if (ctx->tool_ctx->action & ACTION_VERIFY) {
if (rsa2048_pkcs1_verify(&ctx->header.magic, 0x100, ctx->header.header_sig, xci_header_pubk)) {
ctx->header_sig_validity = VALIDITY_VALID;
@ -44,31 +44,31 @@ void xci_process(xci_ctx_t *ctx) {
ctx->header_sig_validity = VALIDITY_INVALID;
}
}
ctx->hfs0_hash_validity = check_memory_hash_table(ctx->file, ctx->header.hfs0_header_hash, ctx->header.hfs0_offset, ctx->header.hfs0_header_size, ctx->header.hfs0_header_size, 0);
if (ctx->hfs0_hash_validity != VALIDITY_VALID) {
fprintf(stderr, "Error: XCI partition is corrupt!\n");
exit(EXIT_FAILURE);
}
hactool_ctx_t blank_ctx;
memset(&blank_ctx, 0, sizeof(blank_ctx));
blank_ctx.action = ctx->tool_ctx->action & ~(ACTION_EXTRACT | ACTION_INFO);
ctx->partition_ctx.file = ctx->file;
ctx->partition_ctx.offset = ctx->header.hfs0_offset;
ctx->partition_ctx.tool_ctx = &blank_ctx;
ctx->partition_ctx.name = "rootpt";
hfs0_process(&ctx->partition_ctx);
if (ctx->partition_ctx.header->num_files > 4) {
fprintf(stderr, "Error: Invalid XCI partition!\n");
exit(EXIT_FAILURE);
exit(EXIT_FAILURE);
}
for (unsigned int i = 0; i < ctx->partition_ctx.header->num_files; i++) {
hfs0_ctx_t *cur_ctx = NULL;
hfs0_file_entry_t *cur_file = hfs0_get_file_entry(ctx->partition_ctx.header, i);
char *cur_name = hfs0_get_file_name(ctx->partition_ctx.header, i);
if (!strcmp(cur_name, "update") && ctx->update_ctx.file == NULL) {
@ -79,20 +79,20 @@ void xci_process(xci_ctx_t *ctx) {
cur_ctx = &ctx->secure_ctx;
} else if (!strcmp(cur_name, "logo") && ctx->logo_ctx.file == NULL) {
cur_ctx = &ctx->logo_ctx;
}
}
if (cur_ctx == NULL) {
fprintf(stderr, "Unknown XCI partition: %s\n", cur_name);
exit(EXIT_FAILURE);
}
cur_ctx->name = cur_name;
cur_ctx->offset = ctx->partition_ctx.offset + hfs0_get_header_size(ctx->partition_ctx.header) + cur_file->offset;
cur_ctx->tool_ctx = &blank_ctx;
cur_ctx->file = ctx->file;
hfs0_process(cur_ctx);
}
for (unsigned int i = 0; i < 0x10; i++) {
ctx->iv[i] = ctx->header.reversed_iv[0xF-i];
}
@ -111,12 +111,12 @@ void xci_process(xci_ctx_t *ctx) {
} else {
ctx->has_decrypted_header = 0;
}
if (ctx->tool_ctx->action & ACTION_INFO) {
xci_print(ctx);
}
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
xci_save(ctx);
}
@ -130,7 +130,7 @@ void xci_save(xci_ctx_t *ctx) {
os_makedir(dirpath->os_path);
for (unsigned int i = 0; i < ctx->partition_ctx.header->num_files; i++) {
hfs0_ctx_t *cur_ctx = NULL;
char *cur_name = hfs0_get_file_name(ctx->partition_ctx.header, i);
if (!strcmp(cur_name, "update")) {
cur_ctx = &ctx->update_ctx;
@ -199,7 +199,7 @@ void xci_save(xci_ctx_t *ctx) {
hfs0_save_file(&ctx->logo_ctx, i, &ctx->tool_ctx->settings.logo_dir_path);
}
printf("\n");
}
}
}
}
@ -250,7 +250,7 @@ static void xci_print_hfs0(hfs0_ctx_t *ctx) {
print_magic(" Magic: ", ctx->header->magic);
printf(" Offset: %012"PRIx64"\n", ctx->offset);
printf(" Number of files: %"PRId32"\n", ctx->header->num_files);
if (ctx->header->num_files > 0 && (ctx->header->num_files < 100 || ctx->tool_ctx->action & ACTION_VERIFY)) {
printf(" Files:");
for (unsigned int i = 0; i < ctx->header->num_files; i++) {
@ -264,7 +264,7 @@ static void xci_print_hfs0(hfs0_ctx_t *ctx) {
}
}
}
void xci_print(xci_ctx_t *ctx) {
printf("\nXCI:\n");
print_magic("Magic: ", ctx->header.magic);
@ -278,10 +278,10 @@ void xci_print(xci_ctx_t *ctx) {
} else {
memdump(stdout, "Header Signature: ", &ctx->header.header_sig, 0x100);
}
printf("Cartridge Type: %s\n", xci_get_cartridge_type(ctx));
printf("Cartridge Size: %012"PRIx64"\n", media_to_real(ctx->header.cart_size + 1));
memdump(stdout, "Header IV: ", ctx->iv, 0x10);
memdump(stdout, "Encrypted Header: ", ctx->header.encrypted_data, 0x70);
if (ctx->has_decrypted_header) {
@ -294,7 +294,7 @@ void xci_print(xci_ctx_t *ctx) {
printf(" Write Time Wait1: %08"PRIx32"\n", gc_info->write_time_wait_1);
printf(" Write Time Wait2: %08"PRIx32"\n", gc_info->write_time_wait_2);
printf(" Firmware Mode: %08"PRIx32"\n", gc_info->firmware_mode);
// decode version
uint32_t ver[4] = {0};
ver[0] = ((gc_info->cup_version >> 26) & 0x3f);
@ -314,16 +314,16 @@ void xci_print(xci_ctx_t *ctx) {
printf("Root Partition:\n");
}
xci_print_hfs0(&ctx->partition_ctx);
printf("Update Partition:\n");
xci_print_hfs0(&ctx->update_ctx);
printf("Normal Partition:\n");
xci_print_hfs0(&ctx->normal_ctx);
printf("Secure Partition:\n");
xci_print_hfs0(&ctx->secure_ctx);
/* Ensure that Logo partition exists. */
if (ctx->partition_ctx.header->num_files == 4) {
printf("Logo Partition:\n");