1 // Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
2 // Licensed under the terms of the GNU GPL, version 2
3 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
7 #include <stddef.h> // to accommodate certain broken versions of openssl
8 #include <openssl/md5.h>
9 #include <openssl/aes.h>
10 #include <openssl/sha.h>
22 return (p
[0] << 8) | p
[1];
27 return (p
[0] << 24) | (p
[1] << 16) | (p
[2] << 8) | p
[3];
32 return ((u64
)be32(p
) << 32) | be32(p
+ 4);
37 return 4 * (u64
)be32(p
);
40 void wbe16(u8
*p
, u16 x
)
46 void wbe32(u8
*p
, u32 x
)
52 void wbe64(u8
*p
, u64 x
)
62 void md5(u8
*data
, u32 len
, u8
*hash
)
67 void sha(u8
*data
, u32 len
, u8
*hash
)
69 SHA1(data
, len
, hash
);
72 void get_key(const char *name
, u8
*key
, u32 len
)
78 home
= getenv("HOME");
80 fatal("cannot find HOME");
81 snprintf(path
, sizeof path
, "%s/.wii/%s", home
, name
);
83 fp
= fopen(path
, "rb");
85 fatal("cannot open %s", name
);
86 if (fread(key
, len
, 1, fp
) != 1)
87 fatal("error reading %s", name
);
91 void aes_cbc_dec(u8
*key
, u8
*iv
, u8
*in
, u32 len
, u8
*out
)
95 AES_set_decrypt_key(key
, 128, &aes_key
);
96 AES_cbc_encrypt(in
, out
, len
, &aes_key
, iv
, AES_DECRYPT
);
99 void aes_cbc_enc(u8
*key
, u8
*iv
, u8
*in
, u32 len
, u8
*out
)
103 AES_set_encrypt_key(key
, 128, &aes_key
);
104 AES_cbc_encrypt(in
, out
, len
, &aes_key
, iv
, AES_ENCRYPT
);
107 void decrypt_title_key(u8
*tik
, u8
*title_key
)
112 get_key("common-key", common_key
, 16);
114 memset(iv
, 0, sizeof iv
);
115 memcpy(iv
, tik
+ 0x01dc, 8);
116 aes_cbc_dec(common_key
, iv
, tik
+ 0x01bf, 16, title_key
);
119 static u8 root_key
[0x204];
120 static u8
*get_root_key(void)
122 get_key("root-key", root_key
, sizeof root_key
);
126 static u32
get_sig_len(u8
*sig
)
131 switch (type
- 0x10000) {
142 fprintf(stderr
, "get_sig_len(): unhandled sig type %08x\n", type
);
146 static u32
get_sub_len(u8
*sub
)
150 type
= be32(sub
+ 0x40);
162 fprintf(stderr
, "get_sub_len(): unhandled sub type %08x\n", type
);
166 int check_ec(u8
*ng
, u8
*ap
, u8
*sig
, u8
*sig_hash
)
169 u8
*ng_Q
, *ap_R
, *ap_S
;
170 u8
*ap_Q
, *sig_R
, *sig_S
;
176 SHA1(ap
+ 0x80, 0x100, ap_hash
);
182 return check_ecdsa(ng_Q
, ap_R
, ap_S
, ap_hash
)
183 && check_ecdsa(ap_Q
, sig_R
, sig_S
, sig_hash
);
186 static int check_rsa(u8
*h
, u8
*sig
, u8
*key
, u32 n
)
190 static const u8 ber
[16] = "\x00\x30\x21\x30\x09\x06\x05\x2b"
191 "\x0e\x03\x02\x1a\x05\x00\x04\x14";
193 //fprintf(stderr, "n = %x\n", n);
194 //fprintf(stderr, "key:\n");
196 //fprintf(stderr, "sig:\n");
201 memset(correct
+ 2, 0xff, n
- 38);
202 memcpy(correct
+ n
- 36, ber
, 16);
203 memcpy(correct
+ n
- 20, h
, 20);
204 //fprintf(stderr, "correct is:\n");
205 //hexdump(correct, n);
207 bn_exp(x
, sig
, key
, n
, key
+ n
, 4);
208 //fprintf(stderr, "x is:\n");
211 if (memcmp(correct
, x
, n
) == 0)
217 static int check_hash(u8
*h
, u8
*sig
, u8
*key
)
221 type
= be32(sig
) - 0x10000;
222 if (type
!= be32(key
+ 0x40))
227 return check_rsa(h
, sig
+ 4, key
+ 0x88, 0x100);
233 static u8
*find_cert_in_chain(u8
*sub
, u8
*cert
, u32 cert_len
)
237 u32 sig_len
, sub_len
;
241 strncpy(parent
, sub
, sizeof parent
);
242 parent
[sizeof parent
- 1] = 0;
243 child
= strrchr(parent
, '-');
251 for (p
= cert
; p
< cert
+ cert_len
; p
+= sig_len
+ sub_len
) {
252 sig_len
= get_sig_len(p
);
255 issuer
= p
+ sig_len
;
256 sub_len
= get_sub_len(issuer
);
260 if (strcmp(parent
, issuer
) == 0
261 && strcmp(child
, issuer
+ 0x44) == 0)
268 int check_cert_chain(u8
*data
, u32 data_len
, u8
*cert
, u32 cert_len
)
280 sig_len
= get_sig_len(sig
);
283 sub
= data
+ sig_len
;
284 sub_len
= data_len
- sig_len
;
289 fprintf(stderr
, ">>>>>> checking sig by %s...\n", sub
);
290 if (strcmp(sub
, "Root") == 0) {
291 key
= get_root_key();
292 sha(sub
, sub_len
, h
);
293 if (be32(sig
) != 0x10000)
295 return check_rsa(h
, sig
+ 4, key
, 0x200);
298 key_cert
= find_cert_in_chain(sub
, cert
, cert_len
);
302 key
= key_cert
+ get_sig_len(key_cert
);
304 sha(sub
, sub_len
, h
);
305 ret
= check_hash(h
, sig
, key
);
310 sig_len
= get_sig_len(sig
);
314 sub_len
= get_sub_len(sub
);
324 void do_yaz0(u8
*in
, u32 in_size
, u8
*out
, u32 out_size
)
334 for (nout
= 0; nout
< out_size
; ) {
340 if ((bits
& 0x80) != 0) {
346 d
|= (n
<< 8) & 0xf00;
353 for (i
= 0; i
< n
; i
++) {
369 void fatal(const char *s
, ...)
375 vsnprintf(message
, sizeof message
, s
, ap
);
386 void print_bytes(u8
*x
, u32 n
)
390 for (i
= 0; i
< n
; i
++)
391 fprintf(stderr
, "%02x", x
[i
]);
394 void hexdump(u8
*x
, u32 n
)
398 for (i
= 0; i
< n
; i
+= 16) {
399 fprintf(stderr
, "%04x:", i
);
400 for (j
= 0; j
< 16 && i
+ j
< n
; j
++) {
402 fprintf(stderr
, " ");
403 fprintf(stderr
, "%02x", *x
++);
405 fprintf(stderr
, "\n");
409 void dump_tmd(u8
*tmd
)
414 printf(" issuer: %s\n", tmd
+ 0x140);
415 printf(" sys_version: %016llx\n", be64(tmd
+ 0x0184));
416 printf(" title_id: %016llx\n", be64(tmd
+ 0x018c));
417 printf(" title_type: %08x\n", be32(tmd
+ 0x0194));
418 printf(" group_id: %04x\n", be16(tmd
+ 0x0198));
419 printf("title_version: %04x\n", be16(tmd
+ 0x01dc));
420 printf(" num_contents: %04x\n", be16(tmd
+ 0x01de));
421 printf(" boot_index: %04x\n", be16(tmd
+ 0x01e0));
423 n
= be16(tmd
+ 0x01de);
425 for (i
= 0; i
< n
; i
++) {
426 printf("cid %08x index %04x type %04x size %08llx\n",
427 be32(p
), be16(p
+ 4), be16(p
+ 6), be64(p
+ 8));