pc1crypt.c 6.7 KB

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