big update

lots cleaned, added cia to cci conv, it
's called a block, separated reading from building, improved ncch keyx
stuff, and basic verbose for keys, elf checking and romfs
This commit is contained in:
applestash
2014-08-26 00:34:28 +10:00
parent c6e98ca578
commit 9c548197c1
66 changed files with 2970 additions and 2551 deletions
+5 -5
View File
@@ -1,8 +1,8 @@
# Makerom Sources
UTILS_OBJS = utils.o dir.o utf.o keyset.o titleid.o
CIA_OBJS = cia.o cia_read.o certs.o tik.o tmd.o tmd_read.o
NCCH_OBJS = ncch.o exheader.o accessdesc.o exefs.o elf.o romfs.o romfs_import.o romfs_binary.o
NCSD_OBJS = ncsd.o
UTILS_OBJS = utils.o ctr_utils.o dir.o utf.o keyset.o titleid.o
CIA_OBJS = cia.o certs.o tik.o tmd.o
NCCH_OBJS = ncch.o exheader.o accessdesc.o exefs.o elf.o romfs.o romfs_import.o romfs_gen.o
NCSD_OBJS = ncsd.o cardinfo.o
SETTINGS_OBJS = user_settings.o rsf_settings.o
LIB_API_OBJS = crypto.o yaml_parser.o blz.o
@@ -21,7 +21,7 @@ CC = gcc
# MAKEROM Build Settings
MAKEROM_BUILD_FLAGS = #-DDEBUG
VER_MAJOR = 0
VER_MINOR = 10
VER_MINOR = 11
OUTPUT = makerom
main: build
+29 -82
View File
@@ -1,13 +1,11 @@
#include "lib.h"
#include "ncch.h"
#include "exheader.h"
#include "ncch_build.h"
#include "exheader_build.h"
#include "accessdesc.h"
#include "polarssl/base64.h"
#include "desc_presets.h"
#include "desc_dev_sigdata.h"
#include "desc_prod_sigdata.h"
#include "desc/presets.h"
#include "desc/dev_sigdata.h"
#include "desc/prod_sigdata.h"
const int RSF_RSA_DATA_LEN = 344;
const int RSF_DESC_DATA_LEN = 684;
@@ -19,20 +17,16 @@ int accessdesc_GetSignFromPreset(exheader_settings *exhdrset);
void accessdesc_GetPresetData(u8 **desc, u8 **accessDesc, u8 **depList, keys_struct *keys);
void accessdesc_GetPresetSigData(u8 **accessDescSig, u8 **cxiPubk, u8 **cxiPvtk, keys_struct *keys);
bool IsValidB64Char(char chr);
u32 b64_strlen(char *str);
void b64_strcpy(char *dst, char *src);
int set_AccessDesc(exheader_settings *exhdrset)
{
if(exhdrset->useAccessDescPreset)
if(exhdrset->useAccessDescPreset) // Use AccessDesc Template
return accessdesc_GetSignFromPreset(exhdrset);
else if(exhdrset->rsf->CommonHeaderKey.Found) // Keydata exists in RSF
return accessdesc_GetSignFromRsf(exhdrset);
else if(!exhdrset->keys->rsa.requiresPresignedDesc) // Else if The AccessDesc can be signed with key
return accessdesc_SignWithKey(exhdrset);
else{ // No way the access desc signature can be 'obtained'
fprintf(stderr,"[EXHEADER ERROR] Current keyset cannot sign AccessDesc, please appropriatly setup RSF, or specify a preset with -accessdesc\n");
fprintf(stderr,"[ACEXDESC ERROR] Current keyset cannot sign AccessDesc, please appropriately set-up RSF, or specify a preset with \"-desc\"\n");
return CANNOT_SIGN_ACCESSDESC;
}
}
@@ -65,7 +59,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
{
/* Yaml Option Sanity Checks */
if(!exhdrset->rsf->CommonHeaderKey.Found){
fprintf(stderr,"[EXHEADER ERROR] RSF Section \"CommonHeaderKey\" not found\n");
fprintf(stderr,"[ACEXDESC ERROR] RSF Section \"CommonHeaderKey\" not found\n");
return COMMON_HEADER_KEY_NOT_FOUND;
}
@@ -74,7 +68,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
return COMMON_HEADER_KEY_NOT_FOUND;
}
if(b64_strlen(exhdrset->rsf->CommonHeaderKey.D) != RSF_RSA_DATA_LEN){
fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/D\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.D));
fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/D\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.D));
return COMMON_HEADER_KEY_NOT_FOUND;
}
@@ -83,7 +77,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
return COMMON_HEADER_KEY_NOT_FOUND;
}
if(b64_strlen(exhdrset->rsf->CommonHeaderKey.Modulus) != RSF_RSA_DATA_LEN){
fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Modulus\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.Modulus));
fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/Modulus\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.Modulus));
return COMMON_HEADER_KEY_NOT_FOUND;
}
@@ -92,7 +86,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
return COMMON_HEADER_KEY_NOT_FOUND;
}
if(b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign) != RSF_RSA_DATA_LEN){
fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Signature\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign));
fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/Signature\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign));
return COMMON_HEADER_KEY_NOT_FOUND;
}
@@ -101,41 +95,30 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
return COMMON_HEADER_KEY_NOT_FOUND;
}
if(b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin) != RSF_DESC_DATA_LEN){
fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Descriptor\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin));
fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/Descriptor\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin));
return COMMON_HEADER_KEY_NOT_FOUND;
}
/* Set RSA Keys */
int result = 0;
u32 out;
out = 0x100;
result = base64_decode(exhdrset->keys->rsa.cxiHdrPub,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.Modulus,strlen(exhdrset->rsf->CommonHeaderKey.Modulus));
if(out != 0x100)
result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
if(result) goto finish;
out = 0x100;
result = base64_decode(exhdrset->keys->rsa.cxiHdrPvt,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.D,strlen(exhdrset->rsf->CommonHeaderKey.D));
if(out != 0x100)
result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
if(result) goto finish;
// NCCH Header pubk
result = b64_decode(exhdrset->keys->rsa.cxiHdrPub,exhdrset->rsf->CommonHeaderKey.Modulus,0x100);
if(result) return result;
// NCCH Header privk
result = b64_decode(exhdrset->keys->rsa.cxiHdrPvt,exhdrset->rsf->CommonHeaderKey.D,0x100);
if(result) return result;
/* Set AccessDesc */
out = 0x100;
result = base64_decode(exhdrset->acexDesc->signature,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.AccCtlDescSign, strlen( exhdrset->rsf->CommonHeaderKey.AccCtlDescSign));
if(out != 0x100)
result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
if(result) goto finish;
// Signature
result = b64_decode(exhdrset->acexDesc->signature,exhdrset->rsf->CommonHeaderKey.AccCtlDescSign,0x100);
if(result) return result;
// NCCH Header pubk
memcpy(exhdrset->acexDesc->ncchRsaPubKey,exhdrset->keys->rsa.cxiHdrPub,0x100);
out = 0x200;
result = base64_decode((u8*)&exhdrset->acexDesc->arm11SystemLocalCapabilities,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.AccCtlDescBin,strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin));
if(out != 0x200)
result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
if(result) goto finish;
finish:
return result;
// Access Control
result = b64_decode((u8*)&exhdrset->acexDesc->arm11SystemLocalCapabilities,exhdrset->rsf->CommonHeaderKey.AccCtlDescBin,0x200);
if(result) return result;
return 0;
}
int accessdesc_GetSignFromPreset(exheader_settings *exhdrset)
@@ -153,12 +136,12 @@ int accessdesc_GetSignFromPreset(exheader_settings *exhdrset)
// Error Checking
if(!desc || !depList){
fprintf(stderr,"[EXHEADER ERROR] AccessDesc preset is unavailable, please configure RSF file\n");
fprintf(stderr,"[ACEXDESC ERROR] AccessDesc template is unavailable, please configure RSF file\n");
return CANNOT_SIGN_ACCESSDESC;
}
if((!cxiPubk || !cxiPvtk || !accessDesc || !accessDescSig) && exhdrset->keys->rsa.requiresPresignedDesc){
fprintf(stderr,"[EXHEADER ERROR] This AccessDesc preset needs to be signed, the current keyset is incapable of doing so. Please configure RSF file with the appropriate signature data.\n");
fprintf(stderr,"[ACEXDESC ERROR] This AccessDesc template needs to be signed, the current keyset is incapable of doing so. Please configure RSF file with the appropriate signature data.\n");
return CANNOT_SIGN_ACCESSDESC;
}
@@ -451,40 +434,4 @@ void accessdesc_GetPresetSigData(u8 **accessDescSig, u8 **cxiPubk, u8 **cxiPvtk,
break;
}
}
}
bool IsValidB64Char(char chr)
{
return (isalnum(chr) || chr == '+' || chr == '/' || chr == '=');
}
u32 b64_strlen(char *str)
{
u32 count = 0;
u32 i = 0;
while(str[i] != 0x0){
if(IsValidB64Char(str[i])) {
//printf("Is Valid: %c\n",str[i]);
count++;
}
i++;
}
return count;
}
void b64_strcpy(char *dst, char *src)
{
u32 src_len = strlen(src);
u32 j = 0;
for(u32 i = 0; i < src_len; i++){
if(IsValidB64Char(src[i])){
dst[j] = src[i];
j++;
}
}
dst[j] = 0;
//memdump(stdout,"src: ",(u8*)src,src_len+1);
//memdump(stdout,"dst: ",(u8*)dst,j+1);
}
+207
View File
@@ -0,0 +1,207 @@
#include "lib.h"
#include "ncch_read.h"
#include "ncsd_build.h"
#include "cardinfo.h"
void InitCardInfoHdr(cardinfo_hdr **cihdr, devcardinfo_hdr **dcihdr, cci_settings *set);
int SetWriteableAddress(cardinfo_hdr *hdr, cci_settings *set);
int SetCardInfoBitmask(cardinfo_hdr *hdr, cci_settings *set);
int SetCardInfoNotes(cardinfo_hdr *hdr, cci_settings *set);
void ImportNcch0Data(cardinfo_hdr *hdr, cci_settings *set);
void SetInitialData(cardinfo_hdr *hdr, cci_settings *set);
void SetDevCardInfo(devcardinfo_hdr *hdr, cci_settings *set);
int GenCardInfoHdr(cci_settings *set)
{
cardinfo_hdr *cihdr;
devcardinfo_hdr *dcihdr;
InitCardInfoHdr(&cihdr,&dcihdr,set);
if(SetWriteableAddress(cihdr,set))
return GEN_HDR_FAIL;
if(SetCardInfoBitmask(cihdr,set))
return GEN_HDR_FAIL;
if(SetCardInfoNotes(cihdr,set))
return GEN_HDR_FAIL;
ImportNcch0Data(cihdr,set);
SetInitialData(cihdr,set);
if(dcihdr)
SetDevCardInfo(dcihdr,set);
return 0;
}
void InitCardInfoHdr(cardinfo_hdr **cihdr, devcardinfo_hdr **dcihdr, cci_settings *set)
{
set->headers.cardinfohdr.size = sizeof(cardinfo_hdr);
if(set->options.useExternalSdkCardInfo)
set->headers.cardinfohdr.size += sizeof(devcardinfo_hdr);
set->headers.cardinfohdr.buffer = calloc(1,set->headers.cardinfohdr.size);
*cihdr = (cardinfo_hdr*)set->headers.cardinfohdr.buffer;
if(set->headers.cardinfohdr.size > sizeof(cardinfo_hdr))
*dcihdr = (devcardinfo_hdr*)(set->headers.cardinfohdr.buffer+sizeof(cardinfo_hdr));
else
*dcihdr = NULL;
return;
}
u64 GetCciUnusedSize(u64 mediaSize, u8 cardType)
{
if(cardType == mediatype_CARD1){
switch(mediaSize){
case (u64)MB*128: return (u64)2621440;
case (u64)MB*256: return (u64)5242880;
case (u64)MB*512: return (u64)10485760;
case (u64)GB*1: return (u64)73924608;
case (u64)GB*2: return (u64)147324928;
case (u64)GB*4: return (u64)294649856;
case (u64)GB*8: return (u64)587202560;
default: return 0;
}
}
else if(cardType == mediatype_CARD2){
switch(mediaSize){
case (u64)MB*512: return (u64)37224448;
case (u64)GB*1: return (u64)73924608;
case (u64)GB*2: return (u64)147324928;
case (u64)GB*4: return (u64)294649856;
case (u64)GB*8: return (u64)587202560;
default: return 0;
}
}
return 0;
}
int SetWriteableAddress(cardinfo_hdr *hdr, cci_settings *set)
{
if(set->romInfo.mediaType != mediatype_CARD2){ // Can only be set for Card2 Media
u32_to_u8(hdr->writableAddress,(u32)-1,LE);
return 0;
}
char *str = set->rsf->CardInfo.WritableAddress;
set->romInfo.card2SaveOffset = -1;
if(str){
if(strncmp(str,"0x",2) != 0){
fprintf(stderr,"[CCI ERROR] WritableAddress requires a Hexadecimal value\n");
return INVALID_RSF_OPT;
}
set->romInfo.card2SaveOffset = strtoull(str,NULL,16);
}
else{
if ((set->romInfo.mediaSize / 2) < set->romInfo.saveSize || set->romInfo.saveSize > (u64)(2047*MB)){
u64 saveDataSize = set->romInfo.saveSize / KB;
fprintf(stderr,"[CCI ERROR] Too large SavedataSize %"PRIu64"K\n",saveDataSize);
return SAVE_DATA_TOO_LARGE;
}
if(set->options.closeAlignWR)
set->romInfo.card2SaveOffset = align(set->romInfo.usedSize, set->romInfo.blockSize); // invalid for "real" chips
else{
u64 unusedSize = GetCciUnusedSize(set->romInfo.mediaSize,set->romInfo.mediaType); // Some value related to the physical implementation of gamecards
if(unusedSize > 0)
set->romInfo.card2SaveOffset = set->romInfo.mediaSize - unusedSize - set->romInfo.saveSize; // Nintendo's method for calculating writable region offset
else{
fprintf(stderr,"[CCI WARNING] Nintendo does not support CARD2 for the current MediaSize, aligning save offset after last NCCH\n");
set->romInfo.card2SaveOffset = align(set->romInfo.usedSize, set->romInfo.blockSize); // invalid for "real" chips
}
}
}
u32_to_u8(hdr->writableAddress,(u32)(set->romInfo.card2SaveOffset/set->romInfo.blockSize),LE);
return 0;
}
int SetCardInfoBitmask(cardinfo_hdr *hdr, cci_settings *set)
{
u32 bitmask = 0;
char *str = set->rsf->CardInfo.CardType;
if(!str)
bitmask |= 0;
else{
if(strcasecmp(str,"s1") == 0)
bitmask |= 0;
else if(strcasecmp(str,"s2") == 0)
bitmask |= 0x20;
else {
fprintf(stderr,"[CCI ERROR] Invalid CardType: %s\n",str);
return INVALID_RSF_OPT;
}
}
str = set->rsf->CardInfo.CryptoType;
if(!str)
bitmask |= 0;//(3*0x40);
else{
int val = strtol(str,NULL,10);
if(val < 0 || val > 3) {
fprintf(stderr,"[CCI ERROR] Invalid CryptoType: %s\n",str);
return INVALID_RSF_OPT;
}
if(val != 3)
fprintf(stderr,"[CCI WARNING] Card crypto type = '%d'\n",val);
bitmask |= val * 0x40;
}
u32_to_u8(hdr->cardInfoBitmask,bitmask,BE);
return 0;
}
int SetCardInfoNotes(cardinfo_hdr *hdr, cci_settings *set)
{
u64_to_u8(hdr->notes.mediaSizeUsed,set->romInfo.usedSize,LE);
u32_to_u8(hdr->notes.unknown,0,LE);
if(set->options.tmdHdr){
u64_to_u8(hdr->notes.cverTitleId,GetTmdTitleId(set->options.tmdHdr),LE);
u16_to_u8(hdr->notes.cverTitleId,GetTmdVersion(set->options.tmdHdr),LE);
}
return 0;
}
void ImportNcch0Data(cardinfo_hdr *hdr, cci_settings *set)
{
u8 *ncch;
ncch_hdr *ncchHdr;
ncch = set->content.data + set->content.dOffset[0];
ncchHdr = (ncch_hdr*)ncch;
memcpy(hdr->ncch0TitleId,ncchHdr->titleId,8);
memcpy(hdr->ncch0Hdr,GetNcchHdrData(ncchHdr),GetNcchHdrDataLen(ncchHdr));
return;
}
void SetInitialData(cardinfo_hdr *hdr, cci_settings *set)
{
clrmem(hdr->initialData,0x30);
if(set->options.useExternalSdkCardInfo)
memcpy(hdr->initialData,(u8*)stock_initial_data,0x30);
else
rndset(hdr->initialData,0x2c);
return;
}
void SetDevCardInfo(devcardinfo_hdr *hdr, cci_settings *set)
{
clrmem(hdr,sizeof(devcardinfo_hdr));
if(set->options.useExternalSdkCardInfo)
memcpy(hdr->titleKey,(u8*)stock_title_key,0x10);
else
rndset(hdr->titleKey,0x10);
return;
}
+53
View File
@@ -0,0 +1,53 @@
#pragma once
typedef struct
{
u8 reserved0[0xf8];
u8 mediaSizeUsed[8];
u8 reserved1[0x8];
u8 unknown[0x4];
u8 reserved2[0xc];
u8 cverTitleId[8];
u8 cverTitleVersion[2];
u8 reserved3[0xcd6];
} cardinfo_notes; // reserved[0xDF8];
typedef struct
{
u8 writableAddress[4];
u8 cardInfoBitmask[4];
cardinfo_notes notes;
u8 ncch0TitleId[8];
u8 reserved0[8];
u8 initialData[0x30];
u8 reserved1[0xc0];
u8 ncch0Hdr[0x100];
} cardinfo_hdr;
typedef struct
{
u8 cardDeviceReserved1[0x200];
u8 titleKey[0x10];
u8 cardDeviceReserved2[0xf0];
} devcardinfo_hdr;
static const u8 stock_initial_data[0x30] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xAD, 0x88,
0xAC, 0x41, 0xA2, 0xB1, 0x5E, 0x8F,
0x66, 0x9C, 0x97, 0xE5, 0xE1, 0x5E,
0xA3, 0xEB, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const u8 stock_title_key[0x10] =
{
0x6E, 0xC7, 0x5F, 0xB2, 0xE2, 0xB4,
0x87, 0x46, 0x1E, 0xDD, 0xCB, 0xB8,
0x97, 0x11, 0x92, 0xBA
};
int GenCardInfoHdr(cci_settings *set);
+198 -89
View File
@@ -1,41 +1,44 @@
#include "lib.h"
#include "ncch.h"
#include "exheader.h"
#include "exefs.h"
#include "certs.h"
#include "cia.h"
#include "tik.h"
#include "tmd.h"
#include "titleid.h"
#include "srl.h"
#include "ncsd.h"
#include "ncsd_read.h"
#include "ncch_read.h"
#include "exheader_read.h"
#include "exefs_read.h"
#include "cia_build.h"
#include "cia_read.h"
#include "tik_build.h"
#include "tmd_build.h"
#include "titleid.h"
#include "certs.h"
const int CIA_ALIGN_SIZE = 0x40;
const int CIA_CONTENT_ALIGN = 0x10;
// Private Prototypes
/* cia_settings tools */
void init_CIASettings(cia_settings *set);
void free_CIASettings(cia_settings *set);
int get_CIASettings(cia_settings *ciaset, user_settings *usrset);
void InitCiaSettings(cia_settings *set);
void FreeCiaSettings(cia_settings *set);
int GetCiaSettings(cia_settings *ciaset, user_settings *usrset);
int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset);
int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset);
int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key);
int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key);
int GetTmdDataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *key);
int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *key);
int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset);
int ImportNcchContent(cia_settings *ciaset);
int GetSettingsFromSrl(cia_settings *ciaset);
int GetSettingsFromCci(cia_settings *ciaset);
u16 SetupVersion(u16 Major, u16 Minor, u16 Micro);
u16 SetupVersion(u16 major, u16 minor, u16 micro);
void GetContentHashes(cia_settings *ciaset);
void EncryptContent(cia_settings *ciaset);
int BuildCIA_CertChain(cia_settings *ciaset);
int BuildCIA_Header(cia_settings *ciaset);
int BuildCiaCertChain(cia_settings *ciaset);
int BuildCiaHdr(cia_settings *ciaset);
int WriteCIAtoFile(cia_settings *ciaset);
int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode);
int WriteCiaToFile(cia_settings *ciaset);
int build_CIA(user_settings *usrset)
@@ -50,8 +53,8 @@ int build_CIA(user_settings *usrset)
}
// Get Settings
init_CIASettings(ciaset);
result = get_CIASettings(ciaset,usrset);
InitCiaSettings(ciaset);
result = GetCiaSettings(ciaset,usrset);
if(result) goto finish;
// Create Output File
@@ -65,7 +68,7 @@ int build_CIA(user_settings *usrset)
// Create CIA Sections
/* Certificate Chain */
result = BuildCIA_CertChain(ciaset);
result = BuildCiaCertChain(ciaset);
if(result) goto finish;
/* Ticket */
@@ -77,28 +80,28 @@ int build_CIA(user_settings *usrset)
if(result) goto finish;
/* CIA Header */
result = BuildCIA_Header(ciaset);
result = BuildCiaHdr(ciaset);
if(result) goto finish;
/* Write To File */
result = WriteCIAtoFile(ciaset);
result = WriteCiaToFile(ciaset);
if(result) goto finish;
finish:
if(result != FAILED_TO_CREATE_OUTFILE && ciaset->out)
fclose(ciaset->out);
free_CIASettings(ciaset);
FreeCiaSettings(ciaset);
return result;
}
void init_CIASettings(cia_settings *set)
void InitCiaSettings(cia_settings *set)
{
memset(set,0,sizeof(cia_settings));
}
void free_CIASettings(cia_settings *set)
void FreeCiaSettings(cia_settings *set)
{
if(set->content.filePtrs){
for(u32 i = 1; i < set->content.count; i++){
@@ -117,7 +120,7 @@ void free_CIASettings(cia_settings *set)
free(set);
}
int get_CIASettings(cia_settings *ciaset, user_settings *usrset)
int GetCiaSettings(cia_settings *ciaset, user_settings *usrset)
{
int result = 0;
@@ -125,26 +128,21 @@ int get_CIASettings(cia_settings *ciaset, user_settings *usrset)
result = GetSettingsFromUsrset(ciaset,usrset);
if(usrset->common.workingFileType == infile_ncch){
result = GetSettingsFromNcch0(ciaset,0);
if(result)
if((result = GetSettingsFromNcch0(ciaset,0)) != 0)
return result;
result = GetContentFilePtrs(ciaset,usrset);
if(result)
if((result = GetContentFilePtrs(ciaset,usrset)) != 0)
return result;
result = ImportNcchContent(ciaset);
if(result)
if((result = ImportNcchContent(ciaset)) != 0)
return result;
}
else if(usrset->common.workingFileType == infile_srl){
result = GetSettingsFromSrl(ciaset);
if(result)
if((result = GetSettingsFromSrl(ciaset)) != 0)
return result;
}
else if(usrset->common.workingFileType == infile_ncsd){
result = GetSettingsFromCci(ciaset);
if(result)
if((result = GetSettingsFromCci(ciaset)) != 0)
return result;
}
@@ -165,7 +163,9 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset)
ciaset->ciaSections.content.size = usrset->common.workingFile.size;
usrset->common.workingFile.buffer = NULL;
ciaset->ciaSections.content.size = 0;
ciaset->content.includeUpdateNcch = usrset->cia.includeUpdateNcch;
ciaset->verbose = usrset->common.verbose;
u32_to_u8(ciaset->tmd.titleType,TYPE_CTR,BE);
ciaset->content.encryptCia = usrset->common.rsfSet.Option.EnableCrypt;
ciaset->content.IsDlc = usrset->cia.DlcContent;
@@ -183,16 +183,19 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset)
// Ticket Data
rndset(ciaset->tik.ticketId,8);
clrmem(ciaset->tik.deviceId,4);
clrmem(ciaset->tik.eshopAccId,4);
u32_to_u8(ciaset->tik.deviceId,usrset->cia.deviceId,BE);
u32_to_u8(ciaset->tik.eshopAccId,usrset->cia.eshopAccId,BE);
ciaset->tik.licenceType = 0;
ciaset->tik.audit = 0;
if(usrset->cia.randomTitleKey)
rndset(ciaset->common.titleKey,16);
rndset(ciaset->common.titleKey,AES_128_KEY_SIZE);
else
clrmem(ciaset->common.titleKey,16);
clrmem(ciaset->common.titleKey,AES_128_KEY_SIZE);
if(ciaset->verbose)
memdump(stdout,"[CIA] CIA title key: ",ciaset->common.titleKey,AES_128_KEY_SIZE);
ciaset->tik.formatVersion = 1;
int result = GenCertChildIssuer(ciaset->tik.issuer,ciaset->keys->certs.xsCert);
@@ -217,33 +220,29 @@ int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset)
u8 *ncch0 = (u8*)(ciaset->ciaSections.content.buffer+ncch0_offset);
if(!IsNCCH(NULL,ncch0)){
if(!IsNcch(NULL,ncch0)){
fprintf(stderr,"[CIA ERROR] Content0 is not NCCH\n");
return CIA_INVALID_NCCH0;
}
/* Get Ncch0 Header */
ncch_hdr *hdr = NULL;
hdr = GetNCCH_CommonHDR(hdr,NULL,ncch0);
if(IsCfa(hdr)){
ciaset->content.IsCfa = true;
}
ncch_hdr *hdr = (ncch_hdr*)ncch0;
ciaset->content.IsCfa = IsCfa(hdr);
ciaset->content.offset[0] = 0;
ciaset->content.size[0] = align(GetNCCH_MediaSize(hdr)*GetNCCH_MediaUnitSize(hdr),0x10);
ciaset->content.size[0] = align(GetNcchSize(hdr),0x10);
ciaset->content.totalSize = ciaset->content.size[0];
/* Get Ncch0 Import Context */
ncch_struct *ncch_ctx = malloc(sizeof(ncch_struct));
if(!ncch_ctx){
ncch_info *info = calloc(1,sizeof(ncch_info));
if(!info){
fprintf(stderr,"[CIA ERROR] Not enough memory\n");
return MEM_ERROR;
}
memset(ncch_ctx,0x0,sizeof(ncch_struct));
GetNCCHStruct(ncch_ctx,hdr);
GetNcchInfo(info,hdr);
/* Verify Ncch0 (Sig&Hash Checks) */
int result = VerifyNCCH(ncch0,ciaset->keys,false,true);
int result = VerifyNcch(ncch0,ciaset->keys,false,true);
if(result == UNABLE_TO_LOAD_NCCH_KEY){
ciaset->content.keyNotFound = true;
if(!ciaset->content.IsCfa){
@@ -261,31 +260,35 @@ int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset)
/* Getting ncch key */
ncch_key_type keyType = GetNCCHKeyType(hdr);
u8 *ncchkey = NULL;
if(!ciaset->content.keyNotFound){
SetNcchUnfixedKeys(ciaset->keys,ncch0);
ncchkey = GetNCCHKey0(keyType,ciaset->keys);
if(!ciaset->content.keyNotFound || IsNcchEncrypted(hdr)){
SetNcchKeys(ciaset->keys,hdr);
ncchkey = ciaset->keys->aes.ncchKey0;
if(ciaset->verbose){
printf("[CIA] NCCH AES keys:\n");
memdump(stdout," > key0: ",ciaset->keys->aes.ncchKey0,AES_128_KEY_SIZE);
memdump(stdout," > key1: ",ciaset->keys->aes.ncchKey1,AES_128_KEY_SIZE);
}
}
/* Get TMD Data from ncch */
result = GetCIADataFromNcch(ciaset,ncch0,ncch_ctx,ncchkey); // Data For TMD
result = GetTmdDataFromNcch(ciaset,ncch0,info,ncchkey); // Data For TMD
if(result) goto finish;
/* Get META Region from ncch */
result = GetMetaRegion(ciaset,ncch0,ncch_ctx,ncchkey); // Meta Region
result = GetMetaRegion(ciaset,ncch0,info,ncchkey); // Meta Region
/* Finish */
finish:
/* Return */
free(ncch_ctx);
free(info);
return result;
}
int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key)
int GetTmdDataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *key)
{
extended_hdr *exhdr = malloc(sizeof(extended_hdr));
memcpy(exhdr,ncch+ncch_ctx->exhdrOffset,sizeof(extended_hdr));
if(key != NULL)
CryptNCCHSection((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr);
CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr);
u16 Category = u8_to_u16((ciaset->common.titleId+2),BE);
if(IsPatch(Category)||ciaset->content.IsCfa||ciaset->content.keyNotFound)
@@ -318,28 +321,26 @@ int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8
ciaset->common.titleVersion[VER_MAJOR] = GetRemasterVersion_frm_exhdr(exhdr);
}
u16 version = SetupVersion(ciaset->common.titleVersion[VER_MAJOR],ciaset->common.titleVersion[VER_MINOR],ciaset->common.titleVersion[VER_MICRO]);
ciaset->tik.version = version;
ciaset->tmd.version = version;
ciaset->tmd.version = ciaset->tik.version = SetupVersion(ciaset->common.titleVersion[VER_MAJOR],ciaset->common.titleVersion[VER_MINOR],ciaset->common.titleVersion[VER_MICRO]);
free(exhdr);
return 0;
}
int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key)
int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_info *info, u8 *key)
{
if(ciaset->content.IsCfa || ciaset->content.keyNotFound)
return 0;
extended_hdr *exhdr = malloc(sizeof(extended_hdr));
memcpy(exhdr,ncch+ncch_ctx->exhdrOffset,sizeof(extended_hdr));
memcpy(exhdr,ncch+info->exhdrOffset,sizeof(extended_hdr));
if(key != NULL)
CryptNCCHSection((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr);
CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,info,key,ncch_exhdr);
exefs_hdr *exefsHdr = malloc(sizeof(exefs_hdr));
memcpy(exefsHdr,ncch+ncch_ctx->exefsOffset,sizeof(exefs_hdr));
memcpy(exefsHdr,ncch+info->exefsOffset,sizeof(exefs_hdr));
if(key != NULL)
CryptNCCHSection((u8*)exefsHdr,sizeof(exefs_hdr),0,ncch_ctx,key,ncch_exefs);
CryptNcchRegion((u8*)exefsHdr,sizeof(exefs_hdr),0,info,key,ncch_exefs);
u32 icon_size = 0;
u32 icon_offset = 0;
@@ -349,7 +350,7 @@ int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key
icon_offset = u8_to_u32(exefsHdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr);
}
}
ciaset->ciaSections.meta.size = sizeof(cia_metadata) + icon_size;
ciaset->ciaSections.meta.buffer = malloc(ciaset->ciaSections.meta.size);
if(!ciaset->ciaSections.meta.buffer){
@@ -362,9 +363,9 @@ int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key
GetCoreVersion_frm_exhdr(hdr->coreVersion,exhdr);
if(icon_size > 0){
u8 *IconDestPos = (ciaset->ciaSections.meta.buffer + sizeof(cia_metadata));
memcpy(IconDestPos,ncch+ncch_ctx->exefsOffset+icon_offset,icon_size);
memcpy(IconDestPos,ncch+info->exefsOffset+icon_offset,icon_size);
if(key != NULL)
CryptNCCHSection(IconDestPos,icon_size,icon_offset,ncch_ctx,key,ncch_exefs);
CryptNcchRegion(IconDestPos,icon_size,icon_offset,info,key,ncch_exefs);
//memdump(stdout,"Icon: ",IconDestPos,0x10);
}
@@ -389,7 +390,7 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset)
fprintf(stderr,"[CIA ERROR] Failed to open \"%s\"\n",usrset->common.contentPath[i]);
return FAILED_TO_OPEN_FILE;
}
ciaset->content.fileSize[j] = GetFileSize_u64(usrset->common.contentPath[i]);
ciaset->content.fileSize[j] = GetFileSize64(usrset->common.contentPath[i]);
ciaset->content.filePtrs[j] = fopen(usrset->common.contentPath[i],"rb");
if(usrset->cia.contentId[i] > MAX_U32)
@@ -400,10 +401,10 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset)
ciaset->content.index[j] = (u16)i;
// Get Data from ncch HDR
GetNCCH_CommonHDR(hdr,ciaset->content.filePtrs[j],NULL);
ReadNcchHdr(hdr,ciaset->content.filePtrs[j]);
// Get Size
u64 calcSize = (u64)GetNCCH_MediaSize(hdr) * (u64)GetNCCH_MediaUnitSize(hdr);
u64 calcSize = GetNcchSize(hdr);
if(calcSize != ciaset->content.fileSize[j]){
fprintf(stderr,"[CIA ERROR] \"%s\" is corrupt\n",usrset->common.contentPath[i]);
return FAILED_TO_OPEN_FILE;
@@ -447,7 +448,7 @@ int ImportNcchContent(cia_settings *ciaset)
// Import
u8 *ncchpos = (u8*)(ciaset->ciaSections.content.buffer+ciaset->content.offset[i]);
ReadFile_64(ncchpos, ciaset->content.fileSize[i], 0, ciaset->content.filePtrs[i]);
ReadFile64(ncchpos, ciaset->content.fileSize[i], 0, ciaset->content.filePtrs[i]);
if(ModifyNcchIds(ncchpos, NULL, ncch0hdr->programId, ciaset->keys) != 0)
return -1;
@@ -528,6 +529,11 @@ int GetSettingsFromCci(cia_settings *ciaset)
cciContentOffsets[0] = ncch0_offset;
for(int i = 1; i < 8; i++){
if(GetPartitionSize(ciaset->ciaSections.content.buffer,i)){
ncch_hdr *ncchHdr = (ncch_hdr*)GetPartition(ciaset->ciaSections.content.buffer, i);
if(IsUpdateCfa(ncchHdr) && !ciaset->content.includeUpdateNcch)
continue;
cciContentOffsets[j] = GetPartitionOffset(ciaset->ciaSections.content.buffer,i);
// Get Size
@@ -557,9 +563,9 @@ int GetSettingsFromCci(cia_settings *ciaset)
return 0;
}
u16 SetupVersion(u16 Major, u16 Minor, u16 Micro)
u16 SetupVersion(u16 major, u16 minor, u16 micro)
{
return (((Major << 10) & 0xFC00) | ((Minor << 4) & 0x3F0) | (Micro & 0xf));
return (((major << 10) & 0xFC00) | ((minor << 4) & 0x3F0) | (micro & 0xf));
}
void GetContentHashes(cia_settings *ciaset)
@@ -577,7 +583,7 @@ void EncryptContent(cia_settings *ciaset)
}
}
int BuildCIA_CertChain(cia_settings *ciaset)
int BuildCiaCertChain(cia_settings *ciaset)
{
ciaset->ciaSections.certChain.size = GetCertSize(ciaset->keys->certs.caCert) + GetCertSize(ciaset->keys->certs.xsCert) + GetCertSize(ciaset->keys->certs.cpCert);
ciaset->ciaSections.certChain.buffer = malloc(ciaset->ciaSections.certChain.size);
@@ -591,7 +597,7 @@ int BuildCIA_CertChain(cia_settings *ciaset)
return 0;
}
int BuildCIA_Header(cia_settings *ciaset)
int BuildCiaHdr(cia_settings *ciaset)
{
// Allocating memory for header
ciaset->ciaSections.ciaHdr.size = sizeof(cia_hdr);
@@ -644,7 +650,7 @@ int BuildCIA_Header(cia_settings *ciaset)
return 0;
}
int WriteCIAtoFile(cia_settings *ciaset)
int WriteCiaToFile(cia_settings *ciaset)
{
WriteBuffer(ciaset->ciaSections.ciaHdr.buffer,ciaset->ciaSections.ciaHdr.size,0,ciaset->out);
WriteBuffer(ciaset->ciaSections.certChain.buffer,ciaset->ciaSections.certChain.size,ciaset->ciaSections.certChainOffset,ciaset->out);
@@ -656,7 +662,7 @@ int WriteCIAtoFile(cia_settings *ciaset)
}
int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode)
int CryptContent(u8 *enc, u8 *dec, u64 size, u8 *title_key, u16 index, u8 mode)
{
//generating IV
u8 iv[16];
@@ -667,7 +673,110 @@ int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index,
ctr_aes_context ctx;
memset(&ctx,0x0,sizeof(ctr_aes_context));
ctr_init_aes_cbc(&ctx,title_key,iv,mode);
if(mode == ENC) ctr_aes_cbc(&ctx,DecBuffer,EncBuffer,size,ENC);
else ctr_aes_cbc(&ctx,EncBuffer,DecBuffer,size,DEC);
if(mode == ENC) ctr_aes_cbc(&ctx,dec,enc,size,ENC);
else ctr_aes_cbc(&ctx,enc,dec,size,DEC);
return 0;
}
bool IsCia(u8 *cia)
{
if(!cia)
return false;
cia_hdr *hdr = (cia_hdr*)cia;
if(u8_to_u32(hdr->hdrSize,LE) != sizeof(cia_hdr) || u8_to_u16(hdr->type,LE) != 0 || u8_to_u16(hdr->version,LE) != 0)
return false;
if(!GetCiaCertSize(hdr) || !GetCiaTikSize(hdr) || !GetCiaTmdSize(hdr) || !GetCiaContentSize(hdr))
return false;
return true;
}
u64 GetCiaCertOffset(cia_hdr *hdr)
{
u64 hdrSize = u8_to_u32(hdr->hdrSize,LE);
return align(hdrSize,CIA_ALIGN_SIZE);
}
u64 GetCiaCertSize(cia_hdr *hdr)
{
return u8_to_u32(hdr->certChainSize,LE);
}
u64 GetCiaTikOffset(cia_hdr *hdr)
{
u64 certOffset = GetCiaCertOffset(hdr);
u64 certSize = GetCiaCertSize(hdr);
return align(certOffset + certSize,CIA_ALIGN_SIZE);
}
u64 GetCiaTikSize(cia_hdr *hdr)
{
return u8_to_u32(hdr->tikSize,LE);
}
u64 GetCiaTmdOffset(cia_hdr *hdr)
{
u64 tikOffset = GetCiaTikOffset(hdr);
u64 tikSize = GetCiaTikSize(hdr);
return align(tikOffset + tikSize,CIA_ALIGN_SIZE);
}
u64 GetCiaTmdSize(cia_hdr *hdr)
{
return u8_to_u32(hdr->tmdSize,LE);
}
u64 GetCiaContentOffset(cia_hdr *hdr)
{
u64 tmdOffset = GetCiaTmdOffset(hdr);
u64 tmdSize = GetCiaTmdSize(hdr);
return align(tmdOffset + tmdSize,CIA_ALIGN_SIZE);
}
u64 GetCiaContentSize(cia_hdr *hdr)
{
return u8_to_u64(hdr->contentSize,LE);
}
u64 GetCiaMetaOffset(cia_hdr *hdr)
{
u64 contentOffset = GetCiaContentOffset(hdr);
u64 contentSize = GetCiaContentSize(hdr);
return align(contentOffset + contentSize,CIA_ALIGN_SIZE);
}
u64 GetCiaMetaSize(cia_hdr *hdr)
{
return u8_to_u32(hdr->metaSize,LE);
}
u8* GetCiaCert(u8 *cia)
{
return cia + GetCiaCertOffset((cia_hdr*)cia);
}
u8* GetCiaTik(u8 *cia)
{
return cia + GetCiaTikOffset((cia_hdr*)cia);
}
u8* GetCiaTmd(u8 *cia)
{
return cia + GetCiaTmdOffset((cia_hdr*)cia);
}
u8* GetCiaContent(u8 *cia)
{
return cia + GetCiaContentOffset((cia_hdr*)cia);
}
u8* GetCiaMeta(u8 *cia)
{
if(GetCiaMetaSize((cia_hdr*)cia))
return cia + GetCiaMetaOffset((cia_hdr*)cia);
else
return NULL;
}
+1 -115
View File
@@ -1,17 +1,5 @@
#pragma once
static const int CIA_ALIGN_SIZE = 0x40;
static const int CIA_CONTENT_ALIGN = 0x10;
// Enums
typedef enum
{
CIA_NO_NCCH0 = -1,
CIA_INVALID_NCCH0 = -2,
CIA_CONFILCTING_CONTENT_IDS = -3,
CIA_BAD_VERSION = -4,
} cia_errors;
// Structs
typedef struct
{
@@ -34,107 +22,5 @@ typedef struct
u8 padding1[0xfc];
} cia_metadata;
typedef struct
{
u8 *inFile;
u64 inFileSize;
int CryptContent(u8 *enc, u8 *dec, u64 size, u8 *title_key, u16 index, u8 mode);
FILE *out;
rsf_settings *rsf;
keys_struct *keys;
struct{
u8 titleId[8];
u16 titleVersion[4];
u8 titleKey[16];
} common;
struct{
u8 caCrlVersion;
u8 signerCrlVersion;
} cert;
struct{
u8 issuer[0x40];
u8 formatVersion;
u16 version;
u8 ticketId[8];
u8 deviceId[4];
u8 licenceType;
u8 audit;
u8 eshopAccId[4];
} tik;
struct{
u8 issuer[0x40];
u8 formatVersion;
u16 version;
u8 titleType[4];
u8 savedataSize[4];
u8 privSavedataSize[4];
u8 twlFlag;
} tmd;
struct{
bool IsCfa;
bool IsDlc;
bool encryptCia;
bool keyNotFound;
FILE **filePtrs;
u64 fileSize[CIA_MAX_CONTENT];
/* Misc Records */
u16 count;
u64 offset[CIA_MAX_CONTENT];
u64 totalSize;
/* Content Chunk Records */
u64 size[CIA_MAX_CONTENT];
u16 index[CIA_MAX_CONTENT];
u16 flags[CIA_MAX_CONTENT];
u32 id[CIA_MAX_CONTENT];
u8 hash[CIA_MAX_CONTENT][0x20];
} content;
struct{
buffer_struct ciaHdr;
u32 certChainOffset;
buffer_struct certChain;
u32 tikOffset;
buffer_struct tik;
u32 tmdOffset;
buffer_struct tmd;
u32 metaOffset;
buffer_struct meta;
u64 contentOffset;
buffer_struct content;
} ciaSections;
} cia_settings;
// Public Prototypes
int build_CIA(user_settings *usrset);
// Cia Read Functions
u64 GetCiaCertOffset(cia_hdr *hdr);
u64 GetCiaCertSize(cia_hdr *hdr);
u64 GetTikOffset(cia_hdr *hdr);
u64 GetTikSize(cia_hdr *hdr);
u64 GetTmdOffset(cia_hdr *hdr);
u64 GetTmdSize(cia_hdr *hdr);
u64 GetContentOffset(cia_hdr *hdr);
u64 GetContentSize(cia_hdr *hdr);
u64 GetMetaOffset(cia_hdr *hdr);
u64 GetMetaSize(cia_hdr *hdr);
+107
View File
@@ -0,0 +1,107 @@
#pragma once
#include "cia.h"
// Enums
typedef enum
{
CIA_NO_NCCH0 = -1,
CIA_INVALID_NCCH0 = -2,
CIA_CONFILCTING_CONTENT_IDS = -3,
CIA_BAD_VERSION = -4,
} cia_errors;
typedef struct
{
u8 *inFile;
u64 inFileSize;
FILE *out;
rsf_settings *rsf;
keys_struct *keys;
bool verbose;
struct{
u8 titleId[8];
u16 titleVersion[4];
u8 titleKey[16];
} common;
struct{
u8 caCrlVersion;
u8 signerCrlVersion;
} cert;
struct{
u8 issuer[0x40];
u8 formatVersion;
u16 version;
u8 ticketId[8];
u8 deviceId[4];
u8 licenceType;
u8 audit;
u8 eshopAccId[4];
} tik;
struct{
u8 issuer[0x40];
u8 formatVersion;
u16 version;
u8 titleType[4];
u8 savedataSize[4];
u8 privSavedataSize[4];
u8 twlFlag;
} tmd;
struct{
bool IsCfa;
bool IsDlc;
bool encryptCia;
bool includeUpdateNcch; // for cci -> cia conversions
bool keyNotFound;
FILE **filePtrs;
u64 fileSize[CIA_MAX_CONTENT];
/* Misc Records */
u16 count;
u64 offset[CIA_MAX_CONTENT];
u64 totalSize;
/* Content Chunk Records */
u64 size[CIA_MAX_CONTENT];
u16 index[CIA_MAX_CONTENT];
u16 flags[CIA_MAX_CONTENT];
u32 id[CIA_MAX_CONTENT];
u8 hash[CIA_MAX_CONTENT][0x20];
} content;
struct{
buffer_struct ciaHdr;
u32 certChainOffset;
buffer_struct certChain;
u32 tikOffset;
buffer_struct tik;
u32 tmdOffset;
buffer_struct tmd;
u32 metaOffset;
buffer_struct meta;
u64 contentOffset;
buffer_struct content;
} ciaSections;
} cia_settings;
// Public Prototypes
int build_CIA(user_settings *usrset);
-61
View File
@@ -1,61 +0,0 @@
#include "lib.h"
#include "cia.h"
u64 GetCiaCertOffset(cia_hdr *hdr)
{
u64 hdrSize = u8_to_u32(hdr->hdrSize,LE);
return align(hdrSize,CIA_ALIGN_SIZE);
}
u64 GetCiaCertSize(cia_hdr *hdr)
{
return u8_to_u32(hdr->certChainSize,LE);
}
u64 GetTikOffset(cia_hdr *hdr)
{
u64 certOffset = GetCiaCertOffset(hdr);
u64 certSize = GetCiaCertSize(hdr);
return align(certOffset + certSize,CIA_ALIGN_SIZE);
}
u64 GetTikSize(cia_hdr *hdr)
{
return u8_to_u32(hdr->tikSize,LE);
}
u64 GetTmdOffset(cia_hdr *hdr)
{
u64 tikOffset = GetTikOffset(hdr);
u64 tikSize = GetTikSize(hdr);
return align(tikOffset + tikSize,CIA_ALIGN_SIZE);
}
u64 GetTmdSize(cia_hdr *hdr)
{
return u8_to_u32(hdr->tmdSize,LE);
}
u64 GetContentOffset(cia_hdr *hdr)
{
u64 tmdOffset = GetTmdOffset(hdr);
u64 tmdSize = GetTmdSize(hdr);
return align(tmdOffset + tmdSize,CIA_ALIGN_SIZE);
}
u64 GetContentSize(cia_hdr *hdr)
{
return u8_to_u64(hdr->contentSize,LE);
}
u64 GetMetaOffset(cia_hdr *hdr)
{
u64 contentOffset = GetContentOffset(hdr);
u64 contentSize = GetContentSize(hdr);
return align(contentOffset + contentSize,CIA_ALIGN_SIZE);
}
u64 GetMetaSize(cia_hdr *hdr)
{
return u8_to_u32(hdr->metaSize,LE);
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include "cia.h"
// Cia Read Functions
bool IsCia(u8 *cia);
u64 GetCiaCertOffset(cia_hdr *hdr);
u64 GetCiaCertSize(cia_hdr *hdr);
u64 GetCiaTikOffset(cia_hdr *hdr);
u64 GetCiaTikSize(cia_hdr *hdr);
u64 GetCiaTmdOffset(cia_hdr *hdr);
u64 GetCiaTmdSize(cia_hdr *hdr);
u64 GetCiaContentOffset(cia_hdr *hdr);
u64 GetCiaContentSize(cia_hdr *hdr);
u64 GetCiaMetaOffset(cia_hdr *hdr);
u64 GetCiaMetaSize(cia_hdr *hdr);
u8* GetCiaCert(u8 *cia);
u8* GetCiaTik(u8 *cia);
u8* GetCiaTmd(u8 *cia);
u8* GetCiaContent(u8 *cia);
u8* GetCiaMeta(u8 *cia);
+7 -15
View File
@@ -1,6 +1,13 @@
#include "lib.h"
#include "crypto.h"
bool VerifySha256(void *data, u64 size, u8 hash[32])
{
u8 calchash[32];
ctr_sha(data, size, calchash, CTR_SHA_256);
return memcmp(hash,calchash,32) == 0;
}
void ctr_sha(void *data, u64 size, u8 *hash, int mode)
{
switch(mode){
@@ -9,21 +16,6 @@ void ctr_sha(void *data, u64 size, u8 *hash, int mode)
}
}
u8* AesKeyScrambler(u8 *Key, u8 *KeyX, u8 *KeyY)
{
// Process KeyX/KeyY to get raw normal key
for(int i = 0; i < 16; i++)
Key[i] = KeyX[i] ^ ((KeyY[i] >> 2) | ((KeyY[i < 15 ? i+1 : 0] & 3) << 6));
const u8 SCRAMBLE_SECRET[16] = {0x51, 0xD7, 0x5D, 0xBE, 0xFD, 0x07, 0x57, 0x6A, 0x1C, 0xFC, 0x2A, 0xF0, 0x94, 0x4B, 0xD5, 0x6C};
// Apply Secret to get final normal key
for(int i = 0; i < 16; i++)
Key[i] = Key[i] ^ SCRAMBLE_SECRET[i];
return Key;
}
void ctr_add_counter(ctr_aes_context* ctx, u32 carry)
{
u32 counter[4];
+1 -1
View File
@@ -71,9 +71,9 @@ typedef struct
extern "C" {
#endif
// SHA
bool VerifySha256(void *data, u64 size, u8 hash[32]);
void ctr_sha(void *data, u64 size, u8 *hash, int mode);
// AES
u8* AesKeyScrambler(u8 *Key, u8 *KeyX, u8 *KeyY);
void ctr_add_counter(ctr_aes_context* ctx, u32 carry);
void ctr_init_counter(ctr_aes_context* ctx, u8 key[16],u8 ctr[16]);
void ctr_crypt_counter_block(ctr_aes_context* ctx, u8 input[16], u8 output[16]);
+14
View File
@@ -0,0 +1,14 @@
#include "lib.h"
u32 GetCtrBlockSize(u8 flag)
{
return 1 << (flag + 9);
}
u8 GetCtrBlockSizeFlag(u32 size)
{
u8 ret = 0;
for(u32 tmp = size; tmp > 0x200; tmp = tmp >> 1)
ret++;
return ret;
}
+4
View File
@@ -0,0 +1,4 @@
#pragma once
u32 GetCtrBlockSize(u8 flag);
u8 GetCtrBlockSizeFlag(u32 size);
+2 -2
View File
@@ -118,10 +118,10 @@ fs_entry* fs_GetEntry(fs_DIR *dp)
{
entry->IsDir = false;
#ifdef _WIN32
entry->size = wGetFileSize_u64(entry->fs_name);
entry->size = wGetFileSize64(entry->fs_name);
entry->fp = _wfopen(entry->fs_name,L"rb");
#else
entry->size = GetFileSize_u64(entry->fs_name);
entry->size = GetFileSize64(entry->fs_name);
entry->fp = fopen(entry->fs_name,"rb");
#endif
}
+295 -322
View File
File diff suppressed because it is too large Load Diff
+10 -11
View File
@@ -23,7 +23,7 @@ typedef struct
u64 size;
u64 address;
u64 alignment;
} ElfSectionEntry;
} elf_section_entry;
typedef struct
{
@@ -36,18 +36,17 @@ typedef struct
u64 physicalAddress;
u64 sizeInMemory;
u64 alignment;
} ElfProgramEntry;
} elf_program_entry;
typedef struct
{
char *name;
u64 vAddr;
ElfProgramEntry *header;
elf_program_entry *header;
u32 sectionNum;
ElfSectionEntry *sections;
} ElfSegment;
elf_section_entry *sections;
} elf_segment;
typedef struct
{
@@ -55,7 +54,7 @@ typedef struct
u32 size;
u32 maxPageNum;
u8 *data;
} CodeSegment;
} code_segment;
typedef struct
{
@@ -73,12 +72,12 @@ typedef struct
u16 sectionHeaderNameEntryIndex;
ElfSectionEntry *sections;
ElfProgramEntry *programHeaders;
elf_section_entry *sections;
elf_program_entry *programHeaders;
u16 activeSegments;
ElfSegment *segments;
elf_segment *segments;
} ElfContext;
} elf_context;
int BuildExeFsCode(ncch_settings *ncchset);
+7 -8
View File
@@ -1,6 +1,6 @@
#include "lib.h"
#include "ncch.h"
#include "exefs.h"
#include "ncch_build.h"
#include "exefs_build.h"
// Private Prototypes
u32 PredictExeFS_Size(exefs_buildctx *ctx);
@@ -18,7 +18,7 @@ int BuildExeFs(ncch_settings *ncchset)
fprintf(stderr,"[EXEFS ERROR] Not enough memory\n");
return MEM_ERROR;
}
ctx->mediaUnit = ncchset->options.mediaSize;
ctx->blockSize = ncchset->options.blockSize;
/* Importing ExeFs */
if(ncchset->exefsSections.code.size)
@@ -56,10 +56,9 @@ int BuildExeFs(ncch_settings *ncchset)
u32 PredictExeFS_Size(exefs_buildctx *ctx)
{
u32 exefs_size = 0x200; // Size of header
for(int i = 0; i < ctx->fileCount; i++){
exefs_size += align(ctx->fileSize[i],ctx->mediaUnit);
}
u32 exefs_size = sizeof(exefs_hdr); // Size of header
for(int i = 0; i < ctx->fileCount; i++)
exefs_size += align(ctx->fileSize[i],ctx->blockSize);
//exefs_size = align(ctx->exefs_size,ctx->mediaUnit);
return exefs_size;
}
@@ -70,7 +69,7 @@ int GenerateExeFS_Header(exefs_buildctx *ctx, u8 *outbuff)
if(i == 0)
ctx->fileOffset[i] = 0;
else
ctx->fileOffset[i] = align((ctx->fileOffset[i-1]+ctx->fileSize[i-1]),ctx->mediaUnit);
ctx->fileOffset[i] = align((ctx->fileOffset[i-1]+ctx->fileSize[i-1]),ctx->blockSize);
memcpy(ctx->fileHdr[i].name,ctx->fileName[i],8);
u32_to_u8(ctx->fileHdr[i].offset,ctx->fileOffset[i],LE);
-34
View File
@@ -2,14 +2,6 @@
#define MAX_EXEFS_SECTIONS 10 // DO NOT CHANGE
typedef enum
{
PTR_ERROR = -10,
EXEFS_MAX_REACHED = -11,
EXEFS_SECTION_NAME_ERROR = -12,
} exefs_errors;
typedef struct
{
char name[8];
@@ -23,29 +15,3 @@ typedef struct
u8 reserved[0x20];
u8 fileHashes[MAX_EXEFS_SECTIONS][0x20];
} exefs_hdr;
typedef struct
{
//Input
int fileCount;
u8 *file[MAX_EXEFS_SECTIONS];
u32 fileSize[MAX_EXEFS_SECTIONS];
u32 fileOffset[MAX_EXEFS_SECTIONS];
char fileName[MAX_EXEFS_SECTIONS][8];
u32 mediaUnit;
//Working Data
exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS];
u8 fileHashes[MAX_EXEFS_SECTIONS][0x20];
} exefs_buildctx;
/* ExeFs Build Functions */
int BuildExeFs(ncch_settings *ncchset);
/* ExeFs Read Functions */
bool DoesExeFsSectionExist(char *section, u8 *ExeFs);
u8* GetExeFsSection(char *section, u8 *ExeFs);
u8* GetExeFsSectionHash(char *section, u8 *ExeFs);
u32 GetExeFsSectionSize(char *section, u8 *ExeFs);
u32 GetExeFsSectionOffset(char *section, u8 *ExeFs);
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include "exefs.h"
typedef enum
{
PTR_ERROR = -10,
EXEFS_MAX_REACHED = -11,
EXEFS_SECTION_NAME_ERROR = -12,
} exefs_errors;
typedef struct
{
//Input
int fileCount;
u8 *file[MAX_EXEFS_SECTIONS];
u32 fileSize[MAX_EXEFS_SECTIONS];
u32 fileOffset[MAX_EXEFS_SECTIONS];
char fileName[MAX_EXEFS_SECTIONS][8];
u32 blockSize;
//Working Data
exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS];
u8 fileHashes[MAX_EXEFS_SECTIONS][0x20];
} exefs_buildctx;
/* ExeFs Build Functions */
int BuildExeFs(ncch_settings *ncchset);
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "exefs.h"
/* ExeFs Read Functions */
bool DoesExeFsSectionExist(char *section, u8 *ExeFs);
u8* GetExeFsSection(char *section, u8 *ExeFs);
u8* GetExeFsSectionHash(char *section, u8 *ExeFs);
u32 GetExeFsSectionSize(char *section, u8 *ExeFs);
u32 GetExeFsSectionOffset(char *section, u8 *ExeFs);
+4 -4
View File
@@ -1,6 +1,6 @@
#include "lib.h"
#include "ncch.h"
#include "exheader.h"
#include "ncch_build.h"
#include "exheader_build.h"
#include "accessdesc.h"
#include "titleid.h"
@@ -124,13 +124,13 @@ int get_ExHeaderSettingsFromNcchset(exheader_settings *exhdrset, ncch_settings *
/* Import ExHeader Code Section template */
if(ncchset->componentFilePtrs.exhdrSize){
u32 import_size = 0x30; //min_u64(0x30,ncchset->componentFilePtrs.exhdrSize);
u32 import_size = 0x30; //min64(0x30,ncchset->componentFilePtrs.exhdrSize);
u32 import_offset = 0x10;
if((import_size+import_offset) > ncchset->componentFilePtrs.exhdrSize){
fprintf(stderr,"[EXHEADER ERROR] Exheader Template is too small\n");
return FAILED_TO_IMPORT_FILE;
}
ReadFile_64((ncchset->sections.exhdr.buffer+import_offset),import_size,import_offset,ncchset->componentFilePtrs.exhdr);
ReadFile64((ncchset->sections.exhdr.buffer+import_offset),import_size,import_offset,ncchset->componentFilePtrs.exhdr);
}
/* Create ExHeader Struct for output */
+1 -34
View File
@@ -1,12 +1,5 @@
#pragma once
typedef enum
{
COMMON_HEADER_KEY_NOT_FOUND = -10,
EXHDR_BAD_YAML_OPT = -11,
CANNOT_SIGN_ACCESSDESC = -12
} exheader_errors;
typedef enum
{
infoflag_COMPRESS_EXEFS_0 = 1,
@@ -197,37 +190,11 @@ typedef struct
exhdr_ARM9AccessControlInfo arm9AccessControlInfo;
} access_descriptor;
typedef struct
{
keys_struct *keys;
rsf_settings *rsf;
bool useAccessDescPreset;
/* Output */
extended_hdr *exHdr; // is the exheader output buffer ptr(in ncchset) cast as exheader struct ptr;
access_descriptor *acexDesc;
} exheader_settings;
/* ExHeader Signature Functions */
int SignAccessDesc(access_descriptor *acexDesc, keys_struct *keys);
int CheckAccessDescSignature(access_descriptor *acexDesc, keys_struct *keys);
/* ExHeader Build Functions */
int BuildExHeader(ncch_settings *ncchset);
/* ExHeader Binary Print Functions */
void exhdr_Print_ServiceAccessControl(extended_hdr *hdr);
/* ExHeader Binary Read Functions */
u8* GetAcexRsaSig(access_descriptor *acexDesc);
u8* GetAcexNcchPubKey(access_descriptor *acexDesc);
u16 GetRemasterVersion_frm_exhdr(extended_hdr *hdr);
u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr);
int GetDependencyList_frm_exhdr(u8 *Dest,extended_hdr *hdr);
void GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr);
/* ExHeader Settings Read from Yaml */
/* ExHeader Settings Read from Rsf */
int GetSaveDataSizeFromString(u64 *out, char *string, char *moduleName);
int GetRemasterVersion_rsf(u16 *RemasterVersion, user_settings *usrset);
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "exheader.h"
typedef enum
{
COMMON_HEADER_KEY_NOT_FOUND = -10,
EXHDR_BAD_YAML_OPT = -11,
CANNOT_SIGN_ACCESSDESC = -12
} exheader_errors;
typedef struct
{
keys_struct *keys;
rsf_settings *rsf;
bool useAccessDescPreset;
/* Output, these ptrs where created originally in ncchset */
extended_hdr *exHdr;
access_descriptor *acexDesc;
} exheader_settings;
/* ExHeader Build Functions */
int BuildExHeader(ncch_settings *ncchset);
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "exheader.h"
/* ExHeader Binary Print Functions */
void exhdr_Print_ServiceAccessControl(extended_hdr *hdr);
/* ExHeader Binary Read Functions */
u8* GetAcexRsaSig(access_descriptor *acexDesc);
u8* GetAcexNcchPubKey(access_descriptor *acexDesc);
u16 GetRemasterVersion_frm_exhdr(extended_hdr *hdr);
u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr);
int GetDependencyList_frm_exhdr(u8 *Dest,extended_hdr *hdr);
void GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr);
+63 -47
View File
@@ -1,14 +1,16 @@
#include "lib.h"
// KeyData
#include "tpki.h" // Test PKI
#include "ppki.h" // Production PKI
#include "dpki.h" // Development PKI
#include "pki/test.h" // Test PKI
#include "pki/prod.h" // Production PKI
#include "pki/dev.h" // Development PKI
// Private Prototypes
int SetRsaKeySet(u8 **PrivDest, u8 *PrivSource, u8 **PubDest, u8 *PubSource);
int SetunFixedKey(keys_struct *keys, u8 *unFixedKey);
void InitcommonKeySlots(keys_struct *keys);
void InitCommonKeySlots(keys_struct *keys);
void InitNcchKeyXSlots(keys_struct *keys);
int SetNcchKeyX(keys_struct *keys, u8 *keyX, u8 index);
FILE* keyset_OpenFile(char *dir, char *name, bool FileRequired);
void keysetOpenError(char *file);
@@ -33,11 +35,12 @@ void DumpKeyset(keys_struct *keys);
void InitKeys(keys_struct *keys)
{
memset(keys,0,sizeof(keys_struct));
InitcommonKeySlots(keys);
InitCommonKeySlots(keys);
InitNcchKeyXSlots(keys);
keys->rsa.cxiHdrPub = malloc(RSA_2048_KEY_SIZE);
keys->rsa.cxiHdrPvt = malloc(RSA_2048_KEY_SIZE);
keys->aes.unFixedKey0 = malloc(16);
keys->aes.unFixedKey1 = malloc(16);
keys->aes.ncchKey0 = malloc(AES_128_KEY_SIZE);
keys->aes.ncchKey1 = malloc(AES_128_KEY_SIZE);
}
void PrintBadKeySize(char *path, u32 size)
@@ -45,6 +48,21 @@ void PrintBadKeySize(char *path, u32 size)
fprintf(stderr,"[KEYSET ERROR] %s has invalid size (0x%x)\n",path,size);
}
u8* AesKeyScrambler(u8 *key, u8 *keyX, u8 *keyY)
{
// Process keyX/keyY to get raw normal key
for(int i = 0; i < 16; i++)
key[i] = keyX[i] ^ ((keyY[i] >> 2) | ((keyY[i < 15 ? i+1 : 0] & 3) << 6)); // keyX[i] ^
const u8 SCRAMBLE_SECRET[16] = {0x51, 0xD7, 0x5D, 0xBE, 0xFD, 0x07, 0x57, 0x6A, 0x1C, 0xFC, 0x2A, 0xF0, 0x94, 0x4B, 0xD5, 0x6C};
// Apply Secret to get final normal key
for(int i = 0; i < 16; i++)
key[i] = key[i] ^ SCRAMBLE_SECRET[i];
return key;
}
int SetKeys(keys_struct *keys)
{
int result = 0;
@@ -90,9 +108,9 @@ int LoadKeysFromResources(keys_struct *keys)
keys->keysetLoaded = true;
/* AES Keys */
// CIA
for(int i = 0; i < 2; i++){
for(int i = 0; i < 2; i++)
SetCommonKey(keys,(u8*)ctr_common_etd_key_dpki[i],i);
}
if(keys->aes.currentCommonKey > 0xff)
SetCurrentCommonKey(keys,0);
@@ -100,10 +118,9 @@ int LoadKeysFromResources(keys_struct *keys)
SetNormalKey(keys,(u8*)dev_fixed_ncch_key[0]);
SetSystemFixedKey(keys,(u8*)dev_fixed_ncch_key[1]);
/*
keys->aes.ncchKeyX0 = (u8*)dev_unfixed_ncch_keyX[0];
keys->aes.ncchKeyX1 = (u8*)dev_unfixed_ncch_keyX[1];
*/
for(int i = 0; i < 2; i++)
SetNcchKeyX(keys,(u8*)dev_unfixed_ncch_keyX[i],i);
/* RSA Keys */
// CIA
@@ -123,18 +140,19 @@ int LoadKeysFromResources(keys_struct *keys)
keys->keysetLoaded = true;
/* AES Keys */
// CIA
for(int i = 0; i < 6; i++){
keys->aes.commonKey[i] = malloc(16);
AesKeyScrambler(keys->aes.commonKey[i],(u8*)ctr_common_etd_keyX_ppki,(u8*)ctr_common_etd_keyY_ppki[i]);
}
SetCurrentCommonKey(keys,1);
//for(int i = 0; i < 6; i++){
// keys->aes.commonKey[i] = malloc(16);
// AesKeyScrambler(keys->aes.commonKey[i],(u8*)ctr_common_etd_keyX_ppki,(u8*)ctr_common_etd_keyY_ppki[i]);
//}
if(keys->aes.currentCommonKey > 0xff)
SetCurrentCommonKey(keys,0);
// NCCH
keys->aes.normalKey = NULL;
keys->aes.systemFixedKey = NULL;
/*
keys->aes.ncchKeyX0 = (u8*)prod_unfixed_ncch_keyX[0];
keys->aes.ncchKeyX1 = (u8*)prod_unfixed_ncch_keyX[1];
for(int i = 0; i < 2; i++)
SetNcchKeyX(keys,(u8*)prod_unfixed_ncch_keyX[i],i);
*/
/* RSA Keys */
@@ -264,15 +282,19 @@ void FreeKeys(keys_struct *keys)
{
// AES
if(keys->aes.commonKey){
for(int i = 0; i < 256; i++){
for(int i = 0; i <= MAX_CMN_KEY; i++)
free(keys->aes.commonKey[i]);
}
}
free(keys->aes.commonKey);
free(keys->aes.normalKey);
free(keys->aes.systemFixedKey);
free(keys->aes.unFixedKey0);
free(keys->aes.unFixedKey1);
if(keys->aes.ncchKeyX){
for(int i = 0; i <= MAX_NCCH_KEYX; i++)
free(keys->aes.ncchKeyX[i]);
}
free(keys->aes.ncchKeyX);
free(keys->aes.ncchKey0);
free(keys->aes.ncchKey1);
// RSA
free(keys->rsa.xsPvt);
@@ -309,18 +331,28 @@ int SetRsaKeySet(u8 **PrivDest, u8 *PrivSource, u8 **PubDest, u8 *PubSource)
return 0;
}
int SetCommonKey(keys_struct *keys, u8 *commonKey, u8 Index)
int SetCommonKey(keys_struct *keys, u8 *commonKey, u8 index)
{
if(!keys) return -1;
return CopyData(&keys->aes.commonKey[Index],commonKey,16);
return CopyData(&keys->aes.commonKey[index],commonKey,AES_128_KEY_SIZE);
}
void InitcommonKeySlots(keys_struct *keys)
void InitCommonKeySlots(keys_struct *keys)
{
if(!keys->aes.commonKey){
keys->aes.commonKey = malloc(sizeof(u8*)*256);
memset(keys->aes.commonKey,0,sizeof(u8*)*256);
}
if(!keys->aes.commonKey)
keys->aes.commonKey = calloc(MAX_CMN_KEY+1,sizeof(u8*));
}
int SetNcchKeyX(keys_struct *keys, u8 *keyX, u8 index)
{
if(!keys) return -1;
return CopyData(&keys->aes.ncchKeyX[index],keyX,AES_128_KEY_SIZE);
}
void InitNcchKeyXSlots(keys_struct *keys)
{
if(!keys->aes.ncchKeyX)
keys->aes.ncchKeyX = calloc(MAX_NCCH_KEYX+1,sizeof(u8*));
}
int SetCurrentCommonKey(keys_struct *keys, u8 Index)
@@ -342,22 +374,6 @@ int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey)
return CopyData(&keys->aes.systemFixedKey,systemFixedKey,16);
}
int SetNcchUnfixedKeys(keys_struct *keys, u8 *ncchSig)
{
if(!keys) return -1;
//memdump(stdout,"keyY: ",ncchSig,16);
//memdump(stdout,"keyX0: ",keys->aes.ncchKeyX0,16);
//memdump(stdout,"keyX1: ",keys->aes.ncchKeyX1,16);
if(keys->aes.ncchKeyX0)
AesKeyScrambler(keys->aes.unFixedKey0,keys->aes.ncchKeyX0,ncchSig);
if(keys->aes.ncchKeyX1)
AesKeyScrambler(keys->aes.unFixedKey1,keys->aes.ncchKeyX1,ncchSig);
return 0;
}
int SetTIK_RsaKey(keys_struct *keys, u8 *PrivateExp, u8 *PublicMod)
{
if(!keys) return -1;
+12 -7
View File
@@ -1,5 +1,12 @@
#pragma once
typedef enum
{
AES_128_KEY_SIZE = 16,
MAX_CMN_KEY = MAX_U8,
MAX_NCCH_KEYX = MAX_U8
} keydata_limits;
typedef enum
{
KEYSET_ERROR = -10,
@@ -54,11 +61,10 @@ typedef struct
// NCCH Keys
u8 *normalKey;
u8 *systemFixedKey;
u8 *ncchKeyX0;
u8 *ncchKeyX1;
u8 *unFixedKey0;
u8 *unFixedKey1;
u8 **ncchKeyX;
u8 *ncchKey0;
u8 *ncchKey1;
} aes;
struct
@@ -101,5 +107,4 @@ int SetCurrentCommonKey(keys_struct *keys, u8 Index);
int SetNormalKey(keys_struct *keys, u8 *systemFixedKey);
int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey);
int SetNcchUnfixedKeys(keys_struct *keys, u8 *ncchSig);
u8* AesKeyScrambler(u8 *key, u8 *keyX, u8 *keyY);
+1
View File
@@ -27,6 +27,7 @@
#include "types.h"
#include "utils.h"
#include "ctr_utils.h"
#include "crypto.h"
#include "keyset.h"
+41 -48
View File
@@ -1,73 +1,66 @@
#include "lib.h"
#include "ncch.h"
#include "ncsd.h"
#include "cia.h"
#include "ncch_build.h"
#include "ncsd_build.h"
#include "cia_build.h"
int main(int argc, char *argv[])
{
// Setting up user settings
user_settings *usrset = calloc(1,sizeof(user_settings));
if(usrset == NULL) {
user_settings *set = calloc(1,sizeof(user_settings));
if(set == NULL) {
fprintf(stderr,"[!] Not enough memory\n");
return -1;
}
init_UserSettings(usrset);
init_UserSettings(set);
initRand();
int result;
#ifdef DEBUG
printf("[DEBUG] Parseing Args\n");
#endif
// Parsing command args
result = ParseArgs(argc,argv,usrset);
if(result < 0) goto finish;
if((result = ParseArgs(argc,argv,set)) < 0)
goto finish;
#ifdef DEBUG
printf("[DEBUG] Importing Yaml Settings\n");
#endif
// Import RSF Settings if present
result = GetYamlSettings(usrset);
if(result < 0) goto finish;
if((result = GetRsfSettings(set)) < 0)
goto finish;
// Setup Content 0
if(!usrset->ncch.buildNcch0){ // Import Content
if(usrset->common.workingFileType == infile_ncch){
if(!AssertFile(usrset->common.contentPath[0])){
fprintf(stderr,"[MAKEROM ERROR] Failed to open Content 0: %s\n",usrset->common.contentPath[0]);
if(!set->ncch.buildNcch0){ // Import Content
if(set->common.workingFileType == infile_ncch){
if(!AssertFile(set->common.contentPath[0])){
fprintf(stderr,"[MAKEROM ERROR] Failed to open Content 0: %s\n",set->common.contentPath[0]);
goto finish;
}
u64 fileSize = GetFileSize_u64(usrset->common.contentPath[0]);
u64 fileSize = GetFileSize64(set->common.contentPath[0]);
u64 calcSize = 0;
FILE *ncch0 = fopen(usrset->common.contentPath[0],"rb");
FILE *ncch0 = fopen(set->common.contentPath[0],"rb");
ncch_hdr hdr;
GetNCCH_CommonHDR(&hdr,ncch0,NULL);
calcSize = GetNCCH_MediaSize(&hdr) * GetNCCH_MediaUnitSize(&hdr);
ReadNcchHdr(&hdr,ncch0);
calcSize = GetNcchSize(&hdr);
if(calcSize != fileSize){
fprintf(stderr,"[MAKEROM ERROR] Content 0 is corrupt\n");
fclose(ncch0);
goto finish;
}
usrset->common.workingFile.size = fileSize;
usrset->common.workingFile.buffer = malloc(fileSize);
ReadFile_64(usrset->common.workingFile.buffer, usrset->common.workingFile.size,0,ncch0);
set->common.workingFile.size = fileSize;
set->common.workingFile.buffer = malloc(fileSize);
ReadFile64(set->common.workingFile.buffer, set->common.workingFile.size,0,ncch0);
fclose(ncch0);
}
else if(usrset->common.workingFileType == infile_srl || usrset->common.workingFileType == infile_ncsd){
if(!AssertFile(usrset->common.workingFilePath)) {
fprintf(stderr,"[MAKEROM ERROR] Failed to open %s: %s\n",usrset->common.workingFileType == infile_srl? "SRL":"CCI",usrset->common.workingFilePath);
else{
if(!AssertFile(set->common.workingFilePath)) {
fprintf(stderr,"[MAKEROM ERROR] Failed to open: %s\n",set->common.workingFilePath);
goto finish;
}
u64 size = GetFileSize_u64(usrset->common.workingFilePath);
usrset->common.workingFile.size = align(size,0x10);
usrset->common.workingFile.buffer = malloc(usrset->common.workingFile.size);
FILE *fp = fopen(usrset->common.workingFilePath,"rb");
ReadFile_64(usrset->common.workingFile.buffer,size,0,fp);
u64 size = GetFileSize64(set->common.workingFilePath);
set->common.workingFile.size = align(size,0x10);
set->common.workingFile.buffer = malloc(set->common.workingFile.size);
FILE *fp = fopen(set->common.workingFilePath,"rb");
ReadFile64(set->common.workingFile.buffer,size,0,fp);
fclose(fp);
}
}
@@ -75,48 +68,48 @@ int main(int argc, char *argv[])
#ifdef DEBUG
printf("[DEBUG] Build NCCH0\n");
#endif
result = build_NCCH(usrset);
result = build_NCCH(set);
if(result < 0) {
//fprintf(stderr,"[ERROR] %s generation failed\n",usrset->build_ncch_type == CXI? "CXI" : "CFA");
//fprintf(stderr,"[ERROR] %s generation failed\n",set->build_ncch_type == CXI? "CXI" : "CFA");
fprintf(stderr,"[RESULT] Failed to build outfile\n");
goto finish;
}
}
// Make CCI
if(usrset->common.outFormat == CCI){
if(set->common.outFormat == CCI){
#ifdef DEBUG
printf("[DEBUG] Building CCI\n");
#endif
result = build_CCI(usrset);
result = build_CCI(set);
if(result < 0) {
fprintf(stderr,"[RESULT] Failed to build CCI\n");
goto finish;
}
}
// Make CIA
else if(usrset->common.outFormat == CIA){
else if(set->common.outFormat == CIA){
#ifdef DEBUG
printf("[DEBUG] Building CIA\n");
#endif
result = build_CIA(usrset);
result = build_CIA(set);
if(result < 0) {
fprintf(stderr,"[RESULT] Failed to build CIA\n");
goto finish;
}
}
// No Container Raw CXI/CFA
else if(usrset->common.outFormat == CXI || usrset->common.outFormat == CFA){
else if(set->common.outFormat == CXI || set->common.outFormat == CFA){
#ifdef DEBUG
printf("[DEBUG] Outputting NCCH, because No Container\n");
#endif
FILE *ncch_out = fopen(usrset->common.outFileName,"wb");
FILE *ncch_out = fopen(set->common.outFileName,"wb");
if(!ncch_out) {
fprintf(stderr,"[MAKEROM ERROR] Failed to create '%s'\n",usrset->common.outFileName);
fprintf(stderr,"[RESULT] Failed to build '%s'\n",usrset->common.outFormat == CXI? "CXI" : "CFA");
fprintf(stderr,"[MAKEROM ERROR] Failed to create '%s'\n",set->common.outFileName);
fprintf(stderr,"[RESULT] Failed to build '%s'\n",set->common.outFormat == CXI? "CXI" : "CFA");
result = FAILED_TO_CREATE_OUTFILE;
goto finish;
}
WriteBuffer(usrset->common.workingFile.buffer,usrset->common.workingFile.size,0,ncch_out);
WriteBuffer(set->common.workingFile.buffer,set->common.workingFile.size,0,ncch_out);
fclose(ncch_out);
}
@@ -124,7 +117,7 @@ finish:
#ifdef DEBUG
printf("[DEBUG] Free Context\n");
#endif
free_UserSettings(usrset);
free_UserSettings(set);
#ifdef DEBUG
printf("[DEBUG] Finished returning (result=%d)\n",result);
#endif
+444 -491
View File
File diff suppressed because it is too large Load Diff
+31 -126
View File
@@ -15,10 +15,10 @@ typedef enum
ACCESSDESC_SIG_BAD = -10,
NCCH_HDR_SIG_BAD = -11,
// HashCheck Errors
ExHeader_Hashfail = -12,
Logo_Hashfail = -13,
ExeFs_Hashfail = -14,
RomFs_Hashfail = -15,
EXHDR_CORRUPT = -12,
LOGO_CORRUPT = -13,
EXEFS_CORRUPT = -14,
ROMFS_CORRUPT = -15,
// Others
NCCH_BAD_YAML_SET = -16,
DATA_POS_DNE = -17,
@@ -29,34 +29,23 @@ typedef enum
ncch_exhdr = 1,
ncch_exefs,
ncch_romfs,
ncch_Logo,
ncch_PlainRegion,
} ncch_section;
typedef enum
{
NoKey,
KeyIsNormalFixed,
KeyIsSystemFixed,
KeyIsUnFixed,
KeyIsUnFixed2,
} ncch_key_type;
typedef enum
{
SecureCrypto2 = 3,
ContentPlatform = 4,
ContentType = 5,
ContentUnitSize = 6,
OtherFlag = 7
ncchflag_CONTENT_KEYX = 3,
ncchflag_CONTENT_PLATFORM = 4,
ncchflag_CONTENT_TYPE = 5,
ncchflag_CONTENT_BLOCK_SIZE = 6,
ncchflag_OTHER_FLAG = 7
} ncch_flags;
typedef enum
{
UnFixedCryptoKey = 0x0,
FixedCryptoKey = 0x1,
NoMountRomFs = 0x2,
NoCrypto = 0x4,
otherflag_Clear = 0,
otherflag_FixedCryptoKey = (1 << 0),
otherflag_NoMountRomFs = (1 << 1),
otherflag_NoCrypto = (1 << 2),
} ncch_otherflag_bitmask;
typedef enum
@@ -88,10 +77,11 @@ typedef struct
u64 romfsHashDataSize;
u8 titleId[8];
u8 programId[8];
} ncch_struct;
} ncch_info;
typedef struct
{
u8 signature[0x100];
u8 magic[4];
u8 ncchSize[4];
u8 titleId[8];
@@ -122,109 +112,24 @@ typedef struct
u8 romfsHash[0x20];
} ncch_hdr;
typedef struct
{
buffer_struct *out;
keys_struct *keys;
rsf_settings *rsfSet;
struct
{
u32 mediaSize;
bool IncludeExeFsLogo;
bool CompressCode;
bool UseOnSD;
bool Encrypt;
bool FreeProductCode;
bool IsCfa;
bool IsBuildingCodeSection;
bool UseRomFS;
} options;
struct
{
FILE *elf;
u64 elfSize;
FILE *banner;
u64 bannerSize;
FILE *icon;
u64 iconSize;
FILE *logo;
u64 logoSize;
FILE *code;
u64 codeSize;
FILE *exhdr;
u64 exhdrSize;
FILE *romfs;
u64 romfsSize;
FILE *plainregion;
u64 plainregionSize;
} componentFilePtrs;
struct
{
buffer_struct code;
buffer_struct banner;
buffer_struct icon;
} exefsSections;
struct
{
u32 textAddress;
u32 textSize;
u32 textMaxPages;
u32 roAddress;
u32 roSize;
u32 roMaxPages;
u32 rwAddress;
u32 rwSize;
u32 rwMaxPages;
u32 bssSize;
} codeDetails;
struct
{
buffer_struct exhdr;
buffer_struct acexDesc;
buffer_struct logo;
buffer_struct plainRegion;
buffer_struct exeFs;
} sections;
ncch_struct cryptoDetails;
} ncch_settings;
// NCCH Build Functions
int build_NCCH(user_settings *usrset);
// NCCH Read Functions
int VerifyNCCH(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput);
int VerifyNcch(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput);
u8* RetargetNCCH(FILE *fp, u64 size, u8 *TitleId, u8 *ProgramId, keys_struct *keys);
int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys);
ncch_hdr* GetNCCH_CommonHDR(void *out, FILE *fp, u8 *buf);
bool IsNCCH(FILE *fp, u8 *buf);
void ReadNcchHdr(ncch_hdr *hdr, FILE *fp);
u8* GetNcchHdrSig(ncch_hdr *hdr);
u8* GetNcchHdrData(ncch_hdr *hdr);
u32 GetNcchHdrSigLen(ncch_hdr *hdr);
u32 GetNcchHdrDataLen(ncch_hdr *hdr);
bool IsNcch(FILE *fp, u8 *buf);
bool IsCfa(ncch_hdr* hdr);
u32 GetNCCH_MediaUnitSize(ncch_hdr* hdr);
u32 GetNCCH_MediaSize(ncch_hdr* hdr);
ncch_key_type GetNCCHKeyType(ncch_hdr* hdr);
u8* GetNCCHKey0(ncch_key_type keytype, keys_struct *keys);
u8* GetNCCHKey1(ncch_key_type keytype, keys_struct *keys);
int GetNCCHStruct(ncch_struct *ctx, ncch_hdr *header);
void ncch_get_counter(ncch_struct *ctx, u8 counter[16], u8 type);
void CryptNCCHSection(u8 *buffer, u64 size, u64 src_pos, ncch_struct *ctx, u8 key[16], u8 type);
bool IsUpdateCfa(ncch_hdr* hdr);
u32 GetNcchBlockSize(ncch_hdr* hdr);
u8 GetBlockSizeFlag(u32 size);
u64 GetNcchSize(ncch_hdr* hdr);
bool IsNcchEncrypted(ncch_hdr *hdr);
bool SetNcchKeys(keys_struct *keys, ncch_hdr *hdr);
int GetNcchInfo(ncch_info *ctx, ncch_hdr *header);
void GetNcchAesCounter(ncch_info *ctx, u8 counter[16], u8 type);
void CryptNcchRegion(u8 *buffer, u64 size, u64 src_pos, ncch_info *ctx, u8 key[16], u8 type);
+88
View File
@@ -0,0 +1,88 @@
#pragma once
#include "ncch.h"
typedef struct
{
buffer_struct *out;
keys_struct *keys;
rsf_settings *rsfSet;
struct
{
u32 blockSize;
bool verbose;
bool IncludeExeFsLogo;
bool CompressCode;
bool UseOnSD;
bool Encrypt;
bool FreeProductCode;
bool IsCfa;
bool IsBuildingCodeSection;
bool UseRomFS;
bool useSecCrypto;
u8 keyXID;
} options;
struct
{
FILE *elf;
u64 elfSize;
FILE *banner;
u64 bannerSize;
FILE *icon;
u64 iconSize;
FILE *logo;
u64 logoSize;
FILE *code;
u64 codeSize;
FILE *exhdr;
u64 exhdrSize;
FILE *romfs;
u64 romfsSize;
FILE *plainregion;
u64 plainregionSize;
} componentFilePtrs;
struct
{
buffer_struct code;
buffer_struct banner;
buffer_struct icon;
} exefsSections;
struct
{
u32 textAddress;
u32 textSize;
u32 textMaxPages;
u32 roAddress;
u32 roSize;
u32 roMaxPages;
u32 rwAddress;
u32 rwSize;
u32 rwMaxPages;
u32 bssSize;
} codeDetails;
struct
{
buffer_struct exhdr;
buffer_struct acexDesc;
buffer_struct logo;
buffer_struct plainRegion;
buffer_struct exeFs;
} sections;
ncch_info cryptoDetails;
} ncch_settings;
// NCCH Build Functions
int build_NCCH(user_settings *usrset);
+2
View File
@@ -0,0 +1,2 @@
#pragma once
#include "ncch.h"
+595 -579
View File
File diff suppressed because it is too large Load Diff
+30 -175
View File
@@ -1,199 +1,54 @@
#pragma once
// Enums
typedef enum
{
NCSD_NO_NCCH0 = -1,
NCSD_INVALID_NCCH0 = -2,
NCSD_INVALID_NCCH = -3,
INVALID_YAML_OPT = -4,
CCI_SIG_FAIL = -5,
} ncsd_errors;
cciflag_BACKUP_WRITE_WAIT_TIME = 0,
cciflag_FW6_SAVE_CRYPTO = 1,
cciflag_CARD_DEVICE = 3,
cciflag_MEDIA_PLATFORM = 4,
cciflag_MEDIA_TYPE = 5,
cciflag_MEDIA_BLOCK_SIZE = 6,
cciflag_CARD_DEVICE_OLD = 7
} cci_flagindex;
typedef enum
{
FW6x_BackupWriteWaitTime = 0,
FW6x_SaveCryptoFlag = 1,
CardDeviceFlag = 3,
MediaPlatformIndex = 4,
MediaTypeIndex = 5,
MediaUnitSize = 6,
OldCardDeviceFlag = 7
} FlagIndex;
carddevice_NOR_FLASH = 1,
carddevice_NONE = 2,
carddevice_BT = 3
} cci_carddevice;
typedef enum
{
CARD_DEVICE_NOR_FLASH = 1,
CARD_DEVICE_NONE = 2,
CARD_DEVICE_BT = 3
} _CardDevice;
cciplatform_CTR = 1,
} cci_platform;
typedef enum
{
CTR = 1,
} _PlatformIndex;
typedef enum
{
INNER_DEVICE,
CARD1,
CARD2,
EXTENDED_DEVICE
} _TypeIndex;
mediatype_INNER_DEVICE, // NAND
mediatype_CARD1,
mediatype_CARD2,
mediatype_EXTENDED_DEVICE
} cci_mediatype;
// Structs
typedef struct
{
u8 offset[4];
u8 size[4];
} partition_offsetsize;
typedef struct
{
u8 magic[4];
u8 mediaSize[4];
u8 titleId[8];
u8 partitionsFsType[8];
u8 partitionsCryptoType[8];
partition_offsetsize offset_sizeTable[8];
u8 exhdrHash[0x20];
u8 additionalHdrSize[0x4];
u8 sectorZeroOffset[0x4];
u8 partitionFlags[8];
u8 partitionIdTable[8][8];
u8 padding[0x30];
} ncsd_hdr;
typedef struct
{
u8 magic[4];
u8 mediaSize[4];
u8 titleId[8];
u8 contentFsType[8];
u8 contentCryptoType[8];
partition_offsetsize offset_sizeTable[8];
u8 padding0[0x28];
u8 flags[8];
u8 contentIdTable[8][8];
u8 padding1[0x30];
} cci_hdr;
typedef struct
{
u8 writableAddress[4];
u8 cardInfoBitmask[4];
// Notes: reserved[0xDF8];
u8 reserved0[0xf8];
u8 mediaSizeUsed[8];
u8 reserved1[0x8];
u8 unknown[0x4];
u8 reserved2[0xc];
u8 cverTitleId[8];
u8 cverTitleVersion[2];
u8 reserved3[0xcd6];
//
u8 ncch0TitleId[8];
u8 reserved4[8];
u8 initialData[0x30];
u8 reserved5[0xc0];
u8 ncch0Hdr[0x100];
} cardinfo_hdr;
typedef struct
{
u8 cardDeviceReserved1[0x200];
u8 titleKey[0x10];
u8 cardDeviceReserved2[0xf0];
} devcardinfo_hdr;
} ncch_offsetsize;
typedef struct
{
u8 signature[0x100];
cci_hdr cciHdr;
cardinfo_hdr cardinfo;
devcardinfo_hdr devcardinfo;
} InternalCCI_Context;
u8 magic[4];
u8 mediaSize[4];
u8 titleId[8];
u8 padding0[0x10];
ncch_offsetsize offset_sizeTable[8];
u8 padding1[0x28];
u8 flags[8];
u8 ncchIdTable[8][8];
u8 padding2[0x30];
} cci_hdr;
typedef struct
{
FILE *out;
keys_struct *keys;
struct{
bool fillOutCci;
bool useDevCardInfo;
u32 mediaUnit;
u64 savedataSize;
} option;
struct{
/* Data */
buffer_struct *data;
/* Misc Records */
FILE **filePtrs;
u64 fileSize[CCI_MAX_CONTENT];
u16 count;
/* Details for NCSD header */
u8 fsType[CCI_MAX_CONTENT];
u8 cryptoType[CCI_MAX_CONTENT];
u64 offset[CCI_MAX_CONTENT];
u64 size[CCI_MAX_CONTENT];
u8 titleId[CCI_MAX_CONTENT][8];
} content;
struct{
u64 mediaSize;
u8 mediaId[8];
u8 flags[8];
} header;
struct{
u64 writableAddress;
u32 cardInfoBitmask;
u64 cciTotalSize;
// cver details
u8 cverTitleId[8];
u8 cverTitleVersion[2];
u8 initialData[0x30];
ncch_hdr ncchHdr;
u8 titleKey[0x10];
} cardinfo;
} cci_settings;
#ifndef PUBLIC_BUILD
static const u8 stock_initial_data[0x30] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xAD, 0x88,
0xAC, 0x41, 0xA2, 0xB1, 0x5E, 0x8F,
0x66, 0x9C, 0x97, 0xE5, 0xE1, 0x5E,
0xA3, 0xEB, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const u8 stock_title_key[0x10] =
{
0x6E, 0xC7, 0x5F, 0xB2, 0xE2, 0xB4,
0x87, 0x46, 0x1E, 0xDD, 0xCB, 0xB8,
0x97, 0x11, 0x92, 0xBA
};
#endif
// Public Prototypes
// Build Functions
int build_CCI(user_settings *usrset);
// Read Functions
bool IsCci(u8 *ncsd);
u8* GetPartition(u8 *ncsd, u8 index);
u64 GetPartitionOffset(u8 *ncsd, u8 index);
u64 GetPartitionSize(u8 *ncsd, u8 index);
+72
View File
@@ -0,0 +1,72 @@
#pragma once
#include "ncsd.h"
#include "tmd_read.h"
// Enums
typedef enum
{
NCSD_NO_NCCH0 = -1,
NCSD_INVALID_NCCH0 = -2,
NCSD_INVALID_NCCH = -3,
INVALID_RSF_OPT = -4,
GEN_HDR_FAIL = -5,
INCOMPAT_CIA = -6,
CCI_CONFIG_FAIL = -7,
} ncsd_errors;
typedef struct
{
rsf_settings *rsf;
keys_struct *keys;
FILE *out;
struct{
bool verbose;
bool padCci;
bool noModTid;
bool useExternalSdkCardInfo;
bool closeAlignWR;
u8 cverDataType;
char *cverDataPath;
tmd_hdr *tmdHdr;
} options;
struct{
u32 blockSize;
u64 mediaSize;
u64 usedSize;
u8 mediaType;
u8 cardDevice;
u64 saveSize;
u64 card2SaveOffset;
} romInfo;
struct{
u8 *data;
u64 dataLen;
infile_type dataType;
char **path;
bool active[CCI_MAX_CONTENT];
u64 dOffset[CCI_MAX_CONTENT];
u64 *dSize;
u64 titleId[CCI_MAX_CONTENT];
u64 cOffset[CCI_MAX_CONTENT];
} content;
struct{
buffer_struct ccihdr;
buffer_struct cardinfohdr;
} headers;
} cci_settings;
// Public Prototypes
// Build Functions
int build_CCI(user_settings *usrset);
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include "ncsd.h"
// Read Functions
bool IsCci(u8 *ncsd);
u8* GetPartition(u8 *ncsd, u8 index);
u64 GetPartitionOffset(u8 *ncsd, u8 index);
u64 GetPartitionSize(u8 *ncsd, u8 index);
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
#ifdef PKI_LEGACY
#include "dpki_legacy.h"
#include "pki/dev_legacy.h"
#endif
// AES KEYS
+2 -3
View File
@@ -1,7 +1,7 @@
#pragma once
#ifdef PKI_LEGACY
#include "ppki_legacy.h"
#include "pki/prod_legacy.h"
#endif
// AES KEYS
@@ -13,8 +13,7 @@ static const unsigned char prod_unfixed_ncch_keyX[2][16] = // Dummy
static const unsigned char ctr_common_etd_keyX_ppki[16] = // Dummy
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char ctr_common_etd_keyY_ppki[6][16] =
+2 -2
View File
@@ -1,8 +1,8 @@
#include "lib.h"
#include "dir.h"
#include "ncch.h"
#include "ncch_build.h"
#include "romfs.h"
#include "romfs_binary.h"
#include "romfs_gen.h"
#include "romfs_import.h"
void FreeRomFsCtx(romfs_buildctx *ctx);
@@ -1,6 +1,6 @@
#include "lib.h"
#include "dir.h"
#include "ncch.h"
#include "ncch_build.h"
#include "romfs.h"
const int ROMFS_BLOCK_SIZE = 0x1000;
@@ -75,7 +75,10 @@ int PrepareBuildRomFsBinary(ncch_settings *ncchset, romfs_buildctx *ctx)
// Print Filtered FS
//printf("print filtered FS\n");
//fs_PrintDir(ctx->fs,0);
if(ncchset->options.verbose){
printf("[ROMFS] File System:\n");
fs_PrintDir(ctx->fs,0);
}
//printf("predict romfs size\n");
CalcRomfsSize(ctx);
@@ -349,7 +352,7 @@ int AddFileToRomfs(romfs_buildctx *ctx, fs_file *file, u32 parent, u32 sibling)
u64_to_u8(entry->dataoffset,ctx->u_dataLen,LE);
u64_to_u8(entry->datasize,file->size,LE);
u8 *data_pos = (ctx->data + ctx->u_dataLen);
ReadFile_64(data_pos,file->size,0,file->fp);
ReadFile64(data_pos,file->size,0,file->fp);
ctx->u_dataLen += file->size; // adding file size
}
else
+3 -3
View File
@@ -1,6 +1,6 @@
#include "lib.h"
#include "dir.h"
#include "ncch.h"
#include "ncch_build.h"
#include "romfs.h"
int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx)
@@ -11,7 +11,7 @@ int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx
ivfc_hdr *hdr = calloc(1,sizeof(ivfc_hdr));
ReadFile_64(hdr,sizeof(ivfc_hdr),0,ctx->romfsBinary);
ReadFile64(hdr,sizeof(ivfc_hdr),0,ctx->romfsBinary);
if(memcmp(hdr->magic,"IVFC",4) != 0){
fprintf(stderr,"[ROMFS ERROR] Invalid RomFS Binary.\n");
return INVALID_ROMFS_FILE;
@@ -24,7 +24,7 @@ int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx
int ImportRomFsBinaryFromFile(romfs_buildctx *ctx)
{
ReadFile_64(ctx->output,ctx->romfsSize,0,ctx->romfsBinary);
ReadFile64(ctx->output,ctx->romfsSize,0,ctx->romfsBinary);
if(memcmp(ctx->output,"IVFC",4) != 0){
fprintf(stderr,"[ROMFS ERROR] Invalid RomFS Binary.\n");
return INVALID_ROMFS_FILE;
+1 -1
View File
@@ -56,7 +56,7 @@ void GET_Option(ctr_yaml_context *ctx, rsf_settings *rsf)
//else if(cmpYamlValue("NoPadding",ctx)) SetBoolYAMLValue(&rsf->Option.NoPadding,"NoPadding",ctx);
else if(cmpYamlValue("EnableCrypt",ctx)) SetBoolYAMLValue(&rsf->Option.EnableCrypt,"EnableCrypt",ctx);
else if(cmpYamlValue("EnableCompress",ctx)) SetBoolYAMLValue(&rsf->Option.EnableCompress,"EnableCompress",ctx);
else if(cmpYamlValue("FreeProductCode",ctx)) SetBoolYAMLValue(&rsf->Option.EnableCompress,"FreeProductCode",ctx);
else if(cmpYamlValue("FreeProductCode",ctx)) SetBoolYAMLValue(&rsf->Option.FreeProductCode,"FreeProductCode",ctx);
else if(cmpYamlValue("UseOnSD",ctx)) SetBoolYAMLValue(&rsf->Option.UseOnSD,"UseOnSD",ctx);
else if(cmpYamlValue("PageSize",ctx)) SetSimpleYAMLValue(&rsf->Option.PageSize,"PageSize",ctx,0);
//else if(cmpYamlValue("AppendSystemCall",ctx)) rsf->Option.AppendSystemCallNum = SetYAMLSequence(&rsf->Option.AppendSystemCall,"AppendSystemCall",ctx);
+33 -2
View File
@@ -1,6 +1,6 @@
#include "lib.h"
#include "cia.h"
#include "tik.h"
#include "cia_build.h"
#include "tik_build.h"
// Private Prototypes
int SetupTicketBuffer(buffer_struct *tik);
@@ -99,3 +99,34 @@ void SetContentIndexData(tik_hdr *hdr, cia_settings *ciaset) // TODO?
memset(hdr->contentIndex,0,0xAC);
memcpy(hdr->contentIndex,default_contentIndex,0x30);
}
tik_hdr *GetTikHdr(u8 *tik)
{
u32 sigType = u8_to_u32(tik,BE);
switch(sigType){
case(RSA_4096_SHA1):
case(RSA_4096_SHA256):
return (tik_hdr*)(tik+0x240);
case(RSA_2048_SHA1):
case(RSA_2048_SHA256):
return (tik_hdr*)(tik+0x140);
case(ECC_SHA1):
case(ECC_SHA256):
return (tik_hdr*)(tik+0x7C);
}
return NULL;
}
bool GetTikTitleKey(u8 *titleKey, tik_hdr *hdr, keys_struct *keys)
{
if(keys->aes.commonKey[hdr->keyId] == NULL)
return false;
keys->aes.currentCommonKey = hdr->keyId;
CryptTitleKey(hdr->encryptedTitleKey, titleKey, hdr->titleId, keys, DEC);
return true;
}
+2 -13
View File
@@ -1,15 +1,5 @@
#pragma once
static const unsigned char default_contentIndex[0x30] =
{
0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC,
0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84,
0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
};
typedef enum
{
lic_Permanent = 0,
@@ -63,6 +53,5 @@ typedef struct
u8 contentIndex[0xAC];
} tik_hdr;
// Prototypes
int BuildTicket(cia_settings *ciaset);
int CryptTitleKey(u8 *EncTitleKey, u8 *DecTitleKey, u8 *TitleID, keys_struct *keys, u8 mode);
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "tik.h"
static const unsigned char default_contentIndex[0x30] =
{
0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC,
0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84,
0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
};
// Prototypes
int BuildTicket(cia_settings *ciaset);
int CryptTitleKey(u8 *EncTitleKey, u8 *DecTitleKey, u8 *TitleID, keys_struct *keys, u8 mode);
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "tik.h"
tik_hdr *GetTikHdr(u8 *tik);
bool GetTikTitleKey(u8 *titleKey, tik_hdr *hdr, keys_struct *keys);
+2 -2
View File
@@ -1,5 +1,5 @@
#include "lib.h"
#include "ncch.h"
#include "ncch_read.h"
#include "titleid.h"
void SetPIDType(u16 *type);
@@ -22,7 +22,7 @@ int GetProgramID(u64 *dest, rsf_settings *rsf, bool IsForExheader)
u8 variation;
if(rsf->TitleInfo.Category && rsf->TitleInfo.CategoryFlags){
fprintf(stderr,"[ID ERROR] Can not set \"Cateory\" and \"CategoryFlags\" at the same time.\n");
fprintf(stderr,"[ID ERROR] Can not set \"Category\" and \"CategoryFlags\" at the same time.\n");
return PID_BAD_RSF_SET;
}
+92 -7
View File
@@ -1,6 +1,6 @@
#include "lib.h"
#include "cia.h"
#include "tmd.h"
#include "cia_build.h"
#include "tmd_build.h"
// Private Prototypes
int SetupTMDBuffer(buffer_struct *tik);
@@ -85,11 +85,96 @@ int SetupTMDContentRecord(u8 *content_record, cia_settings *ciaset)
{
for(int i = 0; i < ciaset->content.count; i++){
tmd_content_chunk *ptr = (tmd_content_chunk*)(content_record+sizeof(tmd_content_chunk)*i);
u32_to_u8(ptr->contentID,ciaset->content.id[i],BE);
u16_to_u8(ptr->contentIndex,ciaset->content.index[i],BE);
u16_to_u8(ptr->contentFlags,ciaset->content.flags[i],BE);
u64_to_u8(ptr->contentSize,ciaset->content.size[i],BE);
memcpy(ptr->contentHash,ciaset->content.hash[i],0x20);
u32_to_u8(ptr->id,ciaset->content.id[i],BE);
u16_to_u8(ptr->index,ciaset->content.index[i],BE);
u16_to_u8(ptr->flags,ciaset->content.flags[i],BE);
u64_to_u8(ptr->size,ciaset->content.size[i],BE);
memcpy(ptr->hash,ciaset->content.hash[i],0x20);
}
return 0;
}
tmd_hdr *GetTmdHdr(u8 *tmd)
{
u32 sigType = u8_to_u32(tmd,BE);
switch(sigType){
case(RSA_4096_SHA1):
case(RSA_4096_SHA256):
return (tmd_hdr*)(tmd+0x240);
case(RSA_2048_SHA1):
case(RSA_2048_SHA256):
return (tmd_hdr*)(tmd+0x140);
case(ECC_SHA1):
case(ECC_SHA256):
return (tmd_hdr*)(tmd+0x7C);
}
return NULL;
}
tmd_content_chunk* GetTmdContentInfo(u8 *tmd)
{
tmd_hdr *hdr = GetTmdHdr(tmd);
if(!hdr)
return NULL;
return (tmd_content_chunk*)((u8*)hdr + sizeof(tmd_hdr) + (sizeof(tmd_content_info_record)*64));
}
u64 GetTmdTitleId(tmd_hdr *hdr)
{
return u8_to_u64(hdr->titleID,BE);
}
u32 GetTmdSaveSize(tmd_hdr *hdr)
{
return u8_to_u32(hdr->savedataSize,BE);
}
u16 GetTmdContentCount(tmd_hdr *hdr)
{
return u8_to_u16(hdr->contentCount,BE);
}
u16 GetTmdVersion(tmd_hdr *hdr)
{
return u8_to_u16(hdr->titleVersion,BE);
}
u32 GetTmdContentId(tmd_content_chunk info)
{
return u8_to_u32(info.id,BE);
}
u16 GetTmdContentIndex(tmd_content_chunk info)
{
return u8_to_u16(info.index,BE);
}
u16 GetTmdContentFlags(tmd_content_chunk info)
{
return u8_to_u16(info.flags,BE);
}
u64 GetTmdContentSize(tmd_content_chunk info)
{
return u8_to_u64(info.size,BE);
}
u8* GetTmdContentHash(tmd_content_chunk *info)
{
return (u8*)info->hash;
}
bool IsTmdContentEncrypted(tmd_content_chunk info)
{
return (GetTmdContentFlags(info) & content_Encrypted) == content_Encrypted;
}
bool ValidateTmdContent(u8 *data, tmd_content_chunk info)
{
u8 hash[32];
ctr_sha(data,GetTmdContentSize(info),hash,CTR_SHA_256);
return memcmp(hash,GetTmdContentHash(&info),32) == 0;
}
+6 -13
View File
@@ -15,11 +15,11 @@ typedef enum
typedef struct
{
u8 contentID[4];
u8 contentIndex[2];
u8 contentFlags[2];
u8 contentSize[8];
u8 contentHash[0x20]; // SHA 256
u8 id[4];
u8 index[2];
u8 flags[2];
u8 size[8];
u8 hash[0x20]; // SHA 256
} tmd_content_chunk;
typedef struct
@@ -58,11 +58,4 @@ typedef struct
u8 bootContent[2];
u8 padding3[2];
u8 infoRecordHash[0x20]; // SHA-256
} tmd_hdr;
// Prototypes
u32 PredictTMDSize(u16 ContentCount);
int BuildTMD(cia_settings *ciaset);
// Read TMD
tmd_hdr *GetTmdHdr(u8 *tmd);
} tmd_hdr;
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "tmd.h"
// Prototypes
u32 PredictTMDSize(u16 ContentCount);
int BuildTMD(cia_settings *ciaset);
-22
View File
@@ -1,22 +0,0 @@
#include "lib.h"
#include "cia.h"
#include "tmd.h"
tmd_hdr *GetTmdHdr(u8 *tmd)
{
u32 sigType = u8_to_u32(tmd,BE);
switch(sigType){
case(RSA_4096_SHA1):
case(RSA_4096_SHA256):
return (tmd_hdr*)(tmd+0x240);
case(RSA_2048_SHA1):
case(RSA_2048_SHA256):
return (tmd_hdr*)(tmd+0x140);
case(ECC_SHA1):
case(ECC_SHA256):
return (tmd_hdr*)(tmd+0x7C);
}
return NULL;
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "tmd.h"
// Read TMD
tmd_hdr *GetTmdHdr(u8 *tmd);
tmd_content_chunk* GetTmdContentInfo(u8 *tmd);
u64 GetTmdTitleId(tmd_hdr *hdr);
u32 GetTmdSaveSize(tmd_hdr *hdr);
u16 GetTmdContentCount(tmd_hdr *hdr);
u16 GetTmdVersion(tmd_hdr *hdr);
u32 GetTmdContentId(tmd_content_chunk info);
u16 GetTmdContentIndex(tmd_content_chunk info);
u16 GetTmdContentFlags(tmd_content_chunk info);
u64 GetTmdContentSize(tmd_content_chunk info);
u8* GetTmdContentHash(tmd_content_chunk info);
bool IsTmdContentEncrypted(tmd_content_chunk info);
bool ValidateTmdContent(u8 *data, tmd_content_chunk info);
+229 -157
View File
@@ -10,9 +10,9 @@ void PrintArgInvalid(char *arg);
void PrintArgReqParam(char *arg, u32 paramNum);
void PrintNoNeedParam(char *arg);
int ParseArgs(int argc, char *argv[], user_settings *usr_settings)
int ParseArgs(int argc, char *argv[], user_settings *set)
{
if(argv == NULL || usr_settings == NULL)
if(argv == NULL || set == NULL)
return USR_PTR_PASS_FAIL;
if(argc < 2){
@@ -29,26 +29,23 @@ int ParseArgs(int argc, char *argv[], user_settings *usr_settings)
}
// Allocating Memory for Content Path Ptrs
usr_settings->common.contentPath = calloc(CIA_MAX_CONTENT,sizeof(char*));
if(usr_settings->common.contentPath == NULL){
set->common.contentPath = calloc(CIA_MAX_CONTENT,sizeof(char*));
if(set->common.contentPath == NULL){
fprintf(stderr,"[SETTING ERROR] Not Enough Memory\n");
return USR_MEM_ERROR;
}
// Initialise Keys
InitKeys(&usr_settings->common.keys);
InitKeys(&set->common.keys);
// Setting Defaults
SetDefaults(usr_settings);
SetDefaults(set);
// Parsing Arguments
#ifdef DEBUG
fprintf(stdout,"[DEBUG] Parsing Args\n");
#endif
int set_result;
int i = 1;
while(i < argc){
set_result = SetArgument(argc,i,argv,usr_settings);
set_result = SetArgument(argc,i,argv,set);
if(set_result < 1){
fprintf(stderr,"[RESULT] Invalid arguments, see '%s -help'\n",argv[0]);
return set_result;
@@ -57,39 +54,30 @@ int ParseArgs(int argc, char *argv[], user_settings *usr_settings)
}
// Checking arguments
#ifdef DEBUG
fprintf(stdout,"[DEBUG] Checking Args\n");
#endif
set_result = CheckArgumentCombination(usr_settings);
if(set_result) return set_result;
if((set_result = CheckArgumentCombination(set)) != 0)
return set_result;
// Setting Keys
#ifdef DEBUG
fprintf(stdout,"[DEBUG] Setting Keys\n");
#endif
set_result = SetKeys(&usr_settings->common.keys);
if(set_result) return set_result;
if((set_result = SetKeys(&set->common.keys)) != 0)
return set_result;
#ifdef DEBUG
fprintf(stdout,"[DEBUG] Generating output path name if required\n");
#endif
if(!usr_settings->common.outFileName){
// Generating outpath if required
if(!set->common.outFileName){
char *source_path = NULL;
if(usr_settings->ncch.buildNcch0)
source_path = usr_settings->common.rsfPath;
else if(usr_settings->common.workingFileType == infile_ncsd || usr_settings->common.workingFileType == infile_srl)
source_path = usr_settings->common.workingFilePath;
if(set->ncch.buildNcch0)
source_path = set->common.rsfPath;
else if(set->common.workingFileType == infile_ncsd || set->common.workingFileType == infile_cia || set->common.workingFileType == infile_srl)
source_path = set->common.workingFilePath;
else
source_path = usr_settings->common.contentPath[0];
u16 outfile_len = strlen(source_path) + 3;
usr_settings->common.outFileName = calloc(outfile_len,sizeof(char));
if(!usr_settings->common.outFileName){
source_path = set->common.contentPath[0];
u16 outfile_len = strlen(source_path) + 0x10;
set->common.outFileName = calloc(outfile_len,sizeof(char));
if(!set->common.outFileName){
fprintf(stderr,"[SETTING ERROR] Not Enough Memory\n");
return USR_MEM_ERROR;
}
usr_settings->common.outFileName_mallocd = true;
append_filextention(usr_settings->common.outFileName,outfile_len,source_path,(char*)&output_extention[usr_settings->common.outFormat-1]);
set->common.outFileName_mallocd = true;
append_filextention(set->common.outFileName,outfile_len,source_path,(char*)&output_extention[set->common.outFormat-1]);
}
return 0;
}
@@ -101,12 +89,14 @@ void SetDefaults(user_settings *set)
set->common.keys.accessDescSign.presetType = desc_preset_NONE;
// Build NCCH Info
set->ncch.useSecCrypto = false;
set->ncch.buildNcch0 = false;
set->ncch.includeExefsLogo = false;
set->common.outFormat = NCCH;
set->ncch.ncchType = format_not_set;
// RSF Settings
clrmem(&set->common.rsfSet,sizeof(rsf_settings));
set->common.rsfSet.Option.EnableCompress = true;
set->common.rsfSet.Option.EnableCrypt = true;
set->common.rsfSet.Option.UseOnSD = false;
@@ -119,13 +109,15 @@ void SetDefaults(user_settings *set)
set->cci.useSDKStockData = false;
// CIA Info
set->cia.includeUpdateNcch = false;
set->cia.deviceId = 0;
set->cia.eshopAccId = 0;
set->cia.useDataTitleVer = false;
set->cia.titleVersion[VER_MAJOR] = MAX_U16; // invalid so changes can be detected
set->cia.randomTitleKey = false;
set->common.keys.aes.currentCommonKey = MAX_U8 + 1; // invalid so changes can be detected
for(int i = 0; i < CIA_MAX_CONTENT; i++){
for(int i = 0; i < CIA_MAX_CONTENT; i++)
set->cia.contentId[i] = MAX_U32 + 1; // invalid so changes can be detected
}
}
int SetArgument(int argc, int i, char *argv[], user_settings *set)
@@ -137,7 +129,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
// Global Settings
if(strcmp(argv[i],"-rsf") == 0){
if(ParamNum != 1){
PrintArgReqParam("-rsf",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->common.rsfPath = argv[i+1];
@@ -145,7 +137,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-f") == 0){
if(ParamNum != 1){
PrintArgReqParam("-f",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
if(strcasecmp(argv[i+1],"ncch") == 0)
@@ -162,17 +154,25 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-o") == 0){
if(ParamNum != 1){
PrintArgReqParam("-o",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->common.outFileName = argv[i+1];
set->common.outFileName_mallocd = false;
return 2;
}
else if(strcmp(argv[i],"-v") == 0){
if(ParamNum){
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->common.verbose = true;
return 1;
}
// Key Options
else if(strcmp(argv[i],"-target") == 0){
if(ParamNum != 1){
PrintArgReqParam("-target",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
if(strcasecmp(argv[i+1],"test") == 0 || strcasecmp(argv[i+1],"t") == 0)
@@ -181,7 +181,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
set->common.keys.keyset = pki_DEVELOPMENT;
else if(strcasecmp(argv[i+1],"retail") == 0 || strcasecmp(argv[i+1],"production") == 0 || strcasecmp(argv[i+1],"p") == 0)
set->common.keys.keyset = pki_PRODUCTION;
//else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0)
//else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0) // given all known keys are here, this isn't needed
// set->common.keys.keyset = pki_CUSTOM;
else{
fprintf(stderr,"[SETTING ERROR] Unrecognised target '%s'\n",argv[i+1]);
@@ -189,22 +189,36 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
return 2;
}
else if(strcmp(argv[i],"-ckeyID") == 0){
else if(strcmp(argv[i],"-ckeyid") == 0){
if(ParamNum != 1){
PrintArgReqParam("-ckeyID",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->common.keys.aes.currentCommonKey = strtol(argv[i+1],NULL,0);
if(set->common.keys.aes.currentCommonKey > 0xff)
if(set->common.keys.aes.currentCommonKey > MAX_CMN_KEY)
{
fprintf(stderr,"[SETTING ERROR] Invalid Common Key ID: 0x%x\n",set->common.keys.aes.currentCommonKey);
fprintf(stderr,"[SETTING ERROR] Invalid Common Key Index: 0x%x\n",set->common.keys.aes.currentCommonKey);
return USR_BAD_ARG;
}
return 2;
}
else if(strcmp(argv[i],"-ncchseckey") == 0){
if(ParamNum != 1){
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.useSecCrypto = true;
set->ncch.keyXID = strtol(argv[i+1],NULL,0);
if(set->ncch.keyXID > MAX_NCCH_KEYX)
{
fprintf(stderr,"[SETTING ERROR] Invalid NCCH KeyX Index: 0x%x\n",set->ncch.keyXID);
return USR_BAD_ARG;
}
return 2;
}
else if(strcmp(argv[i],"-showkeys") == 0){
if(ParamNum){
PrintNoNeedParam("-showkeys");
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->common.keys.dumpkeys = true;
@@ -212,7 +226,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-fsign") == 0){
if(ParamNum){
PrintNoNeedParam("-fsign");
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->common.keys.rsa.isFalseSign = true;
@@ -222,7 +236,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
// Ncch Options
else if(strcmp(argv[i],"-elf") == 0){
if(ParamNum != 1){
PrintArgReqParam("-elf",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.elfPath = argv[i+1];
@@ -232,7 +246,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
else if(strcmp(argv[i],"-icon") == 0){
if(ParamNum != 1){
PrintArgReqParam("-icon",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.iconPath = argv[i+1];
@@ -241,7 +255,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-banner") == 0){
if(ParamNum != 1){
PrintArgReqParam("-banner",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.bannerPath = argv[i+1];
@@ -250,7 +264,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-logo") == 0){
if(ParamNum != 1){
PrintArgReqParam("-logo",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.logoPath = argv[i+1];
@@ -259,7 +273,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-desc") == 0){
if(ParamNum != 1){
PrintArgReqParam("-desc",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
char *tmp = argv[i+1];
@@ -281,7 +295,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
else if(strcasecmp(app_type,"ECApp") == 0) set->common.keys.accessDescSign.presetType = desc_preset_EC_APP;
else if(strcasecmp(app_type,"Demo") == 0) set->common.keys.accessDescSign.presetType = desc_preset_DEMO;
else if(strcasecmp(app_type,"DlpChild") == 0 || strcasecmp(app_type,"Dlp") == 0) set->common.keys.accessDescSign.presetType = desc_preset_DLP;
//else if(strcasecmp(app_type,"FIRM") == 0) set->common.keys.accessDescSign.presetType = desc_preset_FIRM;
else if(strcasecmp(app_type,"FIRM") == 0) set->common.keys.accessDescSign.presetType = desc_preset_FIRM;
else{
fprintf(stderr,"[SETTING ERROR] Accessdesc AppType preset '%s' not valid, please manually configure RSF\n",app_type);
return USR_BAD_ARG;
@@ -324,7 +338,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-exefslogo") == 0){
if(ParamNum){
PrintNoNeedParam("-exefslogo");
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->ncch.includeExefsLogo = true;
@@ -335,7 +349,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
// Ncch Rebuild Options
else if(strcmp(argv[i],"-code") == 0){
if(ParamNum != 1){
PrintArgReqParam("-code",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.codePath = argv[i+1];
@@ -344,16 +358,16 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-exheader") == 0){
if(ParamNum != 1){
PrintArgReqParam("-exheader",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.exheaderPath = argv[i+1];
set->ncch.ncchType |= CXI;
return 2;
}
else if(strcmp(argv[i],"-plain-region") == 0){
else if(strcmp(argv[i],"-plainrgn") == 0){
if(ParamNum != 1){
PrintArgReqParam("-plain-region",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.plainRegionPath = argv[i+1];
@@ -362,7 +376,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-romfs") == 0){
if(ParamNum != 1){
PrintArgReqParam("-romfs",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.romfsPath = argv[i+1];
@@ -370,9 +384,9 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
return 2;
}
// Cci Options
else if(strcmp(argv[i],"-devcardcci") == 0){
else if(strcmp(argv[i],"-devcci") == 0){
if(ParamNum){
PrintNoNeedParam("-devcardcci");
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->cci.useSDKStockData = true;
@@ -380,7 +394,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-nomodtid") == 0){
if(ParamNum){
PrintNoNeedParam("-nomodtid");
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->cci.dontModifyNcchTitleID = true;
@@ -388,7 +402,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-alignwr") == 0){
if(ParamNum){
PrintNoNeedParam("-alignwr");
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->cci.closeAlignWritableRegion = true;
@@ -396,17 +410,42 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-cverinfo") == 0){
if(ParamNum != 1){
PrintArgReqParam("-cverinfo",1);
PrintArgReqParam(argv[i],1);
return USR_BAD_ARG;
}
set->cci.cverCiaPath = argv[i+1];
char *pos = strstr(argv[i+1],":");
if(!pos || strlen(pos) < 2){
fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]);
fprintf(stderr," %s <DATA PATH>:<'cia'/'tmd'>\n",argv[i]);
return USR_BAD_ARG;
}
char *dtype = pos + 1;
if(strcasecmp(dtype,"tmd") == 0)
set->cci.cverDataType = CVER_DTYPE_TMD;
else if(strcasecmp(dtype,"cia") == 0)
set->cci.cverDataType = CVER_DTYPE_CIA;
else{
fprintf(stderr,"[SETTING ERROR] Unrecognised cver data type:\"%s\"\n",dtype);
return USR_BAD_ARG;
}
u32 path_len = (pos-argv[i+1])+1;
set->cci.cverDataPath = calloc(path_len,sizeof(char));
strncpy(set->cci.cverDataPath,argv[i+1],path_len-1);
if(!AssertFile(set->cci.cverDataPath)){
fprintf(stderr,"[SETTING ERROR] Failed to open '%s'\n",set->cci.cverDataPath);
return USR_BAD_ARG;
}
return 2;
}
// Cia Options
else if(strcmp(argv[i],"-major") == 0){
if(ParamNum != 1){
PrintArgReqParam("-major",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->cia.useNormTitleVer = true;
@@ -420,7 +459,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-minor") == 0){
if(ParamNum != 1){
PrintArgReqParam("-minor",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->cia.useNormTitleVer = true;
@@ -434,7 +473,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-micro") == 0){
if(ParamNum != 1){
PrintArgReqParam("-micro",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
u32 ver = strtoul(argv[i+1],NULL,10);
@@ -447,7 +486,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
}
else if(strcmp(argv[i],"-dver") == 0){
if(ParamNum != 1){
PrintArgReqParam("-dver",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->cia.useDataTitleVer = true;
@@ -457,31 +496,44 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
return USR_BAD_ARG;
}
set->cia.titleVersion[VER_MAJOR] = (ver >> 6) & VER_MAJOR_MAX;
set->cia.titleVersion[VER_MINOR] = ver & VER_MAJOR_MAX;
set->cia.titleVersion[VER_MINOR] = ver & VER_MINOR_MAX;
return 2;
}
else if(strcmp(argv[i],"-deviceid") == 0){
if(ParamNum != 1){
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->cia.deviceId = strtoul(argv[i+1],NULL,16);
return 2;
}
else if(strcmp(argv[i],"-esaccid") == 0){
if(ParamNum != 1){
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->cia.eshopAccId = strtoul(argv[i+1],NULL,16);
return 2;
}
else if(strcmp(argv[i],"-rand") == 0){
if(ParamNum){
PrintNoNeedParam("-rand");
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->cia.randomTitleKey = true;
return 1;
}
else if(strcmp(argv[i],"-cci") == 0){
if(ParamNum != 1){
PrintArgReqParam("-cci",1);
return USR_ARG_REQ_PARAM;
else if(strcmp(argv[i],"-dlc") == 0){
if(ParamNum){
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->ncch.buildNcch0 = false;
set->common.workingFileType = infile_ncsd;
set->common.workingFilePath = argv[i+1];
set->common.outFormat = CIA;
return 2;
set->cia.DlcContent = true;
return 1;
}
else if(strcmp(argv[i],"-srl") == 0){
if(ParamNum != 1){
PrintArgReqParam("-srl",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.buildNcch0 = false;
@@ -491,36 +543,53 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
return 2;
}
else if(strcmp(argv[i],"-dlc") == 0){
// Ncch Container Conversion
else if(strcmp(argv[i],"-ccitocia") == 0){
if(ParamNum != 1){
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.buildNcch0 = false;
set->common.workingFileType = infile_ncsd;
set->common.workingFilePath = argv[i+1];
set->common.outFormat = CIA;
return 2;
}
else if(strcmp(argv[i],"-ciatocci") == 0){
if(ParamNum != 1){
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
set->ncch.buildNcch0 = false;
set->common.workingFileType = infile_cia;
set->common.workingFilePath = argv[i+1];
set->common.outFormat = CCI;
return 2;
}
else if(strcmp(argv[i],"-inclupd") == 0){
if(ParamNum){
PrintNoNeedParam("-dlc");
PrintNoNeedParam(argv[i]);
return USR_BAD_ARG;
}
set->cia.DlcContent = true;
set->cia.includeUpdateNcch = true;
return 1;
}
// Other Setting
else if(strcmp(argv[i],"-content") == 0){
if(ParamNum != 1){
PrintArgReqParam("-content",1);
PrintArgReqParam(argv[i],1);
return USR_ARG_REQ_PARAM;
}
char *pos = strstr(argv[i+1],":");
if(!pos){
if(!pos || strlen(pos) < 2){
fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]);
fprintf(stderr," -content <CONTENT PATH>:<INDEX>\n");
fprintf(stderr," %s <CONTENT PATH>:<INDEX>\n",argv[i]);
fprintf(stderr," If generating a CIA, then use the format:\n");
fprintf(stderr," -content <CONTENT PATH>:<INDEX>:<ID>\n");
fprintf(stderr," %s <CONTENT PATH>:<INDEX>:<ID>\n",argv[i]);
return USR_BAD_ARG;
}
if(strlen(pos) < 2){
fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]);
fprintf(stderr," -content <CONTENT PATH>:<INDEX>\n");
fprintf(stderr," If generating a CIA, then use the format:\n");
fprintf(stderr," -content <CONTENT PATH>:<INDEX>:<ID>\n");
return USR_BAD_ARG;
}
/* Getting Content Index */
u16 content_index = strtol((char*)(pos+1),NULL,0);
@@ -528,7 +597,6 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
/* Storing Content Filepath */
u32 path_len = (u32)(pos-argv[i+1])+1;
if(content_index == 0) set->ncch.buildNcch0 = false;
if(set->common.contentPath[content_index] != NULL){
fprintf(stderr,"[SETTING ERROR] Content %d is already specified\n",content_index);
return USR_BAD_ARG;
@@ -539,12 +607,16 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
return USR_MEM_ERROR;
}
strncpy(set->common.contentPath[content_index],argv[i+1],path_len-1);
if(!AssertFile(set->common.contentPath[content_index])){
fprintf(stderr,"[SETTING ERROR] '%s' could not be opened\n",set->common.contentPath[content_index]);
return USR_BAD_ARG;
}
set->common.contentSize[content_index] = GetFileSize64(set->common.contentPath[content_index]);
/* Get ContentID for CIA gen */
char *pos2 = strstr(pos+1,":");
if(pos2) {
if(pos2)
set->cia.contentId[content_index] = strtoul((pos2+1),NULL,0);
}
/* Return Next Arg Pos*/
return 2;
@@ -563,7 +635,6 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
fprintf(stderr,"[SETTING ERROR] Not enough memory\n");
return MEM_ERROR;
}
//memset(set->dname.items,0,sizeof(dname_item)*set->dname.m_items);
}
else if(set->dname.m_items == set->dname.u_items){
set->dname.m_items *= 2;
@@ -655,7 +726,7 @@ int CheckArgumentCombination(user_settings *set)
return USR_BAD_ARG;
}
if(set->common.outFormat == CIA && set->cci.cverCiaPath){
if(set->common.outFormat == CIA && set->cci.cverDataPath){
fprintf(stderr,"[SETTING ERROR] You cannot use argument \"-cverinfo\" when generating a CIA\n");
return USR_BAD_ARG;
}
@@ -700,7 +771,7 @@ int CheckArgumentCombination(user_settings *set)
return USR_BAD_ARG;
}
if(!buildCXI && set->ncch.plainRegionPath){
PrintArgInvalid("-plain-region");
PrintArgInvalid("-plainrgn");
return USR_BAD_ARG;
}
if(!set->ncch.buildNcch0 && set->ncch.includeExefsLogo){
@@ -715,45 +786,47 @@ int CheckArgumentCombination(user_settings *set)
return 0;
}
void init_UserSettings(user_settings *usr_settings)
void init_UserSettings(user_settings *set)
{
memset(usr_settings,0,sizeof(user_settings));
memset(set,0,sizeof(user_settings));
}
void free_UserSettings(user_settings *usr_settings)
void free_UserSettings(user_settings *set)
{
// Free Content Paths
if(usr_settings->common.contentPath){
if(set->common.contentPath){
for(int i = 0; i < CIA_MAX_CONTENT; i++)
free(usr_settings->common.contentPath[i]);
free(usr_settings->common.contentPath);
free(set->common.contentPath[i]);
free(set->common.contentPath);
}
// free -DNAME=VALUE
for(u32 i = 0; i < usr_settings->dname.u_items; i++){
free(usr_settings->dname.items[i].name);
free(usr_settings->dname.items[i].value);
for(u32 i = 0; i < set->dname.u_items; i++){
free(set->dname.items[i].name);
free(set->dname.items[i].value);
}
free(usr_settings->dname.items);
free(set->dname.items);
free(set->cci.cverDataPath);
// Free Spec File Setting
free_RsfSettings(&usr_settings->common.rsfSet);
free_RsfSettings(&set->common.rsfSet);
// Free Key Data
FreeKeys(&usr_settings->common.keys);
FreeKeys(&set->common.keys);
// Free Working File
free(usr_settings->common.workingFile.buffer);
free(set->common.workingFile.buffer);
// Free outfile path, if malloc'd
if(usr_settings->common.outFileName_mallocd)
free(usr_settings->common.outFileName);
if(set->common.outFileName_mallocd)
free(set->common.outFileName);
// Clear settings
init_UserSettings(usr_settings);
init_UserSettings(set);
// Free
free(usr_settings);
free(set);
}
void PrintNeedsArg(char *arg)
@@ -787,53 +860,52 @@ void DisplayHelp(char *app_name)
printf("Option Parameter Explanation\n");
printf("GLOBAL OPTIONS:\n");
printf(" -help Display this text\n");
printf(" -rsf <file> Rom Specification File (*.rsf)\n");
printf(" -f <ncch|cci|cia> Output Format, defaults to 'ncch'\n");
printf(" -o <file> Output File\n");
//printf(" -v Verbose\n");
printf(" -DNAME=VALUE Substitute values in Spec file\n");
printf(" -rsf <file> ROM Spec File (*.rsf)\n");
printf(" -f <ncch|cci|cia> Output format, defaults to 'ncch'\n");
printf(" -o <file> Output file\n");
printf(" -v Verbose output\n");
printf(" -DNAME=VALUE Substitute values in RSF file\n");
printf("KEY OPTIONS:\n");
//printf(" -target <t|d|p|c> Target for crypto, defaults to 't'\n");
printf(" -target <t|d|p> Target for crypto, defaults to 't'\n");
printf(" 't' Test(false) Keys & prod Certs\n");
printf(" 'd' Development Keys & Certs\n");
printf(" 'p' Production Keys & Certs\n");
//printf(" 'c' Custom Keys & Certs\n");
printf(" -ckeyID <u8 value> Override the automatic commonKey selection\n");
printf(" -showkeys Display the loaded keychain\n");
printf(" -ckeyid <index> Override the automatic common key selection\n");
printf(" -ncchseckey <index> Ncch keyX index ('0'=1.0+, '1'=7.0+)\n");
printf(" -showkeys Display the loaded key chain\n");
printf(" -fsign Ignore invalid signatures\n");
printf("NCCH OPTIONS:\n");
printf(" -elf <file> ELF File\n");
printf(" -icon <file> Icon File\n");
printf(" -banner <file> Banner File\n");
printf(" -logo <file> Logo File (Overrides \"BasicInfo/Logo\" in RSF)\n");
printf(" -desc <apptype>:<fw> Specify Access Descriptor Preset\n");
//printf(" AppTypes:\n");
//printf(" 'SDApp' Normal SD Application\n");
//printf(" 'ECApp' SD Application with DLC Capability\n");
//printf(" 'Demo' SD Demo Application\n");
//printf(" 'Dlp' NAND DLP Child Application\n");
//printf(" 'FIRM' FIRM CXI\n");
printf(" -exefslogo Include Logo in ExeFs (Required for usage on <5.X Systems)\n");
printf(" -elf <file> ELF file\n");
printf(" -icon <file> Icon file\n");
printf(" -banner <file> Banner file\n");
printf(" -logo <file> Logo file (Overrides \"BasicInfo/Logo\" in RSF)\n");
printf(" -desc <apptype>:<fw> Specify Access Descriptor template\n");
printf(" -exefslogo Include Logo in ExeFS (Required for usage on <5.0 systems)\n");
printf("NCCH REBUILD OPTIONS:\n");
printf(" -code <code path> Specify ExeFs code File\n");
printf(" -exheader <exhdr path> ExHeader Template File\n");
printf(" -plain-region <pln region path> PlainRegion File\n");
printf(" -romfs <romfs path> RomFS File\n");
printf(" -code <file> Decompressed ExeFS \".code\"\n");
printf(" -exheader <file> Exheader template\n");
printf(" -plainrgn <file> Plain Region binary\n");
printf(" -romfs <file> RomFS binary\n");
printf("CCI OPTIONS:\n");
printf(" -content <filepath>:<index> Specify content files\n");
printf(" -devcardcci Use SDK CardInfo Method\n");
printf(" -content <file>:<index> Specify content files\n");
printf(" -devcci Use external CTRSDK \"CardInfo\" method\n");
printf(" -nomodtid Don't Modify Content TitleIDs\n");
printf(" -alignwr Align Writeable Region to the end of last NCCH\n");
printf(" -cverinfo <cver cia path> Include CVer title info\n");
printf(" -alignwr Align writeable region to the end of last NCCH\n");
printf(" -cverinfo <file>:<cia|tmd> Include cver title info\n");
printf("CIA OPTIONS:\n");
printf(" -content <filepath>:<index>:<id> Specify content files\n");
printf(" -major <major version> Specify Major Version\n");
printf(" -minor <minor version> Specify Minor Version\n");
printf(" -micro <micro version> Specify Micro Version\n");
printf(" -dver <datatitle ver> Specify Data Title Version\n");
printf(" -content <file>:<index>:<id> Specify content files\n");
printf(" -major <version> Major version\n");
printf(" -minor <version> Minor version\n");
printf(" -micro <version> Micro version\n");
printf(" -dver <version> Data-title version\n");
printf(" -deviceid <hex id> 3DS unique device ID\n");
printf(" -esaccid <hex id> e-Shop account ID\n");
printf(" -rand Use a random title key\n");
printf(" -cci <cci path> Convert CCI to CIA\n");
printf(" -srl <srl path> Use TWL SRL as Content0\n");
printf(" -dlc Create DLC CIA\n");
printf(" -srl <srl file> Package a TWL SRL in a CIA\n");
printf("NCCH CONTAINER CONVERSION:\n");
printf(" -ccitocia <cci file> Convert CCI to CIA\n");
printf(" -ciatocci <cia file> Convert CIA to CCI\n");
printf(" -inclupd Include \"Update NCCH\" in CCI to CIA conversion\n");
}
+24 -5
View File
@@ -21,6 +21,12 @@ typedef enum
VER_DVER_MAX = 4095,
} title_ver_max;
typedef enum
{
CVER_DTYPE_TMD,
CVER_DTYPE_CIA,
} cver_data_type;
typedef enum
{
USR_PTR_PASS_FAIL = -1,
@@ -37,6 +43,7 @@ typedef enum
infile_ncch,
infile_ncsd,
infile_srl,
infile_cia,
} infile_type;
typedef enum
@@ -49,7 +56,7 @@ typedef enum
NCCH
} output_format;
static const char output_extention[4][5] = {".cxi",".cfa",".cci",".cia"};
static const char output_extention[5][5] = {".cxi",".cfa",".cci",".cia",".app"};
/* This does not follow style, so the rsf string names match the variables where they're stored */
typedef struct
@@ -246,6 +253,8 @@ typedef struct
typedef struct
{
struct{
bool verbose;
char *rsfPath;
bool outFileName_mallocd;
char *outFileName;
@@ -259,9 +268,10 @@ typedef struct
// Content Details
char **contentPath;
u64 contentSize[CIA_MAX_CONTENT];
char *workingFilePath;
infile_type workingFileType; // Could Be ncch/ncsd/srl. This is mainly used for CIA gen
infile_type workingFileType; // Could Be ncch/ncsd/srl/cia.
buffer_struct workingFile;
} common;
@@ -282,23 +292,32 @@ typedef struct
char *exheaderPath; // for .code details
char *plainRegionPath; // prebuilt Plain Region
char *romfsPath; // Prebuild _cleartext_ romfs binary
bool useSecCrypto;
u8 keyXID;
} ncch; // Ncch0 Build
struct{
bool useSDKStockData; // incase we want to use the SDK stock data, for whatever reason.
bool dontModifyNcchTitleID;
bool closeAlignWritableRegion;
char *cverCiaPath;
u8 cverDataType;
char *cverDataPath;
} cci; // CCI Settings
struct{
bool randomTitleKey;
bool encryptCia;
bool DlcContent;
bool includeUpdateNcch;
bool useNormTitleVer;
bool useDataTitleVer;
u16 titleVersion[3];
u32 deviceId;
u32 eshopAccId;
u64 contentId[CIA_MAX_CONTENT]; // For CIA
} cia; // CIA Settings
@@ -306,6 +325,6 @@ typedef struct
// Prototypes
void init_UserSettings(user_settings *usr_settings);
void free_UserSettings(user_settings *usr_settings);
void init_UserSettings(user_settings *set);
void free_UserSettings(user_settings *set);
int ParseArgs(int argc, char *argv[], user_settings *usr_settings);
+80 -48
View File
@@ -1,25 +1,9 @@
#include "lib.h"
#include "utf.h"
// Memory
void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base)
{
char tmp[size][2];
unsigned char *byte_array = malloc(size*sizeof(unsigned char));
memset(byte_array, 0, size);
memset(destination, 0, size);
memset(tmp, 0, size*2);
for (int i = 0; i < size; i ++){
tmp[i][0] = source[(i*2)];
tmp[i][1] = source[((i*2)+1)];
tmp[i][2] = '\0';
byte_array[i] = (unsigned char)strtol(tmp[i], NULL, base);
}
endian_memcpy(destination,byte_array,size,endianness);
free(byte_array);
}
#include "polarssl/base64.h"
// Memory
void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness)
{
for (u32 i = 0; i < size; i++){
@@ -65,13 +49,13 @@ u64 align(u64 value, u64 alignment)
return value;
}
u64 min_u64(u64 a, u64 b)
u64 min64(u64 a, u64 b)
{
if(a < b) return a;
return b;
}
u64 max_u64(u64 a, u64 b)
u64 max64(u64 a, u64 b)
{
if(a > b) return a;
return b;
@@ -187,6 +171,56 @@ int str_utf8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len)
}
#endif
// Base64
bool IsValidB64Char(char chr)
{
return (isalnum(chr) || chr == '+' || chr == '/' || chr == '=');
}
u32 b64_strlen(char *str)
{
u32 count = 0;
u32 i = 0;
while(str[i] != 0x0){
if(IsValidB64Char(str[i])) {
//printf("Is Valid: %c\n",str[i]);
count++;
}
i++;
}
return count;
}
void b64_strcpy(char *dst, char *src)
{
u32 src_len = strlen(src);
u32 j = 0;
for(u32 i = 0; i < src_len; i++){
if(IsValidB64Char(src[i])){
dst[j] = src[i];
j++;
}
}
dst[j] = 0;
//memdump(stdout,"src: ",(u8*)src,src_len+1);
//memdump(stdout,"dst: ",(u8*)dst,j+1);
}
int b64_decode(u8 *dst, char *src, u32 dst_size)
{
int ret;
u32 size = dst_size;
ret = base64_decode(dst,(size_t*)&size,(const u8*)src,strlen(src));
if(size != dst_size)
ret = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
return ret;
}
// Pseudo-Random Number Generator
void initRand(void)
{
@@ -227,7 +261,7 @@ bool AssertFile(char *filename)
#endif
}
u64 GetFileSize_u64(char *filename)
u64 GetFileSize64(char *filename)
{
#ifdef _WIN32
struct _stat64 st;
@@ -262,7 +296,7 @@ char *getcwdir(char *buffer,int maxlen)
#endif
}
int TruncateFile_u64(char *filename, u64 filelen)
int TruncateFile64(char *filename, u64 filelen)
{
#ifdef _WIN32
HANDLE fh;
@@ -291,7 +325,7 @@ int TruncateFile_u64(char *filename, u64 filelen)
// Wide Char IO
#ifdef _WIN32
u64 wGetFileSize_u64(u16 *filename)
u64 wGetFileSize64(u16 *filename)
{
struct _stat64 st;
_wstat64((wchar_t*)filename, &st);
@@ -302,12 +336,10 @@ u64 wGetFileSize_u64(u16 *filename)
//IO Misc
u8* ImportFile(char *file, u64 size)
{
u64 fsize = GetFileSize_u64(file);
if(size > 0){
if(size != fsize){
fprintf(stderr,"[!] %s has an invalid size (0x%"PRIx64")\n",file, fsize);
return NULL;
}
u64 fsize = GetFileSize64(file);
if(size > 0 && size != fsize){
fprintf(stderr,"[!] %s has an invalid size (0x%"PRIx64")\n",file, fsize);
return NULL;
}
u8 *data = (u8*)calloc(1,fsize);
@@ -328,7 +360,7 @@ void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output)
fwrite(buffer,size,1,output);
}
void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file)
void ReadFile64(void *outbuff, u64 size, u64 offset, FILE *file)
{
fseek_64(file,offset);
fread(outbuff,size,1,file);
@@ -368,32 +400,32 @@ u32 u8_to_u32(u8 *value, u8 endianness)
u64 u8_to_u64(u8 *value, u8 endianness)
{
u64 u64_return = 0;
u64 ret = 0;
switch(endianness){
case(BE):
u64_return |= (u64)value[7]<<0;
u64_return |= (u64)value[6]<<8;
u64_return |= (u64)value[5]<<16;
u64_return |= (u64)value[4]<<24;
u64_return |= (u64)value[3]<<32;
u64_return |= (u64)value[2]<<40;
u64_return |= (u64)value[1]<<48;
u64_return |= (u64)value[0]<<56;
ret |= (u64)value[7]<<0;
ret |= (u64)value[6]<<8;
ret |= (u64)value[5]<<16;
ret |= (u64)value[4]<<24;
ret |= (u64)value[3]<<32;
ret |= (u64)value[2]<<40;
ret |= (u64)value[1]<<48;
ret |= (u64)value[0]<<56;
break;
//return (value[7]<<0) | (value[6]<<8) | (value[5]<<16) | (value[4]<<24) | (value[3]<<32) | (value[2]<<40) | (value[1]<<48) | (value[0]<<56);
case(LE):
u64_return |= (u64)value[0]<<0;
u64_return |= (u64)value[1]<<8;
u64_return |= (u64)value[2]<<16;
u64_return |= (u64)value[3]<<24;
u64_return |= (u64)value[4]<<32;
u64_return |= (u64)value[5]<<40;
u64_return |= (u64)value[6]<<48;
u64_return |= (u64)value[7]<<56;
ret |= (u64)value[0]<<0;
ret |= (u64)value[1]<<8;
ret |= (u64)value[2]<<16;
ret |= (u64)value[3]<<24;
ret |= (u64)value[4]<<32;
ret |= (u64)value[5]<<40;
ret |= (u64)value[6]<<48;
ret |= (u64)value[7]<<56;
break;
//return (value[0]<<0) | (value[1]<<8) | (value[2]<<16) | (value[3]<<24) | (value[4]<<32) | (value[5]<<40) | (value[6]<<48) | (value[7]<<56);
}
return u64_return;
return ret;
}
int u16_to_u8(u8 *out_value, u16 in_value, u8 endianness)
+12 -7
View File
@@ -7,7 +7,6 @@ typedef struct
} buffer_struct;
// Memory
void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base);
void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness);
int CopyData(u8 **dest, u8 *source, u64 size);
void rndset(void *ptr, u64 num);
@@ -15,8 +14,8 @@ void clrmem(void *ptr, u64 num);
// MISC
u64 align(u64 value, u64 alignment);
u64 min_u64(u64 a, u64 b);
u64 max_u64(u64 a, u64 b);
u64 min64(u64 a, u64 b);
u64 max64(u64 a, u64 b);
// Strings
void memdump(FILE* fout, const char* prefix, const u8* data, u32 size);
@@ -28,6 +27,12 @@ int str_u32_to_u16(u16 **dst, u32 *dst_len, u32 *src, u32 src_len);
int str_utf8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len);
#endif
// Base64
bool IsValidB64Char(char chr);
u32 b64_strlen(char *str);
void b64_strcpy(char *dst, char *src);
int b64_decode(u8 *dst, char *src, u32 dst_size);
// Pseudo-Random Number Generator
void initRand(void);
u8 u8GetRand(void);
@@ -37,20 +42,20 @@ u64 u64GetRand(void);
//Char IO
bool AssertFile(char *filename);
u64 GetFileSize_u64(char *filename);
u64 GetFileSize64(char *filename);
int makedir(const char* dir);
char *getcwdir(char *buffer,int maxlen);
int TruncateFile_u64(char *filename, u64 filelen);
int TruncateFile64(char *filename, u64 filelen);
//Wide Char IO
#ifdef _WIN32
u64 wGetFileSize_u64(u16 *filename);
u64 wGetFileSize64(u16 *filename);
#endif
//IO Misc
u8* ImportFile(char *file, u64 size);
void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output);
void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file);
void ReadFile64(void *outbuff, u64 size, u64 offset, FILE *file);
int fseek_64(FILE *fp, u64 file_pos);
//Data Size conversion
+2 -5
View File
@@ -11,17 +11,14 @@ void CheckEvent(ctr_yaml_context *ctx);
void BadYamlFormatting(void);
// Code
int GetYamlSettings(user_settings *set)
int GetRsfSettings(user_settings *set)
{
memset(&set->common.rsfSet,0,sizeof(rsf_settings));
int ret = 0;
if(set->common.rsfPath) {
FILE *rsf = fopen(set->common.rsfPath,"rb");
if(!rsf) {
if(!AssertFile(set->common.rsfPath)) {
fprintf(stderr,"[RSF ERROR] Failed to open %s\n",set->common.rsfPath);
return FAILED_TO_OPEN_FILE;
}
fclose(rsf);
ret = ParseSpecFile(&set->common.rsfSet,set->common.rsfPath, &set->dname);
}
return ret;
+1 -1
View File
@@ -31,7 +31,7 @@ typedef struct
} ctr_yaml_context;
// Public Prototypes
int GetYamlSettings(user_settings *set);
int GetRsfSettings(user_settings *set);
// For scalar events
char *GetYamlString(ctr_yaml_context *ctx);