Use round_up() a bit more.
[svpe-tools.git] / tachtig.c
blob41e63740af95770cad74c96aa0e2abe3f297f4f7
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 <sys/types.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdio.h>
12 #include "tools.h"
14 #define ERROR(s) do { fprintf(stderr, s "\n"); exit(1); } while (0)
16 static u8 sd_key[16];
17 static u8 sd_iv[16];
18 static u8 md5_blanker[16];
20 static FILE *fp;
21 static u32 n_files;
22 static u32 files_size;
23 static u32 total_size;
24 static u8 header[0xf0c0];
26 static void output_image(u8 *data, u32 w, u32 h, const char *name)
28 FILE *fp;
29 u32 x, y;
31 fp = fopen(name, "wb");
32 if (!fp)
33 fatal("open %s", name);
35 fprintf(fp, "P6 %d %d 255\n", w, h);
37 for (y = 0; y < h; y++)
38 for (x = 0; x < w; x++) {
39 u8 pix[3];
40 u16 raw;
41 u32 x0, x1, y0, y1, off;
43 x0 = x & 3;
44 x1 = x >> 2;
45 y0 = y & 3;
46 y1 = y >> 2;
47 off = x0 + 4 * y0 + 16 * x1 + 4 * w * y1;
49 raw = be16(data + 2*off);
51 // RGB5A3
52 if (raw & 0x8000) {
53 pix[0] = (raw >> 7) & 0xf8;
54 pix[1] = (raw >> 2) & 0xf8;
55 pix[2] = (raw << 3) & 0xf8;
56 } else {
57 pix[0] = (raw >> 4) & 0xf0;
58 pix[1] = raw & 0xf0;
59 pix[2] = (raw << 4) & 0xf0;
62 if (fwrite(pix, 3, 1, fp) != 1)
63 fatal("write %s", name);
66 fclose(fp);
69 static void do_file_header(void)
71 u8 md5_file[16];
72 u8 md5_calc[16];
73 u32 header_size;
74 char name[256];
75 char dir[17];
76 FILE *out;
77 u32 i;
79 if (fread(header, sizeof header, 1, fp) != 1)
80 fatal("read file header");
82 aes_cbc_dec(sd_key, sd_iv, header, sizeof header, header);
84 memcpy(md5_file, header + 0x0e, 16);
85 memcpy(header + 0x0e, md5_blanker, 16);
86 md5(header, sizeof header, md5_calc);
88 if (memcmp(md5_file, md5_calc, 0x10))
89 ERROR("MD5 mismatch");
91 header_size = be32(header + 8);
92 if (header_size != 0x72a0 && header_size != 0xf0a0)
93 ERROR("unknown file header size");
95 snprintf(dir, sizeof dir, "%016llx", be64(header));
96 if (mkdir(dir, 0777))
97 fatal("mkdir %s", dir);
98 if (chdir(dir))
99 fatal("chdir %s", dir);
101 out = fopen("###title###", "wb");
102 if (!out)
103 fatal("open ###title###");
104 if (fwrite(header + 0x40, 0x80, 1, out) != 1)
105 fatal("write ###title###");
106 fclose(out);
108 output_image(header + 0xc0, 192, 64, "###banner###.ppm");
109 if (header_size == 0x72a0)
110 output_image(header + 0x60c0, 48, 48, "###icon###.ppm");
111 else
112 for (i = 0; i < 8; i++) {
113 snprintf(name, sizeof name, "###icon%d###.ppm", i);
114 output_image(header + 0x60c0 + 0x1200*i, 48, 48, name);
118 static void do_backup_header(void)
120 u8 header[0x80];
122 if (fread(header, sizeof header, 1, fp) != 1)
123 fatal("read backup header");
125 if (be32(header + 4) != 0x426b0001)
126 ERROR("no Bk header");
127 if (be32(header) != 0x70)
128 ERROR("wrong Bk header size");
130 fprintf(stderr, "NG id: %08x\n", be32(header + 8));
132 n_files = be32(header + 0x0c);
133 files_size = be32(header + 0x10);
134 total_size = be32(header + 0x1c);
136 fprintf(stderr, "%d files\n", n_files);
139 static mode_t perm_to_mode(u8 perm)
141 mode_t mode;
142 u32 i;
144 mode = 0;
145 for (i = 0; i < 3; i++) {
146 mode <<= 3;
147 if (perm & 0x20)
148 mode |= 3;
149 if (perm & 0x10)
150 mode |= 5;
151 perm <<= 2;
154 return mode;
157 static void do_file(void)
159 u8 header[0x80];
160 u32 size;
161 u32 rounded_size;
162 u8 perm, attr, type;
163 char *name;
164 u8 *data;
165 FILE *out;
166 mode_t mode;
168 if (fread(header, sizeof header, 1, fp) != 1)
169 fatal("read file header");
171 if (be32(header) != 0x03adf17e)
172 ERROR("bad file header");
174 size = be32(header + 4);
175 perm = header[8];
176 attr = header[9];
177 type = header[10];
178 name = header + 11;
180 fprintf(stderr, "file: size=%08x perm=%02x attr=%02x type=%02x name=%s\n", size, perm, attr, type, name);
182 mode = perm_to_mode(perm);
184 switch (type) {
185 case 1:
186 rounded_size = (size + 63) & ~63;
187 data = malloc(rounded_size);
188 if (!data)
189 fatal("malloc");
190 if (fread(data, rounded_size, 1, fp) != 1)
191 fatal("read file data for %s", name);
193 aes_cbc_dec(sd_key, header + 0x50, data, rounded_size, data);
195 out = fopen(name, "wb");
196 if (!out)
197 fatal("open %s", name);
198 if (fwrite(data, size, 1, out) != 1)
199 fatal("write %s", name);
200 fclose(out);
202 mode &= ~0111;
204 free(data);
205 break;
207 case 2:
208 if (mkdir(name, 0777))
209 fatal("mkdir %s", name);
210 break;
212 default:
213 ERROR("unhandled file type");
216 if (chmod(name, mode))
217 fatal("chmod %s", name);
220 static void do_sig(void)
222 u8 sig[0x40];
223 u8 ng_cert[0x180];
224 u8 ap_cert[0x180];
225 u8 hash[0x14];
226 u8 *data;
227 u32 data_size;
228 int ok;
230 if (fread(sig, sizeof sig, 1, fp) != 1)
231 fatal("read signature");
232 if (fread(ng_cert, sizeof ng_cert, 1, fp) != 1)
233 fatal("read NG cert");
234 if (fread(ap_cert, sizeof ap_cert, 1, fp) != 1)
235 fatal("read AP cert");
237 data_size = total_size - 0x340;
239 data = malloc(data_size);
240 if (!data)
241 fatal("malloc");
242 fseek(fp, 0xf0c0, SEEK_SET);
243 if (fread(data, data_size, 1, fp) != 1)
244 fatal("read data for sig check");
245 sha(data, data_size, hash);
246 sha(hash, 20, hash);
247 free(data);
249 ok = check_ec(ng_cert, ap_cert, sig, hash);
250 printf("ok: %d\n", ok);
253 int main(int argc, char **argv)
255 u32 i;
256 u32 mode;
258 if (argc != 2) {
259 fprintf(stderr, "Usage: %s <data.bin>\n", argv[0]);
260 return 1;
263 get_key("sd-key", sd_key, 16);
264 get_key("sd-iv", sd_iv, 16);
265 get_key("md5-blanker", md5_blanker, 16);
267 fp = fopen(argv[1], "rb");
268 if (!fp)
269 fatal("open %s", argv[1]);
271 do_file_header();
272 do_backup_header();
274 for (i = 0; i < n_files; i++)
275 do_file();
277 mode = perm_to_mode(header[0x0c]);
278 if (chmod(".", mode))
279 fatal("chmod .");
280 if (chdir(".."))
281 fatal("chdir ..");
283 do_sig();
285 fclose(fp);
287 return 0;