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