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