diff --git a/ctrtool/ctr.c b/ctrtool/ctr.c index e5198f7..54cfc0f 100644 --- a/ctrtool/ctr.c +++ b/ctrtool/ctr.c @@ -4,6 +4,7 @@ #include #include "ctr.h" +#include "utils.h" void ctr_set_iv( ctr_aes_context* ctx, @@ -15,23 +16,30 @@ void ctr_set_iv( ctr_aes_context* ctx, void ctr_add_counter( ctr_aes_context* ctx, u32 block_num ) { - u32 i, j; - for (i = 0; i < block_num; i++) { - for (j = 0x10; j > 0; j--) { - // increment u8 by 1 - ctx->ctr[j - 1]++; + u32 ctr[4]; + ctr[3] = getbe32(&ctx->ctr[0]); + ctr[2] = getbe32(&ctx->ctr[4]); + ctr[1] = getbe32(&ctx->ctr[8]); + ctr[0] = getbe32(&ctx->ctr[12]); - // if it didn't overflow to 0, then we can exit now - if (ctx->ctr[j - 1]) - break; - - // if we reach here, the next u8 needs to be incremented - - // Loop to beginning back if needed - if (j == 1) - j = 0x10; + for (u32 i = 0; i < 4; i++) { + u64 total = ctr[i] + block_num; + // if there wasn't a wrap around, add the two together and exit + if (total <= 0xffffffff) { + ctr[i] += block_num; + break; } + + // add the difference + ctr[i] = (u32)(total - 0x100000000); + // carry to next word + block_num = (u32)(total >> 32); } + + putbe32(ctx->ctr + 0x00, ctr[3]); + putbe32(ctx->ctr + 0x04, ctr[2]); + putbe32(ctx->ctr + 0x08, ctr[1]); + putbe32(ctx->ctr + 0x0C, ctr[0]); } void ctr_set_counter( ctr_aes_context* ctx, @@ -41,11 +49,15 @@ void ctr_set_counter( ctr_aes_context* ctx, } -void ctr_init_counter( ctr_aes_context* ctx, - u8 key[16], - u8 ctr[16] ) +void ctr_init_key(ctr_aes_context* ctx, + u8 key[16]) { aes_setkey_enc(&ctx->aes, key, 128); +} + +void ctr_init_counter( ctr_aes_context* ctx, + u8 ctr[16] ) +{ ctr_set_counter(ctx, ctr); } diff --git a/ctrtool/ctr.h b/ctrtool/ctr.h index 66caff7..48b61e5 100644 --- a/ctrtool/ctr.h +++ b/ctrtool/ctr.h @@ -61,10 +61,12 @@ void ctr_add_counter( ctr_aes_context* ctx, void ctr_set_counter( ctr_aes_context* ctx, u8 ctr[16] ); +void ctr_init_key(ctr_aes_context* ctx, + u8 key[16]); + void ctr_init_counter( ctr_aes_context* ctx, - u8 key[16], - u8 ctr[16] ); + u8 ctr[16] ); void ctr_crypt_counter_block( ctr_aes_context* ctx, diff --git a/ctrtool/exefs.c b/ctrtool/exefs.c index 3618043..e732e4c 100644 --- a/ctrtool/exefs.c +++ b/ctrtool/exefs.c @@ -124,7 +124,8 @@ void exefs_save(exefs_context* ctx, u32 index, u32 flags) } fseeko64(ctx->file, ctx->offset + offset, SEEK_SET); - ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); + ctr_init_key(&ctx->aes, ctx->key); + ctr_init_counter(&ctx->aes, ctx->counter); ctr_add_counter(&ctx->aes, offset / 0x10); if (index == 0 && (ctx->compressedflag || (flags & DecompressCodeFlag)) && ((flags & RawFlag) == 0)) @@ -210,10 +211,12 @@ void exefs_read_header(exefs_context* ctx, u32 flags) fseeko64(ctx->file, ctx->offset, SEEK_SET); fread(&ctx->header, 1, sizeof(exefs_header), ctx->file); - ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); - - if (ctx->encrypted) + if (ctx->encrypted) { + ctr_init_key(&ctx->aes, ctx->key); + ctr_init_counter(&ctx->aes, ctx->counter); ctr_crypt_counter(&ctx->aes, (u8*)&ctx->header, (u8*)&ctx->header, sizeof(exefs_header)); + } + } void exefs_calculate_hash(exefs_context* ctx, u8 hash[32]) @@ -269,7 +272,8 @@ int exefs_verify(exefs_context* ctx, u32 index, u32 flags) return 0; fseeko64(ctx->file, ctx->offset + offset, SEEK_SET); - ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); + ctr_init_key(&ctx->aes, ctx->key); + ctr_init_counter(&ctx->aes, ctx->counter); ctr_add_counter(&ctx->aes, offset / 0x10); ctr_sha_256_init(&ctx->sha); diff --git a/ctrtool/exheader.c b/ctrtool/exheader.c index 5784479..4a96f0f 100644 --- a/ctrtool/exheader.c +++ b/ctrtool/exheader.c @@ -93,7 +93,8 @@ void exheader_read(exheader_context* ctx, u32 actions) fseeko64(ctx->file, ctx->offset, SEEK_SET); fread(&ctx->header, 1, sizeof(exheader_header), ctx->file); - ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); + ctr_init_key(&ctx->aes, ctx->key); + ctr_init_counter(&ctx->aes, ctx->counter); if (ctx->encrypted) ctr_crypt_counter(&ctx->aes, (u8*)&ctx->header, (u8*)&ctx->header, sizeof(exheader_header)); diff --git a/ctrtool/ivfc.c b/ctrtool/ivfc.c index 041afda..4a77a67 100644 --- a/ctrtool/ivfc.c +++ b/ctrtool/ivfc.c @@ -38,7 +38,7 @@ void ivfc_set_encrypted(ivfc_context* ctx, u32 encrypted) void ivfc_set_key(ivfc_context* ctx, u8 key[16]) { - memcpy(ctx->key, key, 16); + ctr_init_key(&ctx->aes, key); } void ivfc_set_counter(ivfc_context* ctx, u8 counter[16]) @@ -50,8 +50,14 @@ void ivfc_fseek(ivfc_context* ctx, u64 offset) { u64 data_pos = offset - ctx->offset; fseeko64(ctx->file, offset, SEEK_SET); - ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); - ctr_add_counter(&ctx->aes, (u32) (data_pos / 0x10)); + + if (ctx->encrypted) { + //printf("start fseek encrypted prep\n"); + ctr_init_counter(&ctx->aes, ctx->counter); + //printf("middle fseek encrypted prep\n"); + ctr_add_counter(&ctx->aes, (u32)(data_pos / 0x10)); + //printf("finish fseek encrypted prep\n"); + } } size_t ivfc_fread(ivfc_context* ctx, void* buffer, size_t size, size_t count) @@ -124,31 +130,54 @@ void ivfc_verify(ivfc_context* ctx, u32 flags) level->hashcheck = Fail; } - for(i=0; ilevelcount; i++) - { - ivfc_level* level = ctx->level + i; + // Import IVFC level hashes + uint8_t *levelhash[IVFC_MAX_LEVEL] = { NULL }; - blockcount = (u32) (level->datasize / level->hashblocksize); - if (level->datasize % level->hashblocksize != 0) + for (i=0; ilevelcount; i++) + { + blockcount = (u32)(ctx->level[i].datasize / ctx->level[i].hashblocksize); + u32 read_size = align(blockcount * 0x20, ctx->level[i].hashblocksize); + levelhash[i] = malloc(read_size); + ivfc_read(ctx, ctx->level[i].hashoffset, read_size, levelhash[i]); + } + + // Verify blocks + for (i=0; ilevelcount; i++) + { + blockcount = (u32) (ctx->level[i].datasize / ctx->level[i].hashblocksize); + if (ctx->level[i].datasize % ctx->level[i].hashblocksize != 0) { fprintf(stderr, "Error, IVFC block size mismatch\n"); return; } - level->hashcheck = Good; + ctx->level[i].hashcheck = Good; - for(j=0; jdataoffset + level->hashblocksize * j, level->hashblocksize, calchash); - ivfc_read(ctx, level->hashoffset + 0x20 * j, 0x20, testhash); + // a hash level + if (i < 2) { + ctr_sha_256(levelhash[i+1] + ctx->level[i].hashblocksize * j, ctx->level[i].hashblocksize, calchash); + } + // a data level + else { + ivfc_read(ctx, ctx->level[i].dataoffset + j * ctx->level[i].hashblocksize, ctx->level[i].hashblocksize, ctx->buffer); + ctr_sha_256(ctx->buffer, (u32)ctx->level[i].hashblocksize, calchash); + } - if (memcmp(calchash, testhash, 0x20) != 0) - level->hashcheck = Fail; + if (memcmp(calchash, levelhash[i] + 0x20 * j, 0x20) != 0) { + ctx->level[i].hashcheck = Fail; + } + } } + + // Free level hashes + for (int i = 0; i < 3; i++) { + free(levelhash[i]); + } } void ivfc_read(ivfc_context* ctx, u64 offset, u64 size, u8* buffer) diff --git a/ctrtool/ivfc.h b/ctrtool/ivfc.h index 9662f45..67b5c7e 100644 --- a/ctrtool/ivfc.h +++ b/ctrtool/ivfc.h @@ -45,7 +45,6 @@ typedef struct u64 size; settings* usersettings; u8 counter[16]; - u8 key[16]; ctr_aes_context aes; int encrypted; diff --git a/ctrtool/ncch.c b/ctrtool/ncch.c index 8d2a9ff..b553b60 100644 --- a/ctrtool/ncch.c +++ b/ctrtool/ncch.c @@ -135,7 +135,8 @@ int ncch_extract_prepare(ncch_context* ctx, u32 type, u32 flags) ctx->extractflags = flags; fseeko64(ctx->file, offset, SEEK_SET); ncch_get_counter(ctx, counter, type); - ctr_init_counter(&ctx->aes, ctx->key, counter); + ctr_init_key(&ctx->aes, ctx->key); + ctr_init_counter(&ctx->aes, counter); return 1; diff --git a/ctrtool/romfs.c b/ctrtool/romfs.c index f8c9ffb..6f00467 100644 --- a/ctrtool/romfs.c +++ b/ctrtool/romfs.c @@ -38,6 +38,7 @@ void romfs_set_encrypted(romfs_context* ctx, u32 encrypted) void romfs_set_key(romfs_context* ctx, u8 key[16]) { memcpy(ctx->key, key, 16); + ctr_init_key(&ctx->aes, key); } void romfs_set_counter(romfs_context* ctx, u8 counter[16]) @@ -49,8 +50,11 @@ void romfs_fseek(romfs_context* ctx, u64 offset) { u64 data_pos = offset - ctx->offset; fseeko64(ctx->file, offset, SEEK_SET); - ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); - ctr_add_counter(&ctx->aes, (u32) (data_pos / 0x10)); + + if (ctx->encrypted) { + ctr_init_counter(&ctx->aes, ctx->counter); + ctr_add_counter(&ctx->aes, (u32)(data_pos / 0x10)); + } } size_t romfs_fread(romfs_context* ctx, void* buffer, size_t size, size_t count)