xref: /openbsd/usr.bin/x99token/x99token.c (revision 3a7efd93)
1*3a7efd93Smestre /*	$OpenBSD: x99token.c,v 1.13 2017/05/03 09:51:39 mestre Exp $	*/
2dddaaf88Smillert 
3b573928fSmillert /*
4b573928fSmillert  * X9.9 calculator
5b573928fSmillert  * This software is provided AS IS with no express or implied warranty
6b573928fSmillert  * October 1995, Paul Borman <prb@krystal.com>
7ad455a91Smillert  *
8ad455a91Smillert  * Donated to the Public Domain by Paul Borman
9b573928fSmillert  */
10b9fc9a72Sderaadt 
1158844e06Smillert #include <sys/stat.h>
1258844e06Smillert 
13b573928fSmillert #include <ctype.h>
1458844e06Smillert #include <err.h>
1558844e06Smillert #include <pwd.h>
1658844e06Smillert #include <readpassphrase.h>
17b573928fSmillert #include <stdio.h>
18b573928fSmillert #include <stdlib.h>
19b573928fSmillert #include <string.h>
20b573928fSmillert #include <unistd.h>
21b9fc9a72Sderaadt #include <limits.h>
220456bce5Sjsg #include <openssl/des.h>
23b573928fSmillert 
24b573928fSmillert #define	KEYFILE		".keyfile.des"
25b573928fSmillert #define	HEXDIGITS	"0123456789abcdef"
26b573928fSmillert #define	DECDIGITS	"0123456789012345"
27b573928fSmillert 
280456bce5Sjsg void predict(DES_key_schedule, const char *, int);
2958844e06Smillert 
30b573928fSmillert char *digits = HEXDIGITS;
3158844e06Smillert extern char *__progname;
32b573928fSmillert 
33b573928fSmillert int
main(int argc,char ** argv)3458844e06Smillert main(int argc, char **argv)
35b573928fSmillert {
36b573928fSmillert 	int i;
37b573928fSmillert 	char buf[256];
380456bce5Sjsg 	DES_key_schedule ks;
390456bce5Sjsg 	DES_cblock key;
40b9fc9a72Sderaadt 	char _keyfile[PATH_MAX];
41b573928fSmillert 	char *keyfile = 0;
42b573928fSmillert 	FILE *fp;
43b573928fSmillert 	int init = 0;
44b573928fSmillert 	int hex = 1;
45b573928fSmillert 	int cnt = 1;
4658844e06Smillert 	unsigned int pin;
47b573928fSmillert 	struct passwd *pwd;
48b573928fSmillert 
49d2efe238Sbluhm 	if (pledge("stdio rpath wpath cpath getpw tty", NULL) == -1)
5051bb89dbSbluhm 		err(1, "pledge");
5151bb89dbSbluhm 
5258844e06Smillert 	while ((i = getopt(argc, argv, "dk:in:")) != -1) {
53b573928fSmillert 		switch (i) {
54b573928fSmillert 		case 'k':
55b573928fSmillert 			keyfile = optarg;
56b573928fSmillert 			break;
57b573928fSmillert 		case 'i':
58b573928fSmillert 			init = 1;
59b573928fSmillert 			break;
60b573928fSmillert 		case 'd':
61b573928fSmillert 			hex = 0;
62b573928fSmillert 			break;
63b573928fSmillert 		case 'n':
64b573928fSmillert 			cnt = atoi(optarg);
6558844e06Smillert 			if (cnt <= 0)
6658844e06Smillert 				err(1, "invalid count: %s", optarg);
67b573928fSmillert 			break;
68b573928fSmillert 		default:
6905343367Sjmc 			fprintf(stderr,
7005343367Sjmc 			    "usage: %s [-d] [-k keyfile] [-n count]\n"
7105343367Sjmc 			    "       %s -i [-k keyfile]\n",
7205343367Sjmc 			    __progname, __progname);
73b573928fSmillert 			exit(1);
74b573928fSmillert 		}
7558844e06Smillert 	}
76b573928fSmillert 
77b573928fSmillert 	if (!keyfile) {
7858844e06Smillert 		if ((pwd = getpwuid(getuid())) == NULL) {
79b573928fSmillert 			fprintf(stderr, "Say, just who are you, anyhow?\n");
80b573928fSmillert 			exit(1);
81b573928fSmillert 		}
8258844e06Smillert 		snprintf(_keyfile, sizeof(_keyfile), "%s/%s", pwd->pw_dir,
8358844e06Smillert 		    KEYFILE);
84b573928fSmillert 		keyfile = _keyfile;
85b573928fSmillert 	}
86b573928fSmillert 
8758844e06Smillert 	if (init)
8858844e06Smillert 		readpassphrase("Enter Key: ", buf, sizeof(buf), 0);
8958844e06Smillert 	else if ((fp = fopen(keyfile, "r")) == NULL)
9058844e06Smillert 		err(1, "unable to open %s", keyfile);
9158844e06Smillert 	else {
92b573928fSmillert 		if (fgets(buf, sizeof(buf), fp) == NULL) {
93b573928fSmillert 			fprintf(stderr, "No key in %s\n", keyfile);
94b573928fSmillert 			exit(1);
95b573928fSmillert 		}
96b573928fSmillert 		fclose(fp);
97b573928fSmillert 	}
98b573928fSmillert 
99b573928fSmillert 	memset(key, 0, sizeof(key));
100b573928fSmillert 	if (init && buf[3] == ' ') {
101b573928fSmillert 		char *b = buf;
102b573928fSmillert 		/* Assume octal input */
103b573928fSmillert 		for (i = 0; i < 8; ++i) {
104c3959627Smillert 			if (!*b)
105b573928fSmillert 				fprintf(stderr, "%s: invalid key\n", buf);
1060e71acc1Sderaadt 			while (isdigit((unsigned char)*b))
107c3959627Smillert 				key[i] = key[i] << 3 | (*b++ - '0');
1080e71acc1Sderaadt 			while (*b && !isdigit((unsigned char)*b))
109b573928fSmillert 				++b;
110b573928fSmillert 		}
11158844e06Smillert 	} else {
112b573928fSmillert 		for (i = 0; i < 16; ++i) {
113b573928fSmillert 			int d;
114b573928fSmillert 
1150e71acc1Sderaadt 			if (islower((unsigned char)buf[i]))
1160e71acc1Sderaadt 				buf[i] = toupper((unsigned char)buf[i]);
117b573928fSmillert 			if (buf[i] >= '0' && buf[i] <= '9')
118b573928fSmillert 				d = buf[i] - '0';
119b573928fSmillert 			else if (buf[i] >= 'A' && buf[i] <= 'F')
120b573928fSmillert 				d = buf[i] - 'A' + 10;
121b573928fSmillert 			else {
122b573928fSmillert 				fprintf(stderr, "invalid key: %s\n", buf);
123b573928fSmillert 				exit(1);
124b573928fSmillert 			}
125b573928fSmillert 			key[i>>1] |= d << ((i & 1) ? 0 : 4);
126b573928fSmillert 		}
12758844e06Smillert 	}
128b573928fSmillert 
12958844e06Smillert 	/* XXX - should warn on non-space or non-digit */
13058844e06Smillert 	readpassphrase("Enter Pin: ", buf, sizeof(buf), 0);
13158844e06Smillert 	for (i = 0, pin = 0; buf[i] && buf[i] != '\n'; ++i)
1320e71acc1Sderaadt 		if (isdigit((unsigned char)buf[i]))
133b573928fSmillert 			pin = pin * 16 + buf[i] - '0' + 1;
134b573928fSmillert 
13558844e06Smillert 	if ((pin & 0xffff0000) == 0)
136b573928fSmillert 		pin |= pin << 16;
137b573928fSmillert 
138b573928fSmillert 	for (i = 0; i < 8; ++i)
139b573928fSmillert 		key[0] ^= (pin >> ((i * 7) % 26)) & 0x7f;
140b573928fSmillert 
141b573928fSmillert 	if (init) {
142d2efe238Sbluhm 		umask(S_IRWXG | S_IRWXO);
143d2efe238Sbluhm 		unlink(keyfile);
14458844e06Smillert 		if ((fp = fopen(keyfile, "w")) == NULL)
14558844e06Smillert 			err(1, "could not open %s for writing", keyfile);
146b573928fSmillert 		for (i = 0; i < 8; ++i) {
147b573928fSmillert 			fprintf(fp, "%c", digits[(key[i]>>4)&0xf]);
148b573928fSmillert 			fprintf(fp, "%c", digits[(key[i]>>0)&0xf]);
149b573928fSmillert 		}
15058844e06Smillert 		fputc('\n', fp);
151b573928fSmillert 		fclose(fp);
152b573928fSmillert 		exit(0);
153b573928fSmillert 	}
154b573928fSmillert 
1550456bce5Sjsg 	DES_fixup_key_parity(&key);
1560456bce5Sjsg 	DES_key_sched(&key, &ks);
157b573928fSmillert 
15858844e06Smillert 	buf[0] = '\0';
159c0141d96Sderaadt 	readpassphrase("Enter challenge: ", buf, sizeof(buf), RPP_ECHO_ON);
16058844e06Smillert 	if (buf[0] == '\0')
161b573928fSmillert 		exit(0);
162b573928fSmillert 
163b573928fSmillert 	for (i = 0; i < 8; ++i)
164b573928fSmillert 		if (buf[i] == '\n')
165b573928fSmillert 			buf[i] = '\0';
166b573928fSmillert 
167b573928fSmillert 	if (!hex)
168b573928fSmillert 		digits = DECDIGITS;
169b573928fSmillert 
170b573928fSmillert 	predict(ks, buf, cnt);
171b573928fSmillert 
172*3a7efd93Smestre 	explicit_bzero(&ks, sizeof(ks));
173*3a7efd93Smestre 	explicit_bzero(buf, sizeof(buf));
17458844e06Smillert 
175b573928fSmillert 	exit(0);
176b573928fSmillert }
177b573928fSmillert 
178b573928fSmillert void
predict(DES_key_schedule ks,const char * chal,int cnt)1790456bce5Sjsg predict(DES_key_schedule ks, const char *chal, int cnt)
180b573928fSmillert {
181b573928fSmillert 	int i;
1820456bce5Sjsg 	DES_cblock cb;
183b573928fSmillert 
184c3959627Smillert 	memcpy(&cb, chal, sizeof(cb));
185b573928fSmillert 	while (cnt-- > 0) {
186c3959627Smillert 		printf("%.8s: ", (char *)cb);
1870456bce5Sjsg 		DES_ecb_encrypt(&cb, &cb, &ks, DES_ENCRYPT);
188b573928fSmillert 		for (i = 0; i < 4; ++i) {
18958844e06Smillert 			printf("%c", digits[(cb[i]>>4) & 0xf]);
19058844e06Smillert 			printf("%c", digits[(cb[i]>>0) & 0xf]);
191b573928fSmillert 		}
19258844e06Smillert 		putchar('\n');
193b573928fSmillert 		for (i = 0; i < 8; ++i) {
19458844e06Smillert 			if ((cb[i] &= 0xf) > 9)
19558844e06Smillert 				cb[i] -= 10;
19658844e06Smillert 			cb[i] |= 0x30;
197b573928fSmillert 		}
198b573928fSmillert 	}
19958844e06Smillert 	memset(&cb, 0, sizeof(cb));
200b573928fSmillert }
201