OpenBSD-4.6/usr.bin/x99token/x99token.c

Compare this file to the similar file:
Show the results in this format:

/*	$OpenBSD: x99token.c,v 1.7 2007/03/29 10:59:13 jmc 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/param.h>
#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 <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[MAXPATHLEN];
	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(*b))
				key[i] = key[i] << 3 | (*b++ - '0');
			while (*b && !isdigit(*b))
				++b;
		}
	} else {
		for (i = 0; i < 16; ++i) {
			int d;

			if (islower(buf[i]))
				buf[i] = toupper(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(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));
}