122347Spst/* opiekey.c: Stand-alone program for computing responses to OTP challenges. 222347Spst 322347Spst Takes a sequence number and seed (presumably from an OPIE challenge) 422347Spst as command line arguments, prompts for the user's secret pass phrase, 522347Spst and outputs a response. 622347Spst 729964Sache%%% portions-copyright-cmetz-96 892914SmarkmPortions of this software are Copyright 1996-1999 by Craig Metz, All Rights 922347SpstReserved. The Inner Net License Version 2 applies to these portions of 1022347Spstthe software. 1122347SpstYou should have received a copy of the license with this software. If 1222347Spstyou didn't get a copy, you may request one from <license@inner.net>. 1322347Spst 1422347SpstPortions of this software are Copyright 1995 by Randall Atkinson and Dan 1522347SpstMcDonald, All Rights Reserved. All Rights under this copyright are assigned 1622347Spstto the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 1722347SpstLicense Agreement applies to this software. 1822347Spst 1922347Spst History: 2022347Spst 2192914Smarkm Modified by cmetz for OPIE 2.4. Use struct opie_key for key blocks. 2229964Sache Modified by cmetz for OPIE 2.31. Renamed "init" and RESPONSE_INIT 2329964Sache to "init-hex" and RESPONSE_INIT_HEX. Removed active attack 2429964Sache protection support. 2522347Spst Modified by cmetz for OPIE 2.3. OPIE_PASS_MAX changed to 2622347Spst OPIE_SECRET_MAX. Added extended responses, which created 2722347Spst lots of changes. Eliminated extra variable. Added -x and 2822347Spst -t to help. Added -f flag. Added SHA support. 2922347Spst Modified by cmetz for OPIE 2.22. Print newline after seed too long 3022347Spst message. Check for minimum seed length. Correct a grammar 3122347Spst error. 3222347Spst Modified at NRL for OPIE 2.2. Check opiereadpass() return. 3322347Spst Change opiereadpass() calls to add echo arg. Use FUNCTION 3422347Spst definition et al. Check seed length here, too. Added back 3522347Spst hex output. Reworked final output function. 3622347Spst Modified at NRL for OPIE 2.0. 3722347Spst Written at Bellcore for the S/Key Version 1 software distribution 3822347Spst (skey.c). 3981596Sache 4081596Sache$FreeBSD$ 4181596Sache 4222347Spst*/ 4322347Spst#include "opie_cfg.h" 4422347Spst 4522347Spst#include <stdio.h> 4622347Spst#include <string.h> 4722347Spst#include <stdlib.h> 4822347Spst 4922347Spst#include "opie.h" 5022347Spst 5122347Spst#ifdef __MSDOS__ 5222347Spst#include <dos.h> 5322347Spst#endif 5422347Spst 5522347Spst#if HAVE_FCNTL_H 5622347Spst#include <fcntl.h> 5722347Spst#endif /* HAVE_FCNTL_H */ 5822347Spst 5922347Spstextern char *optarg; 6022347Spstextern int optind, opterr; 6122347Spst 6222347Spstint aflag = 0; 6322347Spst 6422347Spstchar *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" }; 6522347Spstchar *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" }; 6622347Spst 6722347Spst/******** Begin real source code ***************/ 6822347Spst 6922347Spststatic VOIDRET usage FUNCTION((s), char *s) 7022347Spst{ 7122347Spst fprintf(stderr, "usage: %s [-v] [-h] [-f] [-x] [-t type] [-4 | -5 | -s] [-a] [-n count] sequence_number seed\n", s); 7222347Spst exit(1); 7322347Spst} 7422347Spst 7522347Spst#define RESPONSE_STANDARD 0 7622347Spst#define RESPONSE_WORD 1 7722347Spst#define RESPONSE_HEX 2 7829964Sache#define RESPONSE_INIT_HEX 3 7922347Spst#define RESPONSE_INIT_WORD 4 8022347Spst#define RESPONSE_UNKNOWN 5 8122347Spst 8222347Spststruct _rtrans { 8322347Spst int type; 8422347Spst char *name; 8522347Spst}; 8622347Spst 8722347Spststatic struct _rtrans rtrans[] = { 8822347Spst { RESPONSE_WORD, "word" }, 8922347Spst { RESPONSE_HEX, "hex" }, 9029964Sache { RESPONSE_INIT_HEX, "init-hex" }, 9122347Spst { RESPONSE_INIT_WORD, "init-word" }, 9222347Spst { RESPONSE_STANDARD, "" }, 9322347Spst { RESPONSE_STANDARD, "standard" }, 9422347Spst { RESPONSE_STANDARD, "otp" }, 9522347Spst { RESPONSE_UNKNOWN, NULL } 9622347Spst}; 9722347Spst 9822347Spststatic void getsecret FUNCTION((secret, promptextra, retype), char *secret AND char *promptextra AND int flags) 9922347Spst{ 10022347Spst fprintf(stderr, "Enter %ssecret pass phrase: ", promptextra); 10122347Spst if (!opiereadpass(secret, OPIE_SECRET_MAX, 0)) { 10222347Spst fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra); 10322347Spst exit(1); 10422347Spst } 10522347Spst if (secret[0] && (flags & 1)) { 10622347Spst char verify[OPIE_SECRET_MAX + 1]; 10722347Spst 10822347Spst fprintf(stderr, "Again %ssecret pass phrase: ", promptextra); 10922347Spst if (!opiereadpass(verify, OPIE_SECRET_MAX, 0)) { 11022347Spst fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra); 11122347Spst memset(verify, 0, sizeof(verify)); 112246873Sdim memset(secret, 0, OPIE_SECRET_MAX + 1); 11322347Spst exit(1); 11422347Spst } 11522347Spst if (verify[0] && strcmp(verify, secret)) { 11622347Spst fprintf(stderr, "They don't match. Try again.\n"); 11722347Spst memset(verify, 0, sizeof(verify)); 118246873Sdim memset(secret, 0, OPIE_SECRET_MAX + 1); 11922347Spst exit(1); 12022347Spst } 12122347Spst memset(verify, 0, sizeof(verify)); 12222347Spst } 12389135Sjoerg if (!(flags & 2) && !aflag && opiepasscheck(secret)) { 124246873Sdim memset(secret, 0, OPIE_SECRET_MAX + 1); 12522347Spst fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX); 12622347Spst exit(1); 12722347Spst }; 12822347Spst} 12922347Spst 13022347Spstint main FUNCTION((argc, argv), int argc AND char *argv[]) 13122347Spst{ 13222347Spst /* variable declarations */ 13322347Spst unsigned algorithm = MDX; /* default algorithm per Makefile's MDX 13422347Spst symbol */ 13522347Spst int keynum = 0; 13622347Spst int i; 13722347Spst int count = 1; 13822347Spst char secret[OPIE_SECRET_MAX + 1], newsecret[OPIE_SECRET_MAX + 1]; 13992914Smarkm struct opie_otpkey key, newkey; 14022347Spst char *seed, newseed[OPIE_SEED_MAX + 1]; 14122347Spst char response[OPIE_RESPONSE_MAX + 1]; 14222347Spst char *slash; 14322347Spst int hex = 0; 14422347Spst int type = RESPONSE_STANDARD; 14581596Sache int force = 0; 14622347Spst 147270120Sache if (slash = strrchr(argv[0], '/')) 14822347Spst slash++; 14922347Spst else 15022347Spst slash = argv[0]; 15122347Spst 15222347Spst if (!strcmp(slash, "key") || strstr(slash, "md4")) 15322347Spst algorithm = 4; 15422347Spst 15522347Spst if (strstr(slash, "md5")) 15622347Spst algorithm = 5; 15722347Spst 15822347Spst if (strstr(slash, "sha")) 15922347Spst algorithm = 3; 16022347Spst 16122347Spst while ((i = getopt(argc, argv, "fhvn:x45at:s")) != EOF) { 16222347Spst switch (i) { 16322347Spst case 'v': 16422347Spst opieversion(); 16522347Spst 16622347Spst case 'n': 16722347Spst count = atoi(optarg); 16822347Spst break; 16922347Spst 17022347Spst case 'x': 17122347Spst hex = 1; 17222347Spst break; 17322347Spst 17422347Spst case 'f': 17522347Spst#if INSECURE_OVERRIDE 17622347Spst force = 1; 17722347Spst#else /* INSECURE_OVERRIDE */ 17822347Spst fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n"); 17922347Spst#endif /* INSECURE_OVERRIDE */ 18022347Spst break; 18122347Spst 18222347Spst case '4': 18322347Spst /* use MD4 algorithm */ 18422347Spst algorithm = 4; 18522347Spst break; 18622347Spst 18722347Spst case '5': 18822347Spst /* use MD5 algorithm */ 18922347Spst algorithm = 5; 19022347Spst break; 19122347Spst 19222347Spst case 'a': 19322347Spst aflag = 1; 19422347Spst break; 19522347Spst 19622347Spst case 't': 19722347Spst { 19822347Spst struct _rtrans *r; 19922347Spst for (r = rtrans; r->name && strcmp(r->name, optarg); r++); 20022347Spst if (!r->name) { 20122347Spst fprintf(stderr, "%s: %s: unknown response type.\n", argv[0], optarg); 20222347Spst exit(1); 20322347Spst } 20422347Spst type = r->type; 20522347Spst } 20622347Spst break; 20722347Spst 20822347Spst case 's': 20922347Spst algorithm = 3; 21022347Spst break; 21122347Spst 21222347Spst default: 21322347Spst usage(argv[0]); 21422347Spst } 21522347Spst } 21622347Spst 21722347Spst if ((argc - optind) < 2) 21822347Spst usage(argv[0]); 21922347Spst 22022347Spst fprintf(stderr, "Using the %s algorithm to compute response.\n", algnames[algorithm]); 22122347Spst 22222347Spst /* get sequence number, which is next-to-last parameter */ 22322347Spst keynum = atoi(argv[optind]); 22422347Spst if (keynum < 1) { 22522347Spst fprintf(stderr, "Sequence number %s is not positive.\n", argv[optind]); 22622347Spst exit(1); 22722347Spst } 22822347Spst /* get seed string, which is last parameter */ 22922347Spst seed = argv[optind + 1]; 23022347Spst { 23122347Spst i = strlen(seed); 23222347Spst 23322347Spst if (i > OPIE_SEED_MAX) { 23422347Spst fprintf(stderr, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX); 23522347Spst exit(1); 23622347Spst } 23722347Spst if (i < OPIE_SEED_MIN) { 23822347Spst fprintf(stderr, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN); 23922347Spst exit(1); 24022347Spst } 24122347Spst } 24222347Spst 24322347Spst fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n"); 24422347Spst 24522347Spst if (opieinsecure()) { 24622347Spst fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n"); 24722347Spst#if INSECURE_OVERRIDE 24822347Spst if (force) 24922347Spst fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n"); 25022347Spst else 25122347Spst#endif /* INSECURE_OVERRIDE */ 25222347Spst exit(1); 25322347Spst } 25422347Spst 25529964Sache if ((type == RESPONSE_INIT_HEX) || (type == RESPONSE_INIT_WORD)) { 25622347Spst#if RETYPE 25722347Spst getsecret(secret, "old ", 1); 25822347Spst#else /* RETYPE */ 25922347Spst getsecret(secret, "old ", 0); 26022347Spst#endif /* RETYPE */ 26122347Spst getsecret(newsecret, "new ", 1); 26222347Spst if (!newsecret[0]) 26322347Spst strcpy(newsecret, secret); 26422347Spst 26522347Spst if (opienewseed(strcpy(newseed, seed)) < 0) { 26622347Spst fprintf(stderr, "Error updating seed.\n"); 26722347Spst goto error; 26822347Spst } 26922347Spst 27092914Smarkm if (opiekeycrunch(algorithm, &newkey, newseed, newsecret)) { 27122347Spst fprintf(stderr, "%s: key crunch failed (1)\n", argv[0]); 27222347Spst goto error; 27322347Spst } 27422347Spst 27522347Spst for (i = 0; i < 499; i++) 27692914Smarkm opiehash(&newkey, algorithm); 27722347Spst } else 27822347Spst#if RETYPE 27922347Spst getsecret(secret, "", 1); 28022347Spst#else /* RETYPE */ 28122347Spst getsecret(secret, "", 0); 28222347Spst#endif /* RETYPE */ 28322347Spst 28422347Spst /* Crunch seed and secret password into starting key normally */ 28592914Smarkm if (opiekeycrunch(algorithm, &key, seed, secret)) { 28622347Spst fprintf(stderr, "%s: key crunch failed\n", argv[0]); 28722347Spst goto error; 28822347Spst } 28922347Spst 29022347Spst for (i = 0; i <= (keynum - count); i++) 29192914Smarkm opiehash(&key, algorithm); 29222347Spst 29322347Spst { 29422347Spst char buf[OPIE_SEED_MAX + 48 + 1]; 29522347Spst char *c; 29622347Spst 29722347Spst for (; i <= keynum; i++) { 29822347Spst if (count > 1) 29922347Spst printf("%d: %s", i, (type == RESPONSE_STANDARD) ? "" : "\n"); 30022347Spst 30122347Spst switch(type) { 30222347Spst case RESPONSE_STANDARD: 30322347Spst if (hex) 30492914Smarkm opiebtoh(response, &key); 30522347Spst else 30692914Smarkm opiebtoe(response, &key); 30722347Spst break; 30822347Spst case RESPONSE_WORD: 30922347Spst strcpy(response, "word:"); 31092914Smarkm strcat(response, opiebtoe(buf, &key)); 31122347Spst break; 31222347Spst case RESPONSE_HEX: 31322347Spst strcpy(response, "hex:"); 31492914Smarkm strcat(response, opiebtoh(buf, &key)); 31522347Spst break; 31629964Sache case RESPONSE_INIT_HEX: 31722347Spst case RESPONSE_INIT_WORD: 31829964Sache if (type == RESPONSE_INIT_HEX) { 31959118Skris strcpy(response, "init-hex:"); 32092914Smarkm strcat(response, opiebtoh(buf, &key)); 32122347Spst sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed); 32222347Spst strcat(response, buf); 32392914Smarkm strcat(response, opiebtoh(buf, &newkey)); 32422347Spst } else { 32522347Spst strcpy(response, "init-word:"); 32692914Smarkm strcat(response, opiebtoe(buf, &key)); 32722347Spst sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed); 32822347Spst strcat(response, buf); 32992914Smarkm strcat(response, opiebtoe(buf, &newkey)); 33022347Spst } 33122347Spst break; 33222347Spst } 33322347Spst puts(response); 33492914Smarkm opiehash(&key, algorithm); 33522347Spst } 33622347Spst } 33722347Spst 33822347Spst memset(secret, 0, sizeof(secret)); 33922347Spst memset(newsecret, 0, sizeof(newsecret)); 34022347Spst return 0; 34122347Spst 34222347Spsterror: 34322347Spst memset(secret, 0, sizeof(secret)); 34422347Spst memset(newsecret, 0, sizeof(newsecret)); 34522347Spst return 1; 34622347Spst} 347