diff options
author | Thom Johansen <thomj@rockbox.org> | 2005-04-25 21:08:36 +0000 |
---|---|---|
committer | Thom Johansen <thomj@rockbox.org> | 2005-04-25 21:08:36 +0000 |
commit | 8e20f02da5fb0fff9e1186aafbcebdb2d1ad90a3 (patch) | |
tree | 15a59767a56ec91c01acacf0d50b6a30f1afac4c /tools/fwpatcher | |
parent | 7254b9cc1506e2906ba70653fca8ad60b59437c1 (diff) | |
download | rockbox-8e20f02da5fb0fff9e1186aafbcebdb2d1ad90a3.tar.gz rockbox-8e20f02da5fb0fff9e1186aafbcebdb2d1ad90a3.zip |
GUI firmware patcher for windows.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6351 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'tools/fwpatcher')
-rw-r--r-- | tools/fwpatcher/checksums.h | 4 | ||||
-rw-r--r-- | tools/fwpatcher/favicon.ico | bin | 0 -> 1400 bytes | |||
-rw-r--r-- | tools/fwpatcher/iriver.c | 393 | ||||
-rw-r--r-- | tools/fwpatcher/iriver.h | 40 | ||||
-rw-r--r-- | tools/fwpatcher/main.c | 367 | ||||
-rw-r--r-- | tools/fwpatcher/md5.c | 246 | ||||
-rw-r--r-- | tools/fwpatcher/md5.h | 25 | ||||
-rw-r--r-- | tools/fwpatcher/resource.h | 3 | ||||
-rw-r--r-- | tools/fwpatcher/resource.rc | 4 |
9 files changed, 1082 insertions, 0 deletions
diff --git a/tools/fwpatcher/checksums.h b/tools/fwpatcher/checksums.h new file mode 100644 index 0000000000..a7de794126 --- /dev/null +++ b/tools/fwpatcher/checksums.h | |||
@@ -0,0 +1,4 @@ | |||
1 | "627d5195b56ebca3b431cccb535c3bfa", /* 1.63 eu */ | ||
2 | "5068bf62d68fdbfcb3d8a2eaf2f4fdfe", /* 1.63 us */ | ||
3 | "1afe2172a4d10f69069084466f7a83ce", /* 1.63 k */ | ||
4 | "5802da654706239f2782510f6ab73b26" /* 1.65 eu */ | ||
diff --git a/tools/fwpatcher/favicon.ico b/tools/fwpatcher/favicon.ico new file mode 100644 index 0000000000..c4989f558d --- /dev/null +++ b/tools/fwpatcher/favicon.ico | |||
Binary files differ | |||
diff --git a/tools/fwpatcher/iriver.c b/tools/fwpatcher/iriver.c new file mode 100644 index 0000000000..e24df8c768 --- /dev/null +++ b/tools/fwpatcher/iriver.c | |||
@@ -0,0 +1,393 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2004 by Dave Hooper | ||
11 | * | ||
12 | * This particular source code file is licensed under the X11 license. See the | ||
13 | * bottom of the COPYING file for details on this license. | ||
14 | * | ||
15 | * Original code from http://www.beermex.com/@spc/ihpfirm.src.zip | ||
16 | * Details at http://www.rockbox.org/twiki/bin/view/Main/IriverToolsGuide | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include <stdio.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | |||
23 | #include "iriver.h" | ||
24 | |||
25 | const unsigned char munge[] = { | ||
26 | 0x7a, 0x36, 0xc4, 0x43, 0x49, 0x6b, 0x35, 0x4e, 0xa3, 0x46, 0x25, 0x84, | ||
27 | 0x4d, 0x73, 0x74, 0x61 | ||
28 | }; | ||
29 | |||
30 | const unsigned char header_modify[] = "* IHPFIRM-DECODED "; | ||
31 | |||
32 | const char * const models[] = { "iHP-100", "iHP-120/iHP-140", "H300 series", | ||
33 | NULL }; | ||
34 | |||
35 | /* aligns with models array; expected min firmware size */ | ||
36 | const unsigned int firmware_minsize[] = { 0x100000, 0x100000, 0x200000 }; | ||
37 | /* aligns with models array; expected max firmware size */ | ||
38 | const unsigned int firmware_maxsize[] = { 0x200000, 0x200000, 0x400000 }; | ||
39 | |||
40 | const unsigned char header[][16] = { | ||
41 | { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, | ||
42 | { 0x20, 0x03, 0x08, 0x27, 0x24, 0x00, 0x02, 0x30, 0x19, 0x17, 0x65, 0x73, | ||
43 | 0x85, 0x32, 0x83, 0x22 }, | ||
44 | { 0x20, 0x04, 0x03, 0x27, 0x20, 0x50, 0x01, 0x70, 0x80, 0x30, 0x80, 0x06, | ||
45 | 0x30, 0x19, 0x17, 0x65 } | ||
46 | }; | ||
47 | |||
48 | static int testheader( const unsigned char * const data ) | ||
49 | { | ||
50 | const unsigned char * const d = data+16; | ||
51 | const char * const * m = models; | ||
52 | int index = 0; | ||
53 | while( *m ) | ||
54 | { | ||
55 | if( memcmp( header[ index ], d, 16 ) == 0 ) | ||
56 | return index; | ||
57 | index++; | ||
58 | m++; | ||
59 | }; | ||
60 | return -1; | ||
61 | }; | ||
62 | |||
63 | static void modifyheader( unsigned char * data ) | ||
64 | { | ||
65 | const unsigned char * h = header_modify; | ||
66 | int i; | ||
67 | for( i=0; i<512; i++ ) | ||
68 | { | ||
69 | if( *h == '\0' ) | ||
70 | h = header_modify; | ||
71 | *data++ ^= *h++; | ||
72 | }; | ||
73 | }; | ||
74 | |||
75 | static FILE * openinfile( const TCHAR * filename ) | ||
76 | { | ||
77 | FILE * F = _tfopen( filename, TEXT("rb") ); | ||
78 | if( F == NULL ) | ||
79 | { | ||
80 | fprintf( stderr, "Couldn't open input file %s\n", filename ); | ||
81 | perror( "Error was " ); | ||
82 | }; | ||
83 | return F; | ||
84 | }; | ||
85 | |||
86 | static FILE * openoutfile( const TCHAR * filename ) | ||
87 | { | ||
88 | FILE * F = _tfopen( filename, TEXT("wb") ); | ||
89 | if( F == NULL ) | ||
90 | { | ||
91 | fprintf( stderr, "Couldn't open output file %s\n", filename ); | ||
92 | perror( "Error was " ); | ||
93 | }; | ||
94 | return F; | ||
95 | }; | ||
96 | |||
97 | int iriver_decode(TCHAR *infile_name, TCHAR *outfile_name, unsigned int modify, | ||
98 | enum striptype stripmode ) | ||
99 | { | ||
100 | FILE * infile = NULL; | ||
101 | FILE * outfile = NULL; | ||
102 | int i = -1; | ||
103 | unsigned char headerdata[512]; | ||
104 | unsigned long dwLength1, dwLength2, dwLength3, fp = 0; | ||
105 | unsigned char blockdata[16+16]; | ||
106 | unsigned char out[16]; | ||
107 | unsigned char newmunge; | ||
108 | signed long lenread; | ||
109 | int s = 0; | ||
110 | unsigned char * pChecksums, * ppChecksums = 0; | ||
111 | unsigned char ck; | ||
112 | |||
113 | infile = openinfile(infile_name); | ||
114 | outfile = openoutfile(outfile_name); | ||
115 | if (!infile || !outfile) return -1; | ||
116 | |||
117 | lenread = fread( headerdata, 1, 512, infile ); | ||
118 | if( lenread != 512 ) | ||
119 | { | ||
120 | fprintf( stderr, "This doesn't look like a valid encrypted iHP " | ||
121 | "firmware - reason: header length\n" ); | ||
122 | goto error; | ||
123 | }; | ||
124 | |||
125 | i = testheader( headerdata ); | ||
126 | if( i == -1 ) | ||
127 | { | ||
128 | fprintf( stderr, "This firmware is for an unknown model, or is not" | ||
129 | " a valid encrypted iHP firmware\n" ); | ||
130 | goto error; | ||
131 | }; | ||
132 | fprintf( stderr, "Model %s\n", models[ i ] ); | ||
133 | |||
134 | dwLength1 = headerdata[0] | (headerdata[1]<<8) | | ||
135 | (headerdata[2]<<16) | (headerdata[3]<<24); | ||
136 | dwLength2 = headerdata[4] | (headerdata[5]<<8) | | ||
137 | (headerdata[6]<<16) | (headerdata[7]<<24); | ||
138 | dwLength3 = headerdata[8] | (headerdata[9]<<8) | | ||
139 | (headerdata[10]<<16) | (headerdata[11]<<24); | ||
140 | |||
141 | if( dwLength1 < firmware_minsize[ i ] || | ||
142 | dwLength1 > firmware_maxsize[ i ] || | ||
143 | dwLength2 < firmware_minsize[ i ] || | ||
144 | dwLength2 > dwLength1 || | ||
145 | dwLength3 > dwLength1 || | ||
146 | dwLength2>>9 != dwLength3 || | ||
147 | dwLength2+dwLength3+512 != dwLength1 ) | ||
148 | { | ||
149 | fprintf( stderr, "This doesn't look like a valid encrypted " | ||
150 | "iHP firmware - reason: file 'length' data\n" ); | ||
151 | goto error; | ||
152 | }; | ||
153 | |||
154 | pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) ); | ||
155 | |||
156 | if( modify ) | ||
157 | { | ||
158 | modifyheader( headerdata ); | ||
159 | }; | ||
160 | |||
161 | if( stripmode == STRIP_NONE ) | ||
162 | fwrite( headerdata, 512, 1, outfile ); | ||
163 | |||
164 | memset( blockdata, 0, 16 ); | ||
165 | |||
166 | ck = 0; | ||
167 | while( ( fp < dwLength2 ) && | ||
168 | ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 ) | ||
169 | { | ||
170 | fp += 16; | ||
171 | |||
172 | for( i=0; i<16; ++i ) | ||
173 | { | ||
174 | newmunge = blockdata[16+i] ^ munge[i]; | ||
175 | out[i] = newmunge ^ blockdata[i]; | ||
176 | blockdata[i] = newmunge; | ||
177 | ck += out[i]; | ||
178 | } | ||
179 | |||
180 | if( fp > ESTF_SIZE || stripmode != STRIP_HEADER_CHECKSUM_ESTF ) | ||
181 | { | ||
182 | fwrite( out+4, 1, 12, outfile ); | ||
183 | fwrite( out, 1, 4, outfile ); | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | if( ESTF_SIZE - fp < 16 ) | ||
188 | { | ||
189 | memcpy( out+4, blockdata+16, 12 ); | ||
190 | memcpy( out, blockdata+28, 4 ); | ||
191 | fwrite( blockdata+16+ESTF_SIZE-fp, 1, ESTF_SIZE-fp, outfile ); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | |||
196 | if( s == 496 ) | ||
197 | { | ||
198 | s = 0; | ||
199 | memset( blockdata, 0, 16 ); | ||
200 | *ppChecksums++ = ck; | ||
201 | ck = 0; | ||
202 | } | ||
203 | else | ||
204 | s+=16; | ||
205 | }; | ||
206 | |||
207 | if( fp != dwLength2 ) | ||
208 | { | ||
209 | fprintf( stderr, "This doesn't look like a valid encrypted " | ||
210 | "iHP firmware - reason: 'length2' mismatch\n" ); | ||
211 | goto error; | ||
212 | }; | ||
213 | |||
214 | fp = 0; | ||
215 | ppChecksums = pChecksums; | ||
216 | while( ( fp < dwLength3 ) && | ||
217 | ( lenread = fread( blockdata, 1, 32, infile ) ) > 0 ) | ||
218 | { | ||
219 | fp += lenread; | ||
220 | if( stripmode == STRIP_NONE ) | ||
221 | fwrite( blockdata, 1, lenread, outfile ); | ||
222 | if( memcmp( ppChecksums, blockdata, lenread ) != 0 ) | ||
223 | { | ||
224 | fprintf( stderr, "This doesn't look like a valid encrypted " | ||
225 | "iHP firmware - reason: Checksum mismatch!" ); | ||
226 | goto error; | ||
227 | }; | ||
228 | ppChecksums += lenread; | ||
229 | }; | ||
230 | |||
231 | if( fp != dwLength3 ) | ||
232 | { | ||
233 | fprintf( stderr, "This doesn't look like a valid encrypted " | ||
234 | "iHP firmware - reason: 'length3' mismatch\n" ); | ||
235 | goto error; | ||
236 | }; | ||
237 | |||
238 | |||
239 | fprintf( stderr, "File decoded correctly and all checksums matched!\n" ); | ||
240 | switch( stripmode ) | ||
241 | { | ||
242 | default: | ||
243 | case STRIP_NONE: | ||
244 | fprintf(stderr, "Output file contains all headers and " | ||
245 | "checksums\n"); | ||
246 | break; | ||
247 | case STRIP_HEADER_CHECKSUM: | ||
248 | fprintf( stderr, "NB: output file contains only ESTFBINR header" | ||
249 | " and decoded firmware code\n" ); | ||
250 | break; | ||
251 | case STRIP_HEADER_CHECKSUM_ESTF: | ||
252 | fprintf( stderr, "NB: output file contains only raw decoded " | ||
253 | "firmware code\n" ); | ||
254 | break; | ||
255 | }; | ||
256 | |||
257 | fclose(infile); | ||
258 | fclose(outfile); | ||
259 | return 0; | ||
260 | error: | ||
261 | fclose(infile); | ||
262 | fclose(outfile); | ||
263 | return -1; | ||
264 | }; | ||
265 | |||
266 | int iriver_encode(TCHAR *infile_name, TCHAR *outfile_name, unsigned int modify ) | ||
267 | { | ||
268 | FILE * infile = NULL; | ||
269 | FILE * outfile = NULL; | ||
270 | int i = -1; | ||
271 | unsigned char headerdata[512]; | ||
272 | unsigned long dwLength1, dwLength2, dwLength3, fp = 0; | ||
273 | unsigned char blockdata[16+16]; | ||
274 | unsigned char out[16]; | ||
275 | unsigned char newmunge; | ||
276 | signed long lenread; | ||
277 | int s = 0; | ||
278 | unsigned char * pChecksums, * ppChecksums; | ||
279 | unsigned char ck; | ||
280 | |||
281 | enum striptype stripmode = STRIP_NONE; | ||
282 | |||
283 | infile = openinfile(infile_name); | ||
284 | outfile = openoutfile(outfile_name); | ||
285 | if (!infile || !outfile) return -1; | ||
286 | |||
287 | lenread = fread( headerdata, 1, 512, infile ); | ||
288 | if( lenread != 512 ) | ||
289 | { | ||
290 | fprintf( stderr, "This doesn't look like a valid decoded " | ||
291 | "iHP firmware - reason: header length\n" ); | ||
292 | goto error; | ||
293 | }; | ||
294 | |||
295 | if( modify ) | ||
296 | { | ||
297 | modifyheader( headerdata ); /* reversible */ | ||
298 | }; | ||
299 | |||
300 | i = testheader( headerdata ); | ||
301 | if( i == -1 ) | ||
302 | { | ||
303 | fprintf( stderr, "This firmware is for an unknown model, or is not" | ||
304 | " a valid decoded iHP firmware\n" ); | ||
305 | goto error; | ||
306 | }; | ||
307 | fprintf( stderr, "Model %s\n", models[ i ] ); | ||
308 | |||
309 | dwLength1 = headerdata[0] | (headerdata[1]<<8) | | ||
310 | (headerdata[2]<<16) | (headerdata[3]<<24); | ||
311 | dwLength2 = headerdata[4] | (headerdata[5]<<8) | | ||
312 | (headerdata[6]<<16) | (headerdata[7]<<24); | ||
313 | dwLength3 = headerdata[8] | (headerdata[9]<<8) | | ||
314 | (headerdata[10]<<16) | (headerdata[11]<<24); | ||
315 | |||
316 | if( dwLength1 < firmware_minsize[i] || | ||
317 | dwLength1 > firmware_maxsize[i] || | ||
318 | dwLength2 < firmware_minsize[i] || | ||
319 | dwLength2 > dwLength1 || | ||
320 | dwLength3 > dwLength1 || | ||
321 | dwLength2+dwLength3+512 != dwLength1 ) | ||
322 | { | ||
323 | fprintf( stderr, "This doesn't look like a valid decoded iHP" | ||
324 | " firmware - reason: file 'length' data\n" ); | ||
325 | goto error; | ||
326 | }; | ||
327 | |||
328 | pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) ); | ||
329 | |||
330 | fwrite( headerdata, 512, 1, outfile ); | ||
331 | |||
332 | memset( blockdata, 0, 16 ); | ||
333 | ck = 0; | ||
334 | while( ( fp < dwLength2 ) && | ||
335 | ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 ) | ||
336 | { | ||
337 | fp += 16; | ||
338 | for( i=0; i<16; ++i ) | ||
339 | { | ||
340 | newmunge = blockdata[16+((12+i)&0xf)] ^ blockdata[i]; | ||
341 | out[i] = newmunge ^ munge[i]; | ||
342 | ck += blockdata[16+i]; | ||
343 | blockdata[i] = newmunge; | ||
344 | }; | ||
345 | fwrite( out, 1, 16, outfile ); | ||
346 | |||
347 | if( s == 496 ) | ||
348 | { | ||
349 | s = 0; | ||
350 | memset( blockdata, 0, 16 ); | ||
351 | *ppChecksums++ = ck; | ||
352 | ck = 0; | ||
353 | } | ||
354 | else | ||
355 | s+=16; | ||
356 | }; | ||
357 | |||
358 | if( fp != dwLength2 ) | ||
359 | { | ||
360 | fprintf( stderr, "This doesn't look like a valid decoded " | ||
361 | "iHP firmware - reason: 'length1' mismatch\n" ); | ||
362 | goto error; | ||
363 | }; | ||
364 | |||
365 | /* write out remainder w/out applying descrambler */ | ||
366 | fp = 0; | ||
367 | lenread = dwLength3; | ||
368 | ppChecksums = pChecksums; | ||
369 | while( ( fp < dwLength3) && | ||
370 | ( lenread = fwrite( ppChecksums, 1, lenread, outfile ) ) > 0 ) | ||
371 | { | ||
372 | fp += lenread; | ||
373 | ppChecksums += lenread; | ||
374 | lenread = dwLength3 - fp; | ||
375 | }; | ||
376 | |||
377 | if( fp != dwLength3 ) | ||
378 | { | ||
379 | fprintf( stderr, "This doesn't look like a valid decoded " | ||
380 | "iHP firmware - reason: 'length2' mismatch\n" ); | ||
381 | goto error; | ||
382 | }; | ||
383 | |||
384 | fprintf( stderr, "File encoded successfully and checksum table built!\n" ); | ||
385 | |||
386 | fclose(infile); | ||
387 | fclose(outfile); | ||
388 | return 0; | ||
389 | error: | ||
390 | fclose(infile); | ||
391 | fclose(outfile); | ||
392 | return -1; | ||
393 | }; | ||
diff --git a/tools/fwpatcher/iriver.h b/tools/fwpatcher/iriver.h new file mode 100644 index 0000000000..d3d00d2eff --- /dev/null +++ b/tools/fwpatcher/iriver.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 by Daniel Stenberg | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include <tchar.h> | ||
21 | #include <windows.h> | ||
22 | |||
23 | #define TRUE 1 | ||
24 | #define FALSE 0 | ||
25 | |||
26 | #define BOOL unsigned int | ||
27 | |||
28 | #define ESTF_SIZE 32 | ||
29 | |||
30 | enum striptype | ||
31 | { | ||
32 | STRIP_NONE, | ||
33 | STRIP_HEADER_CHECKSUM, | ||
34 | STRIP_HEADER_CHECKSUM_ESTF | ||
35 | }; | ||
36 | |||
37 | /* protos for iriver.c */ | ||
38 | int iriver_decode(TCHAR *infile, TCHAR *outfile, BOOL modify, | ||
39 | enum striptype stripmode ); | ||
40 | int iriver_encode(TCHAR *infile_name, TCHAR *outfile_name, BOOL modify ); | ||
diff --git a/tools/fwpatcher/main.c b/tools/fwpatcher/main.c new file mode 100644 index 0000000000..c8fa11ea95 --- /dev/null +++ b/tools/fwpatcher/main.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 by Thom Johansen | ||
11 | * | ||
12 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
13 | * KIND, either express or implied. | ||
14 | * | ||
15 | ****************************************************************************/ | ||
16 | |||
17 | /* TODO: integrate the iriver.c and mkboot stuff better, they're pretty much | ||
18 | * intended to be called from a command line tool, and i haven't changed that. | ||
19 | */ | ||
20 | |||
21 | #include <stdio.h> | ||
22 | #include <string.h> | ||
23 | #include <tchar.h> | ||
24 | #include <windows.h> | ||
25 | #include "iriver.h" | ||
26 | #include "md5.h" | ||
27 | #include "resource.h" | ||
28 | |||
29 | #define WINDOW_WIDTH 280 | ||
30 | #define WINDOW_HEIGHT 130 | ||
31 | |||
32 | #define IDM_RESTORE 1000 | ||
33 | #define IDM_EXIT 1010 | ||
34 | |||
35 | #define LABEL_FILENAME 0 | ||
36 | #define EDIT_FILENAME 1 | ||
37 | #define BUTTON_BROWSE 2 | ||
38 | #define BUTTON_PATCH 3 | ||
39 | |||
40 | #define CTL_NUM 4 | ||
41 | |||
42 | /* include precalculated checksums */ | ||
43 | static char *checksums[] = { | ||
44 | #include "checksums.h" | ||
45 | }; | ||
46 | |||
47 | HICON rbicon; | ||
48 | HFONT deffont; | ||
49 | HWND controls[CTL_NUM]; | ||
50 | |||
51 | /* begin mkboot.c excerpt */ | ||
52 | |||
53 | char image[0x200000 + 0x220 + 0x200000/0x200]; | ||
54 | |||
55 | int mkboot(TCHAR *infile, TCHAR *outfile, unsigned char *bldata, int bllen) | ||
56 | { | ||
57 | FILE *f; | ||
58 | int i; | ||
59 | int len; | ||
60 | int actual_length, total_length, binary_length, num_chksums; | ||
61 | |||
62 | memset(image, 0xff, sizeof(image)); | ||
63 | |||
64 | /* First, read the iriver original firmware into the image */ | ||
65 | f = _tfopen(infile, TEXT("rb")); | ||
66 | if(!f) { | ||
67 | perror(infile); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | i = fread(image, 1, 16, f); | ||
72 | if(i < 16) { | ||
73 | perror(infile); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | /* This is the length of the binary image without the scrambling | ||
78 | overhead (but including the ESTFBINR header) */ | ||
79 | binary_length = image[4] + (image[5] << 8) + | ||
80 | (image[6] << 16) + (image[7] << 24); | ||
81 | |||
82 | /* Read the rest of the binary data, but not the checksum block */ | ||
83 | len = binary_length+0x200-16; | ||
84 | i = fread(image+16, 1, len, f); | ||
85 | if(i < len) { | ||
86 | perror(infile); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | fclose(f); | ||
91 | |||
92 | memcpy(image + 0x220 + 0x1f0000, bldata, bllen); | ||
93 | |||
94 | f = _tfopen(outfile, TEXT("wb")); | ||
95 | if(!f) { | ||
96 | perror(outfile); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | /* Patch the reset vector to start the boot loader */ | ||
101 | image[0x220 + 4] = image[0x1f0000 + 0x220 + 4]; | ||
102 | image[0x220 + 5] = image[0x1f0000 + 0x220 + 5]; | ||
103 | image[0x220 + 6] = image[0x1f0000 + 0x220 + 6]; | ||
104 | image[0x220 + 7] = image[0x1f0000 + 0x220 + 7]; | ||
105 | |||
106 | /* This is the actual length of the binary, excluding all headers */ | ||
107 | actual_length = 0x1f0000 + bllen; | ||
108 | |||
109 | /* Patch the ESTFBINR header */ | ||
110 | image[0x20c] = (actual_length >> 24) & 0xff; | ||
111 | image[0x20d] = (actual_length >> 16) & 0xff; | ||
112 | image[0x20e] = (actual_length >> 8) & 0xff; | ||
113 | image[0x20f] = actual_length & 0xff; | ||
114 | |||
115 | image[0x21c] = (actual_length >> 24) & 0xff; | ||
116 | image[0x21d] = (actual_length >> 16) & 0xff; | ||
117 | image[0x21e] = (actual_length >> 8) & 0xff; | ||
118 | image[0x21f] = actual_length & 0xff; | ||
119 | |||
120 | /* This is the length of the binary, including the ESTFBINR header and | ||
121 | rounded up to the nearest 0x200 boundary */ | ||
122 | binary_length = (actual_length + 0x20 + 0x1ff) & 0xfffffe00; | ||
123 | |||
124 | /* The number of checksums, i.e number of 0x200 byte blocks */ | ||
125 | num_chksums = binary_length / 0x200; | ||
126 | |||
127 | /* The total file length, including all headers and checksums */ | ||
128 | total_length = binary_length + num_chksums + 0x200; | ||
129 | |||
130 | /* Patch the scrambler header with the new length info */ | ||
131 | image[0] = total_length & 0xff; | ||
132 | image[1] = (total_length >> 8) & 0xff; | ||
133 | image[2] = (total_length >> 16) & 0xff; | ||
134 | image[3] = (total_length >> 24) & 0xff; | ||
135 | |||
136 | image[4] = binary_length & 0xff; | ||
137 | image[5] = (binary_length >> 8) & 0xff; | ||
138 | image[6] = (binary_length >> 16) & 0xff; | ||
139 | image[7] = (binary_length >> 24) & 0xff; | ||
140 | |||
141 | image[8] = num_chksums & 0xff; | ||
142 | image[9] = (num_chksums >> 8) & 0xff; | ||
143 | image[10] = (num_chksums >> 16) & 0xff; | ||
144 | image[11] = (num_chksums >> 24) & 0xff; | ||
145 | |||
146 | i = fwrite(image, 1, total_length, f); | ||
147 | if(i < total_length) { | ||
148 | perror(outfile); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | fclose(f); | ||
153 | |||
154 | return 1; | ||
155 | } | ||
156 | |||
157 | /* end mkboot.c excerpt */ | ||
158 | |||
159 | int FileMD5(TCHAR *name, char *md5) | ||
160 | { | ||
161 | int i, read; | ||
162 | md5_context ctx; | ||
163 | unsigned char md5sum[16]; | ||
164 | unsigned char block[32768]; | ||
165 | FILE *file; | ||
166 | |||
167 | file = _tfopen(name, TEXT("rb")); | ||
168 | if (!file) { | ||
169 | MessageBox(NULL, | ||
170 | TEXT("Could not open patched firmware for checksum check"), | ||
171 | TEXT("Error"), MB_ICONERROR); | ||
172 | return 0; | ||
173 | } | ||
174 | md5_starts(&ctx); | ||
175 | while ((read = fread(block, 1, sizeof(block), file)) > 0) { | ||
176 | md5_update(&ctx, block, read); | ||
177 | } | ||
178 | fclose(file); | ||
179 | md5_finish(&ctx, md5sum); | ||
180 | for (i = 0; i < 16; ++i) | ||
181 | sprintf(md5 + 2*i, "%02x", md5sum[i]); | ||
182 | return 1; | ||
183 | } | ||
184 | |||
185 | int PatchFirmware() | ||
186 | { | ||
187 | TCHAR fn[MAX_PATH]; | ||
188 | TCHAR name1[MAX_PATH], name2[MAX_PATH], name3[MAX_PATH]; | ||
189 | HRSRC res; | ||
190 | HGLOBAL resload; | ||
191 | unsigned char *bootloader; | ||
192 | unsigned char md5sum_str[256]; | ||
193 | DWORD blsize; | ||
194 | int i; | ||
195 | |||
196 | /* get pointer to bootloader.bin */ | ||
197 | res = FindResource(NULL, MAKEINTRESOURCE(IDI_BOOTLOADER), TEXT("BIN")); | ||
198 | resload = LoadResource(NULL, res); | ||
199 | bootloader = (unsigned char *)LockResource(resload); | ||
200 | blsize = SizeofResource(NULL, res); | ||
201 | |||
202 | /* get filename from edit box */ | ||
203 | GetWindowText(controls[EDIT_FILENAME], fn, MAX_PATH); | ||
204 | /* store temp files in temp directory */ | ||
205 | GetTempPath(MAX_PATH, name1); | ||
206 | GetTempPath(MAX_PATH, name2); | ||
207 | GetTempPath(MAX_PATH, name3); | ||
208 | _tcscat(name1, TEXT("firmware.bin")); /* descrambled file */ | ||
209 | _tcscat(name2, TEXT("new.bin")); /* patched file */ | ||
210 | _tcscat(name3, TEXT("new.hex")); /* patched and scrambled file */ | ||
211 | if (iriver_decode(fn, name1, FALSE, STRIP_NONE) == -1) { | ||
212 | MessageBox(NULL, TEXT("Error in descramble"), | ||
213 | TEXT("Error"), MB_ICONERROR); | ||
214 | goto error; | ||
215 | } | ||
216 | if (!mkboot(name1, name2, bootloader, blsize)) { | ||
217 | MessageBox(NULL, TEXT("Error in patching"), | ||
218 | TEXT("Error"), MB_ICONERROR); | ||
219 | goto error; | ||
220 | } | ||
221 | if (iriver_encode(name2, name3, FALSE) == -1) { | ||
222 | MessageBox(NULL, TEXT("Error in scramble"), | ||
223 | TEXT("Error"), MB_ICONERROR); | ||
224 | goto error; | ||
225 | } | ||
226 | /* now md5sum it */ | ||
227 | if (!FileMD5(name3, md5sum_str)) goto error; | ||
228 | for (i = 0; i < sizeof(checksums)/sizeof(char *); ++i) { | ||
229 | if (strncmp(checksums[i], md5sum_str, 32) != 0) { | ||
230 | MessageBox(NULL, | ||
231 | TEXT("Checksum doesn't match known good patched firmware.\n") | ||
232 | TEXT("Download another firmware image, then try again."), | ||
233 | TEXT("Error"), MB_ICONERROR); | ||
234 | goto error; | ||
235 | } | ||
236 | } | ||
237 | /* all is fine, rename the patched file to original name of the firmware */ | ||
238 | MoveFileEx(name3, fn, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); | ||
239 | /* delete temp files */ | ||
240 | DeleteFile(name1); | ||
241 | DeleteFile(name2); | ||
242 | return 1; | ||
243 | error: | ||
244 | /* delete all temp files, don't care if some aren't created yet */ | ||
245 | DeleteFile(name1); | ||
246 | DeleteFile(name2); | ||
247 | DeleteFile(name3); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | int FileDialog(TCHAR *fn) | ||
252 | { | ||
253 | OPENFILENAME ofn; | ||
254 | TCHAR filename[MAX_PATH]; | ||
255 | |||
256 | ZeroMemory(&ofn, sizeof(ofn)); | ||
257 | ofn.lStructSize = sizeof(ofn); | ||
258 | ofn.lpstrFile = filename; | ||
259 | ofn.lpstrFile[0] = '\0'; // no default filename | ||
260 | ofn.nMaxFile = sizeof(filename); | ||
261 | ofn.lpstrFilter = TEXT("Firmware\0*.HEX\0"); | ||
262 | ofn.nFilterIndex = 1; | ||
263 | ofn.lpstrFileTitle = NULL; | ||
264 | ofn.nMaxFileTitle = 0; | ||
265 | ofn.lpstrInitialDir = NULL; | ||
266 | ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; | ||
267 | |||
268 | if (GetOpenFileName(&ofn) == TRUE) { | ||
269 | _tcscpy(fn, filename); | ||
270 | return 1; | ||
271 | } | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) | ||
276 | { | ||
277 | int i; | ||
278 | switch (msg) { | ||
279 | case WM_CREATE: | ||
280 | /* text label */ | ||
281 | controls[LABEL_FILENAME] = | ||
282 | CreateWindowEx(0, TEXT("STATIC"), TEXT("Firmware file name:"), | ||
283 | WS_CHILD | WS_VISIBLE, 10, 14, | ||
284 | 100, 32, hwnd, 0, 0, 0); | ||
285 | /* text field for inputing file name */ | ||
286 | controls[EDIT_FILENAME] = | ||
287 | CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT(""), | ||
288 | WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_AUTOHSCROLL, | ||
289 | 10, 35, 180, 20, hwnd, 0, 0, 0); | ||
290 | /* browse button */ | ||
291 | controls[BUTTON_BROWSE] = | ||
292 | CreateWindowEx(0, TEXT("BUTTON"), TEXT("Browse"), | ||
293 | WS_CHILD | WS_TABSTOP | WS_VISIBLE, 200, 32, 70, 25, | ||
294 | hwnd, 0, 0, 0); | ||
295 | /* patch button */ | ||
296 | controls[BUTTON_PATCH] = | ||
297 | CreateWindowEx(0, TEXT("BUTTON"), TEXT("Patch"), | ||
298 | WS_CHILD | WS_TABSTOP | WS_VISIBLE, 90, 70, 90, 25, | ||
299 | hwnd, 0, 0, 0); | ||
300 | /* set default font on all controls, will be ugly if we don't do this */ | ||
301 | deffont = GetStockObject(DEFAULT_GUI_FONT); | ||
302 | for (i = 0; i < CTL_NUM; ++i) | ||
303 | SendMessage(controls[i], WM_SETFONT, (WPARAM)deffont, | ||
304 | MAKELPARAM(FALSE, 0)); | ||
305 | break; | ||
306 | case WM_CLOSE: | ||
307 | DestroyWindow(hwnd); | ||
308 | break; | ||
309 | case WM_DESTROY: | ||
310 | PostQuitMessage(0); | ||
311 | break; | ||
312 | case WM_SIZE: | ||
313 | break; | ||
314 | case WM_COMMAND: | ||
315 | /* user pressed browse button */ | ||
316 | if (((HWND)lParam == controls[BUTTON_BROWSE])) { | ||
317 | TCHAR buf[MAX_PATH]; | ||
318 | if (FileDialog(buf)) | ||
319 | SetWindowText(controls[EDIT_FILENAME], buf); | ||
320 | } | ||
321 | /* user pressed patch button */ | ||
322 | if (((HWND)lParam == controls[BUTTON_PATCH])) { | ||
323 | if (PatchFirmware()) | ||
324 | MessageBox(NULL, TEXT("Firmware patched successfully"), | ||
325 | TEXT("Success"), MB_OK); | ||
326 | } | ||
327 | break; | ||
328 | default: | ||
329 | return DefWindowProc(hwnd, msg, wParam, lParam); | ||
330 | } | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | int WINAPI WinMain(HINSTANCE instance, HINSTANCE prev_instance, | ||
335 | LPSTR command_line, int command_show) | ||
336 | { | ||
337 | HWND window; | ||
338 | WNDCLASSEX wc; | ||
339 | MSG msg; | ||
340 | |||
341 | rbicon = LoadIcon(instance, MAKEINTRESOURCE(IDI_RBICON)); | ||
342 | ZeroMemory(&wc, sizeof(wc)); | ||
343 | wc.cbSize = sizeof(wc); | ||
344 | wc.lpfnWndProc = WndProc; | ||
345 | wc.hInstance = instance; | ||
346 | wc.hIcon = rbicon; | ||
347 | wc.hCursor = LoadCursor(0, IDC_ARROW); | ||
348 | wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); | ||
349 | wc.lpszClassName = TEXT("patcher"); | ||
350 | RegisterClassEx(&wc); | ||
351 | |||
352 | window = CreateWindowEx(0, TEXT("patcher"), TEXT("Rockbox firmware patcher"), | ||
353 | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | | ||
354 | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, | ||
355 | WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, instance, NULL); | ||
356 | if (!window) return 0; | ||
357 | |||
358 | ShowWindow(window, command_show); | ||
359 | while (GetMessage(&msg, 0, 0, 0) > 0) { | ||
360 | if (!IsDialogMessage(window, &msg)) { | ||
361 | TranslateMessage(&msg); | ||
362 | DispatchMessage(&msg); | ||
363 | } | ||
364 | } | ||
365 | return 0; | ||
366 | } | ||
367 | |||
diff --git a/tools/fwpatcher/md5.c b/tools/fwpatcher/md5.c new file mode 100644 index 0000000000..6c5e8127f9 --- /dev/null +++ b/tools/fwpatcher/md5.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * RFC 1321 compliant MD5 implementation | ||
3 | * | ||
4 | * Copyright (C) 2001-2003 Christophe Devine | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <string.h> | ||
22 | |||
23 | #include "md5.h" | ||
24 | |||
25 | #define GET_UINT32(n,b,i) \ | ||
26 | { \ | ||
27 | (n) = ( (uint32) (b)[(i) ] ) \ | ||
28 | | ( (uint32) (b)[(i) + 1] << 8 ) \ | ||
29 | | ( (uint32) (b)[(i) + 2] << 16 ) \ | ||
30 | | ( (uint32) (b)[(i) + 3] << 24 ); \ | ||
31 | } | ||
32 | |||
33 | #define PUT_UINT32(n,b,i) \ | ||
34 | { \ | ||
35 | (b)[(i) ] = (uint8) ( (n) ); \ | ||
36 | (b)[(i) + 1] = (uint8) ( (n) >> 8 ); \ | ||
37 | (b)[(i) + 2] = (uint8) ( (n) >> 16 ); \ | ||
38 | (b)[(i) + 3] = (uint8) ( (n) >> 24 ); \ | ||
39 | } | ||
40 | |||
41 | void md5_starts( md5_context *ctx ) | ||
42 | { | ||
43 | ctx->total[0] = 0; | ||
44 | ctx->total[1] = 0; | ||
45 | |||
46 | ctx->state[0] = 0x67452301; | ||
47 | ctx->state[1] = 0xEFCDAB89; | ||
48 | ctx->state[2] = 0x98BADCFE; | ||
49 | ctx->state[3] = 0x10325476; | ||
50 | } | ||
51 | |||
52 | void md5_process( md5_context *ctx, uint8 data[64] ) | ||
53 | { | ||
54 | uint32 X[16], A, B, C, D; | ||
55 | |||
56 | GET_UINT32( X[0], data, 0 ); | ||
57 | GET_UINT32( X[1], data, 4 ); | ||
58 | GET_UINT32( X[2], data, 8 ); | ||
59 | GET_UINT32( X[3], data, 12 ); | ||
60 | GET_UINT32( X[4], data, 16 ); | ||
61 | GET_UINT32( X[5], data, 20 ); | ||
62 | GET_UINT32( X[6], data, 24 ); | ||
63 | GET_UINT32( X[7], data, 28 ); | ||
64 | GET_UINT32( X[8], data, 32 ); | ||
65 | GET_UINT32( X[9], data, 36 ); | ||
66 | GET_UINT32( X[10], data, 40 ); | ||
67 | GET_UINT32( X[11], data, 44 ); | ||
68 | GET_UINT32( X[12], data, 48 ); | ||
69 | GET_UINT32( X[13], data, 52 ); | ||
70 | GET_UINT32( X[14], data, 56 ); | ||
71 | GET_UINT32( X[15], data, 60 ); | ||
72 | |||
73 | #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) | ||
74 | |||
75 | #define P(a,b,c,d,k,s,t) \ | ||
76 | { \ | ||
77 | a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ | ||
78 | } | ||
79 | |||
80 | A = ctx->state[0]; | ||
81 | B = ctx->state[1]; | ||
82 | C = ctx->state[2]; | ||
83 | D = ctx->state[3]; | ||
84 | |||
85 | #define F(x,y,z) (z ^ (x & (y ^ z))) | ||
86 | |||
87 | P( A, B, C, D, 0, 7, 0xD76AA478 ); | ||
88 | P( D, A, B, C, 1, 12, 0xE8C7B756 ); | ||
89 | P( C, D, A, B, 2, 17, 0x242070DB ); | ||
90 | P( B, C, D, A, 3, 22, 0xC1BDCEEE ); | ||
91 | P( A, B, C, D, 4, 7, 0xF57C0FAF ); | ||
92 | P( D, A, B, C, 5, 12, 0x4787C62A ); | ||
93 | P( C, D, A, B, 6, 17, 0xA8304613 ); | ||
94 | P( B, C, D, A, 7, 22, 0xFD469501 ); | ||
95 | P( A, B, C, D, 8, 7, 0x698098D8 ); | ||
96 | P( D, A, B, C, 9, 12, 0x8B44F7AF ); | ||
97 | P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); | ||
98 | P( B, C, D, A, 11, 22, 0x895CD7BE ); | ||
99 | P( A, B, C, D, 12, 7, 0x6B901122 ); | ||
100 | P( D, A, B, C, 13, 12, 0xFD987193 ); | ||
101 | P( C, D, A, B, 14, 17, 0xA679438E ); | ||
102 | P( B, C, D, A, 15, 22, 0x49B40821 ); | ||
103 | |||
104 | #undef F | ||
105 | |||
106 | #define F(x,y,z) (y ^ (z & (x ^ y))) | ||
107 | |||
108 | P( A, B, C, D, 1, 5, 0xF61E2562 ); | ||
109 | P( D, A, B, C, 6, 9, 0xC040B340 ); | ||
110 | P( C, D, A, B, 11, 14, 0x265E5A51 ); | ||
111 | P( B, C, D, A, 0, 20, 0xE9B6C7AA ); | ||
112 | P( A, B, C, D, 5, 5, 0xD62F105D ); | ||
113 | P( D, A, B, C, 10, 9, 0x02441453 ); | ||
114 | P( C, D, A, B, 15, 14, 0xD8A1E681 ); | ||
115 | P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); | ||
116 | P( A, B, C, D, 9, 5, 0x21E1CDE6 ); | ||
117 | P( D, A, B, C, 14, 9, 0xC33707D6 ); | ||
118 | P( C, D, A, B, 3, 14, 0xF4D50D87 ); | ||
119 | P( B, C, D, A, 8, 20, 0x455A14ED ); | ||
120 | P( A, B, C, D, 13, 5, 0xA9E3E905 ); | ||
121 | P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); | ||
122 | P( C, D, A, B, 7, 14, 0x676F02D9 ); | ||
123 | P( B, C, D, A, 12, 20, 0x8D2A4C8A ); | ||
124 | |||
125 | #undef F | ||
126 | |||
127 | #define F(x,y,z) (x ^ y ^ z) | ||
128 | |||
129 | P( A, B, C, D, 5, 4, 0xFFFA3942 ); | ||
130 | P( D, A, B, C, 8, 11, 0x8771F681 ); | ||
131 | P( C, D, A, B, 11, 16, 0x6D9D6122 ); | ||
132 | P( B, C, D, A, 14, 23, 0xFDE5380C ); | ||
133 | P( A, B, C, D, 1, 4, 0xA4BEEA44 ); | ||
134 | P( D, A, B, C, 4, 11, 0x4BDECFA9 ); | ||
135 | P( C, D, A, B, 7, 16, 0xF6BB4B60 ); | ||
136 | P( B, C, D, A, 10, 23, 0xBEBFBC70 ); | ||
137 | P( A, B, C, D, 13, 4, 0x289B7EC6 ); | ||
138 | P( D, A, B, C, 0, 11, 0xEAA127FA ); | ||
139 | P( C, D, A, B, 3, 16, 0xD4EF3085 ); | ||
140 | P( B, C, D, A, 6, 23, 0x04881D05 ); | ||
141 | P( A, B, C, D, 9, 4, 0xD9D4D039 ); | ||
142 | P( D, A, B, C, 12, 11, 0xE6DB99E5 ); | ||
143 | P( C, D, A, B, 15, 16, 0x1FA27CF8 ); | ||
144 | P( B, C, D, A, 2, 23, 0xC4AC5665 ); | ||
145 | |||
146 | #undef F | ||
147 | |||
148 | #define F(x,y,z) (y ^ (x | ~z)) | ||
149 | |||
150 | P( A, B, C, D, 0, 6, 0xF4292244 ); | ||
151 | P( D, A, B, C, 7, 10, 0x432AFF97 ); | ||
152 | P( C, D, A, B, 14, 15, 0xAB9423A7 ); | ||
153 | P( B, C, D, A, 5, 21, 0xFC93A039 ); | ||
154 | P( A, B, C, D, 12, 6, 0x655B59C3 ); | ||
155 | P( D, A, B, C, 3, 10, 0x8F0CCC92 ); | ||
156 | P( C, D, A, B, 10, 15, 0xFFEFF47D ); | ||
157 | P( B, C, D, A, 1, 21, 0x85845DD1 ); | ||
158 | P( A, B, C, D, 8, 6, 0x6FA87E4F ); | ||
159 | P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); | ||
160 | P( C, D, A, B, 6, 15, 0xA3014314 ); | ||
161 | P( B, C, D, A, 13, 21, 0x4E0811A1 ); | ||
162 | P( A, B, C, D, 4, 6, 0xF7537E82 ); | ||
163 | P( D, A, B, C, 11, 10, 0xBD3AF235 ); | ||
164 | P( C, D, A, B, 2, 15, 0x2AD7D2BB ); | ||
165 | P( B, C, D, A, 9, 21, 0xEB86D391 ); | ||
166 | |||
167 | #undef F | ||
168 | |||
169 | ctx->state[0] += A; | ||
170 | ctx->state[1] += B; | ||
171 | ctx->state[2] += C; | ||
172 | ctx->state[3] += D; | ||
173 | } | ||
174 | |||
175 | void md5_update( md5_context *ctx, uint8 *input, uint32 length ) | ||
176 | { | ||
177 | uint32 left, fill; | ||
178 | |||
179 | if( ! length ) return; | ||
180 | |||
181 | left = ctx->total[0] & 0x3F; | ||
182 | fill = 64 - left; | ||
183 | |||
184 | ctx->total[0] += length; | ||
185 | ctx->total[0] &= 0xFFFFFFFF; | ||
186 | |||
187 | if( ctx->total[0] < length ) | ||
188 | ctx->total[1]++; | ||
189 | |||
190 | if( left && length >= fill ) | ||
191 | { | ||
192 | memcpy( (void *) (ctx->buffer + left), | ||
193 | (void *) input, fill ); | ||
194 | md5_process( ctx, ctx->buffer ); | ||
195 | length -= fill; | ||
196 | input += fill; | ||
197 | left = 0; | ||
198 | } | ||
199 | |||
200 | while( length >= 64 ) | ||
201 | { | ||
202 | md5_process( ctx, input ); | ||
203 | length -= 64; | ||
204 | input += 64; | ||
205 | } | ||
206 | |||
207 | if( length ) | ||
208 | { | ||
209 | memcpy( (void *) (ctx->buffer + left), | ||
210 | (void *) input, length ); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static uint8 md5_padding[64] = | ||
215 | { | ||
216 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
217 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
218 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
219 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
220 | }; | ||
221 | |||
222 | void md5_finish( md5_context *ctx, uint8 digest[16] ) | ||
223 | { | ||
224 | uint32 last, padn; | ||
225 | uint32 high, low; | ||
226 | uint8 msglen[8]; | ||
227 | |||
228 | high = ( ctx->total[0] >> 29 ) | ||
229 | | ( ctx->total[1] << 3 ); | ||
230 | low = ( ctx->total[0] << 3 ); | ||
231 | |||
232 | PUT_UINT32( low, msglen, 0 ); | ||
233 | PUT_UINT32( high, msglen, 4 ); | ||
234 | |||
235 | last = ctx->total[0] & 0x3F; | ||
236 | padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); | ||
237 | |||
238 | md5_update( ctx, md5_padding, padn ); | ||
239 | md5_update( ctx, msglen, 8 ); | ||
240 | |||
241 | PUT_UINT32( ctx->state[0], digest, 0 ); | ||
242 | PUT_UINT32( ctx->state[1], digest, 4 ); | ||
243 | PUT_UINT32( ctx->state[2], digest, 8 ); | ||
244 | PUT_UINT32( ctx->state[3], digest, 12 ); | ||
245 | } | ||
246 | |||
diff --git a/tools/fwpatcher/md5.h b/tools/fwpatcher/md5.h new file mode 100644 index 0000000000..71fa395548 --- /dev/null +++ b/tools/fwpatcher/md5.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #ifndef _MD5_H | ||
2 | #define _MD5_H | ||
3 | |||
4 | #ifndef uint8 | ||
5 | #define uint8 unsigned char | ||
6 | #endif | ||
7 | |||
8 | #ifndef uint32 | ||
9 | #define uint32 unsigned long int | ||
10 | #endif | ||
11 | |||
12 | typedef struct | ||
13 | { | ||
14 | uint32 total[2]; | ||
15 | uint32 state[4]; | ||
16 | uint8 buffer[64]; | ||
17 | } | ||
18 | md5_context; | ||
19 | |||
20 | void md5_starts( md5_context *ctx ); | ||
21 | void md5_update( md5_context *ctx, uint8 *input, uint32 length ); | ||
22 | void md5_finish( md5_context *ctx, uint8 digest[16] ); | ||
23 | |||
24 | #endif /* md5.h */ | ||
25 | |||
diff --git a/tools/fwpatcher/resource.h b/tools/fwpatcher/resource.h new file mode 100644 index 0000000000..9847eee88c --- /dev/null +++ b/tools/fwpatcher/resource.h | |||
@@ -0,0 +1,3 @@ | |||
1 | #define IDI_RBICON 101 | ||
2 | #define IDI_BOOTLOADER 102 | ||
3 | |||
diff --git a/tools/fwpatcher/resource.rc b/tools/fwpatcher/resource.rc new file mode 100644 index 0000000000..eabd9e49bd --- /dev/null +++ b/tools/fwpatcher/resource.rc | |||
@@ -0,0 +1,4 @@ | |||
1 | #include "resource.h" | ||
2 | |||
3 | IDI_RBICON ICON "favicon.ico" | ||
4 | IDI_BOOTLOADER BIN "bootloader.bin" | ||