summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaurus Cuelenaere <mcuelenaere@gmail.com>2008-08-27 20:32:12 +0000
committerMaurus Cuelenaere <mcuelenaere@gmail.com>2008-08-27 20:32:12 +0000
commit944c33403ca92d34d38e82a5778a456a2b5c3e01 (patch)
tree5cf616ab91ccaecfabdced39af9966965ab6210e
parent109a8677425eefd10e4a4df759e3c1c9c857ff45 (diff)
downloadrockbox-944c33403ca92d34d38e82a5778a456a2b5c3e01.tar.gz
rockbox-944c33403ca92d34d38e82a5778a456a2b5c3e01.zip
* Commit dual-boot support for Creative ZVx family
* Add mkzenboot: makes it possible to integrate Rockbox bootloader with Creative firmwares without the need of distributing binaries * Add Tadeusz PyÅ› to credits, who figured out the minifs file system * Fix bootloader git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18352 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--bootloader/SOURCES2
-rw-r--r--bootloader/creativezvm.c113
-rw-r--r--docs/CREDITS1
-rw-r--r--firmware/export/config-creativezvm.h4
-rw-r--r--firmware/target/arm/tms320dm320/boot.lds4
-rw-r--r--firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c105
-rw-r--r--firmware/target/arm/tms320dm320/creative-zvm/ata-target.h1
-rw-r--r--tools/Makefile8
-rw-r--r--tools/mkzenboot.c1181
9 files changed, 1414 insertions, 5 deletions
diff --git a/bootloader/SOURCES b/bootloader/SOURCES
index 9f8cf1c91c..1258f9e1d4 100644
--- a/bootloader/SOURCES
+++ b/bootloader/SOURCES
@@ -33,4 +33,6 @@ telechips.c
33meizu_m6sl.c 33meizu_m6sl.c
34#elif defined(ONDA_VX747) 34#elif defined(ONDA_VX747)
35ondavx747.c 35ondavx747.c
36#elif defined(CREATIVE_ZVM)
37creativezvm.c
36#endif 38#endif
diff --git a/bootloader/creativezvm.c b/bootloader/creativezvm.c
new file mode 100644
index 0000000000..f7a6d343d5
--- /dev/null
+++ b/bootloader/creativezvm.c
@@ -0,0 +1,113 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Copyright (C) 2008 by Maurus Cuelenaere
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 "system.h"
21#include "lcd.h"
22#include "kernel.h"
23#include "thread.h"
24#include "ata.h"
25#include "ata-target.h"
26#include "disk.h"
27#include "font.h"
28#include "backlight.h"
29#include "button.h"
30#include "common.h"
31
32
33static void load_fw(unsigned char* ptr, unsigned int len)
34{
35 (void)ptr;
36 (void)len;
37 asm volatile("ldr pc, =0x1EE0000");
38}
39
40void main(void)
41{
42 unsigned char* loadbuffer;
43 int buffer_size;
44 int(*kernel_entry)(void);
45 int ret;
46
47 /* Make sure interrupts are disabled */
48 set_irq_level(IRQ_DISABLED);
49 set_fiq_status(FIQ_DISABLED);
50 system_init();
51 kernel_init();
52
53 /* Now enable interrupts */
54 set_irq_level(IRQ_ENABLED);
55 set_fiq_status(FIQ_ENABLED);
56 backlight_init();
57 lcd_init();
58 font_init();
59 button_init();
60
61 lcd_enable(true);
62 lcd_setfont(FONT_SYSFIXED);
63 reset_screen();
64 printf("Rockbox boot loader");
65 printf("Version %s", APPSVERSION);
66
67 ret = ata_init();
68 if(ret)
69 printf("ATA error: %d", ret);
70
71 if(1)
72 {
73 printf("Loading Creative firmware...");
74
75 loadbuffer = (unsigned char*)0x00A00000;
76 ret = load_minifs_file("creativeos.jrm", loadbuffer);
77 if(ret != -1)
78 {
79 set_irq_level(IRQ_DISABLED);
80 set_fiq_status(FIQ_DISABLED);
81 /* Doesn't return! */
82 load_fw(loadbuffer, ret);
83 }
84 else
85 printf("FAILED!");
86 }
87 else
88 {
89 disk_init();
90
91 ret = disk_mount_all();
92 if (ret <= 0)
93 error(EDISK, ret);
94
95 printf("Loading Rockbox firmware...");
96
97 loadbuffer = (unsigned char*)0x00900000;
98 buffer_size = (unsigned char*)0x01900000 - loadbuffer;
99
100 ret = load_firmware(loadbuffer, BOOTFILE, buffer_size);
101 if(ret < 0)
102 error(EBOOTFILE, ret);
103
104 else if(ret == EOK)
105 {
106 kernel_entry = (void*) loadbuffer;
107 ret = kernel_entry();
108 printf("FAILED!");
109 }
110 }
111
112 while(1);
113}
diff --git a/docs/CREDITS b/docs/CREDITS
index 8e087e0655..f9bacd51d5 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -412,6 +412,7 @@ Jun Gu
412Daniel Weck 412Daniel Weck
413Clément Pit-Claudel 413Clément Pit-Claudel
414Jelle Geerts 414Jelle Geerts
415Tadeusz PyÅ›
415 416
416The libmad team 417The libmad team
417The wavpack team 418The wavpack team
diff --git a/firmware/export/config-creativezvm.h b/firmware/export/config-creativezvm.h
index b7a0fcef57..647e8e986c 100644
--- a/firmware/export/config-creativezvm.h
+++ b/firmware/export/config-creativezvm.h
@@ -166,11 +166,11 @@
166#define USB_PRODUCT_ID 0x4133 166#define USB_PRODUCT_ID 0x4133
167 167
168/*DEBUGGING!*/ 168/*DEBUGGING!*/
169#ifdef BOOTLOADER 169/*
170#define THREAD_EXTRA_CHECKS 1 170#define THREAD_EXTRA_CHECKS 1
171#define DEBUG 1 171#define DEBUG 1
172#define debug(msg) printf(msg) 172#define debug(msg) printf(msg)
173#define BUTTON_DEBUG 173#define BUTTON_DEBUG
174#endif 174*/
175 175
176#endif 176#endif
diff --git a/firmware/target/arm/tms320dm320/boot.lds b/firmware/target/arm/tms320dm320/boot.lds
index 5a4182fe29..97274a2c04 100644
--- a/firmware/target/arm/tms320dm320/boot.lds
+++ b/firmware/target/arm/tms320dm320/boot.lds
@@ -7,7 +7,7 @@ STARTUP(target/arm/tms320dm320/crt0.o)
7 7
8#define DRAMSIZE (MEMORYSIZE * 0x100000) 8#define DRAMSIZE (MEMORYSIZE * 0x100000)
9 9
10#define DRAMORIG 0x00900000 10#define DRAMORIG 0x01900000 /* actually it's 0x00900000 */
11#define IRAMORIG 0x00000000 11#define IRAMORIG 0x00000000
12#define IRAMSIZE 16K 12#define IRAMSIZE 16K
13#define FLASHORIG 0x00100000 13#define FLASHORIG 0x00100000
@@ -22,7 +22,7 @@ MEMORY
22 22
23SECTIONS 23SECTIONS
24{ 24{
25 . = DRAMORIG + 0x1000000; 25 . = DRAMORIG;
26 26
27 .text : { 27 .text : {
28 loadaddress = .; 28 loadaddress = .;
diff --git a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c
index 0c4dd4bfbe..1732c5d2c4 100644
--- a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c
+++ b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c
@@ -28,6 +28,8 @@
28#include "panic.h" 28#include "panic.h"
29#include "ata-target.h" 29#include "ata-target.h"
30#include "dm320.h" 30#include "dm320.h"
31#include "ata.h"
32#include "string.h"
31 33
32void sleep_ms(int ms) 34void sleep_ms(int ms)
33{ 35{
@@ -109,3 +111,106 @@ void GIO2(void)
109 IO_INTC_IRQ1 = INTR_IRQ1_EXT2; /* Mask GIO2 interrupt */ 111 IO_INTC_IRQ1 = INTR_IRQ1_EXT2; /* Mask GIO2 interrupt */
110 return; 112 return;
111} 113}
114
115/*
116 ---------------------------------------------------------------------------
117 Creative File Systems parsing code
118 ---------------------------------------------------------------------------
119 */
120
121struct main_header
122{
123 char mblk[4];
124 unsigned char sector_size[4];
125 unsigned char disk_size[8];
126 struct partition_header
127 {
128 unsigned char end[4];
129 unsigned char start[4];
130 char name[8];
131 } partitions[31];
132};
133
134struct minifs_file
135{
136 char name[0x10];
137 unsigned char unk[4];
138 unsigned char size[4];
139 unsigned char chain1[4];
140 unsigned char chain2[4];
141};
142
143struct minifs_chain
144{
145 unsigned char unknown[4];
146 unsigned char chain[2*0x27FE];
147 unsigned char unknown2[4];
148 unsigned char length[4];
149};
150
151
152#define DIR_BITMAP_START 0x0143
153#define DIR_START 0x0144
154#define DATASPACE_BITMAP_START 0x0145
155#define DATASPACE_START 0x0146
156
157#define CLUSTER_CHAIN_SIZE 0x5008
158#define CLUSTER_CHAIN_HEAD 0x0000
159#define CLUSTER_CHAIN_BITMAP 0x0001
160#define CLUSTER_CHAIN_CHAIN 0x0002
161
162
163static unsigned short le2int16(unsigned char* buf)
164{
165 return (buf[1] << 8) | buf[0];
166}
167
168static unsigned int le2int32(unsigned char* buf)
169{
170 return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
171}
172
173int load_minifs_file(char* filename, unsigned char* location)
174{
175 struct main_header *hdr;
176 static struct minifs_file files[128];
177 struct minifs_chain *chain;
178 unsigned int i;
179 int found = -1;
180 unsigned char sector[512];
181 static unsigned char chain_data[42*512]; /* stack overflow if not static */
182
183 /* Reading MBLK */
184 ata_read_sectors(0, 1, &sector);
185 hdr = (struct main_header*)&sector;
186
187 /* Reading directory listing */
188#define CLUSTER2SECTOR(x) ( (le2int32(hdr->partitions[0].start) + (x)*8) )
189 ata_read_sectors(CLUSTER2SECTOR(DIR_START), 8, &files);
190
191 for(i=0; i<127; i++)
192 {
193 if(strcmp(files[i].name, filename) == 0)
194 found = i;
195 }
196
197 if(found == -1)
198 return -1;
199
200#define GET_CHAIN(x) ( CLUSTER2SECTOR(CLUSTER_CHAIN_CHAIN)*512 + (x)*CLUSTER_CHAIN_SIZE )
201#define FILE2SECTOR(x) ( CLUSTER2SECTOR(DATASPACE_START + (x)) )
202
203 /* Reading chain list */
204 ata_read_sectors(GET_CHAIN(le2int32(files[found].chain1))/512, 41, &chain_data[0]);
205
206 chain = (struct minifs_chain*)&chain_data[GET_CHAIN(le2int32(files[found].chain1))%512];
207
208 /* Copying data */
209 for(i=0; i<le2int32(chain->length); i++)
210 {
211 ata_read_sectors(FILE2SECTOR(le2int16(&chain->chain[i*2])), 8, location);
212 location += 0x1000;
213 }
214
215 return le2int32(files[found].size);
216}
diff --git a/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h b/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h
index 63417d1219..6e5699e887 100644
--- a/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h
+++ b/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h
@@ -74,5 +74,6 @@ void ata_reset(void);
74void ata_device_init(void); 74void ata_device_init(void);
75bool ata_is_coldstart(void); 75bool ata_is_coldstart(void);
76void ide_power_enable(bool on); 76void ide_power_enable(bool on);
77int load_minifs_file(char* filename, unsigned char* location);
77 78
78#endif 79#endif
diff --git a/tools/Makefile b/tools/Makefile
index f2497291d9..2e3f1e0fc1 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -13,7 +13,7 @@ LDFLAGS := -g
13 13
14CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \ 14CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \
15 generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat database \ 15 generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat database \
16 lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc 16 lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc mkzenboot
17 17
18all: 18all:
19 @echo "Run make in your build directory!" 19 @echo "Run make in your build directory!"
@@ -51,6 +51,12 @@ mktccboot: mktccboot.c telechips.o
51mknkboot: mknkboot.c 51mknkboot: mknkboot.c
52 $(SILENT)$(CC) $(CFLAGS) $+ -o $@ 52 $(SILENT)$(CC) $(CFLAGS) $+ -o $@
53 53
54mkzenboot.o: mkzenboot.c
55 $(SILENT)$(CC) $(CFLAGS) -DSTANDALONE -c -o $@ $+
56
57mkzenboot: mkzenboot.o hmac-sha1.o
58 $(SILENT)$(CC) $(LDFLAGS) -lz $+ -o $@
59
54lngdump: lngdump.c 60lngdump: lngdump.c
55 $(SILENT)$(CC) $(CFLAGS) $+ -o $@ 61 $(SILENT)$(CC) $(CFLAGS) $+ -o $@
56 62
diff --git a/tools/mkzenboot.c b/tools/mkzenboot.c
new file mode 100644
index 0000000000..2ed9284583
--- /dev/null
+++ b/tools/mkzenboot.c
@@ -0,0 +1,1181 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Maurus Cuelenaere
11 *
12 * Based on zenutils by Rasmus Ry <rasmus.ry{at}gmail.com>
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdbool.h>
27#include <inttypes.h>
28#include <zlib.h>
29#include "hmac-sha1.h"
30
31static int filesize(FILE* fd)
32{
33 int tmp, tmp2 = ftell(fd);
34 fseek(fd, 0, SEEK_END);
35 tmp = ftell(fd);
36 fseek(fd, tmp2, SEEK_SET);
37 return tmp;
38}
39
40static unsigned int le2int(unsigned char* buf)
41{
42 return ((buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]);
43}
44
45static void int2le(unsigned int val, unsigned char* addr)
46{
47 addr[0] = val & 0xFF;
48 addr[1] = (val >> 8) & 0xff;
49 addr[2] = (val >> 16) & 0xff;
50 addr[3] = (val >> 24) & 0xff;
51}
52
53static const char* find_firmware_key(const unsigned char* buffer, size_t len)
54{
55 char szkey1[] = "34d1";
56 size_t cchkey1 = strlen(szkey1);
57 char szkey2[] = "TbnCboEbn";
58 size_t cchkey2 = strlen(szkey2);
59 uint32_t i;
60 for (i = 0; i < (uint32_t)len; i++)
61 {
62 if (len >= cchkey1)
63 {
64 if (!strncmp((char*)&buffer[i], szkey1, cchkey1))
65 return (const char*)&buffer[i];
66 }
67 if (len >= cchkey2)
68 {
69 if (!strncmp((char*)&buffer[i], szkey2, cchkey2))
70 return (const char*)&buffer[i];
71 }
72 }
73 return NULL;
74}
75
76static uint32_t find_firmware_offset(unsigned char* buffer, size_t len)
77{
78 uint32_t i;
79 for (i = 0; i < (uint32_t)len; i += 0x10)
80 {
81 if (buffer[i + sizeof(uint32_t)] != 0
82 && buffer[i + sizeof(uint32_t) + 1] != 0
83 && buffer[i + sizeof(uint32_t) + 2] != 0
84 && buffer[i + sizeof(uint32_t) + 3] != 0)
85 {
86 return i;
87 }
88 if(i > 0xFF) /* Arbitrary guess */
89 return 0;
90 }
91 return 0;
92}
93
94static bool crypt_firmware(const char* key, unsigned char* buffer, size_t len)
95{
96 char key_cpy[255];
97 unsigned int i;
98 unsigned int tmp = 0;
99 int key_length = strlen(key);
100
101 strcpy(key_cpy, key);
102 for(i=0; i < strlen(key); i++)
103 key_cpy[i] = key[i] - 1;
104
105 for(i=0; i < len; i++)
106 {
107 buffer[i] ^= key_cpy[tmp] | 0x80;
108 tmp = (tmp + 1) % key_length;
109 }
110
111 return true;
112}
113
114static bool inflate_to_buffer(const unsigned char *buffer, size_t len, unsigned char* out_buffer, size_t out_len, char** err_msg)
115{
116 /* Initialize Zlib */
117 z_stream d_stream;
118 int ret;
119
120 d_stream.zalloc = Z_NULL;
121 d_stream.zfree = Z_NULL;
122 d_stream.opaque = Z_NULL;
123
124 d_stream.next_in = (unsigned char*)buffer;
125 d_stream.avail_in = len;
126
127 ret = inflateInit(&d_stream);
128 if (ret != Z_OK)
129 {
130 *err_msg = d_stream.msg;
131 return false;
132 }
133
134 d_stream.next_out = out_buffer;
135 d_stream.avail_out = out_len;
136
137 ret = inflate(&d_stream, Z_SYNC_FLUSH);
138 if(ret < 0)
139 {
140 *err_msg = d_stream.msg;
141 return false;
142 }
143 else
144 inflateEnd(&d_stream);
145
146 return true;
147}
148
149#define CODE_MASK 0xC0
150#define ARGS_MASK 0x3F
151
152#define REPEAT_CODE 0x00
153#define BLOCK_CODE 0x40
154#define LONG_RUN_CODE 0x80
155#define SHORT_RUN_CODE 0xC0
156
157#define BLOCK_ARGS 0x1F
158#define BLOCK_MODE 0x20
159
160
161static void decode_run(unsigned char* dst, uint16_t len, unsigned char val,
162 int* dstidx)
163{
164 memset(dst + *dstidx, val, len);
165 *dstidx += len;
166}
167
168static void decode_pattern(unsigned char* src, unsigned char* dst,
169 uint16_t len, int* srcidx, int* dstidx,
170 bool bdecode, int npasses)
171{
172 int i, j;
173 for (i = 0; i < npasses; i++)
174 {
175 if (bdecode)
176 {
177 for (j = 0; j < len; j++)
178 {
179 uint16_t c, d;
180 c = src[*srcidx + j];
181 d = (c >> 5) & 7;
182 c = (c << 3) & 0xF8;
183 src[*srcidx + j] = (unsigned char)(c | d);
184 }
185 bdecode = false;
186 }
187 memcpy(dst + *dstidx, src + *srcidx, len);
188 *dstidx += len;
189 }
190 *srcidx += len;
191}
192
193static int cenc_decode(unsigned char* src, int srclen, unsigned char* dst, int dstlen)
194{
195 int i = 0, j = 0;
196 do
197 {
198 uint16_t c, d, e;
199 c = src[i++];
200 switch (c & CODE_MASK)
201 {
202 case REPEAT_CODE: /* 2 unsigned chars */
203 d = src[i++];
204 d = d + 2;
205
206 e = (c & ARGS_MASK) + 2;
207
208 decode_pattern(src, dst, e, &i, &j, false, d);
209 break;
210
211 case BLOCK_CODE: /* 1/2/3 unsigned chars */
212 d = c & BLOCK_ARGS;
213 if (!(c & BLOCK_MODE))
214 {
215 e = src[i++];
216 e = (d << 8) + (e + 0x21);
217
218 d = (uint16_t)(i ^ j);
219 }
220 else
221 {
222 e = d + 1;
223
224 d = (uint16_t)(i ^ j);
225 }
226 if (d & 1)
227 {
228 i++;
229 }
230
231 decode_pattern(src, dst, e, &i, &j, true, 1);
232 break;
233
234 case LONG_RUN_CODE: /* 3 unsigned chars */
235 d = src[i++];
236 e = ((c & ARGS_MASK) << 8) + (d + 0x42);
237
238 d = src[i++];
239 d = ((d & 7) << 5) | ((d >> 3) & 0x1F);
240
241 decode_run(dst, e, (unsigned char)(d), &j);
242 break;
243
244 case SHORT_RUN_CODE: /* 2 unsigned chars */
245 d = src[i++];
246 d = ((d & 3) << 6) | ((d >> 2) & 0x3F);
247
248 e = (c & ARGS_MASK) + 2;
249
250 decode_run(dst, e, (unsigned char)(d), &j);
251 break;
252 };
253 } while (i < srclen && j < dstlen);
254
255 return j;
256}
257
258/*
259 * Copyright (c) 1999, 2000, 2002 Virtual Unlimited B.V.
260 *
261 * This library is free software; you can redistribute it and/or
262 * modify it under the terms of the GNU Lesser General Public
263 * License as published by the Free Software Foundation; either
264 * version 2.1 of the License, or (at your option) any later version.
265 *
266 * This library is distributed in the hope that it will be useful,
267 * but WITHOUT ANY WARRANTY; without even the implied warranty of
268 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
269 * Lesser General Public License for more details.
270 *
271 * You should have received a copy of the GNU Lesser General Public
272 * License along with this library; if not, write to the Free Software
273 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
274 *
275 */
276
277#define BLOWFISHROUNDS 16
278#define BLOWFISHPSIZE (BLOWFISHROUNDS+2)
279#define WORDS_BIGENDIAN 0
280
281struct blowfishParam
282{
283 uint32_t p[BLOWFISHPSIZE];
284 uint32_t s[1024];
285 uint32_t fdback[2];
286};
287
288typedef enum
289{
290 NOCRYPT,
291 ENCRYPT,
292 DECRYPT
293} cipherOperation;
294
295static inline uint32_t swapu32(uint32_t n)
296{
297 return ( ((n & 0xffU) << 24) |
298 ((n & 0xff00U) << 8) |
299 ((n & 0xff0000U) >> 8) |
300 ((n & 0xff000000U) >> 24) );
301}
302
303static uint32_t _bf_p[BLOWFISHPSIZE] = {
304 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
305 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
306 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
307 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
308 0x9216d5d9, 0x8979fb1b
309};
310
311static uint32_t _bf_s[1024] = {
312 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
313 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
314 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
315 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
316 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
317 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
318 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
319 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
320 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
321 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
322 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
323 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
324 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
325 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
326 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
327 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
328 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
329 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
330 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
331 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
332 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
333 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
334 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
335 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
336 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
337 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
338 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
339 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
340 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
341 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
342 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
343 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
344 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
345 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
346 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
347 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
348 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
349 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
350 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
351 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
352 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
353 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
354 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
355 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
356 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
357 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
358 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
359 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
360 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
361 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
362 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
363 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
364 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
365 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
366 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
367 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
368 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
369 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
370 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
371 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
372 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
373 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
374 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
375 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
376 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
377 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
378 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
379 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
380 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
381 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
382 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
383 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
384 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
385 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
386 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
387 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
388 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
389 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
390 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
391 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
392 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
393 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
394 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
395 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
396 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
397 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
398 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
399 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
400 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
401 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
402 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
403 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
404 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
405 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
406 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
407 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
408 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
409 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
410 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
411 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
412 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
413 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
414 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
415 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
416 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
417 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
418 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
419 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
420 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
421 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
422 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
423 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
424 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
425 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
426 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
427 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
428 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
429 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
430 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
431 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
432 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
433 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
434 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
435 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
436 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
437 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
438 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
439 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
440 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
441 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
442 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
443 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
444 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
445 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
446 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
447 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
448 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
449 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
450 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
451 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
452 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
453 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
454 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
455 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
456 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
457 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
458 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
459 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
460 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
461 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
462 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
463 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
464 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
465 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
466 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
467 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
468 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
469 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
470 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
471 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
472 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
473 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
474 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
475 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
476 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
477 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
478 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
479 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
480 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
481 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
482 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
483 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
484 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
485 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
486 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
487 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
488 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
489 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
490 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
491 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
492 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
493 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
494 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
495 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
496 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
497 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
498 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
499 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
500 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
501 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
502 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
503 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
504 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
505 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
506 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
507 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
508 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
509 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
510 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
511 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
512 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
513 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
514 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
515 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
516 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
517 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
518 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
519 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
520 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
521 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
522 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
523 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
524 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
525 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
526 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
527 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
528 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
529 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
530 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
531 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
532 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
533 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
534 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
535 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
536 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
537 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
538 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
539 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
540 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
541 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
542 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
543 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
544 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
545 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
546 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
547 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
548 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
549 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
550 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
551 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
552 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
553 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
554 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
555 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
556 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
557 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
558 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
559 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
560 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
561 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
562 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
563 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
564 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
565 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
566 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
567 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
568};
569
570#define EROUND(l,r) l ^= *(p++); r ^= ((s[((l>>24)&0xff)+0x000]+s[((l>>16)&0xff)+0x100])^s[((l>>8)&0xff)+0x200])+s[((l>>0)&0xff)+0x300]
571#define DROUND(l,r) l ^= *(p--); r ^= ((s[((l>>24)&0xff)+0x000]+s[((l>>16)&0xff)+0x100])^s[((l>>8)&0xff)+0x200])+s[((l>>0)&0xff)+0x300]
572
573static int blowfishEncrypt(struct blowfishParam* bp, uint32_t* dst, const uint32_t* src)
574{
575 #if WORDS_BIGENDIAN
576 register uint32_t xl = src[0], xr = src[1];
577 #else
578 register uint32_t xl = swapu32(src[0]), xr = swapu32(src[1]);
579 #endif
580 register uint32_t* p = bp->p;
581 register uint32_t* s = bp->s;
582
583 EROUND(xl, xr); EROUND(xr, xl);
584 EROUND(xl, xr); EROUND(xr, xl);
585 EROUND(xl, xr); EROUND(xr, xl);
586 EROUND(xl, xr); EROUND(xr, xl);
587 EROUND(xl, xr); EROUND(xr, xl);
588 EROUND(xl, xr); EROUND(xr, xl);
589 EROUND(xl, xr); EROUND(xr, xl);
590 EROUND(xl, xr); EROUND(xr, xl);
591
592 #if WORDS_BIGENDIAN
593 dst[1] = xl ^ *(p++);
594 dst[0] = xr ^ *(p++);
595 #else
596 dst[1] = swapu32(xl ^ *(p++));
597 dst[0] = swapu32(xr ^ *(p++));
598 #endif
599
600 return 0;
601}
602
603static int blowfishDecrypt(struct blowfishParam* bp, uint32_t* dst, const uint32_t* src)
604{
605 #if WORDS_BIGENDIAN
606 register uint32_t xl = src[0], xr = src[1];
607 #else
608 register uint32_t xl = swapu32(src[0]), xr = swapu32(src[1]);
609 #endif
610 register uint32_t* p = bp->p+BLOWFISHPSIZE-1;
611 register uint32_t* s = bp->s;
612
613 DROUND(xl, xr); DROUND(xr, xl);
614 DROUND(xl, xr); DROUND(xr, xl);
615 DROUND(xl, xr); DROUND(xr, xl);
616 DROUND(xl, xr); DROUND(xr, xl);
617 DROUND(xl, xr); DROUND(xr, xl);
618 DROUND(xl, xr); DROUND(xr, xl);
619 DROUND(xl, xr); DROUND(xr, xl);
620 DROUND(xl, xr); DROUND(xr, xl);
621
622 #if WORDS_BIGENDIAN
623 dst[1] = xl ^ *(p--);
624 dst[0] = xr ^ *(p--);
625 #else
626 dst[1] = swapu32(xl ^ *(p--));
627 dst[0] = swapu32(xr ^ *(p--));
628 #endif
629
630 return 0;
631}
632
633static int blowfishSetup(struct blowfishParam* bp, const unsigned char* key, size_t keybits, cipherOperation op)
634{
635 if ((op != ENCRYPT) && (op != DECRYPT))
636 return -1;
637
638 if (((keybits & 7) == 0) && (keybits >= 32) && (keybits <= 448))
639 {
640 register uint32_t* p = bp->p;
641 register uint32_t* s = bp->s;
642 register unsigned int i, j, k;
643
644 uint32_t tmp, work[2];
645
646 memcpy(s, _bf_s, 1024 * sizeof(uint32_t));
647
648 for (i = 0, k = 0; i < BLOWFISHPSIZE; i++)
649 {
650 tmp = 0;
651 for (j = 0; j < 4; j++)
652 {
653 tmp <<= 8;
654 tmp |= key[k++];
655 if (k >= (keybits >> 3))
656 k = 0;
657 }
658 p[i] = _bf_p[i] ^ tmp;
659 }
660
661 work[0] = work[1] = 0;
662
663 for (i = 0; i < BLOWFISHPSIZE; i += 2, p += 2)
664 {
665 blowfishEncrypt(bp, work, work);
666 #if WORDS_BIGENDIAN
667 p[0] = work[0];
668 p[1] = work[1];
669 #else
670 p[0] = swapu32(work[0]);
671 p[1] = swapu32(work[1]);
672 #endif
673 }
674
675 for (i = 0; i < 1024; i += 2, s += 2)
676 {
677 blowfishEncrypt(bp, work, work);
678 #if WORDS_BIGENDIAN
679 s[0] = work[0];
680 s[1] = work[1];
681 #else
682 s[0] = swapu32(work[0]);
683 s[1] = swapu32(work[1]);
684 #endif
685 }
686
687 /* clear fdback/iv */
688 bp->fdback[0] = 0;
689 bp->fdback[1] = 0;
690
691 return 0;
692 }
693 return -1;
694}
695
696static int blowfishSetIV(struct blowfishParam* bp, const unsigned char* iv)
697{
698 if (iv)
699 memcpy(bp->fdback, iv, 8);
700 else
701 memset(bp->fdback, 0, 8);
702
703 return 0;
704}
705
706#define BLOWFISH_BLOCKSIZE 8
707static int blowfishDecryptCBC(struct blowfishParam* bp, uint32_t* dst, const uint32_t* src, unsigned int nblocks)
708{
709 register const unsigned int blockwords = BLOWFISH_BLOCKSIZE >> 2;
710 register uint32_t* fdback = bp->fdback;
711 register uint32_t* buf = (uint32_t*) malloc(blockwords * sizeof(uint32_t));
712
713 if (buf)
714 {
715 while (nblocks > 0)
716 {
717 register uint32_t tmp;
718 register unsigned int i;
719
720 blowfishDecrypt(bp, buf, src);
721
722 for (i = 0; i < blockwords; i++)
723 {
724 tmp = src[i];
725 dst[i] = buf[i] ^ fdback[i];
726 fdback[i] = tmp;
727 }
728
729 dst += blockwords;
730 src += blockwords;
731
732 nblocks--;
733 }
734 free(buf);
735 return 0;
736 }
737
738 return -1;
739}
740
741static bool bf_cbc_decrypt(const unsigned char* key, size_t keylen,
742 unsigned char* data, size_t datalen,
743 const unsigned char* iv)
744{
745 struct blowfishParam param;
746 unsigned char *cipher;
747 unsigned int nblocks;
748
749 if (datalen % BLOWFISH_BLOCKSIZE)
750 return false;
751
752 if (blowfishSetup(&param, key, keylen * 8, ENCRYPT))
753 return false;
754 if (blowfishSetIV(&param, iv))
755 return false;
756
757 cipher = malloc(datalen);
758 memcpy(cipher, data, datalen);
759
760 nblocks = datalen / BLOWFISH_BLOCKSIZE;
761 if (blowfishDecryptCBC(&param, (uint32_t*)data, (uint32_t*)cipher,
762 nblocks))
763 {
764 free(cipher);
765 return false;
766 }
767
768 free(cipher);
769 return true;
770}
771
772static inline uint32_t swap(uint32_t val)
773{
774 return ((val & 0xFF) << 24)
775 | ((val & 0xFF00) << 8)
776 | ((val & 0xFF0000) >> 8)
777 | ((val & 0xFF000000) >> 24);
778}
779
780const char *tl_key = "1sN0TM3D az u~may th1nk*"
781 "Creative Zen Vision:M";
782const char *null_key = "CTL:N0MAD|PDE0.DPMP.";
783
784int mkboot(const char* infile, const char* bootfile, const char* outfile)
785{
786 FILE *infd, *bootfd, *outfd;
787 unsigned char *buffer, *out_buffer, enc_data[40], hash_key[20];
788 char *err_msg;
789 const char *fw_key;
790 uint32_t i, fw_offset, fw_size, data_ptr, data_size, ciff_size, cenc_size, iv[2];
791
792 infd = fopen(infile, "rb");
793 if(infd == NULL)
794 {
795 fprintf(stderr, "[ERR] Could not open %s\n", infile);
796 return -1;
797 }
798
799 buffer = malloc(filesize(infd));
800 if(buffer == NULL)
801 {
802 fprintf(stderr, "[ERR] Could not allocate %d unsigned chars\n", filesize(infd));
803 fclose(infd);
804 return -2;
805 }
806
807 if(fread(buffer, filesize(infd), 1, infd) != 1)
808 {
809 fprintf(stderr, "[ERR] Short read\n");
810 fclose(infd);
811 free(buffer);
812 return -3;
813 }
814
815 fclose(infd);
816
817 /* Rudimentary Win32 PE reading */
818 if(memcmp(&buffer[0], "MZ", 2) != 0 &&
819 memcmp(&buffer[0x118], "PE", 2) != 0)
820 {
821 fprintf(stderr, "[ERR] Input file isn't an executable\n");
822 free(buffer);
823 return -4;
824 }
825
826 data_ptr = 0, data_size = 0;
827 for(i=0x210; i < 0x1000; i+=0x28)
828 {
829 if(strcmp((char*)&buffer[i], ".data") == 0)
830 {
831 data_ptr = le2int(&buffer[i+0x14]);
832 data_size = le2int(&buffer[i+0x10]);
833 break;
834 }
835 }
836
837 if(data_ptr == 0 || data_size == 0)
838 {
839 fprintf(stderr, "[ERR] Couldn't find .data section\n");
840 free(buffer);
841 return -5;
842 }
843
844 fprintf(stderr, "[INFO] .data section is at 0x%x with size 0x%x\n", data_ptr, data_size);
845
846 fw_offset = find_firmware_offset(&buffer[data_ptr], data_size);
847 if(fw_offset == 0)
848 {
849 fprintf(stderr, "[ERR] Couldn't find firmware offset\n");
850 free(buffer);
851 return -6;
852 }
853 fw_size = le2int(&buffer[data_ptr+fw_offset]);
854 fprintf(stderr, "[INFO] Firmware offset is at 0x%x with size 0x%x\n", data_ptr+fw_offset, fw_size);
855
856 fw_key = find_firmware_key(&buffer[0], filesize(infd));
857 if(fw_key == NULL)
858 {
859 fprintf(stderr, "[ERR] Couldn't find firmware key\n");
860 free(buffer);
861 return -7;
862 }
863 fprintf(stderr, "[INFO] Firmware key is %s\n", fw_key);
864
865 fprintf(stderr, "[INFO] Descrambling firmware... ");
866 if(!crypt_firmware(fw_key, &buffer[data_ptr+fw_offset+4], fw_size))
867 {
868 fprintf(stderr, "Fail!\n");
869 free(buffer);
870 return -8;
871 }
872 else
873 fprintf(stderr, "Done!\n");
874
875 out_buffer = malloc(fw_size*2);
876 if(out_buffer == NULL)
877 {
878 fprintf(stderr, "[ERR] Couldn't allocate %d unsigned chars", fw_size*2);
879 free(buffer);
880 return -9;
881 }
882
883 memset(out_buffer, 0, fw_size*2);
884
885 err_msg = NULL;
886 fprintf(stderr, "[INFO] Decompressing firmware... ");
887 if(!inflate_to_buffer(&buffer[data_ptr+fw_offset+4], fw_size, out_buffer, fw_size*2, &err_msg))
888 {
889 fprintf(stderr, "Fail!\n[ERR] ZLib error: %s\n", err_msg);
890 free(buffer);
891 free(out_buffer);
892 return -10;
893 }
894 else
895 {
896 fprintf(stderr, "Done!\n");
897 free(buffer);
898 }
899
900 if(memcmp(out_buffer, "FFIC", 4) != 0)
901 {
902 fprintf(stderr, "[ERR] CIFF header doesn't match\n");
903 free(out_buffer);
904 return -11;
905 }
906
907 ciff_size = le2int(&out_buffer[4])+8+28; /* CIFF block + NULL block*/
908
909 bootfd = fopen(bootfile, "rb");
910 if(bootfd == NULL)
911 {
912 fprintf(stderr, "[ERR] Could not open %s\n", bootfile);
913 free(out_buffer);
914 return -12;
915 }
916
917 out_buffer = realloc(out_buffer, ciff_size+filesize(bootfd));
918 if(out_buffer == NULL)
919 {
920 fprintf(stderr, "[ERR] Cannot allocate %d unsigned chars\n", ciff_size+40+filesize(bootfd));
921 fclose(bootfd);
922 return -13;
923 }
924
925 fprintf(stderr, "[INFO] Locating encoded block... ");
926
927 i = 8;
928 while(memcmp(&out_buffer[i], " LT©", 4) != 0 && i < ciff_size)
929 {
930 if(memcmp(&out_buffer[i], "FNIC", 4) == 0)
931 i += 4+4+96;
932 else if(memcmp(&out_buffer[i], "ATAD", 4) == 0)
933 {
934 i += 4;
935 i += le2int(&out_buffer[i]);
936 i += 4;
937 }
938 else
939 {
940 fprintf(stderr, "Fail!\n[ERR] Unknown block\n");
941 fclose(bootfd);
942 free(out_buffer);
943 return -14;
944 }
945 }
946
947 if(i > ciff_size || memcmp(&out_buffer[i], " LT©", 4) != 0)
948 {
949 fprintf(stderr, "Fail!\n[ERR] Couldn't find encoded block\n");
950 fclose(bootfd);
951 free(out_buffer);
952 return -15;
953 }
954
955 fprintf(stderr, "Done!\n");
956
957 outfd = fopen(outfile, "wb+");
958 if(outfd == NULL)
959 {
960 fprintf(stderr, "[ERR] Could not open %s\n", outfile);
961 fclose(bootfd);
962 free(out_buffer);
963 return -16;
964 }
965
966 if(fwrite(&out_buffer[0], i, 1, outfd) != 1)
967 {
968 fprintf(stderr, "[ERR] Short write\n");
969 fclose(bootfd);
970 fclose(outfd);
971 free(out_buffer);
972 return -17;
973 }
974
975 fprintf(stderr, "[INFO] Decrypting encoded block... ");
976
977 iv[0] = 0;
978 iv[1] = swap(le2int(&out_buffer[i+4]));
979 if(bf_cbc_decrypt((unsigned char*)tl_key, strlen(tl_key)+1, &out_buffer[i+8],
980 le2int(&out_buffer[i+4]), (const unsigned char*)&iv)
981 == false)
982 {
983 fprintf(stderr, "Fail!\n[ERR] Couldn't decrypt encoded block\n");
984 fclose(bootfd);
985 fclose(outfd);
986 free(out_buffer);
987 return -18;
988 }
989
990 fprintf(stderr, "Done!\n");
991
992 cenc_size = le2int(&out_buffer[i+8]);
993
994 if(cenc_size > le2int(&out_buffer[i+4])*3)
995 {
996 fprintf(stderr, "[ERR] Decrypted length of encoded block is unexpectedly large: 0x%08x\n", cenc_size);
997 fclose(bootfd);
998 fclose(outfd);
999 free(out_buffer);
1000 return -19;
1001 }
1002
1003 buffer = malloc(cenc_size);
1004 if(buffer == NULL)
1005 {
1006 fprintf(stderr, "[ERR] Couldn't allocate %d unsigned chars\n", cenc_size);
1007 fclose(bootfd);
1008 fclose(outfd);
1009 free(out_buffer);
1010 return -20;
1011 }
1012
1013 memset(buffer, 0, cenc_size);
1014
1015 fprintf(stderr, "[INFO] Decompressing encoded block... ");
1016
1017 if(!cenc_decode(&out_buffer[i+12], le2int(&out_buffer[i+4])-4, &buffer[0], cenc_size))
1018 {
1019 fprintf(stderr, "Fail!\n[ERR] Couldn't decompress the encoded block\n");
1020 fclose(bootfd);
1021 fclose(outfd);
1022 free(out_buffer);
1023 free(buffer);
1024 return -21;
1025 }
1026
1027 fprintf(stderr, "Done!\n");
1028
1029 fprintf(stderr, "[INFO] Renaming encoded block to Hcreativeos.jrm... ");
1030
1031 memcpy(&enc_data, "ATAD", 4);
1032 int2le(cenc_size+32, &enc_data[4]);
1033 memset(&enc_data[8], 0, 32);
1034 memcpy(&enc_data[8], "H\0c\0r\0e\0a\0t\0i\0v\0e\0o\0s\0.\0j\0r\0m", 30);
1035 if(fwrite(enc_data, 40, 1, outfd) != 1)
1036 {
1037 fprintf(stderr, "Fail!\n[ERR] Short write\n");
1038 fclose(bootfd);
1039 fclose(outfd);
1040 free(out_buffer);
1041 free(buffer);
1042 return -22;
1043 }
1044
1045 if(fwrite(&buffer[0], cenc_size, 1, outfd) != 1)
1046 {
1047 fprintf(stderr, "Fail!\n[ERR] Short write\n");
1048 fclose(bootfd);
1049 fclose(outfd);
1050 free(out_buffer);
1051 free(buffer);
1052 return -23;
1053 }
1054
1055 free(buffer);
1056 fprintf(stderr, "Done!\n[INFO] Adding Hjukebox2.jrm... ");
1057
1058 memcpy(&enc_data, "ATAD", 4);
1059 int2le(filesize(bootfd)+32, &enc_data[4]);
1060 memset(&enc_data[8], 0, 32);
1061 memcpy(&enc_data[8], "H\0j\0u\0k\0e\0b\0o\0x\0""2\0.\0j\0r\0m", 26);
1062 if(fwrite(enc_data, 40, 1, outfd) != 1)
1063 {
1064 fprintf(stderr, "Fail!\n[ERR] Short write\n");
1065 fclose(bootfd);
1066 fclose(outfd);
1067 free(out_buffer);
1068 return -24;
1069 }
1070
1071 if(fread(&out_buffer[ciff_size], filesize(bootfd), 1, bootfd) != 1)
1072 {
1073 fprintf(stderr, "Fail!\n[ERR] Short read\n");
1074 fclose(bootfd);
1075 fclose(outfd);
1076 free(out_buffer);
1077 return -25;
1078 }
1079
1080 if(memcmp(&out_buffer[ciff_size], "EDOC", 4) != 0)
1081 {
1082 fprintf(stderr, "Fail!\n[ERR] Faulty bootloader\n");
1083 free(out_buffer);
1084 fclose(bootfd);
1085 fclose(outfd);
1086 return -26;
1087 }
1088
1089 if(fwrite(&out_buffer[ciff_size], filesize(bootfd), 1, outfd) != 1)
1090 {
1091 fprintf(stderr, "Fail!\n[ERR] Short write\n");
1092 fclose(bootfd);
1093 fclose(outfd);
1094 free(out_buffer);
1095 return -27;
1096 }
1097
1098 fclose(bootfd);
1099 fprintf(stderr, "Done!\n");
1100
1101 if(fwrite(&out_buffer[i+8+le2int(&out_buffer[i+4])], ciff_size-i-8-le2int(&out_buffer[i+4]), 1, outfd) != 1)
1102 {
1103 fprintf(stderr, "[ERR] Short write\n");
1104 fclose(bootfd);
1105 fclose(outfd);
1106 free(out_buffer);
1107 return -28;
1108 }
1109
1110 fseek(outfd, 4, SEEK_SET);
1111 int2le(filesize(outfd)-8-28, enc_data);
1112 if(fwrite(enc_data, 4, 1, outfd) != 1)
1113 {
1114 fprintf(stderr, "[ERR] Short write\n");
1115 fclose(outfd);
1116 free(out_buffer);
1117 return -29;
1118 }
1119
1120 free(out_buffer);
1121 fflush(outfd);
1122
1123 fprintf(stderr, "[INFO] Updating checksum... ");
1124
1125 buffer = malloc(filesize(outfd)-28);
1126 if(buffer == NULL)
1127 {
1128 fprintf(stderr, "Fail!\n[ERR] Couldn't allocate %d unsigned chars\n", filesize(outfd)-28);
1129 fclose(outfd);
1130 return -30;
1131 }
1132
1133 fseek(outfd, 0, SEEK_SET);
1134 if(fread(buffer, filesize(outfd)-28, 1, outfd) != 1)
1135 {
1136 fprintf(stderr, "Fail!\n[ERR] Short read\n");
1137 fclose(outfd);
1138 free(buffer);
1139 return -31;
1140 }
1141
1142 hmac_sha1((unsigned char*)null_key, strlen(null_key), &buffer[0], filesize(outfd)-28, &hash_key);
1143
1144 fseek(outfd, filesize(outfd)-20, SEEK_SET);
1145 if(fwrite(hash_key, 20, 1, outfd) != 1)
1146 {
1147 fprintf(stderr, "Fail!\n[ERR] Short write\n");
1148 fclose(outfd);
1149 free(buffer);
1150 return -32;
1151 }
1152
1153 fclose(outfd);
1154
1155 fprintf(stderr, "Done!\n");
1156 return 0;
1157}
1158
1159#ifdef STANDALONE
1160static void usage(void)
1161{
1162 printf("Usage: mkzenboot <firmware file> <boot file> <output file>\n");
1163 exit(1);
1164}
1165
1166int main(int argc, char *argv[])
1167{
1168 char *infile, *bootfile, *outfile;
1169
1170 if(argc < 3)
1171 {
1172 usage();
1173 }
1174
1175 infile = argv[1];
1176 bootfile = argv[2];
1177 outfile = argv[3];
1178
1179 return mkboot(infile, bootfile, outfile);
1180}
1181#endif