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-1999 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.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
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
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
40 $FreeBSD: src/contrib/opie/opiekey.c,v 1.1.1.2.6.4 2002/07/15 14:48:43 des Exp $
41 $DragonFly: src/contrib/opie/opiekey.c,v 1.2 2003/06/17 04:24:05 dillon Exp $
58 #endif /* HAVE_FCNTL_H */
61 extern int optind
, opterr
;
65 char *algnames
[] = { NULL
, NULL
, NULL
, "SHA-1", "MD4", "MD5" };
66 char *algids
[] = { NULL
, NULL
, NULL
, "sha1", "md4", "md5" };
68 /******** Begin real source code ***************/
70 static VOIDRET usage
FUNCTION((s
), char *s
)
72 fprintf(stderr
, "usage: %s [-v] [-h] [-f] [-x] [-t type] [-4 | -5 | -s] [-a] [-n count] sequence_number seed\n", s
);
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
88 static 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
}
99 static void getsecret
FUNCTION((secret
, promptextra
, retype
), char *secret AND
char *promptextra AND
int flags
)
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
);
106 if (secret
[0] && (flags
& 1)) {
107 char verify
[OPIE_SECRET_MAX
+ 1];
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, sizeof(secret
));
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, sizeof(secret
));
122 memset(verify
, 0, sizeof(verify
));
124 if (!(flags
& 2) && !aflag
&& opiepasscheck(secret
)) {
125 memset(secret
, 0, sizeof(secret
));
126 fprintf(stderr
, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN
, OPIE_SECRET_MAX
);
131 int main
FUNCTION((argc
, argv
), int argc AND
char *argv
[])
133 /* variable declarations */
134 unsigned algorithm
= MDX
; /* default algorithm per Makefile's MDX
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];
145 int type
= RESPONSE_STANDARD
;
148 if (slash
= strchr(argv
[0], '/'))
153 if (!strcmp(slash
, "key") || strstr(slash
, "md4"))
156 if (strstr(slash
, "md5"))
159 if (strstr(slash
, "sha"))
162 while ((i
= getopt(argc
, argv
, "fhvn:x45at:s")) != EOF
) {
168 count
= atoi(optarg
);
176 #if INSECURE_OVERRIDE
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 */
184 /* use MD4 algorithm */
189 /* use MD5 algorithm */
200 for (r
= rtrans
; r
->name
&& strcmp(r
->name
, optarg
); r
++);
202 fprintf(stderr
, "%s: %s: unknown response type.\n", argv
[0], optarg
);
218 if ((argc
- optind
) < 2)
221 fprintf(stderr
, "Using the %s algorithm to compute response.\n", algnames
[algorithm
]);
223 /* get sequence number, which is next-to-last parameter */
224 keynum
= atoi(argv
[optind
]);
226 fprintf(stderr
, "Sequence number %s is not positive.\n", argv
[optind
]);
229 /* get seed string, which is last parameter */
230 seed
= argv
[optind
+ 1];
234 if (i
> OPIE_SEED_MAX
) {
235 fprintf(stderr
, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX
);
238 if (i
< OPIE_SEED_MIN
) {
239 fprintf(stderr
, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN
);
244 fprintf(stderr
, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n");
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
250 fprintf(stderr
, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
252 #endif /* INSECURE_OVERRIDE */
256 if ((type
== RESPONSE_INIT_HEX
) || (type
== RESPONSE_INIT_WORD
)) {
258 getsecret(secret
, "old ", 1);
260 getsecret(secret
, "old ", 0);
262 getsecret(newsecret
, "new ", 1);
264 strcpy(newsecret
, secret
);
266 if (opienewseed(strcpy(newseed
, seed
)) < 0) {
267 fprintf(stderr
, "Error updating seed.\n");
271 if (opiekeycrunch(algorithm
, &newkey
, newseed
, newsecret
)) {
272 fprintf(stderr
, "%s: key crunch failed (1)\n", argv
[0]);
276 for (i
= 0; i
< 499; i
++)
277 opiehash(&newkey
, algorithm
);
280 getsecret(secret
, "", 1);
282 getsecret(secret
, "", 0);
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]);
291 for (i
= 0; i
<= (keynum
- count
); i
++)
292 opiehash(&key
, algorithm
);
295 char buf
[OPIE_SEED_MAX
+ 48 + 1];
298 for (; i
<= keynum
; i
++) {
300 printf("%d: %s", i
, (type
== RESPONSE_STANDARD
) ? "" : "\n");
303 case RESPONSE_STANDARD
:
305 opiebtoh(response
, &key
);
307 opiebtoe(response
, &key
);
310 strcpy(response
, "word:");
311 strcat(response
, opiebtoe(buf
, &key
));
314 strcpy(response
, "hex:");
315 strcat(response
, opiebtoh(buf
, &key
));
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
));
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
));
335 opiehash(&key
, algorithm
);
339 memset(secret
, 0, sizeof(secret
));
340 memset(newsecret
, 0, sizeof(newsecret
));
344 memset(secret
, 0, sizeof(secret
));
345 memset(newsecret
, 0, sizeof(newsecret
));