Enable direct decrypt of NUS / CDN content

This commit is contained in:
d0k3 2017-02-07 23:18:25 +01:00
parent faba2ebae5
commit 76cfc03a66
5 changed files with 92 additions and 7 deletions

View File

@ -38,7 +38,7 @@
(((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v))
// GodMode9 version
#define VERSION "0.9.7"
#define VERSION "0.9.8"
// input / output paths
#define INPUT_PATHS "0:", "0:/files9", "1:/rw/files9"

View File

@ -11,6 +11,7 @@ u32 IdentifyFileType(const char* path) {
size_t fsize = FileGetSize(path);
char* fname = strrchr(path, '/');
char* ext = (fname) ? strrchr(++fname, '.') : NULL;
u32 id = 0;
if (ext) ext++;
if (FileGetData(path, header, 0x200, 0) < ((fsize > 0x200) ? 0x200 : fsize)) return 0;
@ -49,6 +50,8 @@ u32 IdentifyFileType(const char* path) {
return GAME_TMD | FLAG_NUSCDN; // TMD file from NUS/CDN
else if (fsize >= TMD_SIZE_N(getbe16(header + 0x1DE)))
return GAME_TMD; // TMD file
} else if (ValidateTicket((Ticket*) data) == 0) {
return GAME_TICKET; // Ticket file (not used for anything right now)
} else if (ValidateFirmHeader((FirmHeader*) data, fsize) == 0) {
return SYS_FIRM; // FIRM file
}
@ -60,6 +63,16 @@ u32 IdentifyFileType(const char* path) {
(GetNcchInfoVersion((NcchInfoHeader*) data)) &&
fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) {
return BIN_NCCHNFO; // ncchinfo.bin file
} else if ((strnlen(fname, 16) == 8) && (sscanf(fname, "%08lx", &id) == 1)) {
char path_cdn[256];
char* name_cdn = path_cdn + (fname - path);
strncpy(path_cdn, path, 256);
strncpy(name_cdn, "tmd", 4);
if (FileGetSize(path_cdn) > 0)
return GAME_NUSCDN;
strncpy(name_cdn, "cetk", 5);
if (FileGetSize(path_cdn) > 0)
return GAME_NUSCDN;
#if PAYLOAD_MAX_SIZE <= TEMP_BUFFER_SIZE
} else if ((fsize <= PAYLOAD_MAX_SIZE) && ext && (strncasecmp(ext, "bin", 4) == 0)) {
return BIN_LAUNCH; // assume it's an ARM9 payload

View File

@ -11,9 +11,11 @@
#define GAME_EXEFS (1<<6)
#define GAME_ROMFS (1<<7)
#define GAME_BOSS (1<<8)
#define SYS_FIRM (1<<9)
#define BIN_NCCHNFO (1<<10)
#define BIN_LAUNCH (1<<11)
#define GAME_NUSCDN (1<<9)
#define GAME_TICKET (1<<10)
#define SYS_FIRM (1<<11)
#define BIN_NCCHNFO (1<<12)
#define BIN_LAUNCH (1<<13)
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
#define FLAG_NUSCDN (1<<30)
@ -21,7 +23,7 @@
#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_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|GAME_NUSCDN|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_L(tp) (FTYPE_BUILDABLE(tp) && (tp&(GAME_TMD)))

View File

@ -729,6 +729,8 @@ u32 CheckEncryptedGameFile(const char* path) {
return CheckEncryptedBossFile(path);
else if (filetype & SYS_FIRM)
return CheckEncryptedFirmFile(path);
else if (filetype & GAME_NUSCDN)
return 0; // these should always be encrypted
else return 1;
}
@ -767,7 +769,8 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16
}
fsize = fvx_size(ofp); // for progress bar
if (!size) size = fsize;
if (fsize < offset) return 1;
if (!size) size = fsize - offset;
u32 ret = 0;
if (!ShowProgress(offset, fsize, dest)) ret = 1;
@ -786,7 +789,7 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16
if ((read_bytes != bytes_read) || (bytes_read != bytes_written)) ret = 1;
if (!ShowProgress(offset + i + read_bytes, fsize, dest)) ret = 1;
}
} else if (mode & GAME_CIA) { // for NCCHs inside CIAs
} else if (mode & (GAME_CIA|GAME_NUSCDN)) { // for NCCHs inside CIAs
bool cia_crypto = getbe16(chunk->type) & 0x1;
bool ncch_crypto; // find out by decrypting the NCCH header
UINT bytes_read, bytes_written;
@ -920,6 +923,70 @@ u32 DecryptFirmFile(const char* orig, const char* dest) {
return 0;
}
u32 CryptCdnFile(const char* orig, const char* dest, u16 crypto) {
bool inplace = (strncmp(orig, dest, 256) == 0);
TitleMetaData* tmd = (TitleMetaData*) TEMP_BUFFER;
TmdContentChunk* content_list = (TmdContentChunk*) (tmd + 1);
Ticket* ticket = (Ticket*) (TEMP_BUFFER + TMD_SIZE_MAX);
u8 titlekey[0x10] = { 0xFF };
u32 cnt_id;
// try to load TMD file
char path_tmd[256];
char* name_tmd;
strncpy(path_tmd, orig, 256);
name_tmd = strrchr(path_tmd, '/');
if (!name_tmd) return 1; // will not happen
name_tmd++;
snprintf(name_tmd, 256 - (name_tmd - path_tmd), "tmd");
if (LoadTmdFile(tmd, path_tmd) != 0) tmd = NULL;
// load or build ticket
if (LoadCdnTicketFile(ticket, orig) != 0) {
if (!tmd || (BuildFakeTicket(ticket, tmd->title_id) != 0)) return 1;
if (FindTitleKey(ticket, tmd->title_id) != 0) return 1;
}
// get titlekey
if (GetTitleKey(titlekey, ticket) != 0)
return 1;
// get content id
char* fname;
fname = strrchr(orig, '/');
if (!fname) return 1; // will not happen
if (sscanf(++fname, "%08lx", &cnt_id) != 1)
return 1; // this won't either
// find (build fake) content chunk
TmdContentChunk* chunk = NULL;
if (!tmd) {
chunk = content_list;
memset(chunk, 0, sizeof(TmdContentChunk));
chunk->type[1] = 0x01; // encrypted
} else {
u32 content_count = getbe16(tmd->content_count);
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) {
chunk = &(content_list[i]);
if (getbe32(chunk->id) == cnt_id) break;
chunk = NULL;
}
if (!chunk || !(getbe16(chunk->type) & 0x01)) return 1;
}
// actual crypto
if (CryptNcchNcsdBossFirmFile(orig, dest, GAME_NUSCDN, crypto, 0, 0, chunk, titlekey) != 0)
return 1;
if (inplace && tmd) {
UINT bw; // in that case, write the change to the TMD file, too
u32 offset = ((u8*) chunk) - ((u8*) tmd);
fvx_qwrite(path_tmd, chunk, offset, sizeof(TmdContentChunk), &bw);
}
return 0;
}
u32 CryptGameFile(const char* path, bool inplace, bool encrypt) {
u32 filetype = IdentifyFileType(path);
u16 crypto = encrypt ? CRYPTO_ENCRYPT : CRYPTO_DECRYPT;
@ -943,6 +1010,8 @@ u32 CryptGameFile(const char* path, bool inplace, bool encrypt) {
if (filetype & GAME_CIA)
ret = CryptCiaFile(path, destptr, crypto);
else if (filetype & GAME_NUSCDN)
ret = CryptCdnFile(path, destptr, crypto);
else if (filetype & SYS_FIRM)
ret = DecryptFirmFile(path, destptr);
else if (filetype & (GAME_NCCH|GAME_NCSD|GAME_BOSS))

View File

@ -627,6 +627,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
(filetype & GAME_ROMFS) ? "Mount as ROMFS image" :
(filetype & GAME_TMD) ? "TMD file options..." :
(filetype & GAME_BOSS) ? "BOSS file options..." :
(filetype & GAME_NUSCDN)? "Decrypt NUS/CDN file" :
(filetype & SYS_FIRM) ? "FIRM image options..." :
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
(filetype & BIN_LAUNCH) ? "Launch as arm9 payload" : "???";