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