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 29struct 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 48static void pc1_finish(struct pc1_ctx *pc1) 49{ 50 /* erase all variables */ 51 memset(pc1, 0, sizeof(struct pc1_ctx)); 52} 53 54static 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 97static 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 135static 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 150static 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 165static 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 173static 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 182static 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 */ 194static char *ifname; 195static char *progname; 196static char *ofname; 197static 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 215void 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 235int 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 362