forked from Mirror/GodMode9
Added NCCH/NCSD/CIA/BOSS encrypt options
This commit is contained in:
parent
1a9cad856d
commit
d2e16c9de5
@ -38,7 +38,7 @@
|
|||||||
(((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v))
|
(((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v))
|
||||||
|
|
||||||
// GodMode9 version
|
// GodMode9 version
|
||||||
#define VERSION "0.9.6"
|
#define VERSION "0.9.7"
|
||||||
|
|
||||||
// input / output paths
|
// input / output paths
|
||||||
#define INPUT_PATHS "0:", "0:/files9", "1:/rw/files9"
|
#define INPUT_PATHS "0:", "0:/files9", "1:/rw/files9"
|
||||||
|
@ -59,7 +59,7 @@ u32 IdentifyFileType(const char* path) {
|
|||||||
fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) {
|
fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) {
|
||||||
return BIN_NCCHNFO; // ncchinfo.bin file
|
return BIN_NCCHNFO; // ncchinfo.bin file
|
||||||
#if PAYLOAD_MAX_SIZE <= TEMP_BUFFER_SIZE
|
#if PAYLOAD_MAX_SIZE <= TEMP_BUFFER_SIZE
|
||||||
} else if ((fsize <= PAYLOAD_MAX_SIZE) && (strncasecmp(ext, "bin", 4) == 0)) {
|
} else if ((fsize <= PAYLOAD_MAX_SIZE) && ext && (strncasecmp(ext, "bin", 4) == 0)) {
|
||||||
return BIN_LAUNCH; // assume it's an ARM9 payload
|
return BIN_LAUNCH; // assume it's an ARM9 payload
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -14,15 +14,17 @@
|
|||||||
#define SYS_FIRM (1<<9)
|
#define SYS_FIRM (1<<9)
|
||||||
#define BIN_NCCHNFO (1<<10)
|
#define BIN_NCCHNFO (1<<10)
|
||||||
#define BIN_LAUNCH (1<<11)
|
#define BIN_LAUNCH (1<<11)
|
||||||
|
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
||||||
|
|
||||||
#define FLAG_CXI (1<<31)
|
#define FLAG_CXI (1<<31)
|
||||||
|
|
||||||
#define FTYPE_MOUNTABLE(tp) (tp&(IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS|SYS_FIRM))
|
#define FTYPE_MOUNTABLE(tp) (tp&(IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS|SYS_FIRM))
|
||||||
#define FYTPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
#define FYTPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
||||||
#define FYTPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|SYS_FIRM))
|
#define FYTPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|SYS_FIRM))
|
||||||
|
#define FYTPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS))
|
||||||
#define FTYPE_BUILDABLE(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
#define FTYPE_BUILDABLE(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
||||||
#define FTYPE_BUILDABLE_L(tp) (FTYPE_BUILDABLE(tp) && (tp&(GAME_TMD)))
|
#define FTYPE_BUILDABLE_L(tp) (FTYPE_BUILDABLE(tp) && (tp&(GAME_TMD)))
|
||||||
#define FTYPE_HSINJECTABLE(tp) ((tp&(GAME_NCCH|FLAG_CXI)) == (GAME_NCCH|FLAG_CXI))
|
#define FTYPE_HSINJECTABLE(tp) ((u32) (tp&(GAME_NCCH|FLAG_CXI)) == (u32) (GAME_NCCH|FLAG_CXI))
|
||||||
#define FTYPE_RESTORABLE(tp) (tp&(IMG_NAND))
|
#define FTYPE_RESTORABLE(tp) (tp&(IMG_NAND))
|
||||||
#define FTYPE_XORPAD(tp) (tp&(BIN_NCCHNFO))
|
#define FTYPE_XORPAD(tp) (tp&(BIN_NCCHNFO))
|
||||||
#define FTYPE_PAYLOAD(tp) (tp&(BIN_LAUNCH))
|
#define FTYPE_PAYLOAD(tp) (tp&(BIN_LAUNCH))
|
||||||
|
@ -8,6 +8,10 @@
|
|||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
#include "vff.h"
|
#include "vff.h"
|
||||||
|
|
||||||
|
// use NCCH crypto defines for everything
|
||||||
|
#define CRYPTO_DECRYPT NCCH_NOCRYPTO
|
||||||
|
#define CRYPTO_ENCRYPT NCCH_STDCRYPTO
|
||||||
|
|
||||||
u32 GetOutputPath(char* dest, const char* path, const char* ext) {
|
u32 GetOutputPath(char* dest, const char* path, const char* ext) {
|
||||||
// special handling for input from title directories (somewhat hacky)
|
// special handling for input from title directories (somewhat hacky)
|
||||||
if ((strspn(path, "AB147") > 0) && (strncmp(path + 1, ":/title/", 8) == 0)) {
|
if ((strspn(path, "AB147") > 0) && (strncmp(path + 1, ":/title/", 8) == 0)) {
|
||||||
@ -670,7 +674,7 @@ u32 CheckEncryptedGameFile(const char* path) {
|
|||||||
else return 1;
|
else return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 crypto, // crypto only relevant for NCCH
|
u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 crypto,
|
||||||
u32 offset, u32 size, TmdContentChunk* chunk, const u8* titlekey) { // this line only for CIA contents
|
u32 offset, u32 size, TmdContentChunk* chunk, const u8* titlekey) { // this line only for CIA contents
|
||||||
// this will do a simple copy for unencrypted files
|
// this will do a simple copy for unencrypted files
|
||||||
bool inplace = (strncmp(orig, dest, 256) == 0);
|
bool inplace = (strncmp(orig, dest, 256) == 0);
|
||||||
@ -680,6 +684,14 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16
|
|||||||
FIL* dfp = (inplace) ? &ofile : &dfile;
|
FIL* dfp = (inplace) ? &ofile : &dfile;
|
||||||
FSIZE_t fsize;
|
FSIZE_t fsize;
|
||||||
|
|
||||||
|
// FIRM encryption is not possible (yet)
|
||||||
|
if ((mode & SYS_FIRM) && (crypto != CRYPTO_DECRYPT))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// check for BOSS crypto
|
||||||
|
bool crypt_boss = ((mode & GAME_BOSS) && (CheckEncryptedBossFile(orig) == 0));
|
||||||
|
crypt_boss = ((mode & GAME_BOSS) && (crypt_boss == (crypto == CRYPTO_DECRYPT)));
|
||||||
|
|
||||||
// open file(s)
|
// open file(s)
|
||||||
if (inplace) {
|
if (inplace) {
|
||||||
if (fvx_open(ofp, orig, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
if (fvx_open(ofp, orig, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
|
||||||
@ -701,14 +713,14 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16
|
|||||||
|
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
if (!ShowProgress(offset, fsize, dest)) ret = 1;
|
if (!ShowProgress(offset, fsize, dest)) ret = 1;
|
||||||
if (mode & (GAME_NCCH|GAME_NCSD|GAME_BOSS|SYS_FIRM)) { // for NCCH / NCSD / FIRM files
|
if (mode & (GAME_NCCH|GAME_NCSD|GAME_BOSS|SYS_FIRM)) { // for NCCH / NCSD / BOSS / FIRM files
|
||||||
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
for (u32 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) {
|
||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
||||||
UINT bytes_read, bytes_written;
|
UINT bytes_read, bytes_written;
|
||||||
if (fvx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
if (fvx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
||||||
if (((mode & GAME_NCCH) && (CryptNcchSequential(MAIN_BUFFER, i, read_bytes, crypto) != 0)) ||
|
if (((mode & GAME_NCCH) && (CryptNcchSequential(MAIN_BUFFER, i, read_bytes, crypto) != 0)) ||
|
||||||
((mode & GAME_NCSD) && (DecryptNcsdSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
((mode & GAME_NCSD) && (CryptNcsdSequential(MAIN_BUFFER, i, read_bytes, crypto) != 0)) ||
|
||||||
((mode & GAME_BOSS) && (CryptBossSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
((mode & GAME_BOSS) && crypt_boss && (CryptBossSequential(MAIN_BUFFER, i, read_bytes) != 0)) ||
|
||||||
((mode & SYS_FIRM) && (DecryptFirmSequential(MAIN_BUFFER, i, read_bytes) != 0)))
|
((mode & SYS_FIRM) && (DecryptFirmSequential(MAIN_BUFFER, i, read_bytes) != 0)))
|
||||||
ret = 1;
|
ret = 1;
|
||||||
if (inplace) fvx_lseek(ofp, fvx_tell(ofp) - read_bytes);
|
if (inplace) fvx_lseek(ofp, fvx_tell(ofp) - read_bytes);
|
||||||
@ -726,8 +738,8 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16
|
|||||||
GetTmdCtr(ctr, chunk); // NCCH crypto?
|
GetTmdCtr(ctr, chunk); // NCCH crypto?
|
||||||
if (fvx_read(ofp, MAIN_BUFFER, sizeof(NcchHeader), &bytes_read) != FR_OK) ret = 1;
|
if (fvx_read(ofp, MAIN_BUFFER, sizeof(NcchHeader), &bytes_read) != FR_OK) ret = 1;
|
||||||
if (cia_crypto) DecryptCiaContentSequential(MAIN_BUFFER, sizeof(NcchHeader), ctr, titlekey);
|
if (cia_crypto) DecryptCiaContentSequential(MAIN_BUFFER, sizeof(NcchHeader), ctr, titlekey);
|
||||||
ncch_crypto = ((ValidateNcchHeader(ncch) == 0) && NCCH_ENCRYPTED(ncch));
|
ncch_crypto = ((ValidateNcchHeader(ncch) == 0) && (NCCH_ENCRYPTED(ncch) || !(crypto & NCCH_NOCRYPTO)));
|
||||||
if (ncch_crypto && (SetupNcchCrypto(ncch, NCCH_NOCRYPTO) != 0))
|
if (ncch_crypto && (SetupNcchCrypto(ncch, crypto) != 0))
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
GetTmdCtr(ctr, chunk);
|
GetTmdCtr(ctr, chunk);
|
||||||
@ -737,7 +749,7 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16
|
|||||||
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i));
|
||||||
if (fvx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
if (fvx_read(ofp, MAIN_BUFFER, read_bytes, &bytes_read) != FR_OK) ret = 1;
|
||||||
if (cia_crypto && (DecryptCiaContentSequential(MAIN_BUFFER, read_bytes, ctr, titlekey) != 0)) ret = 1;
|
if (cia_crypto && (DecryptCiaContentSequential(MAIN_BUFFER, read_bytes, ctr, titlekey) != 0)) ret = 1;
|
||||||
if (ncch_crypto && (DecryptNcchSequential(MAIN_BUFFER, i, read_bytes) != 0)) ret = 1;
|
if (ncch_crypto && (CryptNcchSequential(MAIN_BUFFER, i, read_bytes, crypto) != 0)) ret = 1;
|
||||||
if (inplace) fvx_lseek(ofp, fvx_tell(ofp) - read_bytes);
|
if (inplace) fvx_lseek(ofp, fvx_tell(ofp) - read_bytes);
|
||||||
if (fvx_write(dfp, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ret = 1;
|
if (fvx_write(dfp, MAIN_BUFFER, read_bytes, &bytes_written) != FR_OK) ret = 1;
|
||||||
sha_update(MAIN_BUFFER, read_bytes);
|
sha_update(MAIN_BUFFER, read_bytes);
|
||||||
@ -754,7 +766,7 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 DecryptCiaFile(const char* orig, const char* dest) {
|
u32 CryptCiaFile(const char* orig, const char* dest, u16 crypto) {
|
||||||
bool inplace = (strncmp(orig, dest, 256) == 0);
|
bool inplace = (strncmp(orig, dest, 256) == 0);
|
||||||
CiaStub* cia = (CiaStub*) TEMP_BUFFER;
|
CiaStub* cia = (CiaStub*) TEMP_BUFFER;
|
||||||
CiaInfo info;
|
CiaInfo info;
|
||||||
@ -779,7 +791,7 @@ u32 DecryptCiaFile(const char* orig, const char* dest) {
|
|||||||
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) {
|
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) {
|
||||||
TmdContentChunk* chunk = &(cia->content_list[i]);
|
TmdContentChunk* chunk = &(cia->content_list[i]);
|
||||||
u64 size = getbe64(chunk->size);
|
u64 size = getbe64(chunk->size);
|
||||||
if (CryptNcchNcsdBossFirmFile(orig, dest, GAME_CIA, NCCH_NOCRYPTO, next_offset, size, chunk, titlekey) != 0)
|
if (CryptNcchNcsdBossFirmFile(orig, dest, GAME_CIA, crypto, next_offset, size, chunk, titlekey) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
next_offset += size;
|
next_offset += size;
|
||||||
}
|
}
|
||||||
@ -798,7 +810,7 @@ u32 DecryptFirmFile(const char* orig, const char* dest) {
|
|||||||
UINT btr;
|
UINT btr;
|
||||||
|
|
||||||
// actual decryption
|
// actual decryption
|
||||||
if (CryptNcchNcsdBossFirmFile(orig, dest, SYS_FIRM, 0, 0, 0, NULL, NULL) != 0)
|
if (CryptNcchNcsdBossFirmFile(orig, dest, SYS_FIRM, CRYPTO_DECRYPT, 0, 0, NULL, NULL) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// open destination file, get FIRM header
|
// open destination file, get FIRM header
|
||||||
@ -850,8 +862,9 @@ u32 DecryptFirmFile(const char* orig, const char* dest) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 DecryptGameFile(const char* path, bool inplace) {
|
u32 CryptGameFile(const char* path, bool inplace, bool encrypt) {
|
||||||
u32 filetype = IdentifyFileType(path);
|
u32 filetype = IdentifyFileType(path);
|
||||||
|
u16 crypto = encrypt ? CRYPTO_ENCRYPT : CRYPTO_DECRYPT;
|
||||||
char dest[256];
|
char dest[256];
|
||||||
char* destptr = (char*) path;
|
char* destptr = (char*) path;
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
@ -871,11 +884,11 @@ u32 DecryptGameFile(const char* path, bool inplace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (filetype & GAME_CIA)
|
if (filetype & GAME_CIA)
|
||||||
ret = DecryptCiaFile(path, destptr);
|
ret = CryptCiaFile(path, destptr, crypto);
|
||||||
else if (filetype & SYS_FIRM)
|
else if (filetype & SYS_FIRM)
|
||||||
ret = DecryptFirmFile(path, destptr);
|
ret = DecryptFirmFile(path, destptr);
|
||||||
else if (filetype & (GAME_NCCH|GAME_NCSD|GAME_BOSS))
|
else if (filetype & (GAME_NCCH|GAME_NCSD|GAME_BOSS))
|
||||||
ret = CryptNcchNcsdBossFirmFile(path, destptr, filetype, NCCH_NOCRYPTO, 0, 0, NULL, NULL);
|
ret = CryptNcchNcsdBossFirmFile(path, destptr, filetype, crypto, 0, 0, NULL, NULL);
|
||||||
else ret = 1;
|
else ret = 1;
|
||||||
|
|
||||||
if (!inplace && (ret != 0))
|
if (!inplace && (ret != 0))
|
||||||
@ -1302,7 +1315,7 @@ u32 InjectHealthAndSafety(const char* path, const char* destdrv) {
|
|||||||
|
|
||||||
// copy / decrypt the source CXI
|
// copy / decrypt the source CXI
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
if (CryptNcchNcsdBossFirmFile(path, path_cxi, GAME_NCCH, NCCH_NOCRYPTO, 0, 0, NULL, NULL) != 0)
|
if (CryptNcchNcsdBossFirmFile(path, path_cxi, GAME_NCCH, CRYPTO_DECRYPT, 0, 0, NULL, NULL) != 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
||||||
// fix up the injected H&S NCCH header (copy H&S signature, title ID)
|
// fix up the injected H&S NCCH header (copy H&S signature, title ID)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
u32 VerifyGameFile(const char* path);
|
u32 VerifyGameFile(const char* path);
|
||||||
u32 CheckEncryptedGameFile(const char* path);
|
u32 CheckEncryptedGameFile(const char* path);
|
||||||
u32 DecryptGameFile(const char* path, bool inplace);
|
u32 CryptGameFile(const char* path, bool inplace, bool encrypt);
|
||||||
u32 BuildCiaFromGameFile(const char* path, bool force_legit);
|
u32 BuildCiaFromGameFile(const char* path, bool force_legit);
|
||||||
u32 BuildNcchInfoXorpads(const char* destdir, const char* path);
|
u32 BuildNcchInfoXorpads(const char* destdir, const char* path);
|
||||||
u32 InjectHealthAndSafety(const char* path, const char* destdrv);
|
u32 InjectHealthAndSafety(const char* path, const char* destdrv);
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
#define NCCH_ENCRYPTED(ncch) (!((ncch)->flags[7] & 0x04))
|
#define NCCH_ENCRYPTED(ncch) (!((ncch)->flags[7] & 0x04))
|
||||||
#define NCCH_IS_CXI(ncch) ((ncch)->flags[5] & 0x02)
|
#define NCCH_IS_CXI(ncch) ((ncch)->flags[5] & 0x02)
|
||||||
|
|
||||||
#define NCCH_NOCRYPTO 0x0004
|
#define NCCH_NOCRYPTO 0x0004
|
||||||
|
#define NCCH_STDCRYPTO 0x0000
|
||||||
#define NCCH_GET_CRYPTO(ncch) (!NCCH_ENCRYPTED(ncch) ? NCCH_NOCRYPTO : (((ncch)->flags[3] << 8) | ((ncch)->flags[7]&(0x01|0x20))))
|
#define NCCH_GET_CRYPTO(ncch) (!NCCH_ENCRYPTED(ncch) ? NCCH_NOCRYPTO : (((ncch)->flags[3] << 8) | ((ncch)->flags[7]&(0x01|0x20))))
|
||||||
|
|
||||||
// wrapper defines
|
// wrapper defines
|
||||||
|
@ -35,7 +35,7 @@ u64 GetNcsdTrimmedSize(NcsdHeader* header) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// on the fly decryptor for NCSD
|
// on the fly decryptor for NCSD
|
||||||
u32 DecryptNcsdSequential(u8* data, u32 offset_data, u32 size_data) {
|
u32 CryptNcsdSequential(u8* data, u32 offset_data, u32 size_data, u16 crypto) {
|
||||||
// warning: this will only work for sequential processing
|
// warning: this will only work for sequential processing
|
||||||
static NcsdHeader ncsd;
|
static NcsdHeader ncsd;
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ u32 DecryptNcsdSequential(u8* data, u32 offset_data, u32 size_data) {
|
|||||||
if (size_i > size_data - (data_i - data))
|
if (size_i > size_data - (data_i - data))
|
||||||
size_i = size_data - (data_i - data);
|
size_i = size_data - (data_i - data);
|
||||||
// decrypt ncch segment
|
// decrypt ncch segment
|
||||||
if (DecryptNcchSequential(data_i, offset_i, size_i) != 0)
|
if (CryptNcchSequential(data_i, offset_i, size_i, crypto) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
#define NCSD_DINFO_SIZE 0x300
|
#define NCSD_DINFO_SIZE 0x300
|
||||||
#define NCSD_CNT0_OFFSET 0x4000
|
#define NCSD_CNT0_OFFSET 0x4000
|
||||||
|
|
||||||
|
// wrapper defines
|
||||||
|
#define DecryptNcsdSequential(data, offset, size) CryptNcsdSequential(data, offset, size, NCCH_NOCRYPTO)
|
||||||
|
#define EncryptNcsdSequential(data, offset, size, crypto) CryptNcsdSequential(data, offset, size, crypto)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 offset;
|
u32 offset;
|
||||||
u32 size;
|
u32 size;
|
||||||
@ -34,4 +38,4 @@ typedef struct {
|
|||||||
|
|
||||||
u32 ValidateNcsdHeader(NcsdHeader* header);
|
u32 ValidateNcsdHeader(NcsdHeader* header);
|
||||||
u64 GetNcsdTrimmedSize(NcsdHeader* header);
|
u64 GetNcsdTrimmedSize(NcsdHeader* header);
|
||||||
u32 DecryptNcsdSequential(u8* data, u32 offset_data, u32 size_data);
|
u32 CryptNcsdSequential(u8* data, u32 offset_data, u32 size_data, u16 crypto);
|
||||||
|
@ -571,7 +571,7 @@ u32 Sha256Calculator(const char* path) {
|
|||||||
|
|
||||||
u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* current_dir, DirStruct* clipboard) {
|
u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* current_dir, DirStruct* clipboard) {
|
||||||
DirEntry* curr_entry = &(current_dir->entry[*cursor]);
|
DirEntry* curr_entry = &(current_dir->entry[*cursor]);
|
||||||
const char* optionstr[8];
|
const char* optionstr[16];
|
||||||
|
|
||||||
// check for file lock
|
// check for file lock
|
||||||
if (!FileUnlock(curr_entry->path)) return 1;
|
if (!FileUnlock(curr_entry->path)) return 1;
|
||||||
@ -585,14 +585,15 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
bool mountable = (FTYPE_MOUNTABLE(filetype) && !(drvtype & DRV_IMAGE));
|
bool mountable = (FTYPE_MOUNTABLE(filetype) && !(drvtype & DRV_IMAGE));
|
||||||
bool verificable = (FYTPE_VERIFICABLE(filetype));
|
bool verificable = (FYTPE_VERIFICABLE(filetype));
|
||||||
bool decryptable = (FYTPE_DECRYPTABLE(filetype));
|
bool decryptable = (FYTPE_DECRYPTABLE(filetype));
|
||||||
bool decryptable_inplace = (decryptable && (drvtype & (DRV_SDCARD|DRV_RAMDRIVE)));
|
bool encryptable = (FYTPE_ENCRYPTABLE(filetype));
|
||||||
|
bool cryptable_inplace = ((encryptable||decryptable) && (drvtype & DRV_FAT));
|
||||||
bool buildable = (FTYPE_BUILDABLE(filetype));
|
bool buildable = (FTYPE_BUILDABLE(filetype));
|
||||||
bool buildable_legit = (FTYPE_BUILDABLE_L(filetype));
|
bool buildable_legit = (FTYPE_BUILDABLE_L(filetype));
|
||||||
bool hsinjectable = (FTYPE_HSINJECTABLE(filetype));
|
bool hsinjectable = (FTYPE_HSINJECTABLE(filetype));
|
||||||
bool restorable = (FTYPE_RESTORABLE(filetype) && CheckA9lh() && !(drvtype & DRV_SYSNAND));
|
bool restorable = (FTYPE_RESTORABLE(filetype) && CheckA9lh() && !(drvtype & DRV_SYSNAND));
|
||||||
bool xorpadable = (FTYPE_XORPAD(filetype));
|
bool xorpadable = (FTYPE_XORPAD(filetype));
|
||||||
bool launchable = ((FTYPE_PAYLOAD(filetype)) && (drvtype & DRV_FAT));
|
bool launchable = ((FTYPE_PAYLOAD(filetype)) && (drvtype & DRV_FAT));
|
||||||
bool special_opt = mountable || verificable || decryptable || decryptable_inplace ||
|
bool special_opt = mountable || verificable || decryptable || encryptable ||
|
||||||
buildable || buildable_legit || hsinjectable || restorable || xorpadable || launchable;
|
buildable || buildable_legit || hsinjectable || restorable || xorpadable || launchable;
|
||||||
|
|
||||||
char pathstr[32 + 1];
|
char pathstr[32 + 1];
|
||||||
@ -697,7 +698,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
int mount = (mountable) ? ++n_opt : -1;
|
int mount = (mountable) ? ++n_opt : -1;
|
||||||
int restore = (restorable) ? ++n_opt : -1;
|
int restore = (restorable) ? ++n_opt : -1;
|
||||||
int decrypt = (decryptable) ? ++n_opt : -1;
|
int decrypt = (decryptable) ? ++n_opt : -1;
|
||||||
int decrypt_inplace = (decryptable_inplace) ? ++n_opt : -1;
|
int encrypt = (encryptable) ? ++n_opt : -1;
|
||||||
int build = (buildable) ? ++n_opt : -1;
|
int build = (buildable) ? ++n_opt : -1;
|
||||||
int build_legit = (buildable_legit) ? ++n_opt : -1;
|
int build_legit = (buildable_legit) ? ++n_opt : -1;
|
||||||
int verify = (verificable) ? ++n_opt : -1;
|
int verify = (verificable) ? ++n_opt : -1;
|
||||||
@ -707,8 +708,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
int launch = (launchable) ? ++n_opt : -1;
|
int launch = (launchable) ? ++n_opt : -1;
|
||||||
if (mount > 0) optionstr[mount-1] = "Mount image to drive";
|
if (mount > 0) optionstr[mount-1] = "Mount image to drive";
|
||||||
if (restore > 0) optionstr[restore-1] = "Restore SysNAND (safe)";
|
if (restore > 0) optionstr[restore-1] = "Restore SysNAND (safe)";
|
||||||
if (decrypt > 0) optionstr[decrypt-1] = "Decrypt file (SD output)";
|
if (decrypt > 0) optionstr[decrypt-1] = (cryptable_inplace) ? "Decrypt file (...)" : "Decrypt file (" OUTPUT_PATH ")";
|
||||||
if (decrypt_inplace > 0) optionstr[decrypt_inplace-1] = "Decrypt file (inplace)";
|
if (encrypt > 0) optionstr[encrypt-1] = (cryptable_inplace) ? "Encrypt file (...)" : "Encrypt file (" OUTPUT_PATH ")";
|
||||||
if (build > 0) optionstr[build-1] = (build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)";
|
if (build > 0) optionstr[build-1] = (build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)";
|
||||||
if (build_legit > 0) optionstr[build_legit-1] = "Build CIA (legit)";
|
if (build_legit > 0) optionstr[build_legit-1] = "Build CIA (legit)";
|
||||||
if (verify > 0) optionstr[verify-1] = "Verify file";
|
if (verify > 0) optionstr[verify-1] = "Verify file";
|
||||||
@ -741,17 +742,24 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else if ((user_select == decrypt) || (user_select == decrypt_inplace)) { // -> decrypt game file
|
} else if (user_select == decrypt) { // -> decrypt game file
|
||||||
bool inplace = (user_select == decrypt_inplace);
|
if (cryptable_inplace) {
|
||||||
if ((n_marked > 1) && ShowPrompt(true, "Try to decrypt all %lu selected files?", n_marked)) {
|
optionstr[0] = "Decrypt to " OUTPUT_PATH;
|
||||||
|
optionstr[1] = "Decrypt inplace";
|
||||||
|
user_select = (int) ShowSelectPrompt(2, optionstr, pathstr);
|
||||||
|
} else user_select = 1;
|
||||||
|
bool inplace = (user_select == 2);
|
||||||
|
if (!user_select) { // do nothing when no choice is made
|
||||||
|
} else if ((n_marked > 1) && ShowPrompt(true, "Try to decrypt all %lu selected files?", n_marked)) {
|
||||||
u32 n_success = 0;
|
u32 n_success = 0;
|
||||||
u32 n_unencrypted = 0;
|
u32 n_unencrypted = 0;
|
||||||
u32 n_other = 0;
|
u32 n_other = 0;
|
||||||
|
ShowString("Trying to decrypt %lu files...", n_marked);
|
||||||
for (u32 i = 0; i < current_dir->n_entries; i++) {
|
for (u32 i = 0; i < current_dir->n_entries; i++) {
|
||||||
const char* path = current_dir->entry[i].path;
|
const char* path = current_dir->entry[i].path;
|
||||||
if (!current_dir->entry[i].marked)
|
if (!current_dir->entry[i].marked)
|
||||||
continue;
|
continue;
|
||||||
if (IdentifyFileType(path) != filetype) {
|
if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) {
|
||||||
n_other++;
|
n_other++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -760,7 +768,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
current_dir->entry[i].marked = false;
|
current_dir->entry[i].marked = false;
|
||||||
if (DecryptGameFile(path, inplace) == 0) n_success++;
|
if (CryptGameFile(path, inplace, false) == 0) n_success++;
|
||||||
else { // on failure: set cursor on failed title, break;
|
else { // on failure: set cursor on failed title, break;
|
||||||
*cursor = i;
|
*cursor = i;
|
||||||
break;
|
break;
|
||||||
@ -768,19 +776,57 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
}
|
}
|
||||||
if (n_other || n_unencrypted) {
|
if (n_other || n_unencrypted) {
|
||||||
ShowPrompt(false, "%lu/%lu files decrypted ok\n%lu/%lu not encrypted\n%lu/%lu not of same type",
|
ShowPrompt(false, "%lu/%lu files decrypted ok\n%lu/%lu not encrypted\n%lu/%lu not of same type",
|
||||||
n_success, n_marked, n_unencrypted, n_marked, n_other, n_marked);
|
n_success, n_marked, n_unencrypted, n_marked, n_other, n_marked);
|
||||||
} else ShowPrompt(false, "%lu/%lu files decrypted ok", n_success, n_marked);
|
} else ShowPrompt(false, "%lu/%lu files decrypted ok", n_success, n_marked);
|
||||||
if (!inplace && n_success) ShowPrompt(false, "%lu files written to %s", n_success, OUTPUT_PATH);
|
if (!inplace && n_success) ShowPrompt(false, "%lu files written to %s", n_success, OUTPUT_PATH);
|
||||||
} else {
|
} else {
|
||||||
if (CheckEncryptedGameFile(curr_entry->path) != 0) {
|
if (CheckEncryptedGameFile(curr_entry->path) != 0) {
|
||||||
ShowPrompt(false, "%s\nFile is not encrypted", pathstr);
|
ShowPrompt(false, "%s\nFile is not encrypted", pathstr);
|
||||||
} else {
|
} else {
|
||||||
u32 ret = DecryptGameFile(curr_entry->path, inplace);
|
u32 ret = CryptGameFile(curr_entry->path, inplace, false);
|
||||||
if (inplace || (ret != 0)) ShowPrompt(false, "%s\nDecryption %s", pathstr, (ret == 0) ? "success" : "failed");
|
if (inplace || (ret != 0)) ShowPrompt(false, "%s\nDecryption %s", pathstr, (ret == 0) ? "success" : "failed");
|
||||||
else ShowPrompt(false, "%s\nDecrypted to %s", pathstr, OUTPUT_PATH);
|
else ShowPrompt(false, "%s\nDecrypted to %s", pathstr, OUTPUT_PATH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (user_select == encrypt) { // -> encrypt game file
|
||||||
|
if (cryptable_inplace) {
|
||||||
|
optionstr[0] = "Encrypt to " OUTPUT_PATH;
|
||||||
|
optionstr[1] = "Encrypt inplace";
|
||||||
|
user_select = (int) ShowSelectPrompt(2, optionstr, pathstr);
|
||||||
|
} else user_select = 1;
|
||||||
|
bool inplace = (user_select == 2);
|
||||||
|
if (!user_select) { // do nothing when no choice is made
|
||||||
|
} else if ((n_marked > 1) && ShowPrompt(true, "Try to encrypt all %lu selected files?", n_marked)) {
|
||||||
|
u32 n_success = 0;
|
||||||
|
u32 n_other = 0;
|
||||||
|
ShowString("Trying to encrypt %lu files...", n_marked);
|
||||||
|
for (u32 i = 0; i < current_dir->n_entries; i++) {
|
||||||
|
const char* path = current_dir->entry[i].path;
|
||||||
|
if (!current_dir->entry[i].marked)
|
||||||
|
continue;
|
||||||
|
if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) {
|
||||||
|
n_other++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current_dir->entry[i].marked = false;
|
||||||
|
if (CryptGameFile(path, inplace, true) == 0) n_success++;
|
||||||
|
else { // on failure: set cursor on failed title, break;
|
||||||
|
*cursor = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n_other) {
|
||||||
|
ShowPrompt(false, "%lu/%lu files encrypted ok\n%lu/%lu not of same type",
|
||||||
|
n_success, n_marked, n_other, n_marked);
|
||||||
|
} else ShowPrompt(false, "%lu/%lu files encrypted ok", n_success, n_marked);
|
||||||
|
if (!inplace && n_success) ShowPrompt(false, "%lu files written to %s", n_success, OUTPUT_PATH);
|
||||||
|
} else {
|
||||||
|
u32 ret = CryptGameFile(curr_entry->path, inplace, true);
|
||||||
|
if (inplace || (ret != 0)) ShowPrompt(false, "%s\nEncryption %s", pathstr, (ret == 0) ? "success" : "failed");
|
||||||
|
else ShowPrompt(false, "%s\nEncrypted to %s", pathstr, OUTPUT_PATH);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
} else if ((user_select == build) || (user_select == build_legit)) { // -> build CIA
|
} else if ((user_select == build) || (user_select == build_legit)) { // -> build CIA
|
||||||
bool force_legit = (user_select == build_legit);
|
bool force_legit = (user_select == build_legit);
|
||||||
if ((n_marked > 1) && ShowPrompt(true, "Try to process all %lu selected files?", n_marked)) {
|
if ((n_marked > 1) && ShowPrompt(true, "Try to process all %lu selected files?", n_marked)) {
|
||||||
@ -790,7 +836,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
const char* path = current_dir->entry[i].path;
|
const char* path = current_dir->entry[i].path;
|
||||||
if (!current_dir->entry[i].marked)
|
if (!current_dir->entry[i].marked)
|
||||||
continue;
|
continue;
|
||||||
if (IdentifyFileType(path) != filetype) {
|
if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) {
|
||||||
n_other++;
|
n_other++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -822,7 +868,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
const char* path = current_dir->entry[i].path;
|
const char* path = current_dir->entry[i].path;
|
||||||
if (!current_dir->entry[i].marked)
|
if (!current_dir->entry[i].marked)
|
||||||
continue;
|
continue;
|
||||||
if (IdentifyFileType(path) != filetype) {
|
if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) {
|
||||||
n_other++;
|
n_other++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user