1 /* opiekey.c: Stand-alone program for computing responses to OTP challenges.
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.
7 %%% portions-copyright-cmetz-96
8 Portions of this software are Copyright 1996-1997 by Craig Metz, All Rights
9 Reserved. The Inner Net License Version 2 applies to these portions of
11 You should have received a copy of the license with this software. If
12 you didn't get a copy, you may request one from <license@inner.net>.
14 Portions of this software are Copyright 1995 by Randall Atkinson and Dan
15 McDonald, All Rights Reserved. All Rights under this copyright are assigned
16 to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
17 License Agreement applies to this software.
21 Modified by cmetz for OPIE 2.31. Renamed "init" and RESPONSE_INIT
22 to "init-hex" and RESPONSE_INIT_HEX. Removed active attack
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
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
53 #endif /* HAVE_FCNTL_H */
56 extern int optind, opterr;
60 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
61 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
63 /******** Begin real source code ***************/
65 static VOIDRET usage FUNCTION((s), char *s)
67 fprintf(stderr, "usage: %s [-v] [-h] [-f] [-x] [-t type] [-4 | -5 | -s] [-a] [-n count] sequence_number seed\n", s);
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
83 static 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 }
94 static void getsecret FUNCTION((secret, promptextra, retype), char *secret AND char *promptextra AND int flags)
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);
101 if (secret[0] && (flags & 1)) {
102 char verify[OPIE_SECRET_MAX + 1];
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));
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));
117 memset(verify, 0, sizeof(verify));
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);
126 int main FUNCTION((argc, argv), int argc AND char *argv[])
128 /* variable declarations */
129 unsigned algorithm = MDX; /* default algorithm per Makefile's MDX
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];
140 int type = RESPONSE_STANDARD;
143 if (slash = strchr(argv[0], '/'))
148 if (!strcmp(slash, "key") || strstr(slash, "md4"))
151 if (strstr(slash, "md5"))
154 if (strstr(slash, "sha"))
157 while ((i = getopt(argc, argv, "fhvn:x45at:s")) != EOF) {
163 count = atoi(optarg);
171 #if INSECURE_OVERRIDE
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 */
179 /* use MD4 algorithm */
184 /* use MD5 algorithm */
195 for (r = rtrans; r->name && strcmp(r->name, optarg); r++);
197 fprintf(stderr, "%s: %s: unknown response type.\n", argv[0], optarg);
213 if ((argc - optind) < 2)
216 fprintf(stderr, "Using the %s algorithm to compute response.\n", algnames[algorithm]);
218 /* get sequence number, which is next-to-last parameter */
219 keynum = atoi(argv[optind]);
221 fprintf(stderr, "Sequence number %s is not positive.\n", argv[optind]);
224 /* get seed string, which is last parameter */
225 seed = argv[optind + 1];
229 if (i > OPIE_SEED_MAX) {
230 fprintf(stderr, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX);
233 if (i < OPIE_SEED_MIN) {
234 fprintf(stderr, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN);
239 fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n");
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
245 fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
247 #endif /* INSECURE_OVERRIDE */
251 if ((type == RESPONSE_INIT_HEX) || (type == RESPONSE_INIT_WORD)) {
253 getsecret(secret, "old ", 1);
255 getsecret(secret, "old ", 0);
257 getsecret(newsecret, "new ", 1);
259 strcpy(newsecret, secret);
261 if (opienewseed(strcpy(newseed, seed)) < 0) {
262 fprintf(stderr, "Error updating seed.\n");
266 if (opiekeycrunch(algorithm, newkey, newseed, newsecret)) {
267 fprintf(stderr, "%s: key crunch failed (1)\n", argv[0]);
271 for (i = 0; i < 499; i++)
272 opiehash(newkey, algorithm);
275 getsecret(secret, "", 1);
277 getsecret(secret, "", 0);
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]);
286 for (i = 0; i <= (keynum - count); i++)
287 opiehash(key, algorithm);
290 char buf[OPIE_SEED_MAX + 48 + 1];
293 for (; i <= keynum; i++) {
295 printf("%d: %s", i, (type == RESPONSE_STANDARD) ? "" : "\n");
298 case RESPONSE_STANDARD:
300 opiebtoh(response, key);
302 opiebtoe(response, key);
305 strcpy(response, "word:");
306 strcat(response, opiebtoe(buf, key));
309 strcpy(response, "hex:");
310 strcat(response, opiebtoh(buf, key));
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));
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));
330 opiehash(key, algorithm);
334 memset(secret, 0, sizeof(secret));
335 memset(newsecret, 0, sizeof(newsecret));
339 memset(secret, 0, sizeof(secret));
340 memset(newsecret, 0, sizeof(newsecret));