1 /* $OpenBSD: skey.c,v 1.36 2024/08/03 22:00:31 millert Exp $ */ 2 /* 3 * OpenBSD S/Key (skey.c) 4 * 5 * Authors: 6 * Neil M. Haller <nmh@thumper.bellcore.com> 7 * Philip R. Karn <karn@chicago.qualcomm.com> 8 * John S. Walden <jsw@thumper.bellcore.com> 9 * Scott Chasin <chasin@crimelab.com> 10 * Todd C. Miller <millert@openbsd.org> 11 * 12 * 13 * Stand-alone program for computing responses to S/Key challenges. 14 * Takes the iteration count and seed as command line args, prompts 15 * for the user's key, and produces both word and hex format responses. 16 * 17 * Usage example: 18 * >skey 88 ka9q2 19 * Enter password: 20 * OMEN US HORN OMIT BACK AHOY 21 * > 22 * 23 */ 24 25 #include <err.h> 26 #include <limits.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 #include <readpassphrase.h> 32 #include <skey.h> 33 34 void usage(); 35 36 extern char *__progname; 37 38 int 39 main(int argc, char *argv[]) 40 { 41 int n, i, cnt = 1, pass = 0, hexmode = 0; 42 char passwd[SKEY_MAX_PW_LEN+1], key[SKEY_BINKEY_SIZE]; 43 char buf[33], *seed, *slash, *algo; 44 const char *errstr; 45 46 if (pledge("stdio tty", NULL) == -1) 47 err(1, "pledge"); 48 49 /* If we were called as otp-METHOD, set algorithm based on that */ 50 if (strncmp(__progname, "otp-", 4) == 0) { 51 algo = __progname + 4; 52 if (skey_set_algorithm(algo) == NULL) 53 errx(1, "Unknown hash algorithm %s", algo); 54 } 55 56 for (i = 1; i < argc && argv[i][0] == '-' && strcmp(argv[i], "--");) { 57 if (argv[i][2] == '\0') { 58 /* Single character switch */ 59 switch (argv[i][1]) { 60 case 'n': 61 if (++i == argc) 62 usage(); 63 cnt = strtonum(argv[i], 1, SKEY_MAX_SEQ + 1, 64 &errstr); 65 if (errstr) 66 usage(); 67 break; 68 case 'p': 69 if (++i == argc) 70 usage(); 71 if (strlcpy(passwd, argv[i], sizeof(passwd)) >= 72 sizeof(passwd)) 73 errx(1, "Password too long"); 74 pass = 1; 75 break; 76 case 'x': 77 hexmode = 1; 78 break; 79 default: 80 usage(); 81 } 82 } else { 83 /* Multi character switches are hash types */ 84 if (skey_set_algorithm(&argv[i][1]) == NULL) { 85 warnx("Unknown hash algorithm %s", &argv[i][1]); 86 usage(); 87 } 88 } 89 i++; 90 } 91 92 if (argc > i + 2) 93 usage(); 94 95 /* Could be in the form <number>/<seed> */ 96 if (argc <= i + 1) { 97 /* look for / in it */ 98 if (argc <= i) 99 usage(); 100 slash = strchr(argv[i], '/'); 101 if (slash == NULL) 102 usage(); 103 *slash++ = '\0'; 104 seed = slash; 105 106 n = strtonum(argv[i], 0, SKEY_MAX_SEQ, &errstr); 107 if (errstr) { 108 warnx("%s: %s", argv[i], errstr); 109 usage(); 110 } 111 } else { 112 n = strtonum(argv[i], 0, SKEY_MAX_SEQ, &errstr); 113 if (errstr) { 114 warnx("%s: %s", argv[i], errstr); 115 usage(); 116 } 117 seed = argv[++i]; 118 } 119 120 /* Get user's secret passphrase */ 121 if (!pass && (readpassphrase("Enter secret passphrase: ", passwd, 122 sizeof(passwd), 0) == NULL || passwd[0] == '\0')) 123 exit(1); 124 125 /* Crunch seed and passphrase into starting key */ 126 if (keycrunch(key, seed, passwd) != 0) { 127 explicit_bzero(passwd, sizeof(passwd)); 128 errx(1, "key crunch failed"); 129 } 130 131 explicit_bzero(passwd, sizeof(passwd)); 132 133 if (cnt == 1) { 134 while (n-- != 0) 135 f(key); 136 (void)puts(hexmode ? put8(buf, key) : btoe(buf, key)); 137 } else { 138 for (i = 0; i <= n - cnt; i++) 139 f(key); 140 for (; i <= n; i++) { 141 if (hexmode) 142 (void)printf("%d: %s\n", i, put8(buf, key)); 143 else 144 (void)printf("%d: %-29s\n", i, btoe(buf, key)); 145 f(key); 146 } 147 } 148 exit(0); 149 } 150 151 void 152 usage(void) 153 { 154 fprintf(stderr, 155 "usage: %s [-x] [-md5 | -rmd160 | -sha1] [-n count]\n\t" 156 "[-p passphrase] <sequence#>[/] key\n", __progname); 157 exit(1); 158 } 159