Scripting: add fixcmac command

fixes #175
check HelloScript.gm9 for how it's done
This commit is contained in:
d0k3 2017-08-21 19:56:30 +02:00
parent 26690f4a90
commit 551a48149f
4 changed files with 53 additions and 3 deletions

View File

@ -128,6 +128,12 @@ set ERRORMSG "SHA check failed (this was expected)"
sha -o $[RENPATH] $[TESTPATH].sha sha -o $[RENPATH] $[TESTPATH].sha
set ERRORMSG "" set ERRORMSG ""
# 'fixcmac' COMMAND
# Use this to fix the CMACs for a file or a whole folder (recursively)
# This will count as success if a file does not contain a CMAC
# More info on CMACs: http://3dbrew.org/wiki/Savegames#AES_CMAC_header
# fixcmac 1:/data
# 'verify' COMMAND # 'verify' COMMAND
# Certain file formats (NAND, NCCH, NCSD, CIA, FIRM, ...) can also be verified. Use 'verify' to do so. # Certain file formats (NAND, NCCH, NCSD, CIA, FIRM, ...) can also be verified. Use 'verify' to do so.
# verify -o s:/firm0.bin # As drive letters are case sensitive, this would fail # verify -o s:/firm0.bin # As drive letters are case sensitive, this would fail

View File

@ -2,6 +2,7 @@
#include "fsutil.h" #include "fsutil.h"
#include "fsinit.h" #include "fsinit.h"
#include "fsperm.h" #include "fsperm.h"
#include "nandcmac.h"
#include "nandutil.h" #include "nandutil.h"
#include "gameutil.h" #include "gameutil.h"
#include "keydbutil.h" #include "keydbutil.h"
@ -46,6 +47,7 @@ typedef enum {
CMD_ID_DECRYPT, CMD_ID_DECRYPT,
CMD_ID_ENCRYPT, CMD_ID_ENCRYPT,
CMD_ID_BUILDCIA, CMD_ID_BUILDCIA,
CMD_ID_BOOT,
CMD_ID_REBOOT, CMD_ID_REBOOT,
CMD_ID_POWEROFF CMD_ID_POWEROFF
} cmd_id; } cmd_id;
@ -78,11 +80,12 @@ Gm9ScriptCmd cmd_list[] = {
{ CMD_ID_FIND , "find" , 2, 0 }, { CMD_ID_FIND , "find" , 2, 0 },
{ CMD_ID_FINDNOT , "findnot" , 2, 0 }, { CMD_ID_FINDNOT , "findnot" , 2, 0 },
{ CMD_ID_SHA , "sha" , 2, 0 }, { CMD_ID_SHA , "sha" , 2, 0 },
// { CMD_ID_FIXCMAC , "fixcmac" , 1, 0 }, // not supported yet { CMD_ID_FIXCMAC , "fixcmac" , 1, 0 },
{ CMD_ID_VERIFY , "verify" , 1, 0 }, { CMD_ID_VERIFY , "verify" , 1, 0 },
{ CMD_ID_DECRYPT , "decrypt" , 1, 0 }, { CMD_ID_DECRYPT , "decrypt" , 1, 0 },
{ CMD_ID_ENCRYPT , "encrypt" , 1, 0 }, { CMD_ID_ENCRYPT , "encrypt" , 1, 0 },
{ CMD_ID_BUILDCIA, "buildcia", 1, _FLG('l') }, { CMD_ID_BUILDCIA, "buildcia", 1, _FLG('l') },
// { CMD_ID_BOOT , "boot" , 1, 0 }, // not supported yet
{ CMD_ID_REBOOT , "reboot" , 0, 0 }, { CMD_ID_REBOOT , "reboot" , 0, 0 },
{ CMD_ID_POWEROFF, "poweroff", 0, 0 } { CMD_ID_POWEROFF, "poweroff", 0, 0 }
}; };
@ -445,6 +448,10 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) {
ret = (memcmp(sha256_fil, sha256_cmp, 0x20) == 0); ret = (memcmp(sha256_fil, sha256_cmp, 0x20) == 0);
if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha does not match"); if (err_str) snprintf(err_str, _ERR_STR_LEN, "sha does not match");
} }
} else if (id == CMD_ID_FIXCMAC) {
ShowString("Fixing CMACs...");
ret = (RecursiveFixFileCmac(argv[0]) == 0);
if (err_str) snprintf(err_str, _ERR_STR_LEN, "fixcmac failed");
} else if (id == CMD_ID_VERIFY) { } else if (id == CMD_ID_VERIFY) {
u32 filetype = IdentifyFileType(argv[0]); u32 filetype = IdentifyFileType(argv[0]);
if (filetype & IMG_NAND) ret = (ValidateNandDump(argv[0]) == 0); if (filetype & IMG_NAND) ret = (ValidateNandDump(argv[0]) == 0);

View File

@ -6,14 +6,14 @@
#include "vff.h" #include "vff.h"
// CMAC types, see: // CMAC types, see:
// https://www.3dbrew.org/wiki/Savegames#AES_CMAC_header // https://3dbrew.org/wiki/Savegames#AES_CMAC_header
// https://3dbrew.org/wiki/Nand/private/movable.sed // https://3dbrew.org/wiki/Nand/private/movable.sed
// https://3dbrew.org/wiki/3DS_Virtual_Console#NAND_Savegame // https://3dbrew.org/wiki/3DS_Virtual_Console#NAND_Savegame
#define CMAC_EXTDATA_SD 1 #define CMAC_EXTDATA_SD 1
#define CMAC_EXTDATA_SYS 2 #define CMAC_EXTDATA_SYS 2
#define CMAC_SAVEDATA_SYS 3 #define CMAC_SAVEDATA_SYS 3
#define CMAC_SAVE_GAMECARD 4 #define CMAC_SAVE_GAMECARD 4
#define CMAC_SAVEGAME 5 // this is not calclated into a CMAC #define CMAC_SAVEGAME 5 // this is not calculated into a CMAC
#define CMAC_SAVEDATA_SD 6 #define CMAC_SAVEDATA_SD 6
#define CMAC_TITLEDB_SYS 7 #define CMAC_TITLEDB_SYS 7
#define CMAC_TITLEDB_SD 8 #define CMAC_TITLEDB_SD 8
@ -233,3 +233,39 @@ u32 FixFileCmac(const char* path) {
u8 ccmac[16]; u8 ccmac[16];
return ((CalculateFileCmac(path, ccmac) == 0) && (WriteFileCmac(path, ccmac) == 0)) ? 0 : 1; return ((CalculateFileCmac(path, ccmac) == 0) && (WriteFileCmac(path, ccmac) == 0)) ? 0 : 1;
} }
u32 RecursiveFixFileCmacWorker(char* path) {
FILINFO fno;
if (fvx_stat(path, &fno) != FR_OK) return 1; // path does not exist
if (fno.fattrib & AM_DIR) { // process folder contents
DIR pdir;
char* fname = path + strnlen(path, 255);
if (fvx_opendir(&pdir, path) != FR_OK) return 1;
*(fname++) = '/';
while (f_readdir(&pdir, &fno) == FR_OK) {
if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
continue; // filter out virtual entries
strncpy(fname, fno.fname, path + 255 - fname);
if (fno.fname[0] == 0) {
break;
} else if (fno.fattrib & AM_DIR) { // directory, recurse through it
if (RecursiveFixFileCmacWorker(path) != 0) return 1;
} else if (CheckCmacPath(path) == 0) { // file, try to fix the CMAC
if (FixFileCmac(path) != 0) return 1;
}
}
f_closedir(&pdir);
*(--fname) = '\0';
} else if (CheckCmacPath(path) == 0)
return FixFileCmac(path);
return 0;
}
u32 RecursiveFixFileCmac(const char* path) {
char lpath[256] = { 0 };
strncpy(lpath, path, 255);
return RecursiveFixFileCmacWorker(lpath);
}

View File

@ -8,3 +8,4 @@ u32 WriteFileCmac(const char* path, u8* cmac);
u32 CalculateFileCmac(const char* path, u8* cmac); u32 CalculateFileCmac(const char* path, u8* cmac);
u32 CheckFileCmac(const char* path); u32 CheckFileCmac(const char* path);
u32 FixFileCmac(const char* path); u32 FixFileCmac(const char* path);
u32 RecursiveFixFileCmac(const char* path);