[BACK]Return to x99token.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / x99token

File: [local] / src / usr.bin / x99token / x99token.c (download)

Revision 1.10, Fri Jan 16 06:40:14 2015 UTC (9 years, 4 months ago) by deraadt
Branch: MAIN
CVS Tags: OPENBSD_5_8_BASE, OPENBSD_5_8, OPENBSD_5_7_BASE, OPENBSD_5_7
Changes since 1.9: +4 -3 lines

Replace <sys/param.h> with <limits.h> and other less dirty headers where
possible.  Annotate <sys/param.h> lines with their current reasons.  Switch
to PATH_MAX, NGROUPS_MAX, HOST_NAME_MAX+1, LOGIN_NAME_MAX, etc.  Change
MIN() and MAX() to local definitions of MINIMUM() and MAXIMUM() where
sensible to avoid pulling in the pollution.  These are the files confirmed
through binary verification.
ok guenther, millert, doug (helped with the verification protocol)

/*	$OpenBSD: x99token.c,v 1.10 2015/01/16 06:40:14 deraadt Exp $	*/

/*
 * X9.9 calculator
 * This software is provided AS IS with no express or implied warranty
 * October 1995, Paul Borman <prb@krystal.com>
 *
 * Donated to the Public Domain by Paul Borman
 */

#include <sys/stat.h>

#include <ctype.h>
#include <err.h>
#include <pwd.h>
#include <readpassphrase.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <openssl/des.h>

#define	KEYFILE		".keyfile.des"
#define	HEXDIGITS	"0123456789abcdef"
#define	DECDIGITS	"0123456789012345"

void predict(DES_key_schedule, const char *, int);

char *digits = HEXDIGITS;
extern char *__progname;

int
main(int argc, char **argv)
{
	int i;
	char buf[256];
	DES_key_schedule ks;
	DES_cblock key;
	char _keyfile[PATH_MAX];
	char *keyfile = 0;
	FILE *fp;
	int init = 0;
	int hex = 1;
	int cnt = 1;
	unsigned int pin;
	struct passwd *pwd;

	while ((i = getopt(argc, argv, "dk:in:")) != -1) {
		switch (i) {
		case 'k':
			keyfile = optarg;
			break;
		case 'i':
			init = 1;
			break;
		case 'd':
			hex = 0;
			break;
		case 'n':
			cnt = atoi(optarg);
			if (cnt <= 0)
				err(1, "invalid count: %s", optarg);
			break;
		default:
			fprintf(stderr,
			    "usage: %s [-d] [-k keyfile] [-n count]\n"
			    "       %s -i [-k keyfile]\n",
			    __progname, __progname);
			exit(1);
		}
	}

	if (!keyfile) {
		if ((pwd = getpwuid(getuid())) == NULL) {
			fprintf(stderr, "Say, just who are you, anyhow?\n");
			exit(1);
		}
		snprintf(_keyfile, sizeof(_keyfile), "%s/%s", pwd->pw_dir,
		    KEYFILE);
		keyfile = _keyfile;
	}

	if (init)
		readpassphrase("Enter Key: ", buf, sizeof(buf), 0);
	else if ((fp = fopen(keyfile, "r")) == NULL)
		err(1, "unable to open %s", keyfile);
	else {
		if (fgets(buf, sizeof(buf), fp) == NULL) {
			fprintf(stderr, "No key in %s\n", keyfile);
			exit(1);
		}
		fclose(fp);
	}

	memset(key, 0, sizeof(key));
	if (init && buf[3] == ' ') {
		char *b = buf;
		/* Assume octal input */
		for (i = 0; i < 8; ++i) {
			if (!*b)
				fprintf(stderr, "%s: invalid key\n", buf);
			while (isdigit((unsigned char)*b))
				key[i] = key[i] << 3 | (*b++ - '0');
			while (*b && !isdigit((unsigned char)*b))
				++b;
		}
	} else {
		for (i = 0; i < 16; ++i) {
			int d;

			if (islower((unsigned char)buf[i]))
				buf[i] = toupper((unsigned char)buf[i]);
			if (buf[i] >= '0' && buf[i] <= '9')
				d = buf[i] - '0';
			else if (buf[i] >= 'A' && buf[i] <= 'F')
				d = buf[i] - 'A' + 10;
			else {
				fprintf(stderr, "invalid key: %s\n", buf);
				exit(1);
			}
			key[i>>1] |= d << ((i & 1) ? 0 : 4);
		}
	}

	/* XXX - should warn on non-space or non-digit */
	readpassphrase("Enter Pin: ", buf, sizeof(buf), 0);
	for (i = 0, pin = 0; buf[i] && buf[i] != '\n'; ++i)
		if (isdigit((unsigned char)buf[i]))
			pin = pin * 16 + buf[i] - '0' + 1;

	if ((pin & 0xffff0000) == 0)
		pin |= pin << 16;

	for (i = 0; i < 8; ++i)
		key[0] ^= (pin >> ((i * 7) % 26)) & 0x7f;

	if (init) {
		if ((fp = fopen(keyfile, "w")) == NULL)
			err(1, "could not open %s for writing", keyfile);
		fchmod(fileno(fp), 0600);
		for (i = 0; i < 8; ++i) {
			fprintf(fp, "%c", digits[(key[i]>>4)&0xf]);
			fprintf(fp, "%c", digits[(key[i]>>0)&0xf]);
		}
		fputc('\n', fp);
		fclose(fp);
		exit(0);
	}

	DES_fixup_key_parity(&key);
	DES_key_sched(&key, &ks);

	buf[0] = '\0';
	readpassphrase("Enter challenge: ", buf, sizeof(buf), RPP_ECHO_ON);
	if (buf[0] == '\0')
		exit(0);

	for (i = 0; i < 8; ++i)
		if (buf[i] == '\n')
			buf[i] = '\0';

	if (!hex)
		digits = DECDIGITS;

	predict(ks, buf, cnt);

	memset(&ks, 0, sizeof(ks));
	memset(buf, 0, sizeof(buf));

	exit(0);
}

void
predict(DES_key_schedule ks, const char *chal, int cnt)
{
	int i;
	DES_cblock cb;

	memcpy(&cb, chal, sizeof(cb));
	while (cnt-- > 0) {
		printf("%.8s: ", (char *)cb);
		DES_ecb_encrypt(&cb, &cb, &ks, DES_ENCRYPT);
		for (i = 0; i < 4; ++i) {
			printf("%c", digits[(cb[i]>>4) & 0xf]);
			printf("%c", digits[(cb[i]>>0) & 0xf]);
		}
		putchar('\n');
		for (i = 0; i < 8; ++i) {
			if ((cb[i] &= 0xf) > 9)
				cb[i] -= 10;
			cb[i] |= 0x30;
		}
	}
	memset(&cb, 0, sizeof(cb));
}