mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 21:52:48 +00:00
Added the ability to install aeskeydb.bin to NAND
This commit is contained in:
parent
de7fe6cfb9
commit
585172f810
@ -121,6 +121,7 @@ With the possibilites GodMode9 provides, not everything may be obvious at first
|
|||||||
* __Restore / dump NAND partitions or even full NANDs__: Just take a look into the `S:` (or `E:`/ `I:`) drive. This is done the same as any other file operation.
|
* __Restore / dump NAND partitions or even full NANDs__: Just take a look into the `S:` (or `E:`/ `I:`) drive. This is done the same as any other file operation.
|
||||||
* __Transfer CTRNAND images between systems__: Transfer the file located at `S:/ctrnand_full.bin` (or `E:`/ `I:`). On the receiving system, press A, select `CTRNAND Options...`, then `Transfer to NAND`.
|
* __Transfer CTRNAND images between systems__: Transfer the file located at `S:/ctrnand_full.bin` (or `E:`/ `I:`). On the receiving system, press A, select `CTRNAND Options...`, then `Transfer to NAND`.
|
||||||
* __Embed an essential backup right into a NAND dump__: This is available in the A button menu for NAND dumps. Essential backups contain NAND header, `movable.sed`, `LocalFriendCodeSeed_B`, `SecureInfo_A`, NAND CID and OTP. If your local SysNAND does not contain an embedded backup, you will be asked to do one at startup.
|
* __Embed an essential backup right into a NAND dump__: This is available in the A button menu for NAND dumps. Essential backups contain NAND header, `movable.sed`, `LocalFriendCodeSeed_B`, `SecureInfo_A`, NAND CID and OTP. If your local SysNAND does not contain an embedded backup, you will be asked to do one at startup.
|
||||||
|
* __Install an AES key database to your NAND__: For `aeskeydb.bin` files the option is found in `aeskeydb.bin options` -> `Install aeskeydb.bin`. Only the recommended key database can be installed (see above). With an installed key database, it is possible to run the GodMode9 bootloader completely from NAND.
|
||||||
* __Install FIRM files to your NAND__: Found inside the A button menu for FIRM files, select `FIRM options` -> `Install FIRM`. __Use this with caution__ - installing an incompatible FIRM file will lead to a __brick__.
|
* __Install FIRM files to your NAND__: Found inside the A button menu for FIRM files, select `FIRM options` -> `Install FIRM`. __Use this with caution__ - installing an incompatible FIRM file will lead to a __brick__.
|
||||||
* __Actually use that extra NAND space__: You can setup a __bonus drive__ via the HOME menu, which will be available via drive letter `8:`. (Only available on systems that have the extra space.)
|
* __Actually use that extra NAND space__: You can setup a __bonus drive__ via the HOME menu, which will be available via drive letter `8:`. (Only available on systems that have the extra space.)
|
||||||
* __Fix certain problems on your NANDs__: You can fix CMACs for a whole drive (works on `A:`, `B:`, `S:` and `E:`) via an entry in the R+A button menu, or even restore borked NAND headers back to a functional state (inside the A button menu of borked NANDs and available for `S:/nand_hdr.bin`). Recommended only for advanced users!
|
* __Fix certain problems on your NANDs__: You can fix CMACs for a whole drive (works on `A:`, `B:`, `S:` and `E:`) via an entry in the R+A button menu, or even restore borked NAND headers back to a functional state (inside the A button menu of borked NANDs and available for `S:/nand_hdr.bin`). Recommended only for advanced users!
|
||||||
@ -148,20 +149,19 @@ This tool would not have been possible without the help of numerous people. Than
|
|||||||
* **Archshift**, for providing the base project infrastructure
|
* **Archshift**, for providing the base project infrastructure
|
||||||
* **Normmatt**, for sdmmc.c / sdmmc.h and gamecart code, and for being of great help on countless other occasions
|
* **Normmatt**, for sdmmc.c / sdmmc.h and gamecart code, and for being of great help on countless other occasions
|
||||||
* **Cha(N)**, **Kane49**, and all other FatFS contributors for [FatFS](http://elm-chan.org/fsw/ff/00index_e.html)
|
* **Cha(N)**, **Kane49**, and all other FatFS contributors for [FatFS](http://elm-chan.org/fsw/ff/00index_e.html)
|
||||||
|
* **Wolfvak** for ARM11 code, FIRM binary launcher, fexception handlers, PCX code, Makefile and for help on countless other occasions
|
||||||
* **SciresM** for helping me figure out RomFS and for boot9strap
|
* **SciresM** for helping me figure out RomFS and for boot9strap
|
||||||
* **SciresM**, **Myria**, **Normmatt**, **TuxSH** and **hedgeberg** for figuring out sighax and giving us access to bootrom
|
* **SciresM**, **Myria**, **Normmatt**, **TuxSH** and **hedgeberg** for figuring out sighax and giving us access to bootrom
|
||||||
* **ihaveamac** for first developing the simple CIA generation method and for being of great help in porting it
|
* **ihaveamac** for first developing the simple CIA generation method and for being of great help in porting it
|
||||||
* **b1l1s** for helping me figure out A9LH compatibility
|
* **b1l1s** for helping me figure out A9LH compatibility
|
||||||
* **Gelex** and **AuroraWright** for helping me figure out various things
|
* **Gelex** and **AuroraWright** for helping me figure out various things
|
||||||
* **stuckpixel** for the new 6x10 font and help on various things
|
* **stuckpixel** for the new 6x10 font and help on various things
|
||||||
* **Wolfvak** for all ARM11 code, for the FIRM binary launcher, for the exception handlers and for help on countless other occasions
|
|
||||||
* **Al3x_10m** for help with countless hours of testing and useful advice
|
* **Al3x_10m** for help with countless hours of testing and useful advice
|
||||||
* **WinterMute** for helping me with his vast knowledge on everything gamecart related
|
* **WinterMute** for helping me with his vast knowledge on everything gamecart related
|
||||||
* **profi200** for always useful advice and helpful hints on various things
|
* **profi200** for always useful advice and helpful hints on various things
|
||||||
* **JaySea**, **YodaDaCoda**, **liomajor**, **Supster131**, **imanoob**, **Kasher_CS** and countless others from freenode #Cakey and the GBAtemp forums for testing, feedback and helpful hints
|
* **JaySea**, **YodaDaCoda**, **liomajor**, **Supster131**, **imanoob**, **Kasher_CS** and countless others from freenode #Cakey and the GBAtemp forums for testing, feedback and helpful hints
|
||||||
* **Shadowhand** for being awesome and [hosting my nightlies](https://d0k3.secretalgorithm.com/)
|
* **Shadowhand** for being awesome and [hosting my nightlies](https://d0k3.secretalgorithm.com/)
|
||||||
* **Plailect** for putting his trust in my tools and recommending this in [The Guide](https://3ds.guide/)
|
* **Plailect** for putting his trust in my tools and recommending this in [The Guide](https://3ds.guide/)
|
||||||
* **Lasse Reinhold** for [QuickLZ](http://www.quicklz.com/)
|
|
||||||
* **Project Nayuki** for [qrcodegen](https://github.com/nayuki/QR-Code-generator)
|
* **Project Nayuki** for [qrcodegen](https://github.com/nayuki/QR-Code-generator)
|
||||||
* **Amazingmax fonts** for the Amazdoom font
|
* **Amazingmax fonts** for the Amazdoom font
|
||||||
* The fine folks on **freenode #Cakey**
|
* The fine folks on **freenode #Cakey**
|
||||||
|
@ -1,21 +1,9 @@
|
|||||||
#include "keydb.h"
|
#include "keydb.h"
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
#include "ff.h"
|
#include "vff.h"
|
||||||
#include "support.h"
|
#include "support.h"
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u8 slot; // keyslot, 0x00...0x39
|
|
||||||
char type; // type 'X' / 'Y' / 'N' for normalKey / 'I' for IV
|
|
||||||
char id[10]; // key ID for special keys, all zero for standard keys
|
|
||||||
} __attribute__((packed)) AesKeyDesc;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
AesKeyDesc desc; // slot, type, id
|
|
||||||
u8 keyUnitType; // 0 for ALL units / 1 for devkit exclusive / 2 for retail exclusive
|
|
||||||
u8 keySha256[32]; // SHA-256 of the key
|
|
||||||
} __attribute__((packed)) AesKeyHashInfo;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 slot; // keyslot, 0x00...0x39
|
u8 slot; // keyslot, 0x00...0x39
|
||||||
u8 keyUnitType; // 0 for ALL units / 1 for devkit exclusive / 2 for retail exclusive
|
u8 keyUnitType; // 0 for ALL units / 1 for devkit exclusive / 2 for retail exclusive
|
||||||
@ -110,17 +98,16 @@ u32 CheckKeySlot(u32 keyslot, char type)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this function creates dependencies to "vff.h" and "support.h"
|
||||||
|
// to get rid of these, you may replace this function with anything that works for you
|
||||||
u32 LoadKeyDb(const char* path_db, AesKeyInfo* keydb, u32 bsize) {
|
u32 LoadKeyDb(const char* path_db, AesKeyInfo* keydb, u32 bsize) {
|
||||||
UINT fsize = 0;
|
UINT fsize = 0;
|
||||||
FIL fp;
|
|
||||||
|
|
||||||
if (path_db) {
|
if (path_db) {
|
||||||
if (f_open(&fp, path_db, FA_READ | FA_OPEN_EXISTING) == FR_OK) {
|
if (fvx_qread (path_db, keydb, 0, bsize, &fsize) != FR_OK) fsize = 0;
|
||||||
if ((f_read(&fp, keydb, bsize, &fsize) != FR_OK) || (fsize >= bsize))
|
} else if (fvx_qread ("S:/" KEYDB_NAME, keydb, 0, bsize, &fsize) != FR_OK) {
|
||||||
fsize = 0;
|
fsize = LoadSupportFile(KEYDB_NAME, keydb, bsize); // load key database support file
|
||||||
f_close(&fp);
|
|
||||||
}
|
}
|
||||||
} else fsize = LoadSupportFile(KEYDB_NAME, keydb, bsize); // load key database support file
|
|
||||||
|
|
||||||
u32 nkeys = 0;
|
u32 nkeys = 0;
|
||||||
if (fsize && !(fsize % sizeof(AesKeyInfo)))
|
if (fsize && !(fsize % sizeof(AesKeyInfo)))
|
||||||
@ -235,6 +222,7 @@ u32 InitKeyDb(const char* path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// creates dependency to "sha.h", not required for base keydb functions
|
||||||
u32 CheckRecommendedKeyDb(const char* path)
|
u32 CheckRecommendedKeyDb(const char* path)
|
||||||
{
|
{
|
||||||
// SHA-256 of the recommended aeskeydb.bin file
|
// SHA-256 of the recommended aeskeydb.bin file
|
||||||
|
@ -4,10 +4,18 @@
|
|||||||
|
|
||||||
#define KEYDB_NAME "aeskeydb.bin"
|
#define KEYDB_NAME "aeskeydb.bin"
|
||||||
|
|
||||||
|
// SHA-256 and size of the recommended aeskeydb.bin file
|
||||||
|
// equals MD5 A5B28945A7C051D7A0CD18AF0E580D1B / 1024 byte
|
||||||
|
#define KEYDB_PERFECT_HASH \
|
||||||
|
0x40, 0x76, 0x54, 0x3D, 0xA3, 0xFF, 0x91, 0x1C, 0xE1, 0xCC, 0x4E, 0xC7, 0x2F, 0x92, 0xE4, 0xB7, \
|
||||||
|
0x2B, 0x24, 0x00, 0x15, 0xBE, 0x9B, 0xFC, 0xDE, 0x7F, 0xED, 0x95, 0x1D, 0xD5, 0xAB, 0x2D, 0xCB
|
||||||
|
#define KEYDB_PERFECT_SIZE (32 * sizeof(AesKeyInfo)) // 32 keys contained
|
||||||
|
|
||||||
#define KEYS_UNKNOWN 0
|
#define KEYS_UNKNOWN 0
|
||||||
#define KEYS_DEVKIT 1
|
#define KEYS_DEVKIT 1
|
||||||
#define KEYS_RETAIL 2
|
#define KEYS_RETAIL 2
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 slot; // keyslot, 0x00...0x3F
|
u8 slot; // keyslot, 0x00...0x3F
|
||||||
char type; // type 'X' / 'Y' / 'N' for normalKey / 'I' for IV
|
char type; // type 'X' / 'Y' / 'N' for normalKey / 'I' for IV
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
#define FTYPE_EBACKUP(tp) (tp&(IMG_NAND))
|
#define FTYPE_EBACKUP(tp) (tp&(IMG_NAND))
|
||||||
#define FTYPE_XORPAD(tp) (tp&(BIN_NCCHNFO))
|
#define FTYPE_XORPAD(tp) (tp&(BIN_NCCHNFO))
|
||||||
#define FTYPE_KEYINIT(tp) (tp&(BIN_KEYDB))
|
#define FTYPE_KEYINIT(tp) (tp&(BIN_KEYDB))
|
||||||
|
#define FTYPE_KEYINSTALL(tp) (tp&(BIN_KEYDB))
|
||||||
#define FTYPE_SCRIPT(tp) (tp&(TXT_SCRIPT))
|
#define FTYPE_SCRIPT(tp) (tp&(TXT_SCRIPT))
|
||||||
#define FTYPE_BOOTABLE(tp) (tp&(SYS_FIRM))
|
#define FTYPE_BOOTABLE(tp) (tp&(SYS_FIRM))
|
||||||
#define FTYPE_INSTALLABLE(tp) (tp&(SYS_FIRM))
|
#define FTYPE_INSTALLABLE(tp) (tp&(SYS_FIRM))
|
||||||
|
@ -937,7 +937,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
bool cia_buildable_legit = (FTYPE_CIABUILD_L(filetype));
|
bool cia_buildable_legit = (FTYPE_CIABUILD_L(filetype));
|
||||||
bool cxi_dumpable = (FTYPE_CXIDUMP(filetype));
|
bool cxi_dumpable = (FTYPE_CXIDUMP(filetype));
|
||||||
bool tik_buildable = (FTYPE_TIKBUILD(filetype)) && !in_output_path;
|
bool tik_buildable = (FTYPE_TIKBUILD(filetype)) && !in_output_path;
|
||||||
bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path;
|
bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path && !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND));
|
||||||
bool titleinfo = (FTYPE_TITLEINFO(filetype));
|
bool titleinfo = (FTYPE_TITLEINFO(filetype));
|
||||||
bool renamable = (FTYPE_RENAMABLE(filetype));
|
bool renamable = (FTYPE_RENAMABLE(filetype));
|
||||||
bool transferable = (FTYPE_TRANSFERABLE(filetype) && IS_A9LH && (drvtype & DRV_FAT));
|
bool transferable = (FTYPE_TRANSFERABLE(filetype) && IS_A9LH && (drvtype & DRV_FAT));
|
||||||
@ -947,7 +947,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
bool ebackupable = (FTYPE_EBACKUP(filetype));
|
bool ebackupable = (FTYPE_EBACKUP(filetype));
|
||||||
bool ncsdfixable = (FTYPE_NCSDFIXABLE(filetype));
|
bool ncsdfixable = (FTYPE_NCSDFIXABLE(filetype));
|
||||||
bool xorpadable = (FTYPE_XORPAD(filetype));
|
bool xorpadable = (FTYPE_XORPAD(filetype));
|
||||||
bool keyinitable = (FTYPE_KEYINIT(filetype));
|
bool keyinitable = (FTYPE_KEYINIT(filetype)) && !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND));
|
||||||
|
bool keyinstallable = (FTYPE_KEYINSTALL(filetype)) && !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND));
|
||||||
bool scriptable = (FTYPE_SCRIPT(filetype));
|
bool scriptable = (FTYPE_SCRIPT(filetype));
|
||||||
bool bootable = (FTYPE_BOOTABLE(filetype));
|
bool bootable = (FTYPE_BOOTABLE(filetype));
|
||||||
bool installable = (FTYPE_INSTALLABLE(filetype));
|
bool installable = (FTYPE_INSTALLABLE(filetype));
|
||||||
@ -963,7 +964,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
extrcodeable = (FTYPE_HASCODE(filetype_cxi));
|
extrcodeable = (FTYPE_HASCODE(filetype_cxi));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || bootable || scriptable || installable || agbexportable || agbimportable;
|
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || keyinstallable || bootable || scriptable || installable || agbexportable || agbimportable;
|
||||||
|
|
||||||
char pathstr[32+1];
|
char pathstr[32+1];
|
||||||
TruncateString(pathstr, file_path, 32, 8);
|
TruncateString(pathstr, file_path, 32, 8);
|
||||||
@ -1151,6 +1152,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
int xorpad = (xorpadable) ? ++n_opt : -1;
|
int xorpad = (xorpadable) ? ++n_opt : -1;
|
||||||
int xorpad_inplace = (xorpadable) ? ++n_opt : -1;
|
int xorpad_inplace = (xorpadable) ? ++n_opt : -1;
|
||||||
int keyinit = (keyinitable) ? ++n_opt : -1;
|
int keyinit = (keyinitable) ? ++n_opt : -1;
|
||||||
|
int keyinstall = (keyinstallable) ? ++n_opt : -1;
|
||||||
int install = (installable) ? ++n_opt : -1;
|
int install = (installable) ? ++n_opt : -1;
|
||||||
int boot = (bootable) ? ++n_opt : -1;
|
int boot = (bootable) ? ++n_opt : -1;
|
||||||
int script = (scriptable) ? ++n_opt : -1;
|
int script = (scriptable) ? ++n_opt : -1;
|
||||||
@ -1177,6 +1179,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
if (xorpad_inplace > 0) optionstr[xorpad_inplace-1] = "Build XORpads (inplace)";
|
if (xorpad_inplace > 0) optionstr[xorpad_inplace-1] = "Build XORpads (inplace)";
|
||||||
if (extrcode > 0) optionstr[extrcode-1] = "Extract " EXEFS_CODE_NAME;
|
if (extrcode > 0) optionstr[extrcode-1] = "Extract " EXEFS_CODE_NAME;
|
||||||
if (keyinit > 0) optionstr[keyinit-1] = "Init " KEYDB_NAME;
|
if (keyinit > 0) optionstr[keyinit-1] = "Init " KEYDB_NAME;
|
||||||
|
if (keyinstall > 0) optionstr[keyinstall-1] = "Install " KEYDB_NAME;
|
||||||
if (install > 0) optionstr[install-1] = "Install FIRM";
|
if (install > 0) optionstr[install-1] = "Install FIRM";
|
||||||
if (boot > 0) optionstr[boot-1] = "Boot FIRM";
|
if (boot > 0) optionstr[boot-1] = "Boot FIRM";
|
||||||
if (script > 0) optionstr[script-1] = "Execute GM9 script";
|
if (script > 0) optionstr[script-1] = "Execute GM9 script";
|
||||||
@ -1558,6 +1561,10 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
ShowPrompt(false, "%s\nAESkeydb init %s", pathstr, (InitKeyDb(file_path) == 0) ? "success" : "failed");
|
ShowPrompt(false, "%s\nAESkeydb init %s", pathstr, (InitKeyDb(file_path) == 0) ? "success" : "failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else if (user_select == keyinstall) { // -> install keys from aeskeydb.bin
|
||||||
|
ShowPrompt(false, "%s\nAESkeydb install %s", pathstr, (SafeInstallKeyDb(file_path) == 0) ? "success" : "failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
else if (user_select == install) { // -> install FIRM
|
else if (user_select == install) { // -> install FIRM
|
||||||
size_t firm_size = FileGetSize(file_path);
|
size_t firm_size = FileGetSize(file_path);
|
||||||
u32 slots = 1;
|
u32 slots = 1;
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "exefs.h"
|
#include "exefs.h"
|
||||||
|
|
||||||
|
#define ESSENTIAL_NAME "essential.exefs"
|
||||||
|
|
||||||
// start sector of the essential backup in NAND
|
// start sector of the essential backup in NAND
|
||||||
// careful with this, essential backup should never reach sector 0x96
|
// careful with this, essential backup should never reach sector 0x96
|
||||||
#define ESSENTIAL_SECTOR 0x1
|
#define ESSENTIAL_SECTOR 0x1
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
#include "fsdrive.h"
|
#include "fsdrive.h"
|
||||||
#include "unittype.h"
|
#include "unittype.h"
|
||||||
#include "keydb.h"
|
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
#include "fatmbr.h"
|
#include "fatmbr.h"
|
||||||
@ -13,7 +12,7 @@
|
|||||||
#define SECTOR_SHA256 ((IS_DEVKIT) ? sector0x96dev_sha256 : sector0x96_sha256)
|
#define SECTOR_SHA256 ((IS_DEVKIT) ? sector0x96dev_sha256 : sector0x96_sha256)
|
||||||
|
|
||||||
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
||||||
static const u32 np_keyslots[9][4] = { // [NP_TYPE][NP_SUBTYPE]
|
static const u32 np_keyslots[10][4] = { // [NP_TYPE][NP_SUBTYPE]
|
||||||
{ 0xFF, 0xFF, 0xFF, 0xFF }, // none
|
{ 0xFF, 0xFF, 0xFF, 0xFF }, // none
|
||||||
{ 0xFF, 0x03, 0x04, 0x05 }, // standard
|
{ 0xFF, 0x03, 0x04, 0x05 }, // standard
|
||||||
{ 0xFF, 0x03, 0x04, 0x05 }, // FAT (custom, not in NCSD)
|
{ 0xFF, 0x03, 0x04, 0x05 }, // FAT (custom, not in NCSD)
|
||||||
@ -21,6 +20,7 @@ static const u32 np_keyslots[9][4] = { // [NP_TYPE][NP_SUBTYPE]
|
|||||||
{ 0xFF, 0xFF, 0x07, 0xFF }, // AGBSAVE
|
{ 0xFF, 0xFF, 0x07, 0xFF }, // AGBSAVE
|
||||||
{ 0xFF, 0xFF, 0xFF, 0xFF }, // NCSD (custom)
|
{ 0xFF, 0xFF, 0xFF, 0xFF }, // NCSD (custom)
|
||||||
{ 0xFF, 0xFF, 0xFF, 0xFF }, // D0K3 (custom)
|
{ 0xFF, 0xFF, 0xFF, 0xFF }, // D0K3 (custom)
|
||||||
|
{ 0xFF, 0xFF, 0xFF, 0xFF }, // KEYDB (custom)
|
||||||
{ 0xFF, 0xFF, 0xFF, 0x11 }, // SECRET (custom)
|
{ 0xFF, 0xFF, 0xFF, 0x11 }, // SECRET (custom)
|
||||||
{ 0xFF, 0xFF, 0xFF, 0xFF } // BONUS (custom)
|
{ 0xFF, 0xFF, 0xFF, 0xFF } // BONUS (custom)
|
||||||
};
|
};
|
||||||
@ -470,14 +470,17 @@ u32 GetNandNcsdPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32
|
|||||||
// special, custom partition types, not in NCSD
|
// special, custom partition types, not in NCSD
|
||||||
if (type >= NP_TYPE_NCSD) {
|
if (type >= NP_TYPE_NCSD) {
|
||||||
if (type == NP_TYPE_NCSD) {
|
if (type == NP_TYPE_NCSD) {
|
||||||
info->sector = 0x00; // hardcoded
|
info->sector = SECTOR_NCSD; // hardcoded
|
||||||
info->count = 0x01;
|
info->count = COUNT_NCSD;
|
||||||
} else if (type == NP_TYPE_D0K3) {
|
} else if (type == NP_TYPE_D0K3) {
|
||||||
info->sector = SECTOR_D0K3; // hardcoded
|
info->sector = SECTOR_D0K3; // hardcoded
|
||||||
info->count = SECTOR_SECRET - info->sector;
|
info->count = COUNT_D0K3;
|
||||||
|
} else if (type == NP_TYPE_KEYDB) {
|
||||||
|
info->sector = SECTOR_KEYDB; // hardcoded
|
||||||
|
info->count = COUNT_KEYDB;
|
||||||
} else if (type == NP_TYPE_SECRET) {
|
} else if (type == NP_TYPE_SECRET) {
|
||||||
info->sector = SECTOR_SECRET;
|
info->sector = SECTOR_SECRET; // hardcoded
|
||||||
info->count = 0x01;
|
info->count = COUNT_SECRET;
|
||||||
} else if (type == NP_TYPE_BONUS) {
|
} else if (type == NP_TYPE_BONUS) {
|
||||||
info->sector = GetNandNcsdMinSizeSectors(ncsd);
|
info->sector = GetNandNcsdMinSizeSectors(ncsd);
|
||||||
info->count = 0x00; // placeholder, actual size needs info from NAND chip
|
info->count = 0x00; // placeholder, actual size needs info from NAND chip
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "essentials.h"
|
||||||
|
#include "keydb.h"
|
||||||
|
|
||||||
#define NAND_SYSNAND (1UL<<0)
|
#define NAND_SYSNAND (1UL<<0)
|
||||||
#define NAND_EMUNAND (1UL<<1)
|
#define NAND_EMUNAND (1UL<<1)
|
||||||
@ -12,9 +14,15 @@
|
|||||||
#define BOOT_NTRBOOT (1UL<<1)
|
#define BOOT_NTRBOOT (1UL<<1)
|
||||||
#define BOOT_WIFI_SPI (1UL<<2)
|
#define BOOT_WIFI_SPI (1UL<<2)
|
||||||
|
|
||||||
// hardcoded start sectors
|
// hardcoded start sectors and counts
|
||||||
#define SECTOR_D0K3 0x000001
|
#define COUNT_NCSD 0x01
|
||||||
|
#define COUNT_SECRET 0x01
|
||||||
|
#define COUNT_D0K3 ((sizeof(EssentialBackup) + 0x1FF) / 0x200)
|
||||||
|
#define COUNT_KEYDB ((KEYDB_PERFECT_SIZE + 0x1FF) / 0x200)
|
||||||
|
#define SECTOR_NCSD 0x000000
|
||||||
#define SECTOR_SECRET 0x000096
|
#define SECTOR_SECRET 0x000096
|
||||||
|
#define SECTOR_D0K3 (SECTOR_NCSD + COUNT_NCSD)
|
||||||
|
#define SECTOR_KEYDB (SECTOR_SECRET - COUNT_KEYDB)
|
||||||
|
|
||||||
// 0x110...0x118 in the NAND NCSD header
|
// 0x110...0x118 in the NAND NCSD header
|
||||||
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
||||||
@ -25,8 +33,9 @@
|
|||||||
#define NP_TYPE_AGB 4
|
#define NP_TYPE_AGB 4
|
||||||
#define NP_TYPE_NCSD 5 // this is of our own making
|
#define NP_TYPE_NCSD 5 // this is of our own making
|
||||||
#define NP_TYPE_D0K3 6 // my own partition ^_^
|
#define NP_TYPE_D0K3 6 // my own partition ^_^
|
||||||
#define NP_TYPE_SECRET 7 // this is of our own making
|
#define NP_TYPE_KEYDB 7 // keydb partition, also my own ^_^
|
||||||
#define NP_TYPE_BONUS 8 // this is of our own making
|
#define NP_TYPE_SECRET 8 // this is of our own making
|
||||||
|
#define NP_TYPE_BONUS 9 // this is of our own making
|
||||||
|
|
||||||
// 0x118...0x120 in the NAND NCSD header
|
// 0x118...0x120 in the NAND NCSD header
|
||||||
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
// see: https://www.3dbrew.org/wiki/NCSD#NCSD_header
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "sdmmc.h"
|
#include "sdmmc.h"
|
||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
#include "sighax.h"
|
#include "sighax.h"
|
||||||
|
#include "keydb.h" // for perfect keydb hash and length
|
||||||
#include "essentials.h" // for essential backup struct
|
#include "essentials.h" // for essential backup struct
|
||||||
#include "unittype.h"
|
#include "unittype.h"
|
||||||
|
|
||||||
@ -558,3 +559,34 @@ u32 SafeInstallFirm(const char* path, u32 slots) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 SafeInstallKeyDb(const char* path)
|
||||||
|
{
|
||||||
|
const u8 perfect_sha[] = { KEYDB_PERFECT_HASH };
|
||||||
|
u8 keydb[KEYDB_PERFECT_SIZE];
|
||||||
|
|
||||||
|
char pathstr[32 + 1]; // truncated path string
|
||||||
|
TruncateString(pathstr, path, 32, 8);
|
||||||
|
|
||||||
|
// already installed?
|
||||||
|
if ((ReadNandBytes(keydb, SECTOR_KEYDB*0x200, KEYDB_PERFECT_SIZE, 0xFF, NAND_SYSNAND) == 0) &&
|
||||||
|
(sha_cmp(perfect_sha, keydb, KEYDB_PERFECT_SIZE, SHA256_MODE) == 0)) {
|
||||||
|
ShowPrompt(false, "Perfect " KEYDB_NAME " is already installed!");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check input path...
|
||||||
|
if ((fvx_qread(path, keydb, 0, KEYDB_PERFECT_SIZE, NULL) != FR_OK) ||
|
||||||
|
(sha_cmp(perfect_sha, keydb, KEYDB_PERFECT_SIZE, SHA256_MODE) != 0)) {
|
||||||
|
ShowPrompt(false, "%s\nNot a perfect " KEYDB_NAME " image.\nCannot install to NAND!", pathstr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// point of no return, install key database
|
||||||
|
if (WriteNandBytes(keydb, SECTOR_KEYDB*0x200, KEYDB_PERFECT_SIZE, 0xFF, NAND_SYSNAND) != 0) {
|
||||||
|
ShowPrompt(false, "%s\nFailed writing " KEYDB_NAME " to NAND!", pathstr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -8,5 +8,6 @@ u32 FixNandHeader(const char* path, bool check_size);
|
|||||||
u32 ValidateNandDump(const char* path);
|
u32 ValidateNandDump(const char* path);
|
||||||
u32 SafeRestoreNandDump(const char* path);
|
u32 SafeRestoreNandDump(const char* path);
|
||||||
u32 SafeInstallFirm(const char* path, u32 slots);
|
u32 SafeInstallFirm(const char* path, u32 slots);
|
||||||
|
u32 SafeInstallKeyDb(const char* path);
|
||||||
u32 DumpGbaVcSavegame(const char* path);
|
u32 DumpGbaVcSavegame(const char* path);
|
||||||
u32 InjectGbaVcSavegame(const char* path, const char* path_vcsave);
|
u32 InjectGbaVcSavegame(const char* path, const char* path_vcsave);
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#include "vnand.h"
|
#include "vnand.h"
|
||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
#include "essentials.h"
|
#include "essentials.h"
|
||||||
|
#include "keydb.h"
|
||||||
|
#include "sha.h"
|
||||||
#include "unittype.h"
|
#include "unittype.h"
|
||||||
|
|
||||||
#define VFLAG_MBR (1UL<<28)
|
#define VFLAG_MBR (1UL<<27)
|
||||||
#define VFLAG_ESSENTIAL (1UL<<29)
|
#define VFLAG_ESSENTIAL (1UL<<28)
|
||||||
|
#define VFLAG_KEYDB (1UL<<29)
|
||||||
#define VFLAG_NEEDS_OTP (1UL<<30)
|
#define VFLAG_NEEDS_OTP (1UL<<30)
|
||||||
#define VFLAG_NAND_SIZE (1UL<<31)
|
#define VFLAG_NAND_SIZE (1UL<<31)
|
||||||
|
|
||||||
@ -20,7 +23,8 @@ typedef struct {
|
|||||||
static const VirtualNandTemplate vNandTemplates[] = {
|
static const VirtualNandTemplate vNandTemplates[] = {
|
||||||
{ "nand_hdr.bin" , NP_TYPE_NCSD , NP_SUBTYPE_CTR , 0, 0 },
|
{ "nand_hdr.bin" , NP_TYPE_NCSD , NP_SUBTYPE_CTR , 0, 0 },
|
||||||
{ "twlmbr.bin" , NP_TYPE_STD , NP_SUBTYPE_TWL , 0, VFLAG_MBR },
|
{ "twlmbr.bin" , NP_TYPE_STD , NP_SUBTYPE_TWL , 0, VFLAG_MBR },
|
||||||
{ "essential.exefs" , NP_TYPE_D0K3 , NP_SUBTYPE_NONE , 0, VFLAG_DELETABLE | VFLAG_ESSENTIAL },
|
{ ESSENTIAL_NAME , NP_TYPE_D0K3 , NP_SUBTYPE_NONE , 0, VFLAG_DELETABLE | VFLAG_ESSENTIAL },
|
||||||
|
{ KEYDB_NAME , NP_TYPE_KEYDB , NP_SUBTYPE_NONE , 0, VFLAG_DELETABLE | VFLAG_KEYDB },
|
||||||
{ "sector0x96.bin" , NP_TYPE_SECRET, NP_SUBTYPE_CTR_N, 0, VFLAG_NEEDS_OTP },
|
{ "sector0x96.bin" , NP_TYPE_SECRET, NP_SUBTYPE_CTR_N, 0, VFLAG_NEEDS_OTP },
|
||||||
{ "twln.bin" , NP_TYPE_FAT , NP_SUBTYPE_TWL , 0, 0 },
|
{ "twln.bin" , NP_TYPE_FAT , NP_SUBTYPE_TWL , 0, 0 },
|
||||||
{ "twlp.bin" , NP_TYPE_FAT , NP_SUBTYPE_TWL , 1, 0 },
|
{ "twlp.bin" , NP_TYPE_FAT , NP_SUBTYPE_TWL , 1, 0 },
|
||||||
@ -87,6 +91,13 @@ bool ReadVNandDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir
|
|||||||
if (memcmp(data, magic, sizeof(magic)) != 0) continue;
|
if (memcmp(data, magic, sizeof(magic)) != 0) continue;
|
||||||
vfile->size = sizeof(EssentialBackup);
|
vfile->size = sizeof(EssentialBackup);
|
||||||
}
|
}
|
||||||
|
if (vfile->flags & VFLAG_KEYDB) {
|
||||||
|
const u8 perfect_sha[] = { KEYDB_PERFECT_HASH };
|
||||||
|
u8 keydb[KEYDB_PERFECT_SIZE];
|
||||||
|
ReadNandBytes(keydb, vfile->offset, KEYDB_PERFECT_SIZE, vfile->keyslot, nand_src);
|
||||||
|
if (sha_cmp(perfect_sha, keydb, KEYDB_PERFECT_SIZE, SHA256_MODE) != 0) continue;
|
||||||
|
vfile->size = KEYDB_PERFECT_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
// found if arriving here
|
// found if arriving here
|
||||||
vfile->flags |= nand_src;
|
vfile->flags |= nand_src;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user