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