From 3a8e0054308145776c63f0871fed21b3965403ee Mon Sep 17 00:00:00 2001 From: BuildTools Date: Thu, 30 Sep 2021 13:12:54 -0400 Subject: [PATCH] add user-facing sha1 support --- arm9/source/filesys/fsutil.c | 17 ++++++----- arm9/source/filesys/fsutil.h | 15 +++++----- arm9/source/godmode.c | 56 ++++++++++++++++++++++------------- arm9/source/utils/gameutil.c | 2 +- arm9/source/utils/scripting.c | 42 +++++++++++++++----------- 5 files changed, 79 insertions(+), 53 deletions(-) diff --git a/arm9/source/filesys/fsutil.c b/arm9/source/filesys/fsutil.c index 39c9853..9f66473 100644 --- a/arm9/source/filesys/fsutil.c +++ b/arm9/source/filesys/fsutil.c @@ -161,7 +161,7 @@ size_t FileGetSize(const char* path) { return fno.fsize; } -bool FileGetSha256(const char* path, u8* sha256, u64 offset, u64 size) { +bool FileGetSha(const char* path, u8* hash, u64 offset, u64 size, bool sha1) { bool ret = true; FIL file; u64 fsize; @@ -179,7 +179,7 @@ bool FileGetSha256(const char* path, u8* sha256, u64 offset, u64 size) { if (!buffer) return false; ShowProgress(0, 0, path); - sha_init(SHA256_MODE); + sha_init(sha1 ? SHA1_MODE : SHA256_MODE); for (u64 pos = 0; (pos < size) && ret; pos += bufsiz) { UINT read_bytes = min(bufsiz, size - pos); UINT bytes_read = 0; @@ -190,7 +190,7 @@ bool FileGetSha256(const char* path, u8* sha256, u64 offset, u64 size) { sha_update(buffer, bytes_read); } - sha_get(sha256); + sha_get(hash); fvx_close(&file); free(buffer); @@ -448,6 +448,7 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, bool silent = (flags && (*flags & SILENT)); bool append = (flags && (*flags & APPEND_ALL)); bool calcsha = (flags && (*flags & CALC_SHA) && !append); + bool sha1 = (flags && (*flags & USE_SHA1)); bool ret = false; // check destination write permission (special paths only) @@ -552,7 +553,7 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, fvx_lseek(&ofile, 0); fvx_sync(&ofile); - if (calcsha) sha_init(SHA256_MODE); + if (calcsha) sha_init(sha1 ? SHA1_MODE : SHA256_MODE); for (u64 pos = 0; (pos < osize) && ret; pos += bufsiz) { UINT bytes_read = 0; UINT bytes_written = 0; @@ -580,11 +581,11 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, if (!ret && ((dsize == 0) || (fvx_lseek(&dfile, dsize) != FR_OK) || (f_truncate(&dfile) != FR_OK))) { fvx_unlink(dest); } else if (!to_virtual && calcsha) { - u8 sha256[0x20]; + u8 hash[0x20]; char* ext_sha = dest + strnlen(dest, 256); - strncpy(ext_sha, ".sha", 256 - (ext_sha - dest)); - sha_get(sha256); - FileSetData(dest, sha256, 0x20, 0, true); + snprintf(ext_sha, 256 - (ext_sha - dest), ".sha%c", sha1 ? '1' : '\0'); + sha_get(hash); + FileSetData(dest, hash, sha1 ? 20 : 32, 0, true); } } diff --git a/arm9/source/filesys/fsutil.h b/arm9/source/filesys/fsutil.h index 1c56429..adde361 100644 --- a/arm9/source/filesys/fsutil.h +++ b/arm9/source/filesys/fsutil.h @@ -7,12 +7,13 @@ #define NO_CANCEL (1UL<<1) #define SILENT (1UL<<2) #define CALC_SHA (1UL<<3) -#define BUILD_PATH (1UL<<4) -#define ALLOW_EXPAND (1UL<<5) -#define ASK_ALL (1UL<<6) -#define SKIP_ALL (1UL<<7) -#define OVERWRITE_ALL (1UL<<8) -#define APPEND_ALL (1UL<<9) +#define USE_SHA1 (1UL<<4) +#define BUILD_PATH (1UL<<5) +#define ALLOW_EXPAND (1UL<<6) +#define ASK_ALL (1UL<<7) +#define SKIP_ALL (1UL<<8) +#define OVERWRITE_ALL (1UL<<9) +#define APPEND_ALL (1UL<<10) // file selector flags #define NO_DIRS (1UL<<0) @@ -43,7 +44,7 @@ size_t FileGetData(const char* path, void* data, size_t size, size_t foffset); size_t FileGetSize(const char* path); /** Get SHA-256 of file **/ -bool FileGetSha256(const char* path, u8* sha256, u64 offset, u64 size); +bool FileGetSha(const char* path, u8* hash, u64 offset, u64 size, bool sha1); /** Find data in file **/ u32 FileFindData(const char* path, u8* data, u32 size_data, u32 offset_file); diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index ab44658..5539798 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -842,37 +842,46 @@ u32 FileHexViewer(const char* path) { return 0; } -u32 Sha256Calculator(const char* path) { +u32 ShaCalculator(const char* path, bool sha1) { + const u8 hashlen = sha1 ? 20 : 32; u32 drvtype = DriveType(path); char pathstr[32 + 1]; - u8 sha256[32]; + u8 hash[32]; TruncateString(pathstr, path, 32, 8); - if (!FileGetSha256(path, sha256, 0, 0)) { - ShowPrompt(false, "Calculating SHA-256: failed!"); + if (!FileGetSha(path, hash, 0, 0, sha1)) { + ShowPrompt(false, "Calculating SHA-%s: failed!", sha1 ? "1" : "256"); return 1; } else { static char pathstr_prev[32 + 1] = { 0 }; - static u8 sha256_prev[32] = { 0 }; + static u8 hash_prev[32] = { 0 }; char sha_path[256]; - u8 sha256_file[32]; + u8 sha_file[32]; - snprintf(sha_path, 256, "%s.sha", path); - bool have_sha = (FileGetData(sha_path, sha256_file, 32, 0) == 32); - bool match_sha = have_sha && (memcmp(sha256, sha256_file, 32) == 0); - bool match_prev = (memcmp(sha256, sha256_prev, 32) == 0); + snprintf(sha_path, 256, "%s.sha%c", path, sha1 ? '1' : '\0'); + bool have_sha = (FileGetData(sha_path, sha_file, hashlen, 0) == hashlen); + bool match_sha = have_sha && (memcmp(hash, sha_file, hashlen) == 0); + bool match_prev = (memcmp(hash, hash_prev, hashlen) == 0); bool write_sha = (!have_sha || !match_sha) && (drvtype & DRV_SDCARD); // writing only on SD - if (ShowPrompt(write_sha, "%s\n%016llX%016llX\n%016llX%016llX%s%s%s%s%s", - pathstr, getbe64(sha256 + 0), getbe64(sha256 + 8), getbe64(sha256 + 16), getbe64(sha256 + 24), + char hash_str[32+1+32+1]; + if (sha1) + snprintf(hash_str, 40+1, "%016llX%016llX%08lX", getbe64(hash + 0), getbe64(hash + 8), + getbe32(hash + 16)); + else + snprintf(hash_str, 32+1+32+1, "%016llX%016llX\n%016llX%016llX", getbe64(hash + 0), getbe64(hash + 8), + getbe64(hash + 16), getbe64(hash + 24)); + if (ShowPrompt(write_sha, "%s\n%s%s%s%s%s%c \nWrite .SHA%s file?", + pathstr, hash_str, (have_sha) ? "\nSHA verification: " : "", (have_sha) ? ((match_sha) ? "passed!" : "failed!") : "", (match_prev) ? "\n \nIdentical with previous file:\n" : "", (match_prev) ? pathstr_prev : "", - (write_sha) ? "\n \nWrite .SHA file?" : "") && write_sha) { - FileSetData(sha_path, sha256, 32, 0, true); + (write_sha) ? '\n' : '\0', + (sha1) ? "1" : "") && write_sha) { + FileSetData(sha_path, hash, hashlen, 0, true); } strncpy(pathstr_prev, pathstr, 32 + 1); - memcpy(sha256_prev, sha256, 32); + memcpy(hash_prev, hash, hashlen); } return 0; @@ -1158,7 +1167,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan int special = (special_opt) ? ++n_opt : -1; int hexviewer = ++n_opt; int textviewer = (filetype & TXT_GENERIC) ? ++n_opt : -1; - int calcsha = ++n_opt; + int calcsha256 = ++n_opt; + int calcsha1 = ++n_opt; int calccmac = (CheckCmacPath(file_path) == 0) ? ++n_opt : -1; int fileinfo = ++n_opt; int copystd = (!in_output_path) ? ++n_opt : -1; @@ -1170,7 +1180,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan int titleman = -1; if (DriveType(current_path) & DRV_TITLEMAN) { // special case: title manager (disable almost everything) - hexviewer = textviewer = calcsha = calccmac = fileinfo = copystd = inject = searchdrv = -1; + hexviewer = textviewer = calcsha256 = calcsha1 = calccmac = fileinfo = copystd = inject = searchdrv = -1; special = 1; titleman = 2; n_opt = 2; @@ -1210,7 +1220,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan (filetype & HDR_NAND) ? "Rebuild NCSD header" : (filetype & NOIMG_NAND) ? "Rebuild NCSD header" : "???"; optionstr[hexviewer-1] = "Show in Hexeditor"; - optionstr[calcsha-1] = "Calculate SHA-256"; + optionstr[calcsha256-1] = "Calculate SHA-256"; + optionstr[calcsha1-1] = "Calculate SHA-1"; optionstr[fileinfo-1] = "Show file info"; if (textviewer > 0) optionstr[textviewer-1] = "Show in Textviewer"; if (calccmac > 0) optionstr[calccmac-1] = "Calculate CMAC"; @@ -1230,8 +1241,13 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan FileTextViewer(file_path, scriptable); return 0; } - else if (user_select == calcsha) { // -> calculate SHA-256 - Sha256Calculator(file_path); + else if (user_select == calcsha256) { // -> calculate SHA-256 + ShaCalculator(file_path, false); + GetDirContents(current_dir, current_path); + return 0; + } + else if (user_select == calcsha1) { // -> calculate SHA-1 + ShaCalculator(file_path, true); GetDirContents(current_dir, current_path); return 0; } diff --git a/arm9/source/utils/gameutil.c b/arm9/source/utils/gameutil.c index 4437bf1..dfbf652 100644 --- a/arm9/source/utils/gameutil.c +++ b/arm9/source/utils/gameutil.c @@ -895,7 +895,7 @@ u32 VerifyTadFile(const char* path) { u8 hash[32]; u32 len = align(hdr->content_size[i], 0x10); if (!len) continue; // non-existant section - if (!FileGetSha256(path, hash, content_start, len) || + if (!FileGetSha(path, hash, content_start, len, false) || (memcmp(hash, ftr->content_sha256[i], 32) != 0)) return 1; content_start += len + sizeof(TadBlockMetaData); diff --git a/arm9/source/utils/scripting.c b/arm9/source/utils/scripting.c index 204d479..2b62c73 100644 --- a/arm9/source/utils/scripting.c +++ b/arm9/source/utils/scripting.c @@ -59,7 +59,7 @@ // some useful macros #define IS_WHITESPACE(c) ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) #define MATCH_STR(s,l,c) ((l == strlen(c)) && (strncmp(s, c, l) == 0)) -#define _FLG(c) ((c >= 'a') ? (1 << (c - 'a')) : 0) +#define _FLG(c) ((c >= 'a') ? (1 << (c - 'a')) : ((c >= '0') ? (1 << (26 + c - '0')) : 0)) #define IS_CTRLFLOW_CMD(id) ((id == CMD_ID_IF) || (id == CMD_ID_ELIF) || (id == CMD_ID_ELSE) || (id == CMD_ID_END) || \ (id == CMD_ID_GOTO) || (id == CMD_ID_LABELSEL) || \ @@ -163,7 +163,7 @@ static const Gm9ScriptCmd cmd_list[] = { { CMD_ID_STRREP , "strrep" , 3, 0 }, { CMD_ID_CHK , "chk" , 2, _FLG('u') }, { CMD_ID_ALLOW , "allow" , 1, _FLG('a') }, - { CMD_ID_CP , "cp" , 2, _FLG('h') | _FLG('w') | _FLG('k') | _FLG('s') | _FLG('n') | _FLG('p')}, + { CMD_ID_CP , "cp" , 2, _FLG('h') | _FLG('1') | _FLG('w') | _FLG('k') | _FLG('s') | _FLG('n') | _FLG('p')}, { CMD_ID_MV , "mv" , 2, _FLG('w') | _FLG('k') | _FLG('s') | _FLG('n') }, { CMD_ID_INJECT , "inject" , 2, _FLG('n') }, { CMD_ID_FILL , "fill" , 2, _FLG('n') }, @@ -176,8 +176,8 @@ static const Gm9ScriptCmd cmd_list[] = { { CMD_ID_FINDNOT , "findnot" , 2, 0 }, { CMD_ID_FGET , "fget" , 2, _FLG('e') }, { CMD_ID_FSET , "fset" , 2, _FLG('e') }, - { CMD_ID_SHA , "sha" , 2, 0 }, - { CMD_ID_SHAGET , "shaget" , 2, 0 }, + { CMD_ID_SHA , "sha" , 2, _FLG('1') }, + { CMD_ID_SHAGET , "shaget" , 2, _FLG('1') }, { CMD_ID_DUMPTXT , "dumptxt" , 2, _FLG('p') }, { CMD_ID_FIXCMAC , "fixcmac" , 1, 0 }, { CMD_ID_VERIFY , "verify" , 1, 0 }, @@ -584,6 +584,7 @@ u32 get_flag(char* str, u32 len, char* err_str) { if ((len < 2) || (*str != '-')) flag_char = '\0'; else if (len == 2) flag_char = str[1]; + else if (strncmp(str, "--sha1", len) == 0) flag_char = '1'; else if (strncmp(str, "--all", len) == 0) flag_char = 'a'; else if (strncmp(str, "--before", len) == 0) flag_char = 'b'; else if (strncmp(str, "--include_dirs", len) == 0) flag_char = 'd'; @@ -603,7 +604,7 @@ u32 get_flag(char* str, u32 len, char* err_str) { else if (strncmp(str, "--overwrite", len) == 0) flag_char = 'w'; else if (strncmp(str, "--explorer", len) == 0) flag_char = 'x'; - if ((flag_char < 'a') && (flag_char > 'z')) { + if (((flag_char < 'a') || (flag_char > 'z')) && ((flag_char < '0') || (flag_char > '5'))) { if (err_str) snprintf(err_str, _ERR_STR_LEN, "illegal flag"); return 0; } @@ -1150,6 +1151,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { else if (id == CMD_ID_CP) { u32 flags_ext = BUILD_PATH; if (flags & _FLG('h')) flags_ext |= CALC_SHA; + if (flags & _FLG('1')) flags_ext |= USE_SHA1; if (flags & _FLG('n')) flags_ext |= NO_CANCEL; if (flags & _FLG('s')) flags_ext |= SILENT; if (flags & _FLG('w')) flags_ext |= OVERWRITE_ALL; @@ -1291,30 +1293,36 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { } } else if (id == CMD_ID_SHA) { - u8 sha256_fil[0x20]; - u8 sha256_cmp[0x20]; - if (!FileGetSha256(argv[0], sha256_fil, at_org, sz_org)) { + const u8 hashlen = (flags & _FLG('1')) ? 20 : 32; + u8 hash_fil[0x20]; + u8 hash_cmp[0x20]; + if (!FileGetSha(argv[0], hash_fil, at_org, sz_org, flags & _FLG('1'))) { ret = false; if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha arg0 fail"); - } else if ((FileGetData(argv[1], sha256_cmp, 0x20, 0) != 0x20) && !strntohex(argv[1], sha256_cmp, 0x20)) { + } else if ((FileGetData(argv[1], hash_cmp, hashlen, 0) != hashlen) && !strntohex(argv[1], hash_cmp, hashlen)) { ret = false; if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha arg1 fail"); } else { - ret = (memcmp(sha256_fil, sha256_cmp, 0x20) == 0); + ret = (memcmp(hash_fil, hash_cmp, hashlen) == 0); if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha does not match"); } } else if (id == CMD_ID_SHAGET) { - u8 sha256_fil[0x20]; - if (!(ret = FileGetSha256(argv[0], sha256_fil, at_org, sz_org))) { + const u8 hashlen = (flags & _FLG('1')) ? 20 : 32; + u8 hash_fil[0x20]; + if (!(ret = FileGetSha(argv[0], hash_fil, at_org, sz_org, flags & _FLG('1')))) { if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha arg0 fail"); } else if (!strchr(argv[1], ':')) { - char sha256_str[64+1]; - snprintf(sha256_str, 64+1, "%016llX%016llX%016llX%016llX", getbe64(sha256_fil + 0), getbe64(sha256_fil + 8), - getbe64(sha256_fil + 16), getbe64(sha256_fil + 24)); - ret = set_var(argv[1], sha256_str); + char hash_str[64+1]; + if (flags & _FLG('1')) + snprintf(hash_str, 64+1, "%016llX%016llX%08lX", getbe64(hash_fil + 0), getbe64(hash_fil + 8), + getbe32(hash_fil + 16)); + else + snprintf(hash_str, 64+1, "%016llX%016llX%016llX%016llX", getbe64(hash_fil + 0), getbe64(hash_fil + 8), + getbe64(hash_fil + 16), getbe64(hash_fil + 24)); + ret = set_var(argv[1], hash_str); if (err_str) snprintf(err_str, _ERR_STR_LEN, "var fail"); - } else if (!(ret = FileSetData(argv[1], sha256_fil, 0x20, 0, true))) { + } else if (!(ret = FileSetData(argv[1], hash_fil, hashlen, 0, true))) { if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha write fail"); } }