mirror of
https://github.com/DarkStore-3DS/Project_CTR.git
synced 2026-07-03 00:39:14 +00:00
+1
-1
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@ typedef enum
|
||||
FILETYPE_LZSS,
|
||||
FILETYPE_FIRM,
|
||||
FILETYPE_CWAV,
|
||||
FILETYPE_EXEFS,
|
||||
FILETYPE_ROMFS
|
||||
} ctr_filetypes;
|
||||
|
||||
|
||||
+3
-1
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
Reference in New Issue
Block a user