crypt-portable

Portable version of the classic crypt(1) utility
git clone git://git.sgregoratto.me/crypt-portable
Log | Files | Refs

crypt.c (3913B)


      1 /*
      2  *	"enigma.c" is in file cbw.tar from
      3  *	anonymous FTP host watmsg.waterloo.edu: pub/crypt/cbw.tar.Z
      4  *
      5  *	A one-rotor machine designed along the lines of Enigma
      6  *	but considerably trivialized.
      7  *
      8  *	A public-domain replacement for the UNIX "crypt" command.
      9  *
     10  *	Upgraded to function properly on 64-bit machines.
     11  */
     12 
     13 #include "config.h"
     14 
     15 #if HAVE_ERR
     16 #include <err.h>
     17 #endif
     18 #if HAVE_READPASSPHRASE
     19 #include <readpassphrase.h>
     20 #endif
     21 #include <stdint.h>
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 #include <unistd.h>
     26 
     27 #include "des.h"
     28 
     29 #define CRYPTKEY_ENV "CrYpTkEy"
     30 #define ROTORSZ 256
     31 #define MASK 0377
     32 
     33 static char t1[ROTORSZ] = {0};
     34 static char t2[ROTORSZ] = {0};
     35 static char t3[ROTORSZ] = {0};
     36 static char deck[ROTORSZ] = {0};
     37 static char buf[13] = {0};
     38 
     39 static void shuffle(void);
     40 static void setup(char *);
     41 
     42 static void
     43 setup(char *passwd)
     44 {
     45 	int32_t ic, i, k;
     46 	static int32_t seed = 123;
     47 	uint32_t rnd;
     48 	char salt[3], cryptpw[DES_BUFFER_SIZE], temp;
     49 
     50 	strlcpy(salt, passwd, sizeof(salt));
     51 
     52 	if (des(passwd, salt, cryptpw) == -1)
     53 		errx(1, "des");
     54 
     55 	memcpy(buf, cryptpw, sizeof(buf));
     56 	explicit_bzero(passwd, sizeof(passwd));
     57 	explicit_bzero(salt, sizeof(salt));
     58 	explicit_bzero(cryptpw, sizeof(cryptpw));
     59 
     60 	for (i = 0; i < 13; i++)
     61 		seed = seed * buf[i] + i;
     62 
     63 	for (i = 0; i < ROTORSZ; i++)
     64 		t1[i] = deck[i] = i;
     65 
     66 	for (i = 0; i < ROTORSZ; i++) {
     67 		seed = 5 * seed + buf[i % 13];
     68 		rnd = seed % 65521;
     69 		k = ROTORSZ - 1 - i;
     70 		ic = (rnd & MASK) % (k + 1);
     71 		rnd >>= 8;
     72 
     73 		temp = t1[k];
     74 		t1[k] = t1[ic];
     75 		t1[ic] = temp;
     76 
     77 		if (t3[k] != 0)
     78 			continue;
     79 
     80 		ic = (rnd & MASK) % k;
     81 		while (t3[ic] != 0)
     82 			ic = (ic + 1) % k;
     83 
     84 		t3[k] = ic;
     85 		t3[ic] = k;
     86 	}
     87 
     88 	for (i = 0; i < ROTORSZ; i++)
     89 		t2[t1[i] & MASK] = i;
     90 }
     91 
     92 int
     93 main(int argc, char **argv)
     94 {
     95 	int i, n1, n2, nr1, nr2, ch;
     96 	int kflag = 0, sflag = 0;
     97 	char *cryptkey, passbuf[31];
     98 
     99 #if HAVE_PLEDGE
    100 	if (pledge("stdio tty", NULL) == -1)
    101 		err(1, "pledge");
    102 #endif
    103 
    104 	while ((ch = getopt(argc, argv, "ks")) != -1) {
    105 		switch (ch) {
    106 		case 'k':
    107 			kflag = 1;
    108 			break;
    109 		case 's':
    110 			sflag = 1;
    111 			break;
    112 		default:
    113 			goto usage;
    114 		}
    115 	}
    116 	argc -= optind;
    117 	argv += optind;
    118 
    119 	if (argc > 1)
    120 		errx(1, "Too many arguments, have %d", argc);
    121 
    122 	if (kflag) {
    123 		if ((cryptkey = getenv(CRYPTKEY_ENV)) == NULL)
    124 			errx(1, "%s is unset", CRYPTKEY_ENV);
    125 		setup(cryptkey);
    126 	} else if (argc == 0) {
    127 		if (readpassphrase("Enter Key: ", passbuf, sizeof(passbuf),
    128 				   RPP_REQUIRE_TTY) == NULL)
    129 			errx(1, "unable to read password");
    130 		cryptkey = passbuf;
    131 	} else {
    132 		cryptkey = argv[0];
    133 	}
    134 
    135 #if HAVE_PLEDGE
    136 	if (pledge("stdio", NULL) == -1)
    137 		err(1, "pledge");
    138 #endif
    139 
    140         /*
    141          * The first two bytes of the key are used as the salt,
    142          * and since we skip the salt check with crypt_set_format(),
    143          * we should check it here.
    144          */
    145         if (strspn(cryptkey, DES_SALT_ALPHABET) != strlen(cryptkey))
    146                 errx(1, "key contains invalid characters");
    147 	setup(cryptkey);
    148 
    149 	n1 = n2 = nr2 = 0;
    150 	while ((i = getchar()) != EOF) {
    151 		if (sflag) {
    152 			nr1 = deck[n1] & MASK;
    153 			nr2 = deck[nr1] & MASK;
    154 		} else {
    155 			nr1 = n1;
    156 		}
    157 
    158 		i = t2[(t3[(t1[(i+nr1)&MASK]+nr2)&MASK]-nr2)&MASK]-nr1;
    159 		if (putchar(i) == EOF)
    160 			err(1, "putchar");
    161 
    162 		n1++;
    163 		if (n1 == ROTORSZ) {
    164 			n1 = 0;
    165 			n2++;
    166 
    167 			if (n2 == ROTORSZ)
    168 				n2 = 0;
    169 
    170 			if (sflag)
    171 				shuffle();
    172 			else
    173 				nr2 = n2;
    174 		}
    175 	}
    176 
    177 	explicit_bzero(buf, sizeof(buf));
    178 
    179 	if (ferror(stdin))
    180 		err(1, "ferror");
    181 	if (fclose(stdout) == EOF)
    182 		err(1, "stdout");
    183 
    184 	return 0;
    185 
    186 usage:
    187 	fprintf(stderr, "usage: %s [-ks] password\n", getprogname());
    188 
    189 	return 1;
    190 }
    191 
    192 static void
    193 shuffle(void)
    194 {
    195 	int32_t i, ic, k;
    196 	static int32_t seed = 123;
    197 	uint32_t rnd;
    198 	char temp;
    199 
    200 	for (i = 0; i < ROTORSZ; i++) {
    201 		seed = 5 * seed + buf[i % 13];
    202 		rnd = seed % 65521;
    203 		k = ROTORSZ - 1 - i;
    204 		ic = (rnd & MASK) % (k + 1);
    205 
    206 		temp = deck[k];
    207 		deck[k] = deck[ic];
    208 		deck[ic] = temp;
    209 	}
    210 }