5eb6e01d4a51b4ab3fae56b3049a6efaadb3bcc2
[openwrt/staging/ldir.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
219 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
220 fprintf(stream,
221 "\n"
222 "Options:\n"
223 " -d decrypt instead of encrypt"
224 " -i <file> read input from the file <file>\n"
225 " -o <file> write output to the file <file>\n"
226 " -h show this screen\n"
227 );
228
229 exit(status);
230 }
231
232 #define BUFSIZE (64 * 1024)
233
234 int main(int argc, char *argv[])
235 {
236 struct pc1_ctx pc1;
237 int res = EXIT_FAILURE;
238 int err;
239 struct stat st;
240 char *buf;
241 unsigned total;
242
243 FILE *outfile, *infile;
244
245 progname = basename(argv[0]);
246
247 while ( 1 ) {
248 int c;
249
250 c = getopt(argc, argv, "di:o:h");
251 if (c == -1)
252 break;
253
254 switch (c) {
255 case 'd':
256 decrypt = 1;
257 break;
258 case 'i':
259 ifname = optarg;
260 break;
261 case 'o':
262 ofname = optarg;
263 break;
264 case 'h':
265 usage(EXIT_SUCCESS);
266 break;
267 default:
268 usage(EXIT_FAILURE);
269 break;
270 }
271 }
272
273 if (ifname == NULL) {
274 ERR("no input file specified");
275 goto err;
276 }
277
278 if (ofname == NULL) {
279 ERR("no output file specified");
280 goto err;
281 }
282
283 err = stat(ifname, &st);
284 if (err){
285 ERRS("stat failed on %s", ifname);
286 goto err;
287 }
288
289 total = st.st_size;
290 buf = malloc(BUFSIZE);
291 if (!buf) {
292 ERR("no memory for buffer\n");
293 goto err;
294 }
295
296 infile = fopen(ifname, "r");
297 if (infile == NULL) {
298 ERRS("could not open \"%s\" for reading", ifname);
299 goto err_free;
300 }
301
302 outfile = fopen(ofname, "w");
303 if (outfile == NULL) {
304 ERRS("could not open \"%s\" for writing", ofname);
305 goto err_close_in;
306 }
307
308 pc1_init(&pc1);
309 while (total > 0) {
310 unsigned datalen;
311
312 if (total > BUFSIZE)
313 datalen = BUFSIZE;
314 else
315 datalen = total;
316
317 errno = 0;
318 fread(buf, datalen, 1, infile);
319 if (errno != 0) {
320 ERRS("unable to read from file %s", ifname);
321 goto err_close_out;
322 }
323
324 if (decrypt)
325 pc1_decrypt_buf(&pc1, buf, datalen);
326 else
327 pc1_encrypt_buf(&pc1, buf, datalen);
328
329 errno = 0;
330 fwrite(buf, datalen, 1, outfile);
331 if (errno) {
332 ERRS("unable to write to file %s", ofname);
333 goto err_close_out;
334 }
335
336 total -= datalen;
337 }
338 pc1_finish(&pc1);
339
340 res = EXIT_SUCCESS;
341
342 fflush(outfile);
343
344 err_close_out:
345 fclose(outfile);
346 if (res != EXIT_SUCCESS) {
347 unlink(ofname);
348 }
349
350 err_close_in:
351 fclose(infile);
352
353 err_free:
354 free(buf);
355
356 err:
357 return res;
358 }
359