firmware-utils: add WNDR3700 image fixing tool (thanks to Anael Orlinski)
[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 "\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