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
15 static int verbose
= 0;
19 #define ERROR(s) do { fprintf(stderr, s "\n"); exit(1); } while (0)
23 static u8 md5_blanker
[16];
28 static u8 ng_priv
[30];
33 static u8 header
[0xf0c0];
36 static u32 files_size
;
38 static u8 files
[MAXFILES
][0x80];
40 static void read_image(u8
*data
, u32 w
, u32 h
, const char *name
)
46 fp
= fopen(name
, "rb");
48 fatal("open %s", name
);
50 if (fscanf(fp
, "P6 %d %d 255\n", &ww
, &hh
) != 2)
52 if (ww
!= w
|| hh
!= h
)
53 ERROR("wrong size ppm");
55 for (y
= 0; y
< h
; y
++)
56 for (x
= 0; x
< w
; x
++) {
59 u32 x0
, x1
, y0
, y1
, off
;
65 off
= x0
+ 4 * y0
+ 16 * x1
+ 4 * w
* y1
;
67 if (fread(pix
, 3, 1, fp
) != 1)
68 fatal("read %s", name
);
70 raw
= (pix
[0] & 0xf8) << 7;
71 raw
|= (pix
[1] & 0xf8) << 2;
72 raw
|= (pix
[2] & 0xf8) >> 3;
75 wbe16(data
+ 2*off
, raw
);
81 static u8
perm_from_path(const char *path
)
89 fatal("stat %s", path
);
93 for (i
= 0; i
< 3; i
++) {
105 static void do_file_header(u64 title_id
)
112 memset(header
, 0, sizeof header
);
114 wbe64(header
, title_id
);
115 header
[0x0c] = perm_from_path(".");
116 memcpy(header
+ 0x0e, md5_blanker
, 16);
117 memcpy(header
+ 0x20, "WIBN", 4);
118 // XXX: what about the stuff at 0x24?
120 in
= fopen("###title###", "rb");
122 fatal("open ###title###");
123 if (fread(header
+ 0x40, 0x80, 1, in
) != 1)
124 fatal("read ###title###");
127 read_image(header
+ 0xc0, 192, 64, "###banner###.ppm");
129 in
= fopen("###icon###.ppm", "rb");
132 wbe32(header
+ 8, 0x72a0);
133 read_image(header
+ 0x60c0, 48, 48, "###icon###.ppm");
135 wbe32(header
+ 8, 0xf0a0);
137 for (i
= 0; i
< 8; i
++) {
138 snprintf(name
, sizeof name
, "###icon%d###.ppm", i
);
139 read_image(header
+ 0x60c0 + 0x1200*i
, 48, 48, name
);
143 md5(header
, sizeof header
, md5_calc
);
144 memcpy(header
+ 0x0e, md5_calc
, 16);
145 aes_cbc_enc(sd_key
, sd_iv
, header
, sizeof header
, header
);
147 if (fwrite(header
, 0xf0c0, 1, fp
) != 1)
148 fatal("write header");
151 static void find_files_recursive(const char *path
)
162 dir
= opendir(path
? path
: ".");
164 fatal("opendir %s", path
? path
: ".");
166 while ((de
= readdir(dir
))) {
167 if (strcmp(de
->d_name
, ".") == 0)
169 if (strcmp(de
->d_name
, "..") == 0)
171 if (strncmp(de
->d_name
, "###", 3) == 0)
175 len
= snprintf(name
, sizeof name
, "%s", de
->d_name
);
177 len
= snprintf(name
, sizeof name
, "%s/%s", path
,
180 if (len
>= sizeof name
)
181 ERROR("path too long");
183 if (de
->d_type
!= DT_REG
&& de
->d_type
!= DT_DIR
)
184 ERROR("not a regular file or a directory");
186 is_dir
= (de
->d_type
== DT_DIR
);
192 fatal("stat %s", name
);
196 p
= files
[n_files
++];
199 p
[8] = perm_from_path(name
);
200 p
[0x0a] = is_dir
? 2 : 1;
201 strcpy(p
+ 0x0b, name
);
202 // maybe fill up with dirt
204 size
= round_up(size
, 0x40);
205 files_size
+= 0x80 + size
;
207 if (de
->d_type
== DT_DIR
)
208 find_files_recursive(name
);
215 static int compar(const void *a
, const void *b
)
217 return strcmp((char *)a
+ 0x0b, (char *)b
+ 0x0b);
220 static void find_files(void)
225 memset(files
, 0, sizeof files
);
227 find_files_recursive(0);
229 qsort(files
, n_files
, 0x80, compar
);
232 static void do_backup_header(u64 title_id
)
236 memset(header
, 0, sizeof header
);
239 wbe32(header
+ 4, 0x426b0001);
240 wbe32(header
+ 8, ng_id
);
241 wbe32(header
+ 0x0c, n_files
);
242 wbe32(header
+ 0x10, files_size
);
243 wbe32(header
+ 0x1c, files_size
+ 0x3c0);
245 wbe64(header
+ 0x60, title_id
);
246 memcpy(header
+ 0x68, ng_mac
, 6);
248 if (fwrite(header
, sizeof header
, 1, fp
) != 1)
249 fatal("write Bk header");
252 static void do_file(u32 file_no
)
262 header
= files
[file_no
];
264 size
= be32(header
+ 4);
272 "file: size=%08x perm=%02x attr=%02x type=%02x name=%s\n",
273 size
, perm
, attr
, type
, name
);
275 if (fwrite(header
, 0x80, 1, fp
) != 1)
276 fatal("write file header %d", file_no
);
279 rounded_size
= round_up(size
, 0x40);
281 data
= malloc(rounded_size
);
283 fatal("malloc data");
285 in
= fopen(name
, "rb");
287 fatal("open %s", name
);
288 if (fread(data
, size
, 1, in
) != 1)
289 fatal("read %s", name
);
292 memset(data
+ size
, 0, rounded_size
- size
);
294 aes_cbc_enc(sd_key
, header
+ 0x50, data
, rounded_size
, data
);
296 if (fwrite(data
, rounded_size
, 1, fp
) != 1)
297 fatal("write file %d", file_no
);
303 static void make_ec_cert(u8
*cert
, u8
*sig
, char *signer
, char *name
, u8
*priv
,
306 memset(cert
, 0, 0x180);
307 wbe32(cert
, 0x10002);
308 memcpy(cert
+ 4, sig
, 60);
309 strcpy(cert
+ 0x80, signer
);
310 wbe32(cert
+ 0xc0, 2);
311 strcpy(cert
+ 0xc4, name
);
312 wbe32(cert
+ 0x104, key_id
);
313 ec_priv_to_pub(priv
, cert
+ 0x108);
316 static void do_sig(void)
329 sprintf(signer
, "Root-CA00000001-MS00000002");
330 sprintf(name
, "NG%08x", ng_id
);
331 make_ec_cert(ng_cert
, ng_sig
, signer
, name
, ng_priv
, ng_key_id
);
333 memset(ap_priv
, 0, sizeof ap_priv
);
336 memset(ap_sig
, 81, sizeof ap_sig
); // temp
338 sprintf(signer
, "Root-CA00000001-MS00000002-NG%08x", ng_id
);
339 sprintf(name
, "AP%08x%08x", 1, 2);
340 make_ec_cert(ap_cert
, ap_sig
, signer
, name
, ap_priv
, 0);
342 sha(ap_cert
+ 0x80, 0x100, hash
);
343 generate_ecdsa(ap_sig
, ap_sig
+ 30, ng_priv
, hash
);
344 make_ec_cert(ap_cert
, ap_sig
, signer
, name
, ap_priv
, 0);
346 data_size
= files_size
+ 0x80;
348 data
= malloc(data_size
);
351 fseek(fp
, 0xf0c0, SEEK_SET
);
352 if (fread(data
, data_size
, 1, fp
) != 1)
353 fatal("read data for sig check");
354 sha(data
, data_size
, hash
);
358 generate_ecdsa(sig
, sig
+ 30, ap_priv
, hash
);
359 wbe32(sig
+ 60, 0x2f536969);
361 if (fwrite(sig
, sizeof sig
, 1, fp
) != 1)
363 if (fwrite(ng_cert
, sizeof ng_cert
, 1, fp
) != 1)
364 fatal("write NG cert");
365 if (fwrite(ap_cert
, sizeof ap_cert
, 1, fp
) != 1)
366 fatal("write AP cert");
369 int main(int argc
, char **argv
)
376 fprintf(stderr
, "Usage: %s <srcdir> <data.bin>\n", argv
[0]);
380 get_key("sd-key", sd_key
, 16);
381 get_key("sd-iv", sd_iv
, 16);
382 get_key("md5-blanker", md5_blanker
, 16);
384 get_key("default/NG-id", tmp
, 4);
386 get_key("default/NG-key-id", tmp
, 4);
387 ng_key_id
= be32(tmp
);
388 get_key("default/NG-mac", ng_mac
, 6);
389 get_key("default/NG-priv", ng_priv
, 30);
390 get_key("default/NG-sig", ng_sig
, 60);
392 if (sscanf(argv
[1], "%016llx", &title_id
) != 1)
393 ERROR("not a correct title id");
395 fp
= fopen(argv
[2], "wb+");
397 fatal("open %s", argv
[2]);
400 fatal("chdir %s", argv
[1]);
402 do_file_header(title_id
);
406 do_backup_header(title_id
);
408 for (i
= 0; i
< n_files
; i
++)