// rc2.c, version 0.2.0 // OMKOV cryptutils rc2 // Copyright (C) 2021, Jakob Wakeling // MIT Licence #include "util/error.c" #include "util/optget.h" #include "util/rc2.h" #include "util/util.h" #include #include #include #define VERSION "0.2.0" static struct lop lops[] = { { "help", ARG_NUL, 256 }, { "version", ARG_NUL, 257 }, { NULL, 0, 0 } }; static int mode = 0; static char *karg; static int larg; static inline void rc2(const char *ifile, const char *ofile); static void hlp(void); static void ver(void); int main(int ac, char *av[]) { A0 = av[0]; struct opt opt = OPTGET_INIT; opt.str = "dek:l:m"; opt.lops = lops; for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) { case 'e': { mode = 0; } break; case 'd': { mode = 1; } break; case 'k': { karg = opt.arg; } break; case 'l': { register int d; register char *p = opt.arg; for (larg = 0; *p >= '0' && *p < '9'; ++p) { d = (int)*p - '0'; if (larg > (INT_MAX - d) / 10) { break; } larg = larg * 10 + d; } if (*p) { error(1, "invalid length"); } if (larg > 1024) { error(1, "length must be at most 1024"); } if (larg == 0) { error(1, "length must be greater than 0"); } } break; case 'm': { /* TODO */ error(1, "-m not implemented"); } break; case 256: { hlp(); } return 0; case 257: { ver(); } return 0; default: {} return 1; } if (!larg) { larg = 1024; } if (opt.ind == ac) { error(1, "missing operand"); } else if (opt.ind == ac - 1) { rc2(av[opt.ind], NULL); } else if (opt.ind == ac - 2) { rc2(av[opt.ind], av[opt.ind + 1]); } else { error(1, "excess operand"); } return 0; } static inline void rc2(const char *ifile, const char *ofile) { struct rc2 ctx; u8 b1[128], b2[16]; FILE *fk, *fi, *fo; size_t kl, fl; if (!karg) { error(1, "-k is required"); } else if (!(fk = fopen(karg, "r"))) { error(1, "%s: %s", karg, serr()); } // TODO Check key size is within bounds kl = fread(b1, 1, sizeof (b1), fk); fclose(fk); fk = NULL; rc2expand(&ctx, b1, kl, larg); if (!ifile) { fi = stdin; } else if (!(fi = fopen(ifile, "r"))) { error(1, "%s: %s", ifile, serr()); } if (!ofile) { fo = stdout; } else if (!(fo = fopen(ofile, "w"))) { error(1, "%s: %s", ofile, serr()); } for (size_t c; (c = fread(b1, 1, 8, fi));) { while (c >= 8) { memset(b2, 0, 8); if (mode == 0) { rc2encrypt(&ctx, b1, b2); } if (mode == 1) { rc2decrypt(&ctx, b1, b2); } fwrite(b2, 1, 8, fo); c -= 8; } if (c != 0) { // Should only be true during encryption memset(b2, 0, 8); if (mode == 0) { rc2encrypt(&ctx, b1, b2); } fwrite(b2, 1, 8, fo); } memset(b1, 0, 8); } if (fi != stdin) { fclose(fi); } if (fo != stdin) { fclose(fo); } return; } /* Print help information. */ static void hlp(void) { puts("rc2 - encrypt and decrypt files using rc2\n"); puts("usage: rc2 [-d|-e] [-k keyfile] [-l length] [-m mode] [infile] " "[outfile]\n"); puts("options:"); puts(" -d Decrypt the input data"); puts(" -e Encrypt the input data (default)"); puts(" -k file Specify keyfile"); puts(" -l length Override effective key length"); puts(" -m mode Specify block cipher mode of operation"); puts(" --help Display help information"); puts(" --version Display version information"); } /* Print version information. */ static void ver(void) { puts("OMKOV cryptutils rc2, version " VERSION); puts("Copyright (C) 2021, Jakob Wakeling"); puts("MIT Licence (https://opensource.org/licenses/MIT)"); }