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
*title_key_crypted
, u8
*title_id
, u8
*title_key
)
85 get_key("common-key", common_key
, 16);
87 memset(iv
, 0, sizeof iv
);
88 memcpy(iv
, title_id
, 8);
89 aes_cbc_dec(common_key
, iv
, title_key_crypted
, 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";
168 memset(correct
+ 2, 0xff, n
- 38);
169 memcpy(correct
+ n
- 36, ber
, 16);
170 memcpy(correct
+ n
- 20, h
, 20);
171 //fprintf(stderr, "correct is:\n");
172 //hexdump(correct, n);
174 bn_exp(x
, sig
, key
, n
, key
+ n
, 4);
175 //fprintf(stderr, "x is:\n");
178 if (memcmp(correct
, x
, n
) == 0)
184 static int check_hash(u8
*h
, u8
*sig
, u8
*key
)
188 type
= be32(sig
) - 0x10000;
189 if (type
!= be32(key
+ 0x40))
194 return check_rsa(h
, sig
+ 4, key
+ 0x88, 0x100);
200 static u8
*find_cert_in_chain(u8
*sub
, u8
*cert
, u32 cert_len
)
204 u32 sig_len
, sub_len
;
208 strncpy(parent
, sub
, sizeof parent
);
209 parent
[sizeof parent
- 1] = 0;
210 child
= strrchr(parent
, '-');
218 for (p
= cert
; p
< cert
+ cert_len
; p
+= sig_len
+ sub_len
) {
219 sig_len
= get_sig_len(p
);
222 issuer
= p
+ sig_len
;
223 sub_len
= get_sub_len(issuer
);
227 if (strcmp(parent
, issuer
) == 0
228 && strcmp(child
, issuer
+ 0x44) == 0)
235 int check_cert_chain(u8
*data
, u32 data_len
, u8
*cert
, u32 cert_len
)
247 sig_len
= get_sig_len(sig
);
250 sub
= data
+ sig_len
;
251 sub_len
= data_len
- sig_len
;
256 fprintf(stderr
, ">>>>>> checking sig by %s...\n", sub
);
257 if (strcmp(sub
, "Root") == 0) {
258 key
= get_root_key();
259 sha(sub
, sub_len
, h
);
260 if (be32(sig
) != 0x10000)
262 return check_rsa(h
, sig
+ 4, key
, 0x200);
265 key_cert
= find_cert_in_chain(sub
, cert
, cert_len
);
269 key
= key_cert
+ get_sig_len(key_cert
);
271 sha(sub
, sub_len
, h
);
272 ret
= check_hash(h
, sig
, key
);
277 sig_len
= get_sig_len(sig
);
281 sub_len
= get_sub_len(sub
);
291 void do_yaz0(u8
*in
, u32 in_size
, u8
*out
, u32 out_size
)
300 for (nout
= 0; nout
< out_size
; ) {
306 if ((bits
& 0x80) != 0) {
312 d
|= (n
<< 8) & 0xf00;
319 for (i
= 0; i
< n
; i
++) {
335 void fatal(const char *s
, ...)
341 vsnprintf(message
, sizeof message
, s
, ap
);
352 void print_bytes(u8
*x
, u32 n
)
356 for (i
= 0; i
< n
; i
++)
357 fprintf(stderr
, "%02x", x
[i
]);
360 void hexdump(u8
*x
, u32 n
)
364 for (i
= 0; i
< n
; i
+= 16) {
365 fprintf(stderr
, "%04x:", i
);
366 for (j
= 0; j
< 16 && i
+ j
< n
; j
++) {
368 fprintf(stderr
, " ");
369 fprintf(stderr
, "%02x", *x
++);
371 fprintf(stderr
, "\n");
375 void dump_tmd(u8
*tmd
)
380 printf(" issuer: %s\n", tmd
+ 0x140);
381 printf(" sys_version: %016llx\n", be64(tmd
+ 0x0184));
382 printf(" title_id: %016llx\n", be64(tmd
+ 0x018c));
383 printf(" title_type: %08x\n", be32(tmd
+ 0x0194));
384 printf(" group_id: %04x\n", be16(tmd
+ 0x0198));
385 printf("title_version: %04x\n", be16(tmd
+ 0x01dc));
386 printf(" num_contents: %04x\n", be16(tmd
+ 0x01de));
387 printf(" boot_index: %04x\n", be16(tmd
+ 0x01e0));
389 n
= be16(tmd
+ 0x01de);
391 for (i
= 0; i
< n
; i
++) {
392 printf("cid %08x index %04x type %04x size %08llx\n",
393 be32(p
), be16(p
+ 4), be16(p
+ 6), be64(p
+ 8));