1 /* $OpenBSD: x99token.c,v 1.13 2017/05/03 09:51:39 mestre 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 if (pledge("stdio rpath wpath cpath getpw tty", NULL) == -1) 50 err(1, "pledge"); 51 52 while ((i = getopt(argc, argv, "dk:in:")) != -1) { 53 switch (i) { 54 case 'k': 55 keyfile = optarg; 56 break; 57 case 'i': 58 init = 1; 59 break; 60 case 'd': 61 hex = 0; 62 break; 63 case 'n': 64 cnt = atoi(optarg); 65 if (cnt <= 0) 66 err(1, "invalid count: %s", optarg); 67 break; 68 default: 69 fprintf(stderr, 70 "usage: %s [-d] [-k keyfile] [-n count]\n" 71 " %s -i [-k keyfile]\n", 72 __progname, __progname); 73 exit(1); 74 } 75 } 76 77 if (!keyfile) { 78 if ((pwd = getpwuid(getuid())) == NULL) { 79 fprintf(stderr, "Say, just who are you, anyhow?\n"); 80 exit(1); 81 } 82 snprintf(_keyfile, sizeof(_keyfile), "%s/%s", pwd->pw_dir, 83 KEYFILE); 84 keyfile = _keyfile; 85 } 86 87 if (init) 88 readpassphrase("Enter Key: ", buf, sizeof(buf), 0); 89 else if ((fp = fopen(keyfile, "r")) == NULL) 90 err(1, "unable to open %s", keyfile); 91 else { 92 if (fgets(buf, sizeof(buf), fp) == NULL) { 93 fprintf(stderr, "No key in %s\n", keyfile); 94 exit(1); 95 } 96 fclose(fp); 97 } 98 99 memset(key, 0, sizeof(key)); 100 if (init && buf[3] == ' ') { 101 char *b = buf; 102 /* Assume octal input */ 103 for (i = 0; i < 8; ++i) { 104 if (!*b) 105 fprintf(stderr, "%s: invalid key\n", buf); 106 while (isdigit((unsigned char)*b)) 107 key[i] = key[i] << 3 | (*b++ - '0'); 108 while (*b && !isdigit((unsigned char)*b)) 109 ++b; 110 } 111 } else { 112 for (i = 0; i < 16; ++i) { 113 int d; 114 115 if (islower((unsigned char)buf[i])) 116 buf[i] = toupper((unsigned char)buf[i]); 117 if (buf[i] >= '0' && buf[i] <= '9') 118 d = buf[i] - '0'; 119 else if (buf[i] >= 'A' && buf[i] <= 'F') 120 d = buf[i] - 'A' + 10; 121 else { 122 fprintf(stderr, "invalid key: %s\n", buf); 123 exit(1); 124 } 125 key[i>>1] |= d << ((i & 1) ? 0 : 4); 126 } 127 } 128 129 /* XXX - should warn on non-space or non-digit */ 130 readpassphrase("Enter Pin: ", buf, sizeof(buf), 0); 131 for (i = 0, pin = 0; buf[i] && buf[i] != '\n'; ++i) 132 if (isdigit((unsigned char)buf[i])) 133 pin = pin * 16 + buf[i] - '0' + 1; 134 135 if ((pin & 0xffff0000) == 0) 136 pin |= pin << 16; 137 138 for (i = 0; i < 8; ++i) 139 key[0] ^= (pin >> ((i * 7) % 26)) & 0x7f; 140 141 if (init) { 142 umask(S_IRWXG | S_IRWXO); 143 unlink(keyfile); 144 if ((fp = fopen(keyfile, "w")) == NULL) 145 err(1, "could not open %s for writing", keyfile); 146 for (i = 0; i < 8; ++i) { 147 fprintf(fp, "%c", digits[(key[i]>>4)&0xf]); 148 fprintf(fp, "%c", digits[(key[i]>>0)&0xf]); 149 } 150 fputc('\n', fp); 151 fclose(fp); 152 exit(0); 153 } 154 155 DES_fixup_key_parity(&key); 156 DES_key_sched(&key, &ks); 157 158 buf[0] = '\0'; 159 readpassphrase("Enter challenge: ", buf, sizeof(buf), RPP_ECHO_ON); 160 if (buf[0] == '\0') 161 exit(0); 162 163 for (i = 0; i < 8; ++i) 164 if (buf[i] == '\n') 165 buf[i] = '\0'; 166 167 if (!hex) 168 digits = DECDIGITS; 169 170 predict(ks, buf, cnt); 171 172 explicit_bzero(&ks, sizeof(ks)); 173 explicit_bzero(buf, sizeof(buf)); 174 175 exit(0); 176 } 177 178 void 179 predict(DES_key_schedule ks, const char *chal, int cnt) 180 { 181 int i; 182 DES_cblock cb; 183 184 memcpy(&cb, chal, sizeof(cb)); 185 while (cnt-- > 0) { 186 printf("%.8s: ", (char *)cb); 187 DES_ecb_encrypt(&cb, &cb, &ks, DES_ENCRYPT); 188 for (i = 0; i < 4; ++i) { 189 printf("%c", digits[(cb[i]>>4) & 0xf]); 190 printf("%c", digits[(cb[i]>>0) & 0xf]); 191 } 192 putchar('\n'); 193 for (i = 0; i < 8; ++i) { 194 if ((cb[i] &= 0xf) > 9) 195 cb[i] -= 10; 196 cb[i] |= 0x30; 197 } 198 } 199 memset(&cb, 0, sizeof(cb)); 200 } 201