Line 20:
Line 20:
// Version 1.2 Decrypts contents provided you have prng seed extracted from your wii via xyzzy. (caitsith2)
// Version 1.2 Decrypts contents provided you have prng seed extracted from your wii via xyzzy. (caitsith2)
// for some unknown reason, u64s were being treated like u32s, causing tmd misalignment in my setup.
// for some unknown reason, u64s were being treated like u32s, causing tmd misalignment in my setup.
+
// Version 1.3 Verifies content hashes, and ecc (eliptic curve cryptography) signature.
Line 34:
Line 35:
static u8 md5_blanker[16];
static u8 md5_blanker[16];
static u8 prngseed[16];
static u8 prngseed[16];
+
+
static FILE *fp;
static FILE *fp;
Line 42:
Line 45:
static u16 num_contents;
static u16 num_contents;
static size_t* content_sizes;
static size_t* content_sizes;
+
static u8* hashes;
+
static u32 total_size;
typedef struct {
typedef struct {
Line 124:
Line 129:
memcpy(header.md5, md5_blanker, 16);
memcpy(header.md5, md5_blanker, 16);
md5((u8*) &header, sizeof header, md5_calc);
md5((u8*) &header, sizeof header, md5_calc);
−
+
if (memcmp(md5_file, md5_calc, 0x10)) {
if (memcmp(md5_file, md5_calc, 0x10)) {
ERROR("MD5 mismatch");
ERROR("MD5 mismatch");
Line 249:
Line 254:
printf("Part B unknown field: %x\n", unknown);
printf("Part B unknown field: %x\n", unknown);
+
write_part(data,rounded_size,"02_banner");
write_part(data, sizeof(partB_header_t), "02a_banner_header");
write_part(data, sizeof(partB_header_t), "02a_banner_header");
+
//write_part(data + sizeof(partB_header_t), partB_size - sizeof(partB_header_t), "02b_banner_compressed");
decompressed_data = decompress_lz77(data + sizeof(partB_header_t), partB_size - sizeof(partB_header_t), &decompressed_size);
decompressed_data = decompress_lz77(data + sizeof(partB_header_t), partB_size - sizeof(partB_header_t), &decompressed_size);
Line 270:
Line 277:
fprintf(stderr, "NG id: %08x\n", be32(header + 8));
fprintf(stderr, "NG id: %08x\n", be32(header + 8));
+
+
total_size = be32(header + 0x1c);
write_part(header, sizeof(header), "03_bk_header");
write_part(header, sizeof(header), "03_bk_header");
Line 298:
Line 307:
content_sizes = calloc(1, sizeof (size_t) * num_contents);
content_sizes = calloc(1, sizeof (size_t) * num_contents);
+
hashes = calloc(20, num_contents);
rec = (content_record_t*) &data[sizeof(tmd)];
rec = (content_record_t*) &data[sizeof(tmd)];
for (i = 0; i < num_contents; i++, rec++) {
for (i = 0; i < num_contents; i++, rec++) {
u16 type = be16((u8*) &rec->type);
u16 type = be16((u8*) &rec->type);
−
+
memcpy(hashes + (20*i), rec->hash, 20);
+
if (!(type & 0x8000)) {
if (!(type & 0x8000)) {
content_sizes[i] = (size_t)be32((u8*) &rec->size_hi);
content_sizes[i] = (size_t)be32((u8*) &rec->size_hi);
Line 313:
Line 324:
int i;
int i;
u8 partE_iv[16];
u8 partE_iv[16];
+
u8 hash[0x14];
for (i=0; i < num_contents; i++) {
for (i=0; i < num_contents; i++) {
+
printf("Content index %d: ",i);
if (content_sizes[i] != 0) {
if (content_sizes[i] != 0) {
char name[128];
char name[128];
Line 324:
Line 337:
memset(partE_iv,0,16);
memset(partE_iv,0,16);
+
wbe16(partE_iv,i);
aes_cbc_dec(prngseed, partE_iv, data, rounded_size, data);
aes_cbc_dec(prngseed, partE_iv, data, rounded_size, data);
snprintf(name, 128, "05_content_%02d", i);
snprintf(name, 128, "05_content_%02d", i);
−
printf("Writing included content index %d of size: %x\n", i, content_sizes[i]);
+
printf("is included. Written size: %x, ", content_sizes[i]);
+
+
sha(data, content_sizes[i],hash);
+
if(memcmp(hash,hashes+(i*20),20))
+
printf("hash invalid\n");
+
else
+
printf("hash ok\n");
write_part(data, rounded_size, name);
write_part(data, rounded_size, name);
free (data);
free (data);
+
}
+
else
+
{
+
printf("is not included (shared)\n");
}
}
}
}
}
}
−
+
−
static void do_partF_cert(void)
+
static void do_sig(void)
{
{
−
u8 cert[0x340];
+
u8 sig[0x40];
−
+
u8 ng_cert[0x180];
−
fread(cert, 1, sizeof cert, fp);
+
u8 ap_cert[0x180];
−
+
u8 hash[0x14];
−
write_part(cert, sizeof(cert), "06_cert");
+
u8 *data;
+
u32 data_size;
+
u32 rounded_size;
+
int ok;
+
if (fread(sig, sizeof sig, 1, fp) != 1)
+
fatal("read signature");
+
if (fread(ng_cert, sizeof ng_cert, 1, fp) != 1)
+
fatal("read NG cert");
+
if (fread(ap_cert, sizeof ap_cert, 1, fp) != 1)
+
fatal("read AP cert");
+
+
write_part(sig, 0x340, "06_cert");
+
+
rounded_size = (partB_size + 63) & ~63;
+
rounded_size += 0x640;
+
data_size = total_size - 0x340;
+
+
data = malloc(data_size);
+
if (!data)
+
fatal("malloc");
+
fseek(fp, rounded_size, SEEK_SET);
+
if (fread(data, data_size, 1, fp) != 1)
+
fatal("read data for sig check");
+
sha(data, data_size, hash);
+
sha(hash, 20, hash);
+
free(data);
+
+
ok = check_ec(ng_cert, ap_cert, sig, hash);
+
printf("ECC Signature: %s\n", ok?"ok":"invalid");
}
}
−
int main(int argc, char **argv)
int main(int argc, char **argv)
Line 355:
Line 406:
get_key("sd-iv", sd_iv, 16);
get_key("sd-iv", sd_iv, 16);
get_key("md5-blanker", md5_blanker, 16);
get_key("md5-blanker", md5_blanker, 16);
−
get_key("prngseed", prngseed, 16);
+
get_key("default/prng-seed", prngseed, 16);
fp = fopen(argv[1], "rb");
fp = fopen(argv[1], "rb");
Line 364:
Line 415:
do_partD_tmd();
do_partD_tmd();
do_partE_contents();
do_partE_contents();
−
do_partF_cert();
+
do_sig();
fclose(fp);
fclose(fp);