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 <sys/cdefs.h>
14__FBSDID("$FreeBSD$");
15
16#include <sys/types.h>
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22
23#define MINUSKVAR "CrYpTkEy"
24
25#define ROTORSZ 256
26#define MASK 0377
27static char	t1[ROTORSZ];
28static char	t2[ROTORSZ];
29static char	t3[ROTORSZ];
30static char	deck[ROTORSZ];
31static char	buf[13];
32
33static void	shuffle(char *);
34static void	setup(char *);
35
36static void
37setup(char *pw)
38{
39	int ic, i, k, temp;
40	char salt[3];
41	unsigned rnd;
42	int32_t seed;
43	char *cryptpw;
44
45	if (crypt_set_format("des") == 0) {
46		fprintf(stderr, "crypt_set_format(\"des\") failed.\n");
47		exit(1);
48	}
49
50	strlcpy(salt, pw, sizeof(salt));
51	cryptpw = crypt(pw, salt);
52	if (cryptpw == NULL) {
53		fprintf(stderr, "crypt(3) failure\n");
54		exit(1);
55	}
56	memcpy(buf, cryptpw, sizeof(buf));
57	seed = 123;
58	for (i=0; i<13; i++)
59		seed = seed*buf[i] + i;
60	for(i=0;i<ROTORSZ;i++) {
61		t1[i] = i;
62		deck[i] = i;
63	}
64	for(i=0;i<ROTORSZ;i++) {
65		seed = 5*seed + buf[i%13];
66		rnd = seed % 65521;
67		k = ROTORSZ-1 - i;
68		ic = (rnd&MASK)%(k+1);
69		rnd >>= 8;
70		temp = t1[k];
71		t1[k] = t1[ic];
72		t1[ic] = temp;
73		if(t3[k]!=0) continue;
74		ic = (rnd&MASK) % k;
75		while(t3[ic]!=0) ic = (ic+1) % k;
76		t3[k] = ic;
77		t3[ic] = k;
78	}
79	for(i=0;i<ROTORSZ;i++)
80		t2[t1[i]&MASK] = i;
81}
82
83int
84main(int argc, char *argv[])
85{
86	int i, n1, n2, nr1, nr2;
87	int secureflg = 0, kflag = 0;
88	char *cp;
89
90	if (argc > 1 && argv[1][0] == '-') {
91		if (argv[1][1] == 's') {
92			argc--;
93			argv++;
94			secureflg = 1;
95		} else if (argv[1][1] == 'k') {
96			argc--;
97			argv++;
98			kflag = 1;
99		}
100	}
101	if (kflag) {
102		if ((cp = getenv(MINUSKVAR)) == NULL) {
103			fprintf(stderr, "%s not set\n", MINUSKVAR);
104			exit(1);
105		}
106		setup(cp);
107	} else if (argc != 2) {
108		setup(getpass("Enter key:"));
109	}
110	else
111		setup(argv[1]);
112	n1 = 0;
113	n2 = 0;
114	nr2 = 0;
115
116	while((i=getchar()) != -1) {
117		if (secureflg) {
118			nr1 = deck[n1]&MASK;
119			nr2 = deck[nr1]&MASK;
120		} else {
121			nr1 = n1;
122		}
123		i = t2[(t3[(t1[(i+nr1)&MASK]+nr2)&MASK]-nr2)&MASK]-nr1;
124		putchar(i);
125		n1++;
126		if(n1==ROTORSZ) {
127			n1 = 0;
128			n2++;
129			if(n2==ROTORSZ) n2 = 0;
130			if (secureflg) {
131				shuffle(deck);
132			} else {
133				nr2 = n2;
134			}
135		}
136	}
137
138	return 0;
139}
140
141static void
142shuffle(char deckary[])
143{
144	int i, ic, k, temp;
145	unsigned rnd;
146	static int32_t seed = 123;
147
148	for(i=0;i<ROTORSZ;i++) {
149		seed = 5*seed + buf[i%13];
150		rnd = seed % 65521;
151		k = ROTORSZ-1 - i;
152		ic = (rnd&MASK)%(k+1);
153		temp = deckary[k];
154		deckary[k] = deckary[ic];
155		deckary[ic] = temp;
156	}
157}
158