summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2020-08-10 23:09:46 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2020-10-11 13:08:03 +0200
commit8ce60c54f762b2f1392bee586dc8292170c87696 (patch)
treed979e6ebe4a54b07c57a9995cf2973118504e799
parent7cba59910669062b320eb57d831f3a9c50efb364 (diff)
downloadrockbox-8ce60c54f762b2f1392bee586dc8292170c87696.tar.gz
rockbox-8ce60c54f762b2f1392bee586dc8292170c87696.zip
nwztools/upgtool: add support for MD5
When compressing, it is possible to tell the tool to add an entry to the MD5 file (index 1), it is still necessary to give an empty file for that index. To do so, pass the option "-z idx,name" insteas of "-z idx". This will create an entry of the form "size md5 name". For instance "-z 6,system.img". When decompressing, if one passes "-z idx,name" instead of "-z idx", the tool will decompress and check against the value in the MD5 file. Change-Id: Ifb945f6121644ae9105265d2d83ce6067301c5b2
-rw-r--r--utils/nwztools/upgtools/mg.cpp18
-rw-r--r--utils/nwztools/upgtools/mg.h4
-rw-r--r--utils/nwztools/upgtools/upgtool.c141
3 files changed, 159 insertions, 4 deletions
diff --git a/utils/nwztools/upgtools/mg.cpp b/utils/nwztools/upgtools/mg.cpp
index df2dbbfd4f..a4d06cd77f 100644
--- a/utils/nwztools/upgtools/mg.cpp
+++ b/utils/nwztools/upgtools/mg.cpp
@@ -215,6 +215,24 @@ void MD5_CalculateDigest(void *digest, const void *input, size_t length)
215 MD5().CalculateDigest((byte *)digest, (const byte *)input, length); 215 MD5().CalculateDigest((byte *)digest, (const byte *)input, length);
216} 216}
217 217
218void *md5_start()
219{
220 return new MD5;
221}
222
223void md5_update(void *md5_obj, const void *input, size_t length)
224{
225 MD5 *md5 = reinterpret_cast<MD5 *>(md5_obj);
226 md5->Update(reinterpret_cast<const uint8_t *>(input), length);
227}
228
229void md5_final(void *md5_obj, void *digest)
230{
231 MD5 *md5 = reinterpret_cast<MD5 *>(md5_obj);
232 md5->Final(reinterpret_cast<uint8_t *>(digest));
233 delete md5;
234}
235
218void mg_decrypt_fw(void *in, int size, void *out, uint8_t *key) 236void mg_decrypt_fw(void *in, int size, void *out, uint8_t *key)
219{ 237{
220 ECB_Mode< DES >::Decryption dec; 238 ECB_Mode< DES >::Decryption dec;
diff --git a/utils/nwztools/upgtools/mg.h b/utils/nwztools/upgtools/mg.h
index 3f7de2cd9b..a2de5952fd 100644
--- a/utils/nwztools/upgtools/mg.h
+++ b/utils/nwztools/upgtools/mg.h
@@ -30,6 +30,10 @@ extern "C" {
30 30
31/* Compute the MD5 digest of a buffer */ 31/* Compute the MD5 digest of a buffer */
32void MD5_CalculateDigest(void *digest, const void *input, size_t length); 32void MD5_CalculateDigest(void *digest, const void *input, size_t length);
33/* Compute MD5 in more than one step */
34void *md5_start(); /* return an opaque pointer */
35void md5_update(void *md5_obj, const void *input, size_t length);
36void md5_final(void *md5_obj, void *digest); /* destroys the MD5 object */
33 37
34/* size must be a multiple of 8, this function is thread-safe */ 38/* size must be a multiple of 8, this function is thread-safe */
35void mg_decrypt_fw(void *in, int size, void *out, uint8_t key[8]); 39void mg_decrypt_fw(void *in, int size, void *out, uint8_t key[8]);
diff --git a/utils/nwztools/upgtools/upgtool.c b/utils/nwztools/upgtools/upgtool.c
index 8a9194ebe4..03d7d706d7 100644
--- a/utils/nwztools/upgtools/upgtool.c
+++ b/utils/nwztools/upgtools/upgtool.c
@@ -49,6 +49,7 @@ static char *g_sig = NULL;
49static int g_nr_threads = 1; 49static int g_nr_threads = 1;
50#define MAX_NR_FILES 32 50#define MAX_NR_FILES 32
51bool g_compress[MAX_NR_FILES] = {false}; 51bool g_compress[MAX_NR_FILES] = {false};
52const char *g_md5name[MAX_NR_FILES] = {NULL};
52 53
53enum keysig_search_method_t g_keysig_search = KEYSIG_SEARCH_NONE; 54enum keysig_search_method_t g_keysig_search = KEYSIG_SEARCH_NONE;
54 55
@@ -148,6 +149,93 @@ static int get_key_and_sig(bool is_extract, void *buf)
148 return 0; 149 return 0;
149} 150}
150 151
152static unsigned xdigit2val(char c)
153{
154 if('0' <= c && c <= '9')
155 return c - '0';
156 if('a' <= c && c <= 'f')
157 return c - 'a' + 10;
158 if('A' <= c && c <= 'F')
159 return c - 'A' + 10;
160 return 0;
161}
162
163static bool find_md5_entry(struct upg_file_t *file, const char *name, size_t *out_size, uint8_t *md5)
164{
165 char *content = file->files[1].data;
166 size_t size = file->files[1].size;
167 /* we expect the file to have a terminating zero because it is padded with zeroes, if not, add one */
168 if(content[size - 1] != 0)
169 {
170 content = file->files[1].data = realloc(content, size + 1);
171 content[size] = 0;
172 size++;
173 }
174 /* now we can parse safely by stopping t the first 0 */
175 size_t pos = 0;
176 while(true)
177 {
178 /* format of each line: filesize md5 name */
179 char *end;
180 if(content[pos] == 0)
181 break; /* stop on zero */
182 if(!isdigit(content[pos]))
183 goto Lskipline;
184 /* parse size */
185 *out_size = strtoul(content + pos, &end, 0);
186 pos = end - content;
187 while(content[pos] == ' ')
188 pos++;
189 /* parse md5 */
190 for(int i = 0; i < NWZ_MD5_SIZE; i++)
191 {
192 if(!isxdigit(content[pos]))
193 goto Lskipline;
194 if(!isxdigit(content[pos + 1]))
195 goto Lskipline;
196 md5[i] = xdigit2val(content[pos]) << 4 | xdigit2val(content[pos + 1]);
197 pos += 2;
198 }
199 /* parse name: this is a stupid comparison, no trimming */
200 while(content[pos] == ' ')
201 pos++;
202 size_t name_begin = pos;
203 while(content[pos] != 0 && content[pos] != '\n')
204 pos++;
205 if(strlen(name) == pos - name_begin && !memcmp(content + name_begin, name, pos - name_begin))
206 return true;
207 /* fallthrough: eat end of line */
208 Lskipline:
209 while(content[pos] != 0 && content[pos] != '\n')
210 pos++;
211 if(content[pos] == '\n')
212 pos++;
213 }
214 return false;
215}
216
217static void compare_md5(struct upg_file_t *file, int idx, size_t filesize, uint8_t *md5)
218{
219 if(g_md5name[idx] == NULL)
220 return;
221 size_t expected_size;
222 uint8_t expected_md5[NWZ_MD5_SIZE * 2];
223 bool found = find_md5_entry(file, g_md5name[idx], &expected_size, expected_md5);
224 cprintf(BLUE, "File %d\n", idx);
225 cprintf_field(" Name: ", "%s ", g_md5name[idx]);
226 cprintf(RED, found ? "Found" : " Not found");
227 printf("\n");
228 cprintf_field(" Size: ", "%lu", filesize);
229 cprintf(RED, " %s", !found ? "Cannot check" : filesize == expected_size ? "Ok" : "Mismatch");
230 printf("\n");
231 cprintf_field(" MD5:", " ");
232 for(int i = 0; i < NWZ_MD5_SIZE; i++)
233 printf("%02x", md5[i]);
234 bool ok_md5 = !memcmp(md5, expected_md5, NWZ_MD5_SIZE);
235 cprintf(RED, " %s", !found ? "Cannot check" : ok_md5 ? "Ok" : "Mismatch");
236 printf("\n");
237}
238
151static int do_upg(void *buf, long size) 239static int do_upg(void *buf, long size)
152{ 240{
153 int ret = get_key_and_sig(true, buf); 241 int ret = get_key_and_sig(true, buf);
@@ -171,8 +259,11 @@ static int do_upg(void *buf, long size)
171 continue; 259 continue;
172 } 260 }
173 free(str); 261 free(str);
262 /* we will compute the MD5 during writing/decompress */
174 if(g_compress[i]) 263 if(g_compress[i])
175 { 264 {
265 void *md5_obj = md5_start();
266 uint8_t md5[NWZ_MD5_SIZE];
176 void *buf = file->files[i].data; 267 void *buf = file->files[i].data;
177 int size = file->files[i].size; 268 int size = file->files[i].size;
178 int pos = 0; 269 int pos = 0;
@@ -182,6 +273,7 @@ static int do_upg(void *buf, long size)
182 void *chunk = malloc(max_chunk_size); 273 void *chunk = malloc(max_chunk_size);
183 if(g_debug) 274 if(g_debug)
184 cprintf(GREY, "decompressing file %d with chunk size %d...\n", i, max_chunk_size); 275 cprintf(GREY, "decompressing file %d with chunk size %d...\n", i, max_chunk_size);
276 size_t total_size = 0;
185 while(pos + 4 <= size) 277 while(pos + 4 <= size)
186 { 278 {
187 int compressed_chunk_size = *(uint32_t *)(buf + pos); 279 int compressed_chunk_size = *(uint32_t *)(buf + pos);
@@ -206,11 +298,15 @@ static int do_upg(void *buf, long size)
206 break; 298 break;
207 } 299 }
208 pos += 4 + compressed_chunk_size; 300 pos += 4 + compressed_chunk_size;
301 md5_update(md5_obj, chunk, chunk_size);
209 fwrite(chunk, 1, chunk_size, f); 302 fwrite(chunk, 1, chunk_size, f);
303 total_size += chunk_size;
210 } 304 }
211 free(chunk); 305 free(chunk);
212 if(g_debug) 306 if(g_debug)
213 cprintf(GREY, "done."); 307 cprintf(GREY, "done.");
308 md5_final(md5_obj, md5);
309 compare_md5(file, i, total_size, md5);
214 } 310 }
215 else 311 else
216 { 312 {
@@ -297,6 +393,9 @@ static int create_upg(int argc, char **argv)
297 struct upg_file_t *upg = upg_new(); 393 struct upg_file_t *upg = upg_new();
298 int nr_files = argc - 1; 394 int nr_files = argc - 1;
299 395
396 char *md5_prepend = malloc(1);
397 md5_prepend[0] = 0;
398 size_t md5_prepend_sz = 0;
300 for(int i = 0; i < nr_files; i++) 399 for(int i = 0; i < nr_files; i++)
301 { 400 {
302 FILE *f = fopen(argv[1 + i], "rb"); 401 FILE *f = fopen(argv[1 + i], "rb");
@@ -316,9 +415,24 @@ static int create_upg(int argc, char **argv)
316 return 1; 415 return 1;
317 } 416 }
318 fclose(f); 417 fclose(f);
418 /* add the MD5 of files *before* any kind of treatment. Does nothing if not resquested,
419 * which is important on v1 where the second file might not be the md5 file */
420 if(g_md5name[i])
421 {
422 uint8_t md5[NWZ_MD5_SIZE];
423 MD5_CalculateDigest(md5, buf, size);
424 size_t inc_sz = 16 + NWZ_MD5_SIZE * 2 + strlen(g_md5name[i]);
425 md5_prepend = realloc(md5_prepend, md5_prepend_sz + inc_sz);
426 md5_prepend_sz += sprintf(md5_prepend + md5_prepend_sz, "%lu ", size);
427 for(int i = 0; i < NWZ_MD5_SIZE; i++)
428 md5_prepend_sz += sprintf(md5_prepend + md5_prepend_sz, "%02x", md5[i]);
429 md5_prepend_sz += sprintf(md5_prepend + md5_prepend_sz, " %s\n", g_md5name[i]);
430 }
319 if(g_compress[i]) 431 if(g_compress[i])
320 { 432 {
321 int out_buf_max_sz = size; /* we expect that the output will not take more space */ 433 /* in the worst case, maybe the compressor will double the size, also we always need
434 * at least 4 bytes to write the size of a block */
435 int out_buf_max_sz = 4 + 2 * size;
322 void *out_buf = malloc(out_buf_max_sz); 436 void *out_buf = malloc(out_buf_max_sz);
323 int out_buf_pos = 0, in_buf_pos = 0; 437 int out_buf_pos = 0, in_buf_pos = 0;
324 int max_chunk_size = 4096; /* the OF encoder/decoder expect that */ 438 int max_chunk_size = 4096; /* the OF encoder/decoder expect that */
@@ -329,7 +443,7 @@ static int create_upg(int argc, char **argv)
329 int zres = compress(out_buf + out_buf_pos + 4, &dest_len, buf + in_buf_pos, chunk_size); 443 int zres = compress(out_buf + out_buf_pos + 4, &dest_len, buf + in_buf_pos, chunk_size);
330 if(zres == Z_BUF_ERROR) 444 if(zres == Z_BUF_ERROR)
331 { 445 {
332 cprintf(RED, "the compresser produced a file greater than its input, I can't handle that\n"); 446 cprintf(RED, "the compresser produced a file much greater than its input, I can't handle that\n");
333 return 1; 447 return 1;
334 } 448 }
335 else if(zres != Z_OK) 449 else if(zres != Z_OK)
@@ -352,6 +466,11 @@ static int create_upg(int argc, char **argv)
352 upg_append(upg, buf, size); 466 upg_append(upg, buf, size);
353 } 467 }
354 468
469 /* modify md5 file (if any) */
470 upg->files[1].data = realloc(upg->files[1].data, upg->files[1].size + md5_prepend_sz);
471 memmove(upg->files[1].data + md5_prepend_sz, upg->files[1].data, upg->files[1].size);
472 memcpy(upg->files[1].data, md5_prepend, md5_prepend_sz);
473
355 size_t size = 0; 474 size_t size = 0;
356 void *buf = upg_write_memory(upg, g_key, g_sig, &size, NULL, generic_std_printf); 475 void *buf = upg_write_memory(upg, g_key, g_sig, &size, NULL, generic_std_printf);
357 upg_free(upg); 476 upg_free(upg);
@@ -398,7 +517,11 @@ static void usage(void)
398 printf(" -e/--extract\t\tExtract a UPG archive\n"); 517 printf(" -e/--extract\t\tExtract a UPG archive\n");
399 printf(" -c/--create\t\tCreate a UPG archive\n"); 518 printf(" -c/--create\t\tCreate a UPG archive\n");
400 printf(" -z/--compress <idx>\t\t(De)compress file <idx> (starts at 0)\n"); 519 printf(" -z/--compress <idx>\t\t(De)compress file <idx> (starts at 0)\n");
401 printf("keysig search method:\n"); 520 printf(" -z/--compress <idx>,<md5name>\t\t(De)compress file <idx> and add it to the MD5 file\n");
521 printf("When using -z <idx>,<md5name>, the file file size and MD5 prior to compression will\n");
522 printf("be prepended to the contect of the second file (index 1). The name can be arbitrary and\n");
523 printf("has meaning only the script, e.g. \"-z 6,system.img\".\n");
524 printf("Keysig search method:\n");
402 for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++) 525 for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++)
403 printf(" %-10s\t%s\n", keysig_search_desc[i].name, keysig_search_desc[i].comment); 526 printf(" %-10s\t%s\n", keysig_search_desc[i].name, keysig_search_desc[i].comment);
404 exit(1); 527 exit(1);
@@ -494,13 +617,23 @@ int main(int argc, char **argv)
494 break; 617 break;
495 case 'z': 618 case 'z':
496 { 619 {
497 int idx = strtol(optarg, NULL, 0); 620 char *end;
621 int idx = strtol(optarg, &end, 0);
498 if(idx < 0 || idx >= MAX_NR_FILES) 622 if(idx < 0 || idx >= MAX_NR_FILES)
499 { 623 {
500 cprintf(GREY, "Invalid file index\n"); 624 cprintf(GREY, "Invalid file index\n");
501 return 1; 625 return 1;
502 } 626 }
503 g_compress[idx] = true; 627 g_compress[idx] = true;
628 /* distinguish betwen -z <idx> and -z <idx>,<md5name> */
629 if(*end == 0)
630 break;
631 if(*end != ',')
632 {
633 cprintf(GREY, "Invalid file index\n");
634 return 1;
635 }
636 g_md5name[idx] = end + 1;
504 break; 637 break;
505 } 638 }
506 default: 639 default: