xref: /openbsd-src/usr.bin/x99token/x99token.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*
2  * X9.9 calculator
3  * This software is provided AS IS with no express or implied warranty
4  * October 1995, Paul Borman <prb@krystal.com>
5  */
6 #include <sys/param.h>
7 #include <sys/stat.h>
8 
9 #include <ctype.h>
10 #include <err.h>
11 #include <pwd.h>
12 #include <readpassphrase.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <des.h>
18 
19 #define	KEYFILE		".keyfile.des"
20 #define	HEXDIGITS	"0123456789abcdef"
21 #define	DECDIGITS	"0123456789012345"
22 
23 void predict(des_key_schedule, char *, int);
24 
25 char *digits = HEXDIGITS;
26 extern char *__progname;
27 
28 int
29 main(int argc, char **argv)
30 {
31 	int i;
32 	char buf[256];
33 	des_key_schedule ks;
34 	des_cblock key;
35 	char _keyfile[MAXPATHLEN];
36 	char *keyfile = 0;
37 	FILE *fp;
38 	int init = 0;
39 	int hex = 1;
40 	int cnt = 1;
41 	unsigned int pin;
42 	struct passwd *pwd;
43 
44 	while ((i = getopt(argc, argv, "dk:in:")) != -1) {
45 		switch (i) {
46 		case 'k':
47 			keyfile = optarg;
48 			break;
49 		case 'i':
50 			init = 1;
51 			break;
52 		case 'd':
53 			hex = 0;
54 			break;
55 		case 'n':
56 			cnt = atoi(optarg);
57 			if (cnt <= 0)
58 				err(1, "invalid count: %s", optarg);
59 			break;
60 		default:
61 			fprintf(stderr, "usage: %s [-n cnt] [-h] [-k keyfile]\n"
62 			    "       %s -i [-k keyfile]\n", __progname,
63 			    __progname);
64 			exit(1);
65 		}
66 	}
67 
68 	if (!keyfile) {
69 		if ((pwd = getpwuid(getuid())) == NULL) {
70 			fprintf(stderr, "Say, just who are you, anyhow?\n");
71 			exit(1);
72 		}
73 		snprintf(_keyfile, sizeof(_keyfile), "%s/%s", pwd->pw_dir,
74 		    KEYFILE);
75 		keyfile = _keyfile;
76 	}
77 
78 	if (init)
79 		readpassphrase("Enter Key: ", buf, sizeof(buf), 0);
80 	else if ((fp = fopen(keyfile, "r")) == NULL)
81 		err(1, "unable to open %s", keyfile);
82 	else {
83 		if (fgets(buf, sizeof(buf), fp) == NULL) {
84 			fprintf(stderr, "No key in %s\n", keyfile);
85 			exit(1);
86 		}
87 		fclose(fp);
88 	}
89 
90 	memset(key, 0, sizeof(key));
91 	if (init && buf[3] == ' ') {
92 		char *b = buf;
93 		/* Assume octal input */
94 		for (i = 0; i < 8; ++i) {
95 			if (!*b) {
96 				fprintf(stderr, "%s: invalid key\n", buf);
97 			}
98 			while (isdigit(*b))
99 				key[i] = key[i] << 3 | *b++ - '0';
100 			while (*b && !isdigit(*b))
101 				++b;
102 		}
103 	} else {
104 		for (i = 0; i < 16; ++i) {
105 			int d;
106 
107 			if (islower(buf[i]))
108 				buf[i] = toupper(buf[i]);
109 			if (buf[i] >= '0' && buf[i] <= '9')
110 				d = buf[i] - '0';
111 			else if (buf[i] >= 'A' && buf[i] <= 'F')
112 				d = buf[i] - 'A' + 10;
113 			else {
114 				fprintf(stderr, "invalid key: %s\n", buf);
115 				exit(1);
116 			}
117 			key[i>>1] |= d << ((i & 1) ? 0 : 4);
118 		}
119 	}
120 
121 	/* XXX - should warn on non-space or non-digit */
122 	readpassphrase("Enter Pin: ", buf, sizeof(buf), 0);
123 	for (i = 0, pin = 0; buf[i] && buf[i] != '\n'; ++i)
124 		if (isdigit(buf[i]))
125 			pin = pin * 16 + buf[i] - '0' + 1;
126 
127 	if ((pin & 0xffff0000) == 0)
128 		pin |= pin << 16;
129 
130 	for (i = 0; i < 8; ++i)
131 		key[0] ^= (pin >> ((i * 7) % 26)) & 0x7f;
132 
133 	if (init) {
134 		if ((fp = fopen(keyfile, "w")) == NULL)
135 			err(1, "could not open %s for writing", keyfile);
136 		fchmod(fileno(fp), 0600);
137 		for (i = 0; i < 8; ++i) {
138 			fprintf(fp, "%c", digits[(key[i]>>4)&0xf]);
139 			fprintf(fp, "%c", digits[(key[i]>>0)&0xf]);
140 		}
141 		fputc('\n', fp);
142 		fclose(fp);
143 		exit(0);
144 	}
145 
146 	des_fixup_key_parity(&key);
147 	des_key_sched(&key, ks);
148 
149 	buf[0] = '\0';
150 	readpassphrase("Enter challange: ", buf, sizeof(buf), RPP_ECHO_ON);
151 	if (buf[0] == '\0')
152 		exit(0);
153 
154 	for (i = 0; i < 8; ++i)
155 		if (buf[i] == '\n')
156 			buf[i] = '\0';
157 
158 	if (!hex)
159 		digits = DECDIGITS;
160 
161 	predict(ks, buf, cnt);
162 
163 	memset(&ks, 0, sizeof(ks));
164 	memset(buf, 0, sizeof(buf));
165 
166 	exit(0);
167 }
168 
169 void
170 predict(des_key_schedule ks, char *chal, int cnt)
171 {
172 	int i;
173 	des_cblock cb;
174 
175 	while (cnt-- > 0) {
176 		printf("%.8s: ", chal);
177 		des_ecb_encrypt((des_cblock *)chal, &cb, ks, DES_ENCRYPT);
178 		for (i = 0; i < 4; ++i) {
179 			printf("%c", digits[(cb[i]>>4) & 0xf]);
180 			printf("%c", digits[(cb[i]>>0) & 0xf]);
181 		}
182 		putchar('\n');
183 		for (i = 0; i < 8; ++i) {
184 			if ((cb[i] &= 0xf) > 9)
185 				cb[i] -= 10;
186 			cb[i] |= 0x30;
187 		}
188 	}
189 	memset(&cb, 0, sizeof(cb));
190 }
191