diff --git a/source/config/ini.c b/source/config/ini.c index fab7ce2..3f9d090 100644 --- a/source/config/ini.c +++ b/source/config/ini.c @@ -64,7 +64,7 @@ ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type return csec; } -int ini_parse(link_t *dst, char *ini_path, bool is_dir) +int ini_parse(link_t *dst, const char *ini_path, bool is_dir) { u32 lblen; u32 pathlen = strlen(ini_path); diff --git a/source/config/ini.h b/source/config/ini.h index dffbe86..030c982 100644 --- a/source/config/ini.h +++ b/source/config/ini.h @@ -43,7 +43,7 @@ typedef struct _ini_sec_t u32 color; } ini_sec_t; -int ini_parse(link_t *dst, char *ini_path, bool is_dir); +int ini_parse(link_t *dst, const char *ini_path, bool is_dir); char *ini_check_payload_section(ini_sec_t *cfg); #endif diff --git a/source/tegraexplorer/common/common.h b/source/tegraexplorer/common/common.h index 4bca51c..2a4b468 100644 --- a/source/tegraexplorer/common/common.h +++ b/source/tegraexplorer/common/common.h @@ -23,7 +23,8 @@ enum utils_err_codes_te_call { ERR_SD_EJECTED, ERR_PARSE_FAIL, ERR_CANNOT_COPY_FILE_TO_FS_PART, - ERR_NO_DESTINATION + ERR_NO_DESTINATION, + ERR_INI_PARSE_FAIL }; extern const char *utils_err_codes_te[]; @@ -86,7 +87,8 @@ enum fs_menu_file_return { FILE_PAYLOAD, FILE_SCRIPT, FILE_HEXVIEW, - FILE_DUMPBIS + FILE_DUMPBIS, + FILE_SIGN }; extern menu_entry fs_menu_file[]; diff --git a/source/tegraexplorer/common/strings.c b/source/tegraexplorer/common/strings.c index 7f414d0..de8c615 100644 --- a/source/tegraexplorer/common/strings.c +++ b/source/tegraexplorer/common/strings.c @@ -52,7 +52,8 @@ const char *utils_err_codes_te[] = { // these start at 50 "SD EJECTED", "PARSING FAILED", "CANNOT COPY FILE TO FS PART", - "NO DESTINATION" + "NO DESTINATION", + "INI PARSE FAIL" }; /* const char *pkg2names[] = { diff --git a/source/tegraexplorer/common/structs.c b/source/tegraexplorer/common/structs.c index b9d8b92..a85f404 100644 --- a/source/tegraexplorer/common/structs.c +++ b/source/tegraexplorer/common/structs.c @@ -53,7 +53,8 @@ menu_entry fs_menu_file[] = { {"Launch Payload", COLOR_ORANGE, {ISMENU}}, {"Launch Script", COLOR_YELLOW, {ISMENU}}, {"View Hex", COLOR_GREEN, {ISMENU}}, - {"\nExtract BIS", COLOR_YELLOW, {ISMENU}} + {"\nExtract BIS", COLOR_YELLOW, {ISMENU}}, + {"Sign Save", COLOR_ORANGE, {ISMENU}} }; menu_entry fs_menu_folder[] = { diff --git a/source/tegraexplorer/fs/filemenu.c b/source/tegraexplorer/fs/filemenu.c index 16fb1c0..4e18fd8 100644 --- a/source/tegraexplorer/fs/filemenu.c +++ b/source/tegraexplorer/fs/filemenu.c @@ -16,6 +16,7 @@ #include "../emmc/emmcoperations.h" #include "../../hid/hid.h" #include "../utils/menuUtils.h" +#include "savesign.h" extern char *currentpath; extern char *clipboard; @@ -150,6 +151,7 @@ int filemenu(menu_entry file){ fs_menu_file[8].isHide = (!(strstr(file.name, ".bin") != NULL && file.size == 1) && strstr(file.name, ".rom") == NULL); fs_menu_file[9].isHide = (strstr(file.name, ".te") == NULL); fs_menu_file[11].isHide = (strstr(file.name, ".bis") == NULL); + fs_menu_file[12].isHide = (!!strcmp(currentpath, "emmc:/save")); /* SETBIT(fs_menu_file[6].property, ISHIDE, !hidConnected()); @@ -158,7 +160,7 @@ int filemenu(menu_entry file){ SETBIT(fs_menu_file[11].property, ISHIDE, strstr(file.name, ".bis") == NULL); */ - temp = menu_make(fs_menu_file, 12, "-- File Menu --"); + temp = menu_make(fs_menu_file, 13, "-- File Menu --"); switch (temp){ case FILE_COPY: fsreader_writeclipboard(fsutil_getnextloc(currentpath, file.name), OPERATIONCOPY); @@ -213,6 +215,17 @@ int filemenu(menu_entry file){ extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath); fsreader_readfolder(currentpath); hidWait(); + break; + case FILE_SIGN: + if (gfx_defaultWaitMenu("WARNING!\n\nThis should only be used if you know what signing and a save is\nDo not do this if you don't know what this does\n\nRequires you to have a prod.keys located in the switch folder\n", 5)){ + gfx_clearscreen(); + gfx_printf("Signing save...\n"); + if (save_sign("sd:/switch/prod.keys", fsutil_getnextloc(currentpath, file.name))){ + gfx_printf("Done!\nPress any key to exit"); + hidWait(); + } + } + break; case -1: return -1; diff --git a/source/tegraexplorer/fs/savesign.c b/source/tegraexplorer/fs/savesign.c new file mode 100644 index 0000000..af8167f --- /dev/null +++ b/source/tegraexplorer/fs/savesign.c @@ -0,0 +1,123 @@ +#include "savesign.h" +#include "../../utils/types.h" +#include "../../libs/fatfs/ff.h" +#include "../../sec/se.h" +#include "../../mem/heap.h" +#include "../gfx/gfxutils.h" +#include "../../config/ini.h" +#include "../common/common.h" +#include + +bool save_commit(const char *path, u8 *save_mac_key){ + FIL file; + int res; + u8 *buf, hash[0x20], *cmac_data, cmac[0x10]; + const u32 hashed_data_size = 0x3D00, cmac_data_size = 0x200; + bool success = false; + + buf = malloc(hashed_data_size); + cmac_data = malloc(cmac_data_size); + + if ((res = f_open(&file, path, FA_OPEN_EXISTING | FA_READ | FA_WRITE))){ + gfx_errDisplay("save_commit", res, 1); + goto out_free; + } + + f_lseek(&file, 0x300); + if ((res = f_read(&file, buf, hashed_data_size, NULL))){ + gfx_errDisplay("save_commit", res, 2); + goto out_free; + } + + se_calc_sha256(hash, buf, hashed_data_size); + + f_lseek(&file, 0x108); + if ((res = f_write(&file, hash, sizeof(hash), NULL))){ + gfx_errDisplay("save_commit", res, 3); + goto out_free; + } + + f_lseek(&file, 0x100); + if ((res = f_read(&file, cmac_data, cmac_data_size, NULL))){ + gfx_errDisplay("save_commit", res, 4); + goto out_free; + } + + se_aes_key_set(3, save_mac_key, 0x10); + se_aes_cmac(3, cmac, 0x10, cmac_data, cmac_data_size); + + f_lseek(&file, 0); + + if ((res = f_write(&file, cmac, sizeof(cmac), NULL))){ + gfx_errDisplay("save_commit", res, 5); + goto out_free; + } + + success = true; + +out_free:; + free(buf); + free(cmac_data); + f_close(&file); + return success; +} + + +char *getKey(const char *search, link_t *inilist){ + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, inilist, link){ + if (ini_sec->type == INI_CHOICE){ + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp(search, kv->key)) + return kv->val; + } + } + } + return NULL; +} + +u8 getHexSingle(const char c) { + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; +} + +u8 *getHex(const char *in){ + u32 len = strlen(in), count = 0; + u8 *out = calloc(len / 2, sizeof(u8)); + + for (u32 i = 0; i < len; i += 2){ + out[count++] = (u8)(getHexSingle(in[i]) << 4) | (getHexSingle(in[i + 1])); + } + + return out; +} + +bool save_sign(const char *keypath, const char *savepath){ + LIST_INIT(inilist); + char *key; + u8 *hex; + bool success = false; + + if (!ini_parse(&inilist, keypath, false)){ + gfx_errDisplay("save_sign", ERR_INI_PARSE_FAIL, 1); + goto out_free; + } + + if ((key = getKey("save_mac_key", &inilist)) == NULL){ + gfx_errDisplay("save_sign", ERR_INI_PARSE_FAIL, 2); + goto out_free; + } + + hex = getHex(key); + + if (!save_commit(savepath, hex)) + goto out_free; + + success = true; + +out_free:; + list_empty(&inilist); + return success; +} \ No newline at end of file diff --git a/source/tegraexplorer/fs/savesign.h b/source/tegraexplorer/fs/savesign.h new file mode 100644 index 0000000..72cce8e --- /dev/null +++ b/source/tegraexplorer/fs/savesign.h @@ -0,0 +1,4 @@ +#pragma once +#include "../../utils/types.h" + +bool save_sign(const char *keypath, const char *savepath); \ No newline at end of file diff --git a/source/tegraexplorer/gfx/gfxutils.c b/source/tegraexplorer/gfx/gfxutils.c index 541ab26..3e8e65c 100644 --- a/source/tegraexplorer/gfx/gfxutils.c +++ b/source/tegraexplorer/gfx/gfxutils.c @@ -52,7 +52,7 @@ u32 gfx_errDisplay(const char *src_func, int err, int loc){ if (err < 15) gfx_printf("Desc: %s\n", utils_err_codes[err]); - else if (err >= ERR_SAME_LOC && err <= ERR_NO_DESTINATION) + else if (err >= ERR_SAME_LOC && err <= ERR_INI_PARSE_FAIL) gfx_printf("Desc: %s\n", utils_err_codes_te[err - 50]); if (loc)