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