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
57 #endif /* HAVE_FCNTL_H */
60 extern int optind, opterr;
64 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
65 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
67 /******** Begin real source code ***************/
69 static VOIDRET usage FUNCTION((s), char *s)
71 fprintf(stderr, "usage: %s [-v] [-h] [-f] [-x] [-t type] [-4 | -5 | -s] [-a] [-n count] sequence_number seed\n", s);
75 #define RESPONSE_STANDARD 0
76 #define RESPONSE_WORD 1
77 #define RESPONSE_HEX 2
78 #define RESPONSE_INIT_HEX 3
79 #define RESPONSE_INIT_WORD 4
80 #define RESPONSE_UNKNOWN 5
87 static struct _rtrans rtrans[] = {
88 { RESPONSE_WORD, "word" },
89 { RESPONSE_HEX, "hex" },
90 { RESPONSE_INIT_HEX, "init-hex" },
91 { RESPONSE_INIT_WORD, "init-word" },
92 { RESPONSE_STANDARD, "" },
93 { RESPONSE_STANDARD, "standard" },
94 { RESPONSE_STANDARD, "otp" },
95 { RESPONSE_UNKNOWN, NULL }
98 static void getsecret FUNCTION((secret, promptextra, retype), char *secret AND char *promptextra AND int flags)
100 fprintf(stderr, "Enter %ssecret pass phrase: ", promptextra);
101 if (!opiereadpass(secret, OPIE_SECRET_MAX, 0)) {
102 fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra);
105 if (secret[0] && (flags & 1)) {
106 char verify[OPIE_SECRET_MAX + 1];
108 fprintf(stderr, "Again %ssecret pass phrase: ", promptextra);
109 if (!opiereadpass(verify, OPIE_SECRET_MAX, 0)) {
110 fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra);
111 memset(verify, 0, sizeof(verify));
112 memset(secret, 0, sizeof(secret));
115 if (verify[0] && strcmp(verify, secret)) {
116 fprintf(stderr, "They don't match. Try again.\n");
117 memset(verify, 0, sizeof(verify));
118 memset(secret, 0, sizeof(secret));
121 memset(verify, 0, sizeof(verify));
123 if (!(flags & 2) && !aflag && opiepasscheck(secret)) {
124 memset(secret, 0, sizeof(secret));
125 fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX);
130 int main FUNCTION((argc, argv), int argc AND char *argv[])
132 /* variable declarations */
133 unsigned algorithm = MDX; /* default algorithm per Makefile's MDX
138 char secret[OPIE_SECRET_MAX + 1], newsecret[OPIE_SECRET_MAX + 1];
139 struct opie_otpkey key, newkey;
140 char *seed, newseed[OPIE_SEED_MAX + 1];
141 char response[OPIE_RESPONSE_MAX + 1];
144 int type = RESPONSE_STANDARD;
147 if (slash = strchr(argv[0], '/'))
152 if (!strcmp(slash, "key") || strstr(slash, "md4"))
155 if (strstr(slash, "md5"))
158 if (strstr(slash, "sha"))
161 while ((i = getopt(argc, argv, "fhvn:x45at:s")) != EOF) {
167 count = atoi(optarg);
175 #if INSECURE_OVERRIDE
177 #else /* INSECURE_OVERRIDE */
178 fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n");
179 #endif /* INSECURE_OVERRIDE */
183 /* use MD4 algorithm */
188 /* use MD5 algorithm */
199 for (r = rtrans; r->name && strcmp(r->name, optarg); r++);
201 fprintf(stderr, "%s: %s: unknown response type.\n", argv[0], optarg);
217 if ((argc - optind) < 2)
220 fprintf(stderr, "Using the %s algorithm to compute response.\n", algnames[algorithm]);
222 /* get sequence number, which is next-to-last parameter */
223 keynum = atoi(argv[optind]);
225 fprintf(stderr, "Sequence number %s is not positive.\n", argv[optind]);
228 /* get seed string, which is last parameter */
229 seed = argv[optind + 1];
233 if (i > OPIE_SEED_MAX) {
234 fprintf(stderr, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX);
237 if (i < OPIE_SEED_MIN) {
238 fprintf(stderr, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN);
243 fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n");
245 if (opieinsecure()) {
246 fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
247 #if INSECURE_OVERRIDE
249 fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
251 #endif /* INSECURE_OVERRIDE */
255 if ((type == RESPONSE_INIT_HEX) || (type == RESPONSE_INIT_WORD)) {
257 getsecret(secret, "old ", 1);
259 getsecret(secret, "old ", 0);
261 getsecret(newsecret, "new ", 1);
263 strcpy(newsecret, secret);
265 if (opienewseed(strcpy(newseed, seed)) < 0) {
266 fprintf(stderr, "Error updating seed.\n");
270 if (opiekeycrunch(algorithm, &newkey, newseed, newsecret)) {
271 fprintf(stderr, "%s: key crunch failed (1)\n", argv[0]);
275 for (i = 0; i < 499; i++)
276 opiehash(&newkey, algorithm);
279 getsecret(secret, "", 1);
281 getsecret(secret, "", 0);
284 /* Crunch seed and secret password into starting key normally */
285 if (opiekeycrunch(algorithm, &key, seed, secret)) {
286 fprintf(stderr, "%s: key crunch failed\n", argv[0]);
290 for (i = 0; i <= (keynum - count); i++)
291 opiehash(&key, algorithm);
294 char buf[OPIE_SEED_MAX + 48 + 1];
297 for (; i <= keynum; i++) {
299 printf("%d: %s", i, (type == RESPONSE_STANDARD) ? "" : "\n");
302 case RESPONSE_STANDARD:
304 opiebtoh(response, &key);
306 opiebtoe(response, &key);
309 strcpy(response, "word:");
310 strcat(response, opiebtoe(buf, &key));
313 strcpy(response, "hex:");
314 strcat(response, opiebtoh(buf, &key));
316 case RESPONSE_INIT_HEX:
317 case RESPONSE_INIT_WORD:
318 if (type == RESPONSE_INIT_HEX) {
319 strcpy(response, "init-hex:");
320 strcat(response, opiebtoh(buf, &key));
321 sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed);
322 strcat(response, buf);
323 strcat(response, opiebtoh(buf, &newkey));
325 strcpy(response, "init-word:");
326 strcat(response, opiebtoe(buf, &key));
327 sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed);
328 strcat(response, buf);
329 strcat(response, opiebtoe(buf, &newkey));
334 opiehash(&key, algorithm);
338 memset(secret, 0, sizeof(secret));
339 memset(newsecret, 0, sizeof(newsecret));
343 memset(secret, 0, sizeof(secret));
344 memset(newsecret, 0, sizeof(newsecret));