diff --git a/ctrtool/keyset.cpp b/ctrtool/keyset.cpp index 0341cbe..609b7d7 100644 --- a/ctrtool/keyset.cpp +++ b/ctrtool/keyset.cpp @@ -232,7 +232,12 @@ void keyset_merge(keyset* keys, keyset* src) COPY_IF_VALID(ncchkeyX_seven); COPY_IF_VALID(ncchkeyX_ninethree); COPY_IF_VALID(ncchkeyX_ninesix); - COPY_IF_VALID(seed); + if (src->seed_num > 0) + { + keys->seed_num = src->seed_num; + keys->seed_db = (seeddb_entry*)calloc(src->seed_num, sizeof(seeddb_entry)); + memcpy(keys->seed_db, src->seed_db, src->seed_num * sizeof(seeddb_entry)); + } #undef COPY_IF_VALID } @@ -283,9 +288,31 @@ void keyset_parse_ncchkeyX_ninesix(keyset* keys, char* keytext, int keylen) keyset_parse_key128(&keys->ncchkeyX_ninesix, keytext, keylen); } -void keyset_parse_seed(keyset* keys, char* keytext, int keylen) +void keyset_parse_seeddb(keyset* keys, char* path) { - keyset_parse_key128(&keys->seed, keytext, keylen); + //keyset_parse_key128(&keys->seed, keytext, keylen); + FILE* fp = fopen(path, "rb"); + if (fp == NULL) + { + printf("[ERROR] Failed to load SeedDB (failed to open file)\n"); + return; + } + + seeddb_header hdr; + fread(&hdr, sizeof(seeddb_header), 1, fp); + + u32 n_entries = getle32(hdr.n_entries); + for (u32 i = 0; i < 0xC; i++) + { + if (hdr.padding[i] != 0x00) + { + printf("[ERROR] SeedDB is corrupt. (padding malformed)\n"); + return; + } + } + + keys->seed_db = (seeddb_entry*)calloc(n_entries, sizeof(seeddb_entry)); + fread(keys->seed_db, n_entries * sizeof(seeddb_entry), 1, fp); } void keyset_dump_rsakey(rsakey2048* key, const char* keytitle) diff --git a/ctrtool/keyset.h b/ctrtool/keyset.h index 5f71d90..3d6610f 100644 --- a/ctrtool/keyset.h +++ b/ctrtool/keyset.h @@ -21,6 +21,20 @@ typedef enum RSAKEY_PUB } rsakeytype; +typedef struct +{ + u8 title_id[8]; + u8 seed[0x10]; + u8 padding[0x8]; +} seeddb_entry; + +typedef struct +{ + u8 n_entries[4]; + u8 padding[0xC]; +} seeddb_header; + + typedef struct { unsigned char n[256]; @@ -42,8 +56,10 @@ typedef struct typedef struct { + u32 seed_num; + seeddb_entry* seed_db; + key128 titlekey; - key128 seed; key128 commonkeyX; key128 ncchfixedsystemkey; key128 ncchkeyX_old; @@ -66,7 +82,7 @@ void keyset_parse_ncchfixedsystemkey(keyset* keys, char* keytext, int keylen); void keyset_parse_ncchkeyX_seven(keyset* keys, char* keytext, int keylen); void keyset_parse_ncchkeyX_ninethree(keyset* keys, char* keytext, int keylen); void keyset_parse_ncchkeyX_ninesix(keyset* keys, char* keytext, int keylen); -void keyset_parse_seed(keyset* keys, char* keytext, int keylen); +void keyset_parse_seeddb(keyset* keys, char* path); void keyset_dump(keyset* keys); #ifdef __cplusplus diff --git a/ctrtool/main.c b/ctrtool/main.c index 393d272..1711374 100644 --- a/ctrtool/main.c +++ b/ctrtool/main.c @@ -58,7 +58,7 @@ static void usage(const char *argv0) " --titlekey=key Set tik title key.\n" " --ncchkey=key Set ncch key.\n" " --ncchsyskey=key Set ncch fixed system key.\n" - " --seed=key Set seed for ncch seed crypto.\n" + " --seeddb=file Set seeddb for ncch seed crypto.\n" " --showkeys Show the keys being used.\n" " --showsyscalls Show system call names instead of numbers.\n" " -t, --intype=type Specify input file type [ncsd, ncch, exheader, cia, tmd, lzss,\n" @@ -156,7 +156,7 @@ int main(int argc, char* argv[]) {"ncchkeyxseven", 1, NULL, 25}, {"ncchkeyxninethree", 1, NULL, 26}, {"ncchkeyxninesix", 1, NULL, 27}, - {"seed", 1, NULL, 28}, + {"seeddb", 1, NULL, 28}, {NULL}, }; @@ -254,7 +254,7 @@ int main(int argc, char* argv[]) case 25: keyset_parse_ncchkeyX_seven(&tmpkeys, optarg, strlen(optarg)); break; case 26: keyset_parse_ncchkeyX_ninethree(&tmpkeys, optarg, strlen(optarg)); break; case 27: keyset_parse_ncchkeyX_ninesix(&tmpkeys, optarg, strlen(optarg)); break; - case 28: keyset_parse_seed(&tmpkeys, optarg, strlen(optarg)); break; + case 28: keyset_parse_seeddb(&tmpkeys, optarg); break; default: usage(argv[0]); diff --git a/ctrtool/ncch.c b/ctrtool/ncch.c index 1c9f9ee..a847ac2 100644 --- a/ctrtool/ncch.c +++ b/ctrtool/ncch.c @@ -549,11 +549,11 @@ void ncch_determine_key(ncch_context* ctx, u32 actions) if (header->flags[7] & 0x20) { ctx->encrypted = NCCHCRYPTO_SEED; - seed = settings_get_seed(ctx->usersettings); + seed = settings_get_seed(ctx->usersettings, getle64(header->partitionid)); if (!seed) { - fprintf(stderr, "This title uses seed crypto, but no seed is set, unable to decrypt.\n" - "Use -p to avoid decryption or use --seed=SEEDHERE to provide the seed.\n"); + fprintf(stderr, "This title uses seed crypto, but no seed is set in seedDB, unable to decrypt.\n" + "Use -p to avoid decryption or use --seeddb=dbfile to specify the seedDB.\n"); ctx->encrypted = NCCHCRYPTO_BROKEN; return; } diff --git a/ctrtool/settings.c b/ctrtool/settings.c index 95f7dbd..15523b0 100644 --- a/ctrtool/settings.c +++ b/ctrtool/settings.c @@ -173,9 +173,16 @@ unsigned char* settings_get_common_keyX(settings* usersettings) GETKEY(usersettings, commonkeyX); } -unsigned char* settings_get_seed(settings* usersettings) +unsigned char* settings_get_seed(settings* usersettings, u64 title_id) { - GETKEY(usersettings, seed); + for (u32 i = 0; i < usersettings->keys.seed_num; i++) + { + if (title_id == getle64(usersettings->keys.seed_db[i].title_id)) + { + return usersettings->keys.seed_db[i].seed; + } + } + return NULL; } unsigned char* settings_get_title_key(settings* usersettings) diff --git a/ctrtool/settings.h b/ctrtool/settings.h index c3f819f..c90947b 100644 --- a/ctrtool/settings.h +++ b/ctrtool/settings.h @@ -52,7 +52,7 @@ unsigned char* settings_get_ncchkeyX_seven(settings* usersettings); unsigned char* settings_get_ncchkeyX_ninethree(settings* usersettings); unsigned char* settings_get_ncchkeyX_ninesix(settings* usersettings); unsigned char* settings_get_common_keyX(settings* usersettings); -unsigned char* settings_get_seed(settings* usersettings); +unsigned char* settings_get_seed(settings* usersettings, u64 title_id); unsigned char* settings_get_title_key(settings* usersettings); int settings_get_ignore_programid(settings* usersettings); int settings_get_list_romfs_files(settings* usersettings);