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