void cia_verify_contents(cia_context *ctx, u32 actions) { u16 contentflags; ctr_tmd_body *body; ctr_tmd_contentchunk *chunk; u8 *verify_buf; u32 content_size=0; int i; // verify TMD content hashes, requires decryption .. body = tmd_get_body(&ctx->tmd); chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS)); fseek(ctx->file, ctx->offset + ctx->offsetcontent, SEEK_SET); for(i = 0; i < getbe16(body->contentcount); i++) { content_size = getbe64(chunk->size) & 0xffffffff; contentflags = getbe16(chunk->type); verify_buf = malloc(content_size); fread(verify_buf, content_size, 1, ctx->file); if(contentflags & 1 && !(actions & PlainFlag)) // Decrypt if needed { ctx->iv[0] = (getbe16(chunk->index) >> 8) & 0xff; ctx->iv[1] = getbe16(chunk->index) & 0xff; ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv); ctr_decrypt_cbc(&ctx->aes, verify_buf, verify_buf, content_size); } if (ctr_sha_256_verify(verify_buf, content_size, chunk->hash) == Good) ctx->tmd.content_hash_stat[i] = 1; else ctx->tmd.content_hash_stat[i] = 2; free(verify_buf); chunk++; }
void tik_decrypt_titlekey(tik_context* ctx, u8 decryptedkey[0x10]) { u8 iv[16]; u8* keyX = settings_get_common_keyX(ctx->usersettings); u8* keyY = settings_get_common_keyY(ctx->usersettings, ctx->tik.commonkey_idx); u8 key[16]; memset(decryptedkey, 0, 0x10); if (!keyX) { fprintf(stdout, "Warning, could not read common key.\n"); } else { ctr_aes_keygen(keyX, keyY, key); memset(iv, 0, 0x10); memcpy(iv, ctx->tik.title_id, 8); ctr_init_cbc_decrypt(&ctx->aes, key, iv); ctr_decrypt_cbc(&ctx->aes, ctx->tik.encrypted_title_key, decryptedkey, 0x10); } }
void cia_save(cia_context* ctx, u32 type, u32 flags) { u32 offset; u32 size; u16 contentflags; u8 docrypto; filepath* path = 0; ctr_tmd_body *body; ctr_tmd_contentchunk *chunk; int i; char tmpname[255]; switch(type) { case CIATYPE_CERTS: offset = ctx->offsetcerts; size = ctx->sizecert; path = settings_get_certs_path(ctx->usersettings); break; case CIATYPE_TIK: offset = ctx->offsettik; size = ctx->sizetik; path = settings_get_tik_path(ctx->usersettings); break; case CIATYPE_TMD: offset = ctx->offsettmd; size = ctx->sizetmd; path = settings_get_tmd_path(ctx->usersettings); break; case CIATYPE_CONTENT: offset = ctx->offsetcontent; size = ctx->sizecontent; path = settings_get_content_path(ctx->usersettings); break; case CIATYPE_META: offset = ctx->offsetmeta; size = ctx->sizemeta; path = settings_get_meta_path(ctx->usersettings);; break; default: fprintf(stderr, "Error, unknown CIA type specified\n"); return; break; } if (path == 0 || path->valid == 0) return; switch(type) { case CIATYPE_CERTS: fprintf(stdout, "Saving certs to %s\n", path->pathname); break; case CIATYPE_TIK: fprintf(stdout, "Saving tik to %s\n", path->pathname); break; case CIATYPE_TMD: fprintf(stdout, "Saving tmd to %s\n", path->pathname); break; case CIATYPE_CONTENT: body = tmd_get_body(&ctx->tmd); chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS)); for(i = 0; i < getbe16(body->contentcount); i++) { sprintf(tmpname, "%s.%04x.%08x", path->pathname, getbe16(chunk->index), getbe32(chunk->id)); fprintf(stdout, "Saving content #%04x to %s\n", getbe16(chunk->index), tmpname); contentflags = getbe16(chunk->type); docrypto = contentflags & 1 && !(flags & PlainFlag); if(docrypto) // Decrypt if needed { ctx->iv[0] = (getbe16(chunk->index) >> 8) & 0xff; ctx->iv[1] = getbe16(chunk->index) & 0xff; ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv); } cia_save_blob(ctx, tmpname, offset, getbe64(chunk->size) & 0xffffffff, docrypto); offset += getbe64(chunk->size) & 0xffffffff; chunk++; } memset(ctx->iv, 0, 16); return; break; case CIATYPE_META: fprintf(stdout, "Saving meta to %s\n", path->pathname); break; } cia_save_blob(ctx, path->pathname, offset, size, 0); }