Changes

no edit summary
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);
40

edits