Clean up bn.o
[svpe-tools.git] / tools.c
blob7638eb6061c86330cc4c3cbcda9bf12587d24a44
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 <openssl/aes.h>
8 #include <openssl/sha.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
14 // basic data types
17 u32 be32(u8 *p)
19 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
22 u64 be64(u8 *p)
24 return ((u64)be32(p) << 32) | be32(p + 4);
27 u64 be34(u8 *p)
29 return 4 * (u64)be32(p);
33 // crypto
36 void sha(u8 *data, u32 len, u8 *hash)
38 SHA1(data, len, hash);
41 void get_key(const char *name, u8 *key, u32 len)
43 char path[256];
44 char *home;
45 FILE *fp;
47 home = getenv("HOME");
48 if (home == 0)
49 fatal("cannot find HOME");
50 snprintf(path, sizeof path, "%s/.wii/%s", home, name);
52 fp = fopen(path, "rb");
53 if (fp == 0)
54 fatal("cannot open common-key");
55 if (fread(key, len, 1, fp) != 1)
56 fatal("error reading common-key");
57 fclose(fp);
60 void aes_cbc_dec(u8 *key, u8 *iv, u8 *in, u32 len, u8 *out)
62 AES_KEY aes_key;
64 AES_set_decrypt_key(key, 128, &aes_key);
65 AES_cbc_encrypt(in, out, len, &aes_key, iv, AES_DECRYPT);
68 void decrypt_title_key(u8 *title_key_crypted, u8 *title_id, u8 *title_key)
70 u8 common_key[16];
71 u8 iv[16];
73 get_key("common-key", common_key, 16);
75 memset(iv, 0, sizeof iv);
76 memcpy(iv, title_id, 8);
77 aes_cbc_dec(common_key, iv, title_key_crypted, 16, title_key);
80 static u8 root_key[0x204];
81 static u8 *get_root_key(void)
83 get_key("root-key", root_key, sizeof root_key);
84 return root_key;
87 static u32 get_sig_len(u8 *sig)
89 u32 type;
91 type = be32(sig);
92 switch (type - 0x10000) {
93 case 0:
94 return 0x240;
96 case 1:
97 return 0x140;
99 case 2:
100 return 0x80;
103 fprintf(stderr, "get_sig_len(): unhandled sig type %08x\n", type);
104 return 0;
107 static u32 get_sub_len(u8 *sub)
109 u32 type;
111 type = be32(sub + 0x40);
112 switch (type) {
113 case 0:
114 return 0x2c0;
116 case 1:
117 return 0x1c0;
119 case 2:
120 return 0x100;
123 fprintf(stderr, "get_sub_len(): unhandled sub type %08x\n", type);
124 return 0;
127 static int check_rsa(u8 *h, u8 *sig, u8 *key, u32 n)
129 u8 correct[0x200];
130 u8 x[0x200];
131 static const u8 ber[16] = "\x00\x30\x21\x30\x09\x06\x05\x2b"
132 "\x0e\x03\x02\x1a\x05\x00\x04\x14";
134 correct[0] = 0;
135 correct[1] = 1;
136 memset(correct + 2, 0xff, n - 38);
137 memcpy(correct + n - 36, ber, 16);
138 memcpy(correct + n - 20, h, 20);
139 //fprintf(stderr, "correct is:\n");
140 //hexdump(correct, n);
142 bn_exp(x, sig, key, n, key + n, 4);
143 //fprintf(stderr, "x is:\n");
144 //hexdump(x, n);
146 if (memcmp(correct, x, n) == 0)
147 return 0;
149 return -5;
152 static int check_hash(u8 *h, u8 *sig, u8 *key)
154 u32 type;
156 type = be32(sig) - 0x10000;
157 if (type != be32(key + 0x40))
158 return -6;
160 switch (type) {
161 case 1:
162 return check_rsa(h, sig + 4, key + 0x88, 0x100);
165 return -7;
168 static u8 *find_cert_in_chain(u8 *sub, u8 *cert, u32 cert_len)
170 char parent[64];
171 char *child;
172 u32 sig_len, sub_len;
173 u8 *p;
174 u8 *issuer;
176 strncpy(parent, sub, sizeof parent);
177 parent[sizeof parent - 1] = 0;
178 child = strrchr(parent, '-');
179 if (child)
180 *child++ = 0;
181 else {
182 *parent = 0;
183 child = sub;
186 for (p = cert; p < cert + cert_len; p += sig_len + sub_len) {
187 sig_len = get_sig_len(p);
188 if (sig_len == 0)
189 return 0;
190 issuer = p + sig_len;
191 sub_len = get_sub_len(issuer);
192 if (sub_len == 0)
193 return 0;
195 if (strcmp(parent, issuer) == 0
196 && strcmp(child, issuer + 0x44) == 0)
197 return p;
200 return 0;
203 int check_cert_chain(u8 *data, u32 data_len, u8 *cert, u32 cert_len)
205 u8 *sig;
206 u8 *sub;
207 u32 sig_len;
208 u32 sub_len;
209 u8 h[20];
210 u8 *key_cert;
211 u8 *key;
212 int ret;
214 sig = data;
215 sig_len = get_sig_len(sig);
216 if (sig_len == 0)
217 return -1;
218 sub = data + sig_len;
219 sub_len = data_len - sig_len;
220 if (sub_len == 0)
221 return -2;
223 for (;;) {
224 fprintf(stderr, ">>>>>> checking sig by %s...\n", sub);
225 if (strcmp(sub, "Root") == 0) {
226 key = get_root_key();
227 sha(sub, sub_len, h);
228 if (be32(sig) != 0x10000)
229 return -8;
230 return check_rsa(h, sig + 4, key, 0x200);
233 key_cert = find_cert_in_chain(sub, cert, cert_len);
234 if (key_cert == 0)
235 return -3;
237 key = key_cert + get_sig_len(key_cert);
239 sha(sub, sub_len, h);
240 ret = check_hash(h, sig, key);
241 if (ret)
242 return ret;
244 sig = key_cert;
245 sig_len = get_sig_len(sig);
246 if (sig_len == 0)
247 return -4;
248 sub = sig + sig_len;
249 sub_len = get_sub_len(sub);
250 if (sub_len == 0)
251 return -5;
256 // compression
259 void do_yaz0(u8 *in, u32 in_size, u8 *out, u32 out_size)
261 u32 nout;
262 u8 bits;
263 u32 nbits;
264 u32 n, d, i;
266 nbits = 0;
267 in += 0x10;
268 for (nout = 0; nout < out_size; ) {
269 if (nbits == 0) {
270 bits = *in++;
271 nbits = 8;
274 if ((bits & 0x80) != 0) {
275 *out++ = *in++;
276 nout++;
277 } else {
278 n = *in++;
279 d = *in++;
280 d |= (n << 8) & 0xf00;
281 n >>= 4;
282 if (n == 0)
283 n = 0x10 + *in++;
284 n += 2;
285 d++;
287 for (i = 0; i < n; i++) {
288 *out = *(out - d);
289 out++;
291 nout += n;
294 nbits--;
295 bits <<= 1;
300 // error handling
303 void fatal(const char *s)
305 perror(s);
307 exit(1);
311 // output formatting
314 void print_bytes(u8 *x, u32 n)
316 u32 i;
318 for (i = 0; i < n; i++)
319 fprintf(stderr, "%02x", x[i]);
322 void hexdump(u8 *x, u32 n)
324 u32 i, j;
326 for (i = 0; i < n; i += 16) {
327 fprintf(stderr, "%04x:", i);
328 for (j = 0; j < 16 && i + j < n; j++) {
329 if ((j & 3) == 0)
330 fprintf(stderr, " ");
331 fprintf(stderr, "%02x", *x++);
333 fprintf(stderr, "\n");
335 if (n & 15)
336 fprintf(stderr, "\n");