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 <openssl/md5.h>
8 #include <openssl/aes.h>
9 #include <openssl/sha.h>
21 return (p
[0] << 8) | p
[1];
26 return (p
[0] << 24) | (p
[1] << 16) | (p
[2] << 8) | p
[3];
31 return ((u64
)be32(p
) << 32) | be32(p
+ 4);
36 return 4 * (u64
)be32(p
);
43 void md5(u8
*data
, u32 len
, u8
*hash
)
48 void sha(u8
*data
, u32 len
, u8
*hash
)
50 SHA1(data
, len
, hash
);
53 void get_key(const char *name
, u8
*key
, u32 len
)
59 home
= getenv("HOME");
61 fatal("cannot find HOME");
62 snprintf(path
, sizeof path
, "%s/.wii/%s", home
, name
);
64 fp
= fopen(path
, "rb");
66 fatal("cannot open %s", name
);
67 if (fread(key
, len
, 1, fp
) != 1)
68 fatal("error reading %s", name
);
72 void aes_cbc_dec(u8
*key
, u8
*iv
, u8
*in
, u32 len
, u8
*out
)
76 AES_set_decrypt_key(key
, 128, &aes_key
);
77 AES_cbc_encrypt(in
, out
, len
, &aes_key
, iv
, AES_DECRYPT
);
80 void decrypt_title_key(u8
*tik
, u8
*title_key
)
85 get_key("common-key", common_key
, 16);
87 memset(iv
, 0, sizeof iv
);
88 memcpy(iv
, tik
+ 0x01dc, 8);
89 aes_cbc_dec(common_key
, iv
, tik
+ 0x01bf, 16, title_key
);
92 static u8 root_key
[0x204];
93 static u8
*get_root_key(void)
95 get_key("root-key", root_key
, sizeof root_key
);
99 static u32
get_sig_len(u8
*sig
)
104 switch (type
- 0x10000) {
115 fprintf(stderr
, "get_sig_len(): unhandled sig type %08x\n", type
);
119 static u32
get_sub_len(u8
*sub
)
123 type
= be32(sub
+ 0x40);
135 fprintf(stderr
, "get_sub_len(): unhandled sub type %08x\n", type
);
139 int check_ec(u8
*ng
, u8
*ap
, u8
*sig
, u8
*sig_hash
)
142 u8
*ng_Q
, *ap_R
, *ap_S
;
143 u8
*ap_Q
, *sig_R
, *sig_S
;
149 SHA1(ap
+ 0x80, 0x100, ap_hash
);
155 return check_ecdsa(ng_Q
, ap_R
, ap_S
, ap_hash
)
156 && check_ecdsa(ap_Q
, sig_R
, sig_S
, sig_hash
);
159 static int check_rsa(u8
*h
, u8
*sig
, u8
*key
, u32 n
)
163 static const u8 ber
[16] = "\x00\x30\x21\x30\x09\x06\x05\x2b"
164 "\x0e\x03\x02\x1a\x05\x00\x04\x14";
166 //fprintf(stderr, "n = %x\n", n);
167 //fprintf(stderr, "key:\n");
169 //fprintf(stderr, "sig:\n");
174 memset(correct
+ 2, 0xff, n
- 38);
175 memcpy(correct
+ n
- 36, ber
, 16);
176 memcpy(correct
+ n
- 20, h
, 20);
177 //fprintf(stderr, "correct is:\n");
178 //hexdump(correct, n);
180 bn_exp(x
, sig
, key
, n
, key
+ n
, 4);
181 //fprintf(stderr, "x is:\n");
184 if (memcmp(correct
, x
, n
) == 0)
190 static int check_hash(u8
*h
, u8
*sig
, u8
*key
)
194 type
= be32(sig
) - 0x10000;
195 if (type
!= be32(key
+ 0x40))
200 return check_rsa(h
, sig
+ 4, key
+ 0x88, 0x100);
206 static u8
*find_cert_in_chain(u8
*sub
, u8
*cert
, u32 cert_len
)
210 u32 sig_len
, sub_len
;
214 strncpy(parent
, sub
, sizeof parent
);
215 parent
[sizeof parent
- 1] = 0;
216 child
= strrchr(parent
, '-');
224 for (p
= cert
; p
< cert
+ cert_len
; p
+= sig_len
+ sub_len
) {
225 sig_len
= get_sig_len(p
);
228 issuer
= p
+ sig_len
;
229 sub_len
= get_sub_len(issuer
);
233 if (strcmp(parent
, issuer
) == 0
234 && strcmp(child
, issuer
+ 0x44) == 0)
241 int check_cert_chain(u8
*data
, u32 data_len
, u8
*cert
, u32 cert_len
)
253 sig_len
= get_sig_len(sig
);
256 sub
= data
+ sig_len
;
257 sub_len
= data_len
- sig_len
;
262 fprintf(stderr
, ">>>>>> checking sig by %s...\n", sub
);
263 if (strcmp(sub
, "Root") == 0) {
264 key
= get_root_key();
265 sha(sub
, sub_len
, h
);
266 if (be32(sig
) != 0x10000)
268 return check_rsa(h
, sig
+ 4, key
, 0x200);
271 key_cert
= find_cert_in_chain(sub
, cert
, cert_len
);
275 key
= key_cert
+ get_sig_len(key_cert
);
277 sha(sub
, sub_len
, h
);
278 ret
= check_hash(h
, sig
, key
);
283 sig_len
= get_sig_len(sig
);
287 sub_len
= get_sub_len(sub
);
297 void do_yaz0(u8
*in
, u32 in_size
, u8
*out
, u32 out_size
)
306 for (nout
= 0; nout
< out_size
; ) {
312 if ((bits
& 0x80) != 0) {
318 d
|= (n
<< 8) & 0xf00;
325 for (i
= 0; i
< n
; i
++) {
341 void fatal(const char *s
, ...)
347 vsnprintf(message
, sizeof message
, s
, ap
);
358 void print_bytes(u8
*x
, u32 n
)
362 for (i
= 0; i
< n
; i
++)
363 fprintf(stderr
, "%02x", x
[i
]);
366 void hexdump(u8
*x
, u32 n
)
370 for (i
= 0; i
< n
; i
+= 16) {
371 fprintf(stderr
, "%04x:", i
);
372 for (j
= 0; j
< 16 && i
+ j
< n
; j
++) {
374 fprintf(stderr
, " ");
375 fprintf(stderr
, "%02x", *x
++);
377 fprintf(stderr
, "\n");
381 void dump_tmd(u8
*tmd
)
386 printf(" issuer: %s\n", tmd
+ 0x140);
387 printf(" sys_version: %016llx\n", be64(tmd
+ 0x0184));
388 printf(" title_id: %016llx\n", be64(tmd
+ 0x018c));
389 printf(" title_type: %08x\n", be32(tmd
+ 0x0194));
390 printf(" group_id: %04x\n", be16(tmd
+ 0x0198));
391 printf("title_version: %04x\n", be16(tmd
+ 0x01dc));
392 printf(" num_contents: %04x\n", be16(tmd
+ 0x01de));
393 printf(" boot_index: %04x\n", be16(tmd
+ 0x01e0));
395 n
= be16(tmd
+ 0x01de);
397 for (i
= 0; i
< n
; i
++) {
398 printf("cid %08x index %04x type %04x size %08llx\n",
399 be32(p
), be16(p
+ 4), be16(p
+ 6), be64(p
+ 8));