Merge pull request #18 from 3DSGuy/master

house keeping
This commit is contained in:
applestash
2014-09-11 20:09:42 +08:00
26 changed files with 174 additions and 267 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
OBJS = keyset.o main.o ctr.o ncsd.o cia.o tik.o tmd.o filepath.o lzss.o exheader.o exefs.o ncch.o utils.o settings.o firm.o cwav.o stream.o romfs.o ivfc.o
POLAR_OBJS = polarssl/aes.o polarssl/bignum.o polarssl/rsa.o polarssl/sha2.o
TINYXML_OBJS = tinyxml/tinystr.o tinyxml/tinyxml.o tinyxml/tinyxmlerror.o tinyxml/tinyxmlparser.o
LIBS = -lstdc++
LIBS = -static-libstdc++
CXXFLAGS = -I.
CFLAGS = -Wall -Wno-unused-variable -Wno-unused-but-set-variable -I.
OUTPUT = ctrtool
+4 -2
View File
@@ -217,12 +217,14 @@ void cia_process(cia_context* ctx, u32 actions)
if (settings_get_common_key(ctx->usersettings))
tik_get_decrypted_titlekey(&ctx->tik, ctx->titlekey);
else if(settings_get_title_key(ctx->usersettings))
memcpy(ctx->titlekey, settings_get_title_key(ctx->usersettings), 16);
tmd_set_file(&ctx->tmd, ctx->file);
tmd_set_offset(&ctx->tmd, ctx->offsettmd);
tmd_set_size(&ctx->tmd, ctx->sizetmd);
tmd_set_usersettings(&ctx->tmd, ctx->usersettings);
tmd_process(&ctx->tmd, actions);
tmd_process(&ctx->tmd, (actions & ~InfoFlag));
if (actions & VerifyFlag)
{
+1
View File
@@ -26,6 +26,7 @@ typedef enum
FILETYPE_LZSS,
FILETYPE_FIRM,
FILETYPE_CWAV,
FILETYPE_EXEFS,
FILETYPE_ROMFS
} ctr_filetypes;
+3 -1
View File
@@ -129,7 +129,7 @@ void exefs_save(exefs_context* ctx, u32 index, u32 flags)
ctr_init_counter(&ctx->aes, ctx->key, ctx->counter);
ctr_add_counter(&ctx->aes, offset / 0x10);
if (index == 0 && ctx->compressedflag && ((flags & RawFlag) == 0))
if (index == 0 && (ctx->compressedflag || (flags & DecompressCodeFlag)) && ((flags & RawFlag) == 0))
{
fprintf(stdout, "Decompressing section %s to %s...\n", name, outfname);
@@ -200,6 +200,8 @@ void exefs_save(exefs_context* ctx, u32 index, u32 flags)
}
clean:
if (fout)
fclose(fout);
free(compressedbuffer);
free(decompressedbuffer);
return;
+12
View File
@@ -175,6 +175,8 @@ void keyset_merge(keyset* keys, keyset* src)
keyset_set_key128(&keys->ncchfixedsystemkey, src->ncchfixedsystemkey.data);
if (src->commonkey.valid)
keyset_set_key128(&keys->commonkey, src->commonkey.data);
if (src->titlekey.valid)
keyset_set_key128(&keys->titlekey, src->titlekey.data);
}
void keyset_set_key128(key128* key, unsigned char* keydata)
@@ -198,6 +200,16 @@ void keyset_parse_commonkey(keyset* keys, char* keytext, int keylen)
keyset_parse_key128(&keys->commonkey, keytext, keylen);
}
void keyset_set_titlekey(keyset* keys, unsigned char* keydata)
{
keyset_set_key128(&keys->titlekey, keydata);
}
void keyset_parse_titlekey(keyset* keys, char* keytext, int keylen)
{
keyset_parse_key128(&keys->titlekey, keytext, keylen);
}
void keyset_set_ncchkey(keyset* keys, unsigned char* keydata)
{
keyset_set_key128(&keys->ncchkey, keydata);
+3
View File
@@ -43,6 +43,7 @@ typedef struct
typedef struct
{
key128 commonkey;
key128 titlekey;
key128 ncchkey;
key128 ncchfixedsystemkey;
rsakey2048 ncsdrsakey;
@@ -56,6 +57,8 @@ int keyset_load(keyset* keys, const char* fname, int verbose);
void keyset_merge(keyset* keys, keyset* src);
void keyset_set_commonkey(keyset* keys, unsigned char* keydata);
void keyset_parse_commonkey(keyset* keys, char* keytext, int keylen);
void keyset_set_titlekey(keyset* keys, unsigned char* keydata);
void keyset_parse_titlekey(keyset* keys, char* keytext, int keylen);
void keyset_set_ncchkey(keyset* keys, unsigned char* keydata);
void keyset_parse_ncchkey(keyset* keys, char* keytext, int keylen);
void keyset_set_ncchfixedsystemkey(keyset* keys, unsigned char* keydata);
+28 -4
View File
@@ -53,15 +53,16 @@ static void usage(const char *argv0)
" -y, --verify Verify hashes and signatures.\n"
" --unitsize=size Set media unit size (default 0x200).\n"
" --commonkey=key Set common key.\n"
" --titlekey=key Set tik title key.\n"
" --ncchkey=key Set ncch key.\n"
" --ncchsyskey=key Set ncch fixed system key.\n"
" --showkeys Show the keys being used.\n"
" -t, --intype=type Specify input file type [ncsd, ncch, exheader, cia, tmd, lzss,\n"
" firm, cwav, romfs]\n"
" firm, cwav, exefs, romfs]\n"
"LZSS options:\n"
" --lzssout=file Specify lzss output file\n"
"CXI/CCI options:\n"
" -n, --ncch=offs Specify offset for NCCH header.\n"
" -n, --ncch=index Specify NCCH partition index.\n"
" --exefs=file Specify ExeFS file path.\n"
" --exefsdir=dir Specify ExeFS directory path.\n"
" --romfs=file Specify RomFS file path.\n"
@@ -78,6 +79,9 @@ static void usage(const char *argv0)
"CWAV options:\n"
" --wav=file Specify wav output file.\n"
" --wavloops=count Specify wav loop count, default 0.\n"
"EXEFS options:\n"
" --decompresscode Decompress .code section\n"
" (only needed when using raw EXEFS file)\n"
"ROMFS options:\n"
" --romfsdir=dir Specify RomFS directory path.\n"
" --listromfs List files in RomFS.\n"
@@ -93,7 +97,7 @@ int main(int argc, char* argv[])
u8 magic[4];
char infname[512];
int c;
u32 ncchoffset = ~0;
u32 ncchindex = 0;
char keysetfname[512] = "keys.xml";
keyset tmpkeys;
unsigned int checkkeysetfile = 0;
@@ -142,6 +146,8 @@ int main(int argc, char* argv[])
{"listromfs", 0, NULL, 18},
{"wavloops", 1, NULL, 19},
{"logo", 1, NULL, 20},
{"decompresscode", 0, NULL, 21},
{"titlekey", 1, NULL, 22},
{NULL},
};
@@ -176,7 +182,7 @@ int main(int argc, char* argv[])
break;
case 'n':
ncchoffset = strtoul(optarg, 0, 0);
ncchindex = strtoul(optarg, 0, 0);
break;
case 'k':
@@ -201,6 +207,8 @@ int main(int argc, char* argv[])
ctx.filetype = FILETYPE_FIRM;
else if (!strcmp(optarg, "cwav"))
ctx.filetype = FILETYPE_CWAV;
else if (!strcmp(optarg, "exefs"))
ctx.filetype = FILETYPE_EXEFS;
else if (!strcmp(optarg, "romfs"))
ctx.filetype = FILETYPE_ROMFS;
break;
@@ -226,6 +234,8 @@ int main(int argc, char* argv[])
case 18: settings_set_list_romfs_files(&ctx.usersettings, 1); break;
case 19: settings_set_cwav_loopcount(&ctx.usersettings, strtoul(optarg, 0, 0)); break;
case 20: settings_set_logo_path(&ctx.usersettings, optarg); break;
case 21: ctx.actions |= DecompressCodeFlag; break;
case 22: keyset_parse_titlekey(&tmpkeys, optarg, strlen(optarg)); break;
default:
usage(argv[0]);
@@ -324,6 +334,7 @@ int main(int argc, char* argv[])
ncsd_init(&ncsdctx);
ncsd_set_file(&ncsdctx, ctx.infile);
ncsd_set_size(&ncsdctx, ctx.infilesize);
ncsd_set_ncch_index(&ncsdctx, ncchindex);
ncsd_set_usersettings(&ncsdctx, &ctx.usersettings);
ncsd_process(&ncsdctx, ctx.actions);
@@ -424,6 +435,19 @@ int main(int argc, char* argv[])
break;
}
case FILETYPE_EXEFS:
{
exefs_context exefsctx;
exefs_init(&exefsctx);
exefs_set_file(&exefsctx, ctx.infile);
exefs_set_size(&exefsctx, ctx.infilesize);
exefs_set_usersettings(&exefsctx, &ctx.usersettings);
exefs_process(&exefsctx, ctx.actions);
break;
}
case FILETYPE_ROMFS:
{
+13 -2
View File
@@ -28,6 +28,11 @@ void ncsd_set_size(ncsd_context* ctx, u32 size)
ctx->size = size;
}
void ncsd_set_ncch_index(ncsd_context* ctx, u32 ncch_index)
{
ctx->ncch_index = ncch_index;
}
void ncsd_set_usersettings(ncsd_context* ctx, settings* usersettings)
{
ctx->usersettings = usersettings;
@@ -74,9 +79,15 @@ void ncsd_process(ncsd_context* ctx, u32 actions)
if (actions & InfoFlag)
ncsd_print(ctx);
if(ctx->ncch_index > 7 || ctx->header.partitiongeometry[ctx->ncch_index].size == 0)
{
fprintf(stderr," ERROR NCSD partition %d, does not exist\n",ctx->ncch_index);
return;
}
ncch_set_file(&ctx->ncch, ctx->file);
ncch_set_offset(&ctx->ncch, ctx->header.partitiongeometry[0].offset * ncsd_get_mediaunit_size(ctx));
ncch_set_size(&ctx->ncch, ctx->header.partitiongeometry[0].size * ncsd_get_mediaunit_size(ctx));
ncch_set_offset(&ctx->ncch, ctx->header.partitiongeometry[ctx->ncch_index].offset * ncsd_get_mediaunit_size(ctx));
ncch_set_size(&ctx->ncch, ctx->header.partitiongeometry[ctx->ncch_index].size * ncsd_get_mediaunit_size(ctx));
ncch_set_usersettings(&ctx->ncch, ctx->usersettings);
ncch_process(&ctx->ncch, actions);
}
+2
View File
@@ -35,6 +35,7 @@ typedef struct
FILE* file;
u32 offset;
u32 size;
u32 ncch_index;
ctr_ncsdheader header;
settings* usersettings;
int headersigcheck;
@@ -45,6 +46,7 @@ typedef struct
void ncsd_init(ncsd_context* ctx);
void ncsd_set_offset(ncsd_context* ctx, u32 offset);
void ncsd_set_size(ncsd_context* ctx, u32 size);
void ncsd_set_ncch_index(ncsd_context* ctx, u32 ncch_index);
void ncsd_set_file(ncsd_context* ctx, FILE* file);
void ncsd_set_usersettings(ncsd_context* ctx, settings* usersettings);
int ncsd_signature_verify(const void* blob, rsakey2048* key);
+7
View File
@@ -152,6 +152,13 @@ unsigned char* settings_get_common_key(settings* usersettings)
return 0;
}
unsigned char* settings_get_title_key(settings* usersettings)
{
if (usersettings && usersettings->keys.titlekey.valid)
return usersettings->keys.titlekey.data;
else
return 0;
}
int settings_get_ignore_programid(settings* usersettings)
{
+1
View File
@@ -47,6 +47,7 @@ unsigned int settings_get_mediaunit_size(settings* usersettings);
unsigned char* settings_get_ncch_key(settings* usersettings);
unsigned char* settings_get_ncch_fixedsystemkey(settings* usersettings);
unsigned char* settings_get_common_key(settings* usersettings);
unsigned char* settings_get_title_key(settings* usersettings);
int settings_get_ignore_programid(settings* usersettings);
int settings_get_list_romfs_files(settings* usersettings);
int settings_get_cwav_loopcount(settings* usersettings);
-2
View File
@@ -42,12 +42,10 @@ void tmd_process(tmd_context* ctx, u32 actions)
fseek(ctx->file, ctx->offset, SEEK_SET);
fread(ctx->buffer, 1, ctx->size, ctx->file);
/*
if (actions & InfoFlag)
{
tmd_print(ctx);
}
*/
}
}
+2 -1
View File
@@ -21,7 +21,8 @@ enum flags
VerboseFlag = (1<<3),
VerifyFlag = (1<<4),
RawFlag = (1<<5),
ShowKeysFlag = (1<<6)
ShowKeysFlag = (1<<6),
DecompressCodeFlag = (1<<7)
};
enum validstate
+1 -1
View File
@@ -9,7 +9,7 @@ LIB_API_OBJS = crypto.o yaml_parser.o blz.o
OBJS = makerom.o $(UTILS_OBJS) $(LIB_API_OBJS) $(SETTINGS_OBJS) $(NCSD_OBJS) $(NCCH_OBJS) $(CIA_OBJS)
# Libraries
POLAR_OBJS = polarssl/aes.o polarssl/bignum.o polarssl/rsa.o polarssl/sha1.o polarssl/sha2.o polarssl/padlock.o polarssl/md.o polarssl/md_wrap.o polarssl/md2.o polarssl/md4.o polarssl/md5.o polarssl/sha4.o polarssl/base64.o polarssl/cipher.o polarssl/cipher_wrap.o polarssl/camellia.o polarssl/des.o polarssl/blowfish.o
POLAR_OBJS = polarssl/aes.o polarssl/rsa.o polarssl/sha1.o polarssl/sha2.o polarssl/base64.o polarssl/bignum.o polarssl/padlock.o polarssl/md.o polarssl/md_wrap.o polarssl/md5.o polarssl/sha4.o
YAML_OBJS = libyaml/api.o libyaml/dumper.o libyaml/emitter.o libyaml/loader.o libyaml/parser.o libyaml/reader.o libyaml/scanner.o libyaml/writer.o
# Compiler Settings
+8 -12
View File
@@ -289,7 +289,7 @@ int GetTmdDataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *
extended_hdr *exhdr = malloc(sizeof(extended_hdr));
memcpy(exhdr,ncch+ncch_ctx->exhdrOffset,sizeof(extended_hdr));
if(key != NULL)
CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr);
CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx->titleId,key,ncch_exhdr);
if(IsPatch(GetTidCategory(ciaset->common.titleId))||ciaset->content.IsCfa)
ciaset->tmd.savedataSize = 0;
@@ -334,12 +334,12 @@ int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_info *info, u8 *key)
extended_hdr *exhdr = malloc(sizeof(extended_hdr));
memcpy(exhdr,ncch+info->exhdrOffset,sizeof(extended_hdr));
if(key != NULL)
CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,info,key,ncch_exhdr);
CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,info->titleId,key,ncch_exhdr);
exefs_hdr *exefsHdr = malloc(sizeof(exefs_hdr));
memcpy(exefsHdr,ncch+info->exefsOffset,sizeof(exefs_hdr));
if(key != NULL)
CryptNcchRegion((u8*)exefsHdr,sizeof(exefs_hdr),0,info,key,ncch_exefs);
CryptNcchRegion((u8*)exefsHdr,sizeof(exefs_hdr),0,info->titleId,key,ncch_exefs);
u32 icon_size = 0;
u32 icon_offset = 0;
@@ -364,7 +364,7 @@ int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_info *info, u8 *key)
u8 *IconDestPos = (ciaset->ciaSections.meta.buffer + sizeof(cia_metadata));
memcpy(IconDestPos,ncch+info->exefsOffset+icon_offset,icon_size);
if(key != NULL)
CryptNcchRegion(IconDestPos,icon_size,icon_offset,info,key,ncch_exefs);
CryptNcchRegion(IconDestPos,icon_size,icon_offset,info->titleId,key,ncch_exefs);
//memdump(stdout,"Icon: ",IconDestPos,0x10);
}
@@ -628,7 +628,7 @@ int BuildCiaHdr(cia_settings *ciaset)
ciaset->ciaSections.metaOffset = align(ciaset->ciaSections.contentOffset+ciaset->content.totalSize,0x40);
for(int i = 0; i < ciaset->content.count; i++)
hdr->contentIndex[ciaset->content.index[i]/8] |= 1 << (7 - (ciaset->content.index[i] & 7));
hdr->contentIndex[ciaset->content.index[i]/8] |= 0x80 >> (ciaset->content.index[i] & 7);
return 0;
}
@@ -645,19 +645,15 @@ int WriteCiaToFile(cia_settings *ciaset)
}
int CryptContent(u8 *enc, u8 *dec, u64 size, u8 *title_key, u16 index, u8 mode)
int CryptContent(u8 *input, u8 *output, u64 size, u8 *title_key, u16 index, u8 mode)
{
//generating IV
u8 iv[16];
memset(&iv,0x0,16);
clrmem(&iv,16);
iv[0] = (index >> 8) & 0xff;
iv[1] = index & 0xff;
//Crypting content
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,dec,enc,size,ENC);
else ctr_aes_cbc(&ctx,enc,dec,size,DEC);
AesCbc(title_key,iv,input,output,size,mode);
return 0;
}
+1 -1
View File
@@ -22,5 +22,5 @@ typedef struct
u8 padding1[0xfc];
} cia_metadata;
int CryptContent(u8 *enc, u8 *dec, u64 size, u8 *title_key, u16 index, u8 mode);
int CryptContent(u8 *input, u8 *output, u64 size, u8 *title_key, u16 index, u8 mode);
+28 -100
View File
@@ -16,115 +16,43 @@ void ctr_sha(void *data, u64 size, u8 *hash, int mode)
}
}
void ctr_add_counter(ctr_aes_context* ctx, u32 carry)
void SetAesCtrOffset(u8 *ctr, u64 offset)
{
u32 counter[4];
u32 sum;
int i;
for(i=0; i<4; i++)
counter[i] = (ctx->ctr[i*4+0]<<24) | (ctx->ctr[i*4+1]<<16) | (ctx->ctr[i*4+2]<<8) | (ctx->ctr[i*4+3]<<0);
for(i=3; i>=0; i--)
{
sum = counter[i] + carry;
if (sum < counter[i])
carry = 1;
else
carry = 0;
counter[i] = sum;
}
for(i=0; i<4; i++)
{
ctx->ctr[i*4+0] = counter[i]>>24;
ctx->ctr[i*4+1] = counter[i]>>16;
ctx->ctr[i*4+2] = counter[i]>>8;
ctx->ctr[i*4+3] = counter[i]>>0;
}
u64_to_u8(ctr+8,u8_to_u64(ctr+8,BE)|align(offset,16)/16,BE);
}
void ctr_init_counter(ctr_aes_context* ctx, u8 key[16], u8 ctr[16])
{
aes_setkey_enc(&ctx->aes, key, 128);
memcpy(ctx->ctr, ctr, 16);
}
void ctr_crypt_counter_block(ctr_aes_context* ctx, u8 input[16], u8 output[16])
{
int i;
u8 stream[16];
aes_crypt_ecb(&ctx->aes, AES_ENCRYPT, ctx->ctr, stream);
if (input)
{
for(i=0; i<16; i++)
{
output[i] = stream[i] ^ input[i];
}
}
else
{
for(i=0; i<16; i++)
output[i] = stream[i];
}
ctr_add_counter(ctx, 1);
}
void ctr_crypt_counter(ctr_aes_context* ctx, u8* input, u8* output, u32 size)
void AesCtr(u8 *key, u8 *ctr, u8 *input, u8 *output, u64 length, u64 offset)
{
u8 stream[16];
u32 i;
while(size >= 16)
{
ctr_crypt_counter_block(ctx, input, output);
if (input)
input += 16;
if (output)
output += 16;
size -= 16;
}
if (size)
{
memset(stream, 0, 16);
ctr_crypt_counter_block(ctx, stream, stream);
if (input)
{
for(i=0; i<size; i++)
output[i] = input[i] ^ stream[i];
}
else
{
memcpy(output, stream, size);
}
}
aes_context aes;
u64 nc_off = 0;
clrmem(&aes,sizeof(aes_context));
aes_setkey_enc(&aes, key, 128);
SetAesCtrOffset(ctr,offset);
aes_crypt_ctr(&aes, length, &nc_off, ctr, stream, input, output);
return;
}
void ctr_init_aes_cbc(ctr_aes_context* ctx,u8 key[16],u8 iv[16], u8 mode)
void AesCbc(u8 *key, u8 *iv, u8 *input, u8 *output, u64 length, u8 mode)
{
aes_context aes;
clrmem(&aes,sizeof(aes_context));
switch(mode){
case(ENC): aes_setkey_enc(&ctx->aes, key, 128); break;
case(DEC): aes_setkey_dec(&ctx->aes, key, 128); break;
}
memcpy(ctx->iv, iv, 16);
}
void ctr_aes_cbc(ctr_aes_context* ctx,u8* input,u8* output,u32 size,u8 mode)
{
switch(mode){
case(ENC): aes_crypt_cbc(&ctx->aes, AES_ENCRYPT, size, ctx->iv, input, output); break;
case(DEC): aes_crypt_cbc(&ctx->aes, AES_DECRYPT, size, ctx->iv, input, output); break;
case(ENC):
aes_setkey_enc(&aes, key, 128);
aes_crypt_cbc(&aes, AES_ENCRYPT, length, iv, input, output);
return;
case(DEC):
aes_setkey_dec(&aes, key, 128);
aes_crypt_cbc(&aes, AES_DECRYPT, length, iv, input, output);
return;
default:
return;
}
}
+2 -13
View File
@@ -55,13 +55,6 @@ typedef enum
RSAKEY_PUB
} rsakeytype;
typedef struct
{
u8 ctr[16];
u8 iv[16];
aes_context aes;
} ctr_aes_context;
typedef struct
{
rsa_context rsa;
@@ -74,12 +67,8 @@ extern "C" {
bool VerifySha256(void *data, u64 size, u8 hash[32]);
void ctr_sha(void *data, u64 size, u8 *hash, int mode);
// AES
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]);
void ctr_crypt_counter(ctr_aes_context* ctx, u8* input, u8* output, u32 size);
void ctr_init_aes_cbc(ctr_aes_context* ctx,u8 key[16],u8 iv[16], u8 mode);
void ctr_aes_cbc(ctr_aes_context* ctx,u8* input,u8* output,u32 size,u8 mode);
void AesCtr(u8 *key, u8 *ctr, u8 *input, u8 *output, u64 length, u64 offset);
void AesCbc(u8 *key, u8 *iv, u8 *input, u8 *output, u64 length, u8 mode);
// RSA
void ctr_rsa_free(ctr_rsa_context* ctx);
int ctr_rsa_init(ctr_rsa_context* ctx, u8 *modulus, u8 *private_exp, u8 *exponent, u8 rsa_type, u8 mode);
+5 -6
View File
@@ -65,19 +65,18 @@ u32 PredictExeFS_Size(exefs_buildctx *ctx)
int GenerateExeFS_Header(exefs_buildctx *ctx, u8 *outbuff)
{
exefs_hdr *exefs = (exefs_hdr*)outbuff;
for(int i = 0; i < ctx->fileCount; i++){
if(i == 0)
ctx->fileOffset[i] = 0;
else
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);
u32_to_u8(ctx->fileHdr[i].size,ctx->fileSize[i],LE);
ctr_sha(ctx->file[i],ctx->fileSize[i],ctx->fileHashes[9-i],CTR_SHA_256);
memcpy(exefs->fileHdr[i].name,ctx->fileName[i],8);
u32_to_u8(exefs->fileHdr[i].offset,ctx->fileOffset[i],LE);
u32_to_u8(exefs->fileHdr[i].size,ctx->fileSize[i],LE);
ctr_sha(ctx->file[i],ctx->fileSize[i],exefs->fileHashes[MAX_EXEFS_SECTIONS-1-i],CTR_SHA_256);
}
memcpy(outbuff,ctx->fileHdr,sizeof(exefs_filehdr)*10);
memcpy(outbuff+0xc0,ctx->fileHashes,0x20*10);
return 0;
}
+2 -2
View File
@@ -1,6 +1,6 @@
#pragma once
#define MAX_EXEFS_SECTIONS 10 // DO NOT CHANGE
#define MAX_EXEFS_SECTIONS 8
typedef struct
{
@@ -12,6 +12,6 @@ typedef struct
typedef struct
{
exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS];
u8 reserved[0x20];
u8 reserved[0x80];
u8 fileHashes[MAX_EXEFS_SECTIONS][0x20];
} exefs_hdr;
+32 -81
View File
@@ -19,7 +19,6 @@ int CheckCFASignature(ncch_hdr *hdr, keys_struct *keys);
int SignCXI(ncch_hdr *hdr, keys_struct *keys);
int CheckCXISignature(ncch_hdr *hdr, u8 *pubk);
void InitNcchSettings(ncch_settings *set);
void FreeNcchSettings(ncch_settings *set);
int GetNcchSettings(ncch_settings *ncchset, user_settings *usrset);
int GetBasicOptions(ncch_settings *ncchset, user_settings *usrset);
@@ -32,12 +31,7 @@ int FinaliseNcch(ncch_settings *ncchset);
int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr);
bool IsValidProductCode(char *ProductCode, bool FreeProductCode);
int BuildCommonHeader(ncch_settings *ncchset);
int EnCryptNcchRegions(ncch_settings *ncchset);
int WriteNCCHSectionsToBuffer(ncch_settings *ncchset);
// Code
int SignCFA(ncch_hdr *hdr, keys_struct *keys)
{
return ctr_sig(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cciCfaPub,keys->rsa.cciCfaPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
@@ -71,7 +65,6 @@ int build_NCCH(user_settings *usrset)
fprintf(stderr,"[NCCH ERROR] Not enough memory\n");
return MEM_ERROR;
}
InitNcchSettings(ncchset);
// Get Settings
result = GetNcchSettings(ncchset,usrset);
@@ -126,11 +119,6 @@ finish:
return result;
}
void InitNcchSettings(ncch_settings *set)
{
memset(set,0,sizeof(ncch_settings));
}
void FreeNcchSettings(ncch_settings *set)
{
if(set->componentFilePtrs.elf) fclose(set->componentFilePtrs.elf);
@@ -193,7 +181,7 @@ int GetBasicOptions(ncch_settings *ncchset, user_settings *usrset)
if(ncchset->options.IsCfa && !ncchset->options.UseRomFS){
fprintf(stderr,"[NCCH ERROR] \"Rom/HostRoot\" must be set\n");
return NCCH_BAD_YAML_SET;
return NCCH_BAD_RSF_SET;
}
return result;
@@ -352,7 +340,7 @@ int ImportLogo(ncch_settings *set)
}
else if(strcasecmp(set->rsfSet->BasicInfo.Logo,"none") != 0){
fprintf(stderr,"[NCCH ERROR] Invalid logo name\n");
return NCCH_BAD_YAML_SET;
return NCCH_BAD_RSF_SET;
}
}
return 0;
@@ -547,8 +535,8 @@ int FinaliseNcch(ncch_settings *set)
// Crypting Exheader/AcexDesc
if(set->cryptoDetails.exhdrSize){
CryptNcchRegion(exhdr,set->cryptoDetails.exhdrSize,0x0,&set->cryptoDetails,set->keys->aes.ncchKey0,ncch_exhdr);
CryptNcchRegion(acexDesc,set->cryptoDetails.acexSize,set->cryptoDetails.exhdrSize,&set->cryptoDetails,set->keys->aes.ncchKey0,ncch_exhdr);
CryptNcchRegion(exhdr,set->cryptoDetails.exhdrSize,0x0,set->cryptoDetails.titleId,set->keys->aes.ncchKey0,ncch_exhdr);
CryptNcchRegion(acexDesc,set->cryptoDetails.acexSize,set->cryptoDetails.exhdrSize,set->cryptoDetails.titleId,set->keys->aes.ncchKey0,ncch_exhdr);
}
// Crypting ExeFs Files
@@ -565,16 +553,16 @@ int FinaliseNcch(ncch_settings *set)
u32 size = u8_to_u32(exefsHdr->fileHdr[i].size,LE);
if(size)
CryptNcchRegion((exefs+offset),align(size,set->options.blockSize),offset,&set->cryptoDetails,key,ncch_exefs);
CryptNcchRegion((exefs+offset),align(size,set->options.blockSize),offset,set->cryptoDetails.titleId,key,ncch_exefs);
}
// Crypting ExeFs Header
CryptNcchRegion(exefs,sizeof(exefs_hdr),0x0,&set->cryptoDetails,set->keys->aes.ncchKey0,ncch_exefs);
CryptNcchRegion(exefs,sizeof(exefs_hdr),0x0,set->cryptoDetails.titleId,set->keys->aes.ncchKey0,ncch_exefs);
}
// Crypting RomFs
if(set->cryptoDetails.romfsSize)
CryptNcchRegion(romfs,set->cryptoDetails.romfsSize,0x0,&set->cryptoDetails,set->keys->aes.ncchKey1,ncch_romfs);
CryptNcchRegion(romfs,set->cryptoDetails.romfsSize,0x0,set->cryptoDetails.titleId,set->keys->aes.ncchKey1,ncch_romfs);
}
return 0;
@@ -591,18 +579,18 @@ int SetCommonHeaderBasicData(ncch_settings *set, ncch_hdr *hdr)
/* Setting ProgramId/TitleId */
u64 ProgramId = 0;
int result = GetProgramID(&ProgramId,set->rsfSet,false);
u64 programId = 0;
int result = GetProgramID(&programId,set->rsfSet,false);
if(result) return result;
u64_to_u8(hdr->programId,ProgramId,LE);
u64_to_u8(hdr->titleId,ProgramId,LE);
u64_to_u8(hdr->programId,programId,LE);
u64_to_u8(hdr->titleId,programId,LE);
/* Get Product Code and Maker Code */
if(set->rsfSet->BasicInfo.ProductCode){
if(!IsValidProductCode((char*)set->rsfSet->BasicInfo.ProductCode,set->options.FreeProductCode)){
fprintf(stderr,"[NCCH ERROR] Invalid Product Code\n");
return NCCH_BAD_YAML_SET;
return NCCH_BAD_RSF_SET;
}
memcpy(hdr->productCode,set->rsfSet->BasicInfo.ProductCode,strlen((char*)set->rsfSet->BasicInfo.ProductCode));
}
@@ -611,7 +599,7 @@ int SetCommonHeaderBasicData(ncch_settings *set, ncch_hdr *hdr)
if(set->rsfSet->BasicInfo.CompanyCode){
if(strlen((char*)set->rsfSet->BasicInfo.CompanyCode) != 2){
fprintf(stderr,"[NCCH ERROR] CompanyCode length must be 2\n");
return NCCH_BAD_YAML_SET;
return NCCH_BAD_RSF_SET;
}
memcpy(hdr->makerCode,set->rsfSet->BasicInfo.CompanyCode,2);
}
@@ -657,7 +645,7 @@ int SetCommonHeaderBasicData(ncch_settings *set, ncch_hdr *hdr)
else if(strcmp(set->rsfSet->BasicInfo.ContentType,"Trial") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Trial;
else{
fprintf(stderr,"[NCCH ERROR] Invalid ContentType '%s'\n",set->rsfSet->BasicInfo.ContentType);
return NCCH_BAD_YAML_SET;
return NCCH_BAD_RSF_SET;
}
}
@@ -748,7 +736,7 @@ int VerifyNcch(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput)
}
memcpy(exHdr,ncch+ncchInfo->exhdrOffset,ncchInfo->exhdrSize);
if(IsNcchEncrypted(hdr))
CryptNcchRegion((u8*)exHdr,ncchInfo->exhdrSize,0,ncchInfo,keys->aes.ncchKey0,ncch_exhdr);
CryptNcchRegion((u8*)exHdr,ncchInfo->exhdrSize,0,ncchInfo->titleId,keys->aes.ncchKey0,ncch_exhdr);
// Checking Exheader Hash to see if decryption was sucessful
if(!VerifySha256(exHdr, ncchInfo->exhdrSize, hdr->exhdrHash)){
@@ -775,7 +763,7 @@ int VerifyNcch(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput)
}
memcpy(acexDesc,ncch+ncchInfo->acexOffset,ncchInfo->acexSize);
if(IsNcchEncrypted(hdr))
CryptNcchRegion((u8*)acexDesc,ncchInfo->acexSize,ncchInfo->exhdrSize,ncchInfo,keys->aes.ncchKey0,ncch_exhdr);
CryptNcchRegion((u8*)acexDesc,ncchInfo->acexSize,ncchInfo->exhdrSize,ncchInfo->titleId,keys->aes.ncchKey0,ncch_exhdr);
if(CheckAccessDescSignature(acexDesc,keys) != 0 && !keys->rsa.isFalseSign){
if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] AccessDesc Sigcheck Failed\n");
@@ -806,7 +794,7 @@ int VerifyNcch(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput)
}
memcpy(exefs,ncch+ncchInfo->exefsOffset,ncchInfo->exefsHashDataSize);
if(IsNcchEncrypted(hdr))
CryptNcchRegion(exefs,ncchInfo->exefsHashDataSize,0,ncchInfo,keys->aes.ncchKey0,ncch_exefs);
CryptNcchRegion(exefs,ncchInfo->exefsHashDataSize,0,ncchInfo->titleId,keys->aes.ncchKey0,ncch_exefs);
if(!VerifySha256(exefs, ncchInfo->exefsHashDataSize, hdr->exefsHash)){
if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] ExeFs Hashcheck Failed\n");
free(ncchInfo);
@@ -826,7 +814,7 @@ int VerifyNcch(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput)
}
memcpy(romfs,ncch+ncchInfo->romfsOffset,ncchInfo->romfsHashDataSize);
if(IsNcchEncrypted(hdr))
CryptNcchRegion(romfs,ncchInfo->romfsHashDataSize,0,ncchInfo,keys->aes.ncchKey1,ncch_romfs);
CryptNcchRegion(romfs,ncchInfo->romfsHashDataSize,0,ncchInfo->titleId,keys->aes.ncchKey1,ncch_romfs);
if(!VerifySha256(romfs,ncchInfo->romfsHashDataSize,hdr->romfsHash)){
if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] RomFs Hashcheck Failed\n");
free(ncchInfo);
@@ -880,7 +868,7 @@ int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys)
fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n");
return -1;
}
CryptNcchRegion(romfs,ncchInfo.romfsSize,0,&ncchInfo,keys->aes.ncchKey1,ncch_romfs);
CryptNcchRegion(romfs,ncchInfo.romfsSize,0,ncchInfo.titleId,keys->aes.ncchKey1,ncch_romfs);
}
// Editing data and resigning
@@ -898,7 +886,7 @@ int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys)
fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n");
return -1;
}
CryptNcchRegion(romfs,ncchInfo.romfsSize,0,&ncchInfo,keys->aes.ncchKey1,ncch_romfs);
CryptNcchRegion(romfs,ncchInfo.romfsSize,0,ncchInfo.titleId,keys->aes.ncchKey1,ncch_romfs);
}
return 0;
@@ -1023,15 +1011,14 @@ bool SetNcchKeys(keys_struct *keys, ncch_hdr *hdr)
int GetNcchInfo(ncch_info *info, ncch_hdr *hdr)
{
memcpy(info->titleId,hdr->titleId,8);
memcpy(info->programId,hdr->programId,8);
info->titleId = u8_to_u64(hdr->titleId,LE);
info->programId = u8_to_u64(hdr->programId,LE);
u32 block_size = GetNcchBlockSize(hdr);
info->formatVersion = u8_to_u16(hdr->formatVersion,LE);
if(!IsCfa(hdr)){
info->exhdrOffset = 0x200;
info->exhdrOffset = sizeof(ncch_hdr);
info->exhdrSize = u8_to_u32(hdr->exhdrSize,LE);
info->acexOffset = (info->exhdrOffset + info->exhdrSize);
info->acexSize = sizeof(access_descriptor);
@@ -1050,53 +1037,17 @@ int GetNcchInfo(ncch_info *info, ncch_hdr *hdr)
return 0;
}
void CryptNcchRegion(u8 *buffer, u64 size, u64 src_pos, ncch_info *ctx, u8 key[16], u8 type)
void GetNcchAesCounter(u8 ctr[16], u64 titleId, u8 type)
{
if(type < 1 || type > 3)
return;
u8 counter[0x10];
ctr_aes_context aes_ctx;
memset(&aes_ctx,0x0,sizeof(ctr_aes_context));
GetNcchAesCounter(ctx,counter,type);
ctr_init_counter(&aes_ctx, key, counter);
if(src_pos > 0){
u32 carry = 0;
carry = align(src_pos,0x10);
carry /= 0x10;
ctr_add_counter(&aes_ctx,carry);
}
ctr_crypt_counter(&aes_ctx, buffer, buffer, size);
return;
clrmem(ctr,16);
u64_to_u8(ctr,titleId,BE);
ctr[8] = type;
}
void GetNcchAesCounter(ncch_info *ctx, u8 counter[16], u8 type)
void CryptNcchRegion(u8 *buffer, u64 size, u64 src_pos, u64 titleId, u8 key[16], u8 type)
{
u8 *titleId = ctx->titleId;
u32 i;
u32 x = 0;
memset(counter, 0, 16);
if (ctx->formatVersion == 2 || ctx->formatVersion == 0)
{
endian_memcpy(counter,titleId,8,LE);
counter[8] = type;
}
else if (ctx->formatVersion == 1)
{
switch(type){
case ncch_exhdr : x = ctx->exhdrOffset; break;
case ncch_exefs : x = ctx->exefsOffset; break;
case ncch_romfs : x = ctx->romfsOffset; break;
}
for(i=0; i<8; i++)
counter[i] = titleId[i];
for(i=0; i<4; i++)
counter[12+i] = x>>((3-i)*8);
}
//memdump(stdout,"CTR: ",counter,16);
u8 ctr[0x10];
GetNcchAesCounter(ctr,titleId,type);
AesCtr(key,ctr,buffer,buffer,size,src_pos);
return;
}
+6 -6
View File
@@ -20,7 +20,7 @@ typedef enum
EXEFS_CORRUPT = -14,
ROMFS_CORRUPT = -15,
// Others
NCCH_BAD_YAML_SET = -16,
NCCH_BAD_RSF_SET = -16,
DATA_POS_DNE = -17,
} ncch_errors;
@@ -75,8 +75,8 @@ typedef struct
u64 romfsOffset;
u64 romfsSize;
u64 romfsHashDataSize;
u8 titleId[8];
u8 programId[8];
u64 titleId;
u64 programId;
} ncch_info;
typedef struct
@@ -113,7 +113,7 @@ typedef struct
} ncch_hdr;
// 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);
int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys);
@@ -130,5 +130,5 @@ 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);
void GetNcchAesCounter(u8 ctr[16], u64 titleId, u8 type);
void CryptNcchRegion(u8 *buffer, u64 size, u64 src_pos, u64 titleId, u8 key[16], u8 type);
+4 -6
View File
@@ -150,9 +150,9 @@ int ImportNcchForCci(cci_settings *set)
return 0;
}
bool CanCiaBeCci(u16 cat, u16 count, tmd_content_chunk *content)
bool CanCiaBeCci(u64 titleId, u16 count, tmd_content_chunk *content)
{
if(cat != PROGRAM_ID_CATEGORY_APPLICATION && cat != PROGRAM_ID_CATEGORY_SYSTEM_APPLICATION)
if(GetTidCategory(titleId) != PROGRAM_ID_CATEGORY_APPLICATION && GetTidCategory(titleId) != PROGRAM_ID_CATEGORY_SYSTEM_APPLICATION)
return false;
if(count > CCI_MAX_CONTENT)
@@ -235,7 +235,6 @@ int ProcessCiaForCci(cci_settings *set)
tmd_content_chunk *contentInfo = GetTmdContentInfo(GetCiaTmd(set->content.data));
u64 contentOffset = GetCiaContentOffset((cia_hdr*)set->content.data);
u16 titleCat = (GetTmdTitleId(tmd) >> 32) & 0xffff;
u16 contentCount = GetTmdContentCount(tmd);
set->romInfo.saveSize = GetTmdSaveSize(tmd);
if(set->romInfo.saveSize > 0 && set->romInfo.saveSize < (u64)(128*KB))
@@ -245,7 +244,7 @@ int ProcessCiaForCci(cci_settings *set)
else if(set->romInfo.saveSize > (u64)(512*KB))
set->romInfo.saveSize = align(set->romInfo.saveSize,MB);
if(!CanCiaBeCci(titleCat,contentCount,contentInfo)){
if(!CanCiaBeCci(GetTmdTitleId(tmd),contentCount,contentInfo)){
fprintf(stderr,"[CCI ERROR] This CIA cannot be converted to CCI\n");
return INCOMPAT_CIA;
}
@@ -269,9 +268,8 @@ int ProcessCiaForCci(cci_settings *set)
set->content.dSize[index] = GetTmdContentSize(contentInfo[i]);
u8 *content = set->content.data + contentOffset;
if(IsTmdContentEncrypted(contentInfo[i])){
if(canDecrypt){
if(canDecrypt)
CryptContent(content,content,set->content.dSize[index],titleKey,i,DEC);
}
else{
fprintf(stderr,"[CCI ERROR] Failed to decrypt CIA content: 0x%08x\n",GetTmdContentId(contentInfo[i]));
return INCOMPAT_CIA;
+6 -11
View File
@@ -11,6 +11,7 @@ u32 GetContentIndexSegNum(cia_settings *set);
void SetContentIndexHeader(tik_content_index_hdr *hdr, cia_settings *set);
void SetContentIndexData(tik_content_index_struct *data, cia_settings *set);
int CryptTitleKey(u8 *input, u8 *output, u8 *titleId, keys_struct *keys, u8 mode);
int BuildTicket(cia_settings *set)
{
@@ -67,7 +68,7 @@ void SetupTicketHeader(tik_hdr *hdr, cia_settings *ciaset)
// Crypt TitleKey
if(ciaset->content.encryptCia)
CryptTitleKey(hdr->encryptedTitleKey, ciaset->common.titleKey, hdr->titleId, ciaset->keys, ENC);
CryptTitleKey(ciaset->common.titleKey, hdr->encryptedTitleKey, hdr->titleId, ciaset->keys, ENC);
else
rndset(hdr->encryptedTitleKey,AES_128_KEY_SIZE);
}
@@ -85,21 +86,15 @@ int SignTicketHeader(buffer_struct *tik, keys_struct *keys)
return ctr_sig(data,len,sig->data,keys->rsa.xsPub,keys->rsa.xsPvt,RSA_2048_SHA256,CTR_RSA_SIGN);
}
int CryptTitleKey(u8 *encKey, u8 *decKey, u8 *titleId, keys_struct *keys, u8 mode)
int CryptTitleKey(u8 *input, u8 *output, u8 *titleId, keys_struct *keys, u8 mode)
{
//Generating IV
u8 iv[16];
memset(&iv,0x0,16);
clrmem(&iv,16);
memcpy(iv,titleId,0x8);
//Setting up Aes Context
ctr_aes_context ctx;
clrmem(&ctx,sizeof(ctr_aes_context));
//Crypting TitleKey
ctr_init_aes_cbc(&ctx,keys->aes.commonKey[keys->aes.currentCommonKey],iv,mode);
if(mode == ENC) ctr_aes_cbc(&ctx,decKey,encKey,0x10,ENC);
else ctr_aes_cbc(&ctx,encKey,decKey,0x10,DEC);
AesCbc(keys->aes.commonKey[keys->aes.currentCommonKey],iv,input,output,0x10,mode);
// Return
return 0;
+1 -12
View File
@@ -1,16 +1,5 @@
#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);
int BuildTicket(cia_settings *ciaset);
+1 -3
View File
@@ -175,7 +175,5 @@ bool IsTmdContentEncrypted(tmd_content_chunk info)
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;
return VerifySha256(data, GetTmdContentSize(info), GetTmdContentHash(&info));
}