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