tools/mkfwimage2: remove 256 length limit for partition images
[openwrt/openwrt.git] / tools / firmware-utils / src / pc1crypt.c
1 /*
2 * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
7 *
8 * This code was based on:
9 * PC1 Cipher Algorithm ( Pukall Cipher 1 )
10 * By Alexander PUKALL 1991
11 * free code no restriction to use
12 * please include the name of the Author in the final software
13 * the Key is 128 bits
14 * http://membres.lycos.fr/pc1/
15 *
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <string.h>
22 #include <unistd.h> /* for unlink() */
23 #include <libgen.h>
24 #include <getopt.h> /* for getopt() */
25 #include <stdarg.h>
26 #include <errno.h>
27 #include <sys/stat.h>
28
29 struct pc1_ctx {
30 unsigned short ax;
31 unsigned short bx;
32 unsigned short cx;
33 unsigned short dx;
34 unsigned short si;
35 unsigned short tmp;
36 unsigned short x1a2;
37 unsigned short x1a0[8];
38 unsigned short res;
39 unsigned short i;
40 unsigned short inter;
41 unsigned short cfc;
42 unsigned short cfd;
43 unsigned short compte;
44 unsigned char cle[17];
45 short c;
46 };
47
48 static void pc1_finish(struct pc1_ctx *pc1)
49 {
50 /* erase all variables */
51 memset(pc1, 0, sizeof(struct pc1_ctx));
52 }
53
54 static void pc1_code(struct pc1_ctx *pc1)
55 {
56 pc1->dx = pc1->x1a2 + pc1->i;
57 pc1->ax = pc1->x1a0[pc1->i];
58 pc1->cx = 0x015a;
59 pc1->bx = 0x4e35;
60
61 pc1->tmp = pc1->ax;
62 pc1->ax = pc1->si;
63 pc1->si = pc1->tmp;
64
65 pc1->tmp = pc1->ax;
66 pc1->ax = pc1->dx;
67 pc1->dx = pc1->tmp;
68
69 if (pc1->ax != 0) {
70 pc1->ax = pc1->ax * pc1->bx;
71 }
72
73 pc1->tmp = pc1->ax;
74 pc1->ax = pc1->cx;
75 pc1->cx = pc1->tmp;
76
77 if (pc1->ax != 0) {
78 pc1->ax = pc1->ax * pc1->si;
79 pc1->cx = pc1->ax + pc1->cx;
80 }
81
82 pc1->tmp = pc1->ax;
83 pc1->ax = pc1->si;
84 pc1->si = pc1->tmp;
85 pc1->ax = pc1->ax * pc1->bx;
86 pc1->dx = pc1->cx + pc1->dx;
87
88 pc1->ax = pc1->ax + 1;
89
90 pc1->x1a2 = pc1->dx;
91 pc1->x1a0[pc1->i] = pc1->ax;
92
93 pc1->res = pc1->ax ^ pc1->dx;
94 pc1->i = pc1->i + 1;
95 }
96
97 static void pc1_assemble(struct pc1_ctx *pc1)
98 {
99 pc1->x1a0[0] = (pc1->cle[0] * 256) + pc1->cle[1];
100
101 pc1_code(pc1);
102 pc1->inter = pc1->res;
103
104 pc1->x1a0[1] = pc1->x1a0[0] ^ ((pc1->cle[2]*256) + pc1->cle[3]);
105 pc1_code(pc1);
106 pc1->inter = pc1->inter ^ pc1->res;
107
108 pc1->x1a0[2] = pc1->x1a0[1] ^ ((pc1->cle[4]*256) + pc1->cle[5]);
109 pc1_code(pc1);
110 pc1->inter = pc1->inter ^ pc1->res;
111
112 pc1->x1a0[3] = pc1->x1a0[2] ^ ((pc1->cle[6]*256) + pc1->cle[7]);
113 pc1_code(pc1);
114 pc1->inter = pc1->inter ^ pc1->res;
115
116 pc1->x1a0[4] = pc1->x1a0[3] ^ ((pc1->cle[8]*256) + pc1->cle[9]);
117 pc1_code(pc1);
118 pc1->inter = pc1->inter ^ pc1->res;
119
120 pc1->x1a0[5] = pc1->x1a0[4] ^ ((pc1->cle[10]*256) + pc1->cle[11]);
121 pc1_code(pc1);
122 pc1->inter = pc1->inter ^ pc1->res;
123
124 pc1->x1a0[6] = pc1->x1a0[5] ^ ((pc1->cle[12]*256) + pc1->cle[13]);
125 pc1_code(pc1);
126 pc1->inter = pc1->inter ^ pc1->res;
127
128 pc1->x1a0[7] = pc1->x1a0[6] ^ ((pc1->cle[14]*256) + pc1->cle[15]);
129 pc1_code(pc1);
130 pc1->inter = pc1->inter ^ pc1->res;
131
132 pc1->i = 0;
133 }
134
135 static unsigned char pc1_decrypt(struct pc1_ctx *pc1, short c)
136 {
137 pc1_assemble(pc1);
138 pc1->cfc = pc1->inter >> 8;
139 pc1->cfd = pc1->inter & 255; /* cfc^cfd = random byte */
140
141 c = c ^ (pc1->cfc ^ pc1->cfd);
142 for (pc1->compte = 0; pc1->compte <= 15; pc1->compte++) {
143 /* we mix the plaintext byte with the key */
144 pc1->cle[pc1->compte] = pc1->cle[pc1->compte] ^ c;
145 }
146
147 return c;
148 }
149
150 static unsigned char pc1_encrypt(struct pc1_ctx *pc1, short c)
151 {
152 pc1_assemble(pc1);
153 pc1->cfc = pc1->inter >> 8;
154 pc1->cfd = pc1->inter & 255; /* cfc^cfd = random byte */
155
156 for (pc1->compte = 0; pc1->compte <= 15; pc1->compte++) {
157 /* we mix the plaintext byte with the key */
158 pc1->cle[pc1->compte] = pc1->cle[pc1->compte] ^ c;
159 }
160 c = c ^ (pc1->cfc ^ pc1->cfd);
161
162 return c;
163 }
164
165 static void pc1_init(struct pc1_ctx *pc1)
166 {
167 memset(pc1, 0, sizeof(struct pc1_ctx));
168
169 /* ('Remsaalps!123456') is the key used, you can change it */
170 strcpy(pc1->cle, "Remsaalps!123456");
171 }
172
173 static void pc1_decrypt_buf(struct pc1_ctx *pc1, unsigned char *buf,
174 unsigned len)
175 {
176 unsigned i;
177
178 for (i = 0; i < len; i++)
179 buf[i] = pc1_decrypt(pc1, buf[i]);
180 }
181
182 static void pc1_encrypt_buf(struct pc1_ctx *pc1, unsigned char *buf,
183 unsigned len)
184 {
185 unsigned i;
186
187 for (i = 0; i < len; i++)
188 buf[i] = pc1_encrypt(pc1, buf[i]);
189 }
190
191 /*
192 * Globals
193 */
194 static char *ifname;
195 static char *progname;
196 static char *ofname;
197 static int decrypt;
198
199 /*
200 * Message macros
201 */
202 #define ERR(fmt, ...) do { \
203 fflush(0); \
204 fprintf(stderr, "[%s] *** error: " fmt "\n", \
205 progname, ## __VA_ARGS__ ); \
206 } while (0)
207
208 #define ERRS(fmt, ...) do { \
209 int save = errno; \
210 fflush(0); \
211 fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \
212 progname, ## __VA_ARGS__, strerror(save)); \
213 } while (0)
214
215 void usage(int status)
216 {
217 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
218 struct board_info *board;
219
220 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
221 fprintf(stream,
222 "\n"
223 "Options:\n"
224 " -d decrypt instead of encrypt"
225 " -i <file> read input from the file <file>\n"
226 " -o <file> write output to the file <file>\n"
227 " -h show this screen\n"
228 );
229
230 exit(status);
231 }
232
233 #define BUFSIZE (64 * 1024)
234
235 int main(int argc, char *argv[])
236 {
237 struct pc1_ctx pc1;
238 int res = EXIT_FAILURE;
239 int err;
240 struct stat st;
241 char *buf;
242 unsigned total;
243
244 FILE *outfile, *infile;
245
246 progname = basename(argv[0]);
247
248 while ( 1 ) {
249 int c;
250
251 c = getopt(argc, argv, "di:o:h");
252 if (c == -1)
253 break;
254
255 switch (c) {
256 case 'd':
257 decrypt = 1;
258 break;
259 case 'i':
260 ifname = optarg;
261 break;
262 case 'o':
263 ofname = optarg;
264 break;
265 case 'h':
266 usage(EXIT_SUCCESS);
267 break;
268 default:
269 usage(EXIT_FAILURE);
270 break;
271 }
272 }
273
274 if (ifname == NULL) {
275 ERR("no input file specified");
276 goto err;
277 }
278
279 if (ofname == NULL) {
280 ERR("no output file specified");
281 goto err;
282 }
283
284 err = stat(ifname, &st);
285 if (err){
286 ERRS("stat failed on %s", ifname);
287 goto err;
288 }
289
290 total = st.st_size;
291 buf = malloc(BUFSIZE);
292 if (!buf) {
293 ERR("no memory for buffer\n");
294 goto err;
295 }
296
297 infile = fopen(ifname, "r");
298 if (infile == NULL) {
299 ERRS("could not open \"%s\" for reading", ifname);
300 goto err_free;
301 }
302
303 outfile = fopen(ofname, "w");
304 if (outfile == NULL) {
305 ERRS("could not open \"%s\" for writing", ofname);
306 goto err_close_in;
307 }
308
309 pc1_init(&pc1);
310 while (total > 0) {
311 unsigned datalen;
312
313 if (total > BUFSIZE)
314 datalen = BUFSIZE;
315 else
316 datalen = total;
317
318 errno = 0;
319 fread(buf, datalen, 1, infile);
320 if (errno != 0) {
321 ERRS("unable to read from file %s", ifname);
322 goto err_close_out;
323 }
324
325 if (decrypt)
326 pc1_decrypt_buf(&pc1, buf, datalen);
327 else
328 pc1_encrypt_buf(&pc1, buf, datalen);
329
330 errno = 0;
331 fwrite(buf, datalen, 1, outfile);
332 if (errno) {
333 ERRS("unable to write to file %s", ofname);
334 goto err_close_out;
335 }
336
337 total -= datalen;
338 }
339 pc1_finish(&pc1);
340
341 res = EXIT_SUCCESS;
342
343 out_flush:
344 fflush(outfile);
345
346 err_close_out:
347 fclose(outfile);
348 if (res != EXIT_SUCCESS) {
349 unlink(ofname);
350 }
351
352 err_close_in:
353 fclose(infile);
354
355 err_free:
356 free(buf);
357
358 err:
359 return res;
360 }
361