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> 48257264Ssbruno#include <unistd.h> 4922347Spst 5022347Spst#include "opie.h" 5122347Spst 5222347Spst#ifdef __MSDOS__ 5322347Spst#include <dos.h> 5422347Spst#endif 5522347Spst 5622347Spst#if HAVE_FCNTL_H 5722347Spst#include <fcntl.h> 5822347Spst#endif /* HAVE_FCNTL_H */ 5922347Spst 6022347Spstextern char *optarg; 6122347Spstextern int optind, opterr; 6222347Spst 6322347Spstint aflag = 0; 6422347Spst 6522347Spstchar *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" }; 6622347Spstchar *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" }; 6722347Spst 6822347Spst/******** Begin real source code ***************/ 6922347Spst 7022347Spststatic VOIDRET usage FUNCTION((s), char *s) 7122347Spst{ 7222347Spst fprintf(stderr, "usage: %s [-v] [-h] [-f] [-x] [-t type] [-4 | -5 | -s] [-a] [-n count] sequence_number seed\n", s); 7322347Spst exit(1); 7422347Spst} 7522347Spst 7622347Spst#define RESPONSE_STANDARD 0 7722347Spst#define RESPONSE_WORD 1 7822347Spst#define RESPONSE_HEX 2 7929964Sache#define RESPONSE_INIT_HEX 3 8022347Spst#define RESPONSE_INIT_WORD 4 8122347Spst#define RESPONSE_UNKNOWN 5 8222347Spst 8322347Spststruct _rtrans { 8422347Spst int type; 8522347Spst char *name; 8622347Spst}; 8722347Spst 8822347Spststatic struct _rtrans rtrans[] = { 8922347Spst { RESPONSE_WORD, "word" }, 9022347Spst { RESPONSE_HEX, "hex" }, 9129964Sache { RESPONSE_INIT_HEX, "init-hex" }, 9222347Spst { RESPONSE_INIT_WORD, "init-word" }, 9322347Spst { RESPONSE_STANDARD, "" }, 9422347Spst { RESPONSE_STANDARD, "standard" }, 9522347Spst { RESPONSE_STANDARD, "otp" }, 9622347Spst { RESPONSE_UNKNOWN, NULL } 9722347Spst}; 9822347Spst 9922347Spststatic void getsecret FUNCTION((secret, promptextra, retype), char *secret AND char *promptextra AND int flags) 10022347Spst{ 10122347Spst fprintf(stderr, "Enter %ssecret pass phrase: ", promptextra); 10222347Spst if (!opiereadpass(secret, OPIE_SECRET_MAX, 0)) { 10322347Spst fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra); 10422347Spst exit(1); 10522347Spst } 10622347Spst if (secret[0] && (flags & 1)) { 10722347Spst char verify[OPIE_SECRET_MAX + 1]; 10822347Spst 10922347Spst fprintf(stderr, "Again %ssecret pass phrase: ", promptextra); 11022347Spst if (!opiereadpass(verify, OPIE_SECRET_MAX, 0)) { 11122347Spst fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra); 11222347Spst memset(verify, 0, sizeof(verify)); 113246873Sdim memset(secret, 0, OPIE_SECRET_MAX + 1); 11422347Spst exit(1); 11522347Spst } 11622347Spst if (verify[0] && strcmp(verify, secret)) { 11722347Spst fprintf(stderr, "They don't match. Try again.\n"); 11822347Spst memset(verify, 0, sizeof(verify)); 119246873Sdim memset(secret, 0, OPIE_SECRET_MAX + 1); 12022347Spst exit(1); 12122347Spst } 12222347Spst memset(verify, 0, sizeof(verify)); 12322347Spst } 12489135Sjoerg if (!(flags & 2) && !aflag && opiepasscheck(secret)) { 125246873Sdim memset(secret, 0, OPIE_SECRET_MAX + 1); 12622347Spst fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX); 12722347Spst exit(1); 12822347Spst }; 12922347Spst} 13022347Spst 13122347Spstint main FUNCTION((argc, argv), int argc AND char *argv[]) 13222347Spst{ 13322347Spst /* variable declarations */ 13422347Spst unsigned algorithm = MDX; /* default algorithm per Makefile's MDX 13522347Spst symbol */ 13622347Spst int keynum = 0; 13722347Spst int i; 13822347Spst int count = 1; 13922347Spst char secret[OPIE_SECRET_MAX + 1], newsecret[OPIE_SECRET_MAX + 1]; 14092914Smarkm struct opie_otpkey key, newkey; 14122347Spst char *seed, newseed[OPIE_SEED_MAX + 1]; 14222347Spst char response[OPIE_RESPONSE_MAX + 1]; 14322347Spst char *slash; 14422347Spst int hex = 0; 14522347Spst int type = RESPONSE_STANDARD; 14681596Sache int force = 0; 14722347Spst 148269811Sache if (slash = strrchr(argv[0], '/')) 14922347Spst slash++; 15022347Spst else 15122347Spst slash = argv[0]; 15222347Spst 15322347Spst if (!strcmp(slash, "key") || strstr(slash, "md4")) 15422347Spst algorithm = 4; 15522347Spst 15622347Spst if (strstr(slash, "md5")) 15722347Spst algorithm = 5; 15822347Spst 15922347Spst if (strstr(slash, "sha")) 16022347Spst algorithm = 3; 16122347Spst 16222347Spst while ((i = getopt(argc, argv, "fhvn:x45at:s")) != EOF) { 16322347Spst switch (i) { 16422347Spst case 'v': 16522347Spst opieversion(); 16622347Spst 16722347Spst case 'n': 16822347Spst count = atoi(optarg); 16922347Spst break; 17022347Spst 17122347Spst case 'x': 17222347Spst hex = 1; 17322347Spst break; 17422347Spst 17522347Spst case 'f': 17622347Spst#if INSECURE_OVERRIDE 17722347Spst force = 1; 17822347Spst#else /* INSECURE_OVERRIDE */ 17922347Spst fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n"); 18022347Spst#endif /* INSECURE_OVERRIDE */ 18122347Spst break; 18222347Spst 18322347Spst case '4': 18422347Spst /* use MD4 algorithm */ 18522347Spst algorithm = 4; 18622347Spst break; 18722347Spst 18822347Spst case '5': 18922347Spst /* use MD5 algorithm */ 19022347Spst algorithm = 5; 19122347Spst break; 19222347Spst 19322347Spst case 'a': 19422347Spst aflag = 1; 19522347Spst break; 19622347Spst 19722347Spst case 't': 19822347Spst { 19922347Spst struct _rtrans *r; 20022347Spst for (r = rtrans; r->name && strcmp(r->name, optarg); r++); 20122347Spst if (!r->name) { 20222347Spst fprintf(stderr, "%s: %s: unknown response type.\n", argv[0], optarg); 20322347Spst exit(1); 20422347Spst } 20522347Spst type = r->type; 20622347Spst } 20722347Spst break; 20822347Spst 20922347Spst case 's': 21022347Spst algorithm = 3; 21122347Spst break; 21222347Spst 21322347Spst default: 21422347Spst usage(argv[0]); 21522347Spst } 21622347Spst } 21722347Spst 21822347Spst if ((argc - optind) < 2) 21922347Spst usage(argv[0]); 22022347Spst 22122347Spst fprintf(stderr, "Using the %s algorithm to compute response.\n", algnames[algorithm]); 22222347Spst 22322347Spst /* get sequence number, which is next-to-last parameter */ 22422347Spst keynum = atoi(argv[optind]); 22522347Spst if (keynum < 1) { 22622347Spst fprintf(stderr, "Sequence number %s is not positive.\n", argv[optind]); 22722347Spst exit(1); 22822347Spst } 22922347Spst /* get seed string, which is last parameter */ 23022347Spst seed = argv[optind + 1]; 23122347Spst { 23222347Spst i = strlen(seed); 23322347Spst 23422347Spst if (i > OPIE_SEED_MAX) { 23522347Spst fprintf(stderr, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX); 23622347Spst exit(1); 23722347Spst } 23822347Spst if (i < OPIE_SEED_MIN) { 23922347Spst fprintf(stderr, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN); 24022347Spst exit(1); 24122347Spst } 24222347Spst } 24322347Spst 24422347Spst fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n"); 24522347Spst 24622347Spst if (opieinsecure()) { 24722347Spst fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n"); 24822347Spst#if INSECURE_OVERRIDE 24922347Spst if (force) 25022347Spst fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n"); 25122347Spst else 25222347Spst#endif /* INSECURE_OVERRIDE */ 25322347Spst exit(1); 25422347Spst } 25522347Spst 25629964Sache if ((type == RESPONSE_INIT_HEX) || (type == RESPONSE_INIT_WORD)) { 25722347Spst#if RETYPE 25822347Spst getsecret(secret, "old ", 1); 25922347Spst#else /* RETYPE */ 26022347Spst getsecret(secret, "old ", 0); 26122347Spst#endif /* RETYPE */ 26222347Spst getsecret(newsecret, "new ", 1); 26322347Spst if (!newsecret[0]) 26422347Spst strcpy(newsecret, secret); 26522347Spst 26622347Spst if (opienewseed(strcpy(newseed, seed)) < 0) { 26722347Spst fprintf(stderr, "Error updating seed.\n"); 26822347Spst goto error; 26922347Spst } 27022347Spst 27192914Smarkm if (opiekeycrunch(algorithm, &newkey, newseed, newsecret)) { 27222347Spst fprintf(stderr, "%s: key crunch failed (1)\n", argv[0]); 27322347Spst goto error; 27422347Spst } 27522347Spst 27622347Spst for (i = 0; i < 499; i++) 27792914Smarkm opiehash(&newkey, algorithm); 27822347Spst } else 27922347Spst#if RETYPE 28022347Spst getsecret(secret, "", 1); 28122347Spst#else /* RETYPE */ 28222347Spst getsecret(secret, "", 0); 28322347Spst#endif /* RETYPE */ 28422347Spst 28522347Spst /* Crunch seed and secret password into starting key normally */ 28692914Smarkm if (opiekeycrunch(algorithm, &key, seed, secret)) { 28722347Spst fprintf(stderr, "%s: key crunch failed\n", argv[0]); 28822347Spst goto error; 28922347Spst } 29022347Spst 29122347Spst for (i = 0; i <= (keynum - count); i++) 29292914Smarkm opiehash(&key, algorithm); 29322347Spst 29422347Spst { 29522347Spst char buf[OPIE_SEED_MAX + 48 + 1]; 29622347Spst char *c; 29722347Spst 29822347Spst for (; i <= keynum; i++) { 29922347Spst if (count > 1) 30022347Spst printf("%d: %s", i, (type == RESPONSE_STANDARD) ? "" : "\n"); 30122347Spst 30222347Spst switch(type) { 30322347Spst case RESPONSE_STANDARD: 30422347Spst if (hex) 30592914Smarkm opiebtoh(response, &key); 30622347Spst else 30792914Smarkm opiebtoe(response, &key); 30822347Spst break; 30922347Spst case RESPONSE_WORD: 31022347Spst strcpy(response, "word:"); 31192914Smarkm strcat(response, opiebtoe(buf, &key)); 31222347Spst break; 31322347Spst case RESPONSE_HEX: 31422347Spst strcpy(response, "hex:"); 31592914Smarkm strcat(response, opiebtoh(buf, &key)); 31622347Spst break; 31729964Sache case RESPONSE_INIT_HEX: 31822347Spst case RESPONSE_INIT_WORD: 31929964Sache if (type == RESPONSE_INIT_HEX) { 32059118Skris strcpy(response, "init-hex:"); 32192914Smarkm strcat(response, opiebtoh(buf, &key)); 32222347Spst sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed); 32322347Spst strcat(response, buf); 32492914Smarkm strcat(response, opiebtoh(buf, &newkey)); 32522347Spst } else { 32622347Spst strcpy(response, "init-word:"); 32792914Smarkm strcat(response, opiebtoe(buf, &key)); 32822347Spst sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed); 32922347Spst strcat(response, buf); 33092914Smarkm strcat(response, opiebtoe(buf, &newkey)); 33122347Spst } 33222347Spst break; 33322347Spst } 33422347Spst puts(response); 33592914Smarkm opiehash(&key, algorithm); 33622347Spst } 33722347Spst } 33822347Spst 33922347Spst memset(secret, 0, sizeof(secret)); 34022347Spst memset(newsecret, 0, sizeof(newsecret)); 34122347Spst return 0; 34222347Spst 34322347Spsterror: 34422347Spst memset(secret, 0, sizeof(secret)); 34522347Spst memset(newsecret, 0, sizeof(newsecret)); 34622347Spst return 1; 34722347Spst} 348