Zestig: decode/dump Wii flash images
[svpe-tools.git] / tools.c
blobf6e4717f3223516dc02104100572feaa5af9c8db
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
5 #include "tools.h"
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>
11 #include <stdarg.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
17 // basic data types
20 u16 be16(const u8 *p)
22 return (p[0] << 8) | p[1];
25 u32 be32(const u8 *p)
27 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
30 u64 be64(const u8 *p)
32 return ((u64)be32(p) << 32) | be32(p + 4);
35 u64 be34(const u8 *p)
37 return 4 * (u64)be32(p);
40 void wbe16(u8 *p, u16 x)
42 p[0] = x >> 8;
43 p[1] = x;
46 void wbe32(u8 *p, u32 x)
48 wbe16(p, x >> 16);
49 wbe16(p + 2, x);
52 void wbe64(u8 *p, u64 x)
54 wbe32(p, x >> 32);
55 wbe32(p + 4, x);
59 // crypto
62 void md5(u8 *data, u32 len, u8 *hash)
64 MD5(data, len, 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)
74 char path[256];
75 char *home;
76 FILE *fp;
78 home = getenv("HOME");
79 if (home == 0)
80 fatal("cannot find HOME");
81 snprintf(path, sizeof path, "%s/.wii/%s", home, name);
83 fp = fopen(path, "rb");
84 if (fp == 0)
85 fatal("cannot open %s", name);
86 if (fread(key, len, 1, fp) != 1)
87 fatal("error reading %s", name);
88 fclose(fp);
91 void aes_cbc_dec(u8 *key, u8 *iv, u8 *in, u32 len, u8 *out)
93 AES_KEY aes_key;
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)
101 AES_KEY aes_key;
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)
109 u8 common_key[16];
110 u8 iv[16];
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);
123 return root_key;
126 static u32 get_sig_len(u8 *sig)
128 u32 type;
130 type = be32(sig);
131 switch (type - 0x10000) {
132 case 0:
133 return 0x240;
135 case 1:
136 return 0x140;
138 case 2:
139 return 0x80;
142 fprintf(stderr, "get_sig_len(): unhandled sig type %08x\n", type);
143 return 0;
146 static u32 get_sub_len(u8 *sub)
148 u32 type;
150 type = be32(sub + 0x40);
151 switch (type) {
152 case 0:
153 return 0x2c0;
155 case 1:
156 return 0x1c0;
158 case 2:
159 return 0x100;
162 fprintf(stderr, "get_sub_len(): unhandled sub type %08x\n", type);
163 return 0;
166 int check_ec(u8 *ng, u8 *ap, u8 *sig, u8 *sig_hash)
168 u8 ap_hash[20];
169 u8 *ng_Q, *ap_R, *ap_S;
170 u8 *ap_Q, *sig_R, *sig_S;
172 ng_Q = ng + 0x0108;
173 ap_R = ap + 0x04;
174 ap_S = ap + 0x22;
176 SHA1(ap + 0x80, 0x100, ap_hash);
178 ap_Q = ap + 0x0108;
179 sig_R = sig;
180 sig_S = sig + 30;
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)
188 u8 correct[0x200];
189 u8 x[0x200];
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");
195 //hexdump(key, n);
196 //fprintf(stderr, "sig:\n");
197 //hexdump(sig, n);
199 correct[0] = 0;
200 correct[1] = 1;
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");
209 //hexdump(x, n);
211 if (memcmp(correct, x, n) == 0)
212 return 0;
214 return -5;
217 static int check_hash(u8 *h, u8 *sig, u8 *key)
219 u32 type;
221 type = be32(sig) - 0x10000;
222 if (type != be32(key + 0x40))
223 return -6;
225 switch (type) {
226 case 1:
227 return check_rsa(h, sig + 4, key + 0x88, 0x100);
230 return -7;
233 static u8 *find_cert_in_chain(u8 *sub, u8 *cert, u32 cert_len)
235 char parent[64];
236 char *child;
237 u32 sig_len, sub_len;
238 u8 *p;
239 u8 *issuer;
241 strncpy(parent, sub, sizeof parent);
242 parent[sizeof parent - 1] = 0;
243 child = strrchr(parent, '-');
244 if (child)
245 *child++ = 0;
246 else {
247 *parent = 0;
248 child = sub;
251 for (p = cert; p < cert + cert_len; p += sig_len + sub_len) {
252 sig_len = get_sig_len(p);
253 if (sig_len == 0)
254 return 0;
255 issuer = p + sig_len;
256 sub_len = get_sub_len(issuer);
257 if (sub_len == 0)
258 return 0;
260 if (strcmp(parent, issuer) == 0
261 && strcmp(child, issuer + 0x44) == 0)
262 return p;
265 return 0;
268 int check_cert_chain(u8 *data, u32 data_len, u8 *cert, u32 cert_len)
270 u8 *sig;
271 u8 *sub;
272 u32 sig_len;
273 u32 sub_len;
274 u8 h[20];
275 u8 *key_cert;
276 u8 *key;
277 int ret;
279 sig = data;
280 sig_len = get_sig_len(sig);
281 if (sig_len == 0)
282 return -1;
283 sub = data + sig_len;
284 sub_len = data_len - sig_len;
285 if (sub_len == 0)
286 return -2;
288 for (;;) {
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)
294 return -8;
295 return check_rsa(h, sig + 4, key, 0x200);
298 key_cert = find_cert_in_chain(sub, cert, cert_len);
299 if (key_cert == 0)
300 return -3;
302 key = key_cert + get_sig_len(key_cert);
304 sha(sub, sub_len, h);
305 ret = check_hash(h, sig, key);
306 if (ret)
307 return ret;
309 sig = key_cert;
310 sig_len = get_sig_len(sig);
311 if (sig_len == 0)
312 return -4;
313 sub = sig + sig_len;
314 sub_len = get_sub_len(sub);
315 if (sub_len == 0)
316 return -5;
321 // compression
324 void do_yaz0(u8 *in, u32 in_size, u8 *out, u32 out_size)
326 u32 nout;
327 u8 bits;
328 u32 nbits;
329 u32 n, d, i;
331 bits = 0;
332 nbits = 0;
333 in += 0x10;
334 for (nout = 0; nout < out_size; ) {
335 if (nbits == 0) {
336 bits = *in++;
337 nbits = 8;
340 if ((bits & 0x80) != 0) {
341 *out++ = *in++;
342 nout++;
343 } else {
344 n = *in++;
345 d = *in++;
346 d |= (n << 8) & 0xf00;
347 n >>= 4;
348 if (n == 0)
349 n = 0x10 + *in++;
350 n += 2;
351 d++;
353 for (i = 0; i < n; i++) {
354 *out = *(out - d);
355 out++;
357 nout += n;
360 nbits--;
361 bits <<= 1;
366 // error handling
369 void fatal(const char *s, ...)
371 char message[256];
372 va_list ap;
374 va_start(ap, s);
375 vsnprintf(message, sizeof message, s, ap);
377 perror(message);
379 exit(1);
383 // output formatting
386 void print_bytes(u8 *x, u32 n)
388 u32 i;
390 for (i = 0; i < n; i++)
391 fprintf(stderr, "%02x", x[i]);
394 void hexdump(u8 *x, u32 n)
396 u32 i, j;
398 for (i = 0; i < n; i += 16) {
399 fprintf(stderr, "%04x:", i);
400 for (j = 0; j < 16 && i + j < n; j++) {
401 if ((j & 3) == 0)
402 fprintf(stderr, " ");
403 fprintf(stderr, "%02x", *x++);
405 fprintf(stderr, "\n");
409 void dump_tmd(u8 *tmd)
411 u32 i, n;
412 u8 *p;
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);
424 p = tmd + 0x01e4;
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));
428 p += 0x24;