opiekey.c revision 22347
1/* opiekey.c: Stand-alone program for computing responses to OTP challenges. 2 3 Takes a sequence number and seed (presumably from an OPIE challenge) 4 as command line arguments, prompts for the user's secret pass phrase, 5 and outputs a response. 6 7%%% portions-copyright-cmetz 8Portions of this software are Copyright 1996 by Craig Metz, All Rights 9Reserved. The Inner Net License Version 2 applies to these portions of 10the software. 11You should have received a copy of the license with this software. If 12you didn't get a copy, you may request one from <license@inner.net>. 13 14Portions of this software are Copyright 1995 by Randall Atkinson and Dan 15McDonald, All Rights Reserved. All Rights under this copyright are assigned 16to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 17License Agreement applies to this software. 18 19 History: 20 21 Modified by cmetz for OPIE 2.3. OPIE_PASS_MAX changed to 22 OPIE_SECRET_MAX. Added extended responses, which created 23 lots of changes. Eliminated extra variable. Added -x and 24 -t to help. Added -f flag. Added SHA support. 25 Modified by cmetz for OPIE 2.22. Print newline after seed too long 26 message. Check for minimum seed length. Correct a grammar 27 error. 28 Modified at NRL for OPIE 2.2. Check opiereadpass() return. 29 Change opiereadpass() calls to add echo arg. Use FUNCTION 30 definition et al. Check seed length here, too. Added back 31 hex output. Reworked final output function. 32 Modified at NRL for OPIE 2.0. 33 Written at Bellcore for the S/Key Version 1 software distribution 34 (skey.c). 35*/ 36#include "opie_cfg.h" 37 38#include <stdio.h> 39#include <string.h> 40#include <stdlib.h> 41 42#include "opie.h" 43 44#ifdef __MSDOS__ 45#include <dos.h> 46#endif 47 48#if HAVE_FCNTL_H 49#include <fcntl.h> 50#endif /* HAVE_FCNTL_H */ 51 52extern char *optarg; 53extern int optind, opterr; 54 55int aflag = 0; 56 57char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" }; 58char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" }; 59 60/******** Begin real source code ***************/ 61 62static VOIDRET usage FUNCTION((s), char *s) 63{ 64 fprintf(stderr, "usage: %s [-v] [-h] [-f] [-x] [-t type] [-4 | -5 | -s] [-a] [-n count] sequence_number seed\n", s); 65 exit(1); 66} 67 68#define RESPONSE_STANDARD 0 69#define RESPONSE_WORD 1 70#define RESPONSE_HEX 2 71#define RESPONSE_INIT 3 72#define RESPONSE_INIT_WORD 4 73#define RESPONSE_UNKNOWN 5 74 75struct _rtrans { 76 int type; 77 char *name; 78}; 79 80static struct _rtrans rtrans[] = { 81 { RESPONSE_WORD, "word" }, 82 { RESPONSE_HEX, "hex" }, 83 { RESPONSE_INIT, "init" }, 84 { RESPONSE_INIT_WORD, "init-word" }, 85 { RESPONSE_STANDARD, "" }, 86 { RESPONSE_STANDARD, "standard" }, 87 { RESPONSE_STANDARD, "otp" }, 88 { RESPONSE_UNKNOWN, NULL } 89}; 90 91static void getsecret FUNCTION((secret, promptextra, retype), char *secret AND char *promptextra AND int flags) 92{ 93 fprintf(stderr, "Enter %ssecret pass phrase: ", promptextra); 94 if (!opiereadpass(secret, OPIE_SECRET_MAX, 0)) { 95 fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra); 96 exit(1); 97 } 98 if (secret[0] && (flags & 1)) { 99 char verify[OPIE_SECRET_MAX + 1]; 100 101 fprintf(stderr, "Again %ssecret pass phrase: ", promptextra); 102 if (!opiereadpass(verify, OPIE_SECRET_MAX, 0)) { 103 fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra); 104 memset(verify, 0, sizeof(verify)); 105 memset(secret, 0, sizeof(secret)); 106 exit(1); 107 } 108 if (verify[0] && strcmp(verify, secret)) { 109 fprintf(stderr, "They don't match. Try again.\n"); 110 memset(verify, 0, sizeof(verify)); 111 memset(secret, 0, sizeof(secret)); 112 exit(1); 113 } 114 memset(verify, 0, sizeof(verify)); 115 } 116 if (!(flags & 2) && opiepasscheck(secret)) { 117 memset(secret, 0, sizeof(secret)); 118 fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX); 119 exit(1); 120 }; 121} 122 123int main FUNCTION((argc, argv), int argc AND char *argv[]) 124{ 125 /* variable declarations */ 126 unsigned algorithm = MDX; /* default algorithm per Makefile's MDX 127 symbol */ 128 int keynum = 0; 129 int i; 130 int count = 1; 131 char secret[OPIE_SECRET_MAX + 1], newsecret[OPIE_SECRET_MAX + 1]; 132 char key[8], newkey[8]; 133 char cko[8], ckn[8], ckxor[8], cv[8]; 134 char *seed, newseed[OPIE_SEED_MAX + 1]; 135 char response[OPIE_RESPONSE_MAX + 1]; 136 char *slash; 137 int hex = 0; 138 int type = RESPONSE_STANDARD; 139 int force; 140 141 if (slash = strchr(argv[0], '/')) 142 slash++; 143 else 144 slash = argv[0]; 145 146 if (!strcmp(slash, "key") || strstr(slash, "md4")) 147 algorithm = 4; 148 149 if (strstr(slash, "md5")) 150 algorithm = 5; 151 152 if (strstr(slash, "sha")) 153 algorithm = 3; 154 155 while ((i = getopt(argc, argv, "fhvn:x45at:s")) != EOF) { 156 switch (i) { 157 case 'v': 158 opieversion(); 159 160 case 'n': 161 count = atoi(optarg); 162 break; 163 164 case 'x': 165 hex = 1; 166 break; 167 168 case 'f': 169#if INSECURE_OVERRIDE 170 force = 1; 171#else /* INSECURE_OVERRIDE */ 172 fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n"); 173#endif /* INSECURE_OVERRIDE */ 174 break; 175 176 case '4': 177 /* use MD4 algorithm */ 178 algorithm = 4; 179 break; 180 181 case '5': 182 /* use MD5 algorithm */ 183 algorithm = 5; 184 break; 185 186 case 'a': 187 aflag = 1; 188 break; 189 190 case 't': 191 { 192 struct _rtrans *r; 193 for (r = rtrans; r->name && strcmp(r->name, optarg); r++); 194 if (!r->name) { 195 fprintf(stderr, "%s: %s: unknown response type.\n", argv[0], optarg); 196 exit(1); 197 } 198 type = r->type; 199 } 200 break; 201 202 case 's': 203 algorithm = 3; 204 break; 205 206 default: 207 usage(argv[0]); 208 } 209 } 210 211 if ((argc - optind) < 2) 212 usage(argv[0]); 213 214 fprintf(stderr, "Using the %s algorithm to compute response.\n", algnames[algorithm]); 215 216 /* get sequence number, which is next-to-last parameter */ 217 keynum = atoi(argv[optind]); 218 if (keynum < 1) { 219 fprintf(stderr, "Sequence number %s is not positive.\n", argv[optind]); 220 exit(1); 221 } 222 /* get seed string, which is last parameter */ 223 seed = argv[optind + 1]; 224 { 225 i = strlen(seed); 226 227 if (i > OPIE_SEED_MAX) { 228 fprintf(stderr, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX); 229 exit(1); 230 } 231 if (i < OPIE_SEED_MIN) { 232 fprintf(stderr, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN); 233 exit(1); 234 } 235 } 236 237 fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n"); 238 239 if (opieinsecure()) { 240 fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n"); 241#if INSECURE_OVERRIDE 242 if (force) 243 fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n"); 244 else 245#endif /* INSECURE_OVERRIDE */ 246 exit(1); 247 } 248 249 if ((type == RESPONSE_INIT) || (type == RESPONSE_INIT_WORD)) { 250#if RETYPE 251 getsecret(secret, "old ", 1); 252#else /* RETYPE */ 253 getsecret(secret, "old ", 0); 254#endif /* RETYPE */ 255 getsecret(newsecret, "new ", 1); 256 if (!newsecret[0]) 257 strcpy(newsecret, secret); 258 259 if (opienewseed(strcpy(newseed, seed)) < 0) { 260 fprintf(stderr, "Error updating seed.\n"); 261 goto error; 262 } 263 264 if (opiekeycrunch(algorithm, newkey, newseed, newsecret)) { 265 fprintf(stderr, "%s: key crunch failed (1)\n", argv[0]); 266 goto error; 267 } 268 269 for (i = 0; i < 499; i++) 270 opiehash(newkey, algorithm); 271 272 if (opiekeycrunch(algorithm | 0x10, cko, seed, secret)) { 273 fprintf(stderr, "%s: key crunch failed (2)\n", argv[0]); 274 goto error; 275 } 276 277 if (opiekeycrunch(algorithm | 0x10, ckn, newseed, newsecret)) { 278 fprintf(stderr, "%s: key crunch failed (3)\n", argv[0]); 279 goto error; 280 } 281 282 for (i = 0; i < 8; i++) 283 ckxor[i] = cko[i] ^ ckn[i]; 284 } else 285#if RETYPE 286 getsecret(secret, "", 1); 287#else /* RETYPE */ 288 getsecret(secret, "", 0); 289#endif /* RETYPE */ 290 291 /* Crunch seed and secret password into starting key normally */ 292 if (opiekeycrunch(algorithm, key, seed, secret)) { 293 fprintf(stderr, "%s: key crunch failed\n", argv[0]); 294 goto error; 295 } 296 297 for (i = 0; i <= (keynum - count); i++) 298 opiehash(key, algorithm); 299 300 { 301 char buf[OPIE_SEED_MAX + 48 + 1]; 302 char *c; 303 304 for (; i <= keynum; i++) { 305 if (count > 1) 306 printf("%d: %s", i, (type == RESPONSE_STANDARD) ? "" : "\n"); 307 308 switch(type) { 309 case RESPONSE_STANDARD: 310 if (hex) 311 opiebtoh(response, key); 312 else 313 opiebtoe(response, key); 314 break; 315 case RESPONSE_WORD: 316 strcpy(response, "word:"); 317 strcat(response, opiebtoe(buf, key)); 318 break; 319 case RESPONSE_HEX: 320 strcpy(response, "hex:"); 321 strcat(response, opiebtoh(buf, key)); 322 break; 323 case RESPONSE_INIT: 324 case RESPONSE_INIT_WORD: 325 if (type == RESPONSE_INIT) { 326 strcpy(response, "init:"); 327 strcat(response, opiebtoh(buf, key)); 328 sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed); 329 strcat(response, buf); 330 strcat(response, opiebtoh(buf, newkey)); 331 strcat(response, ":"); 332 strcat(response, opiebtoh(buf, ckxor)); 333 strcat(response, ":"); 334 } else { 335 strcpy(response, "init-word:"); 336 strcat(response, opiebtoe(buf, key)); 337 sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed); 338 strcat(response, buf); 339 strcat(response, opiebtoe(buf, newkey)); 340 strcat(response, ":"); 341 strcat(response, opiebtoe(buf, ckxor)); 342 strcat(response, ":"); 343 } 344 345 c = buf; 346 memcpy(c, cko, sizeof(cko)); c += sizeof(cko); 347 memcpy(c, key, sizeof(key)); c += sizeof(key); 348#ifdef HAVE_ANSISPRINTF 349 c += sprintf(c, "%s 499 %s", algids[algorithm], newseed); 350#else /* HAVE_ANSISPRINTF */ 351 sprintf(c, "%s 499 %s", algids[algorithm], newseed); 352 while(*c) c++; 353#endif /* HAVE_ANSISPRINTF */ 354 memcpy(c, newkey, sizeof(newkey)); c += sizeof(newkey); 355 memcpy(c, ckxor, sizeof(ckxor)); c += sizeof(ckxor); 356 memcpy(c, cko, sizeof(cko)); c += sizeof(cko); 357 opiehashlen(algorithm, buf, cv, (unsigned int)c - (unsigned int)buf); 358 359 strcat(response, (type == RESPONSE_INIT) ? opiebtoh(buf, cv) : opiebtoe(buf, cv)); 360 break; 361 } 362 puts(response); 363 opiehash(key, algorithm); 364 } 365 } 366 367 memset(secret, 0, sizeof(secret)); 368 memset(newsecret, 0, sizeof(newsecret)); 369 return 0; 370 371error: 372 memset(secret, 0, sizeof(secret)); 373 memset(newsecret, 0, sizeof(newsecret)); 374 return 1; 375} 376