1 /* $NetBSD: skeysubr.c,v 1.21 2001/07/24 16:43:02 wiz Exp $ */ 2 3 /* S/KEY v1.1b (skeysubr.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 * 10 * Modifications: 11 * Scott Chasin <chasin@crimelab.com> 12 * Todd C. Miller <Todd.Miller@courtesan.com> 13 * 14 * S/KEY misc routines. 15 */ 16 17 #include <ctype.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <signal.h> 22 #include <termios.h> 23 24 #include <md4.h> 25 #include <md5.h> 26 #include <rmd160.h> 27 #include <sha1.h> 28 29 #include "skey.h" 30 31 /* Default hash function to use (index into skey_hash_types array) */ 32 #ifndef SKEY_HASH_DEFAULT 33 #define SKEY_HASH_DEFAULT 0 /* MD4 */ 34 #endif 35 36 static void f_md4 __P((char *)); 37 static void f_md5 __P((char *)); 38 static void f_sha1 __P((char *)); 39 /* static void f_rmd160 __P((char *x)); */ 40 static int keycrunch_md4 __P((char *, const char *, const char *)); 41 static int keycrunch_md5 __P((char *, const char *, const char *)); 42 static int keycrunch_sha1 __P((char *, const char *, const char *)); 43 /* static int keycrunch_rmd160 __P((char *, const char *, const char *)); */ 44 static void lowcase __P((char *)); 45 static void skey_echo __P((int)); 46 static void trapped __P((int)); 47 static char *mkSeedPassword(const char *, const char *, size_t *); 48 49 /* Current hash type (index into skey_hash_types array) */ 50 static int skey_hash_type = SKEY_HASH_DEFAULT; 51 52 /* 53 * Hash types we support. 54 * Each has an associated keycrunch() and f() function. 55 */ 56 57 struct skey_algorithm_table { 58 const char *name; 59 int (*keycrunch) __P((char *, const char *, const char *)); 60 void (*f) __P((char *)); 61 }; 62 static struct skey_algorithm_table skey_algorithm_table[] = { 63 { "md4", keycrunch_md4, f_md4 }, 64 { "md5", keycrunch_md5, f_md5 }, 65 { "sha1", keycrunch_sha1, f_sha1 }, 66 #if 0 67 { "rmd160", keycrunch_rmd160, f_rmd160 }, 68 #endif 69 { NULL } 70 }; 71 72 /* 73 * Crunch a key: 74 * concatenate the (lower cased) seed and the password, run through 75 * the hash algorithm and collapse to 64 bits. 76 * This is defined as the user's starting key. 77 */ 78 int keycrunch(char *result, /* SKEY_BINKEY_SIZE result */ 79 const char *seed, /* Seed, any length */ 80 const char *passwd) /* Password, any length */ 81 { 82 return(skey_algorithm_table[skey_hash_type].keycrunch(result, seed, passwd)); 83 } 84 85 static char *mkSeedPassword(const char *seed, const char *passwd, 86 size_t *buflen) 87 { 88 char *buf; 89 90 *buflen = strlen(seed) + strlen(passwd); 91 if ((buf = (char *) malloc(*buflen + 1)) == NULL) 92 return NULL; 93 strcpy(buf, seed); 94 lowcase(buf); 95 strcat(buf, passwd); 96 sevenbit(buf); 97 98 return buf; 99 } 100 101 static int keycrunch_md4(char *result, /* SKEY_BINKEY_SIZE result */ 102 const char *seed, /* Seed, any length */ 103 const char *passwd) /* Password, any length */ 104 { 105 char *buf; 106 MD4_CTX md; 107 size_t buflen; 108 u_int32_t results[4]; 109 110 if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL) 111 return -1; 112 113 /* Crunch the key through MD4 */ 114 MD4Init(&md); 115 MD4Update(&md, (unsigned char *) buf, buflen); 116 MD4Final((unsigned char *) (void *) results, &md); 117 free(buf); 118 119 /* Fold result from 128 to 64 bits */ 120 results[0] ^= results[2]; 121 results[1] ^= results[3]; 122 123 (void)memcpy(result, results, SKEY_BINKEY_SIZE); 124 125 return 0; 126 } 127 128 static int keycrunch_md5(char *result, /* SKEY_BINKEY_SIZE result */ 129 const char *seed, /* Seed, any length */ 130 const char *passwd) /* Password, any length */ 131 { 132 char *buf; 133 MD5_CTX md; 134 u_int32_t results[4]; 135 size_t buflen; 136 137 if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL) 138 return -1; 139 140 /* Crunch the key through MD5 */ 141 MD5Init(&md); 142 MD5Update(&md, (unsigned char *)buf, buflen); 143 MD5Final((unsigned char *) (void *)results, &md); 144 free(buf); 145 146 /* Fold result from 128 to 64 bits */ 147 results[0] ^= results[2]; 148 results[1] ^= results[3]; 149 150 (void)memcpy((void *)result, (void *)results, SKEY_BINKEY_SIZE); 151 152 return(0); 153 } 154 155 static int keycrunch_sha1(char *result, /* SKEY_BINKEY_SIZE result */ 156 const char *seed, /* Seed, any length */ 157 const char *passwd) /* Password, any length */ 158 { 159 char *buf; 160 SHA1_CTX sha; 161 size_t buflen; 162 int i, j; 163 164 if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL) 165 return -1; 166 167 /* Crunch the key through SHA1 */ 168 SHA1Init(&sha); 169 SHA1Update(&sha, (unsigned char *)buf, buflen); 170 SHA1Final(NULL, &sha); 171 free(buf); 172 173 /* Fold 160 to 64 bits */ 174 sha.state[0] ^= sha.state[2]; 175 sha.state[1] ^= sha.state[3]; 176 sha.state[0] ^= sha.state[4]; 177 178 /* 179 * SHA1 is a big endian algorithm but RFC2289 mandates that 180 * the result be in little endian form, so we copy to the 181 * result buffer manually. 182 */ 183 184 for(i=j=0; j<8; i++, j+=4) { 185 result[j] = (unsigned char)(sha.state[i] & 0xff); 186 result[j+1] = (unsigned char)((sha.state[i] >> 8) & 0xff); 187 result[j+2] = (unsigned char)((sha.state[i] >> 16) & 0xff); 188 result[j+3] = (unsigned char)((sha.state[i] >> 24) & 0xff); 189 } 190 191 return(0); 192 } 193 194 #if 0 195 static int keycrunch_rmd160(char *result, /* SKEY_BINKEY_SIZE result */ 196 const char *seed, /* Seed, any length */ 197 const char *passwd) /* Password, any length */ 198 { 199 char *buf; 200 RMD160_CTX rmd; 201 u_int32_t results[5]; 202 size_t buflen; 203 204 if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL) 205 return -1; 206 207 /* Crunch the key through RMD-160 */ 208 RMD160Init(&rmd); 209 RMD160Update(&rmd, (unsigned char *)buf, buflen); 210 RMD160Final((unsigned char *)(void *)results, &rmd); 211 free(buf); 212 213 /* Fold 160 to 64 bits */ 214 results[0] ^= results[2]; 215 results[1] ^= results[3]; 216 results[0] ^= results[4]; 217 218 (void)memcpy((void *)result, (void *)results, SKEY_BINKEY_SIZE); 219 220 return(0); 221 } 222 #endif 223 224 /* The one-way function f(). Takes 8 bytes and returns 8 bytes in place */ 225 void f(char *x) 226 { 227 skey_algorithm_table[skey_hash_type].f(x); 228 } 229 230 static void f_md4(char *x) 231 { 232 MD4_CTX md; 233 u_int32_t results[4]; 234 235 MD4Init(&md); 236 MD4Update(&md, (unsigned char *) x, SKEY_BINKEY_SIZE); 237 MD4Final((unsigned char *) (void *) results, &md); 238 239 /* Fold 128 to 64 bits */ 240 results[0] ^= results[2]; 241 results[1] ^= results[3]; 242 243 (void)memcpy(x, results, SKEY_BINKEY_SIZE); 244 } 245 246 static void f_md5(char *x) 247 { 248 MD5_CTX md; 249 u_int32_t results[4]; 250 251 MD5Init(&md); 252 MD5Update(&md, (unsigned char *)x, SKEY_BINKEY_SIZE); 253 MD5Final((unsigned char *) (void *)results, &md); 254 255 /* Fold 128 to 64 bits */ 256 results[0] ^= results[2]; 257 results[1] ^= results[3]; 258 259 (void)memcpy((void *)x, (void *)results, SKEY_BINKEY_SIZE); 260 } 261 262 static void f_sha1(char *x) 263 { 264 SHA1_CTX sha; 265 int i, j; 266 267 SHA1Init(&sha); 268 SHA1Update(&sha, (unsigned char *)x, SKEY_BINKEY_SIZE); 269 SHA1Final(NULL, &sha); 270 271 /* Fold 160 to 64 bits */ 272 sha.state[0] ^= sha.state[2]; 273 sha.state[1] ^= sha.state[3]; 274 sha.state[0] ^= sha.state[4]; 275 276 for(i=j=0; j<8; i++, j+=4) { 277 x[j] = (unsigned char)(sha.state[i] & 0xff); 278 x[j+1] = (unsigned char)((sha.state[i] >> 8) & 0xff); 279 x[j+2] = (unsigned char)((sha.state[i] >> 16) & 0xff); 280 x[j+3] = (unsigned char)((sha.state[i] >> 24) & 0xff); 281 } 282 } 283 284 #if 0 285 static void f_rmd160(char *x) 286 { 287 RMD160_CTX rmd; 288 u_int32_t results[5]; 289 290 RMD160Init(&rmd); 291 RMD160Update(&rmd, (unsigned char *)x, SKEY_BINKEY_SIZE); 292 RMD160Final((unsigned char *)(void *)results, &rmd); 293 294 /* Fold 160 to 64 bits */ 295 results[0] ^= results[2]; 296 results[1] ^= results[3]; 297 results[0] ^= results[4]; 298 299 (void)memcpy((void *)x, (void *)results, SKEY_BINKEY_SIZE); 300 } 301 #endif 302 303 /* Strip trailing cr/lf from a line of text */ 304 void rip(char *buf) 305 { 306 buf += strcspn(buf, "\r\n"); 307 308 if (*buf) 309 *buf = '\0'; 310 } 311 312 /* Read in secret password (turns off echo) */ 313 char *readpass(char *buf, int n) 314 { 315 void *old_handler; 316 317 /* Turn off echoing */ 318 skey_echo(0); 319 320 /* Catch SIGINT and save old signal handler */ 321 old_handler = signal(SIGINT, trapped); 322 323 fgets(buf, n, stdin); 324 rip(buf); 325 326 putc('\n', stderr); 327 fflush(stderr); 328 329 /* Restore signal handler and turn echo back on */ 330 if (old_handler != SIG_ERR) 331 (void)signal(SIGINT, old_handler); 332 skey_echo(1); 333 334 sevenbit(buf); 335 336 return buf; 337 } 338 339 /* Read in an s/key OTP (does not turn off echo) */ 340 char *readskey(char *buf, int n) 341 { 342 fgets(buf, n, stdin); 343 344 rip(buf); 345 346 sevenbit (buf); 347 348 return buf; 349 } 350 351 /* Signal handler for trapping ^C */ 352 /*ARGSUSED*/ 353 static void trapped(int sig) 354 { 355 fputs("^C\n", stderr); 356 fflush(stderr); 357 358 /* Turn on echo if necessary */ 359 skey_echo(1); 360 361 exit(1); 362 } 363 364 /* 365 * Convert 8-byte hex-ascii string to binary array 366 * Returns 0 on success, -1 on error 367 */ 368 int atob8(char *out, const char *in) 369 { 370 int i; 371 int val; 372 373 if (in == NULL || out == NULL) 374 return -1; 375 376 for (i=0; i<8; i++) { 377 if ((in = skipspace(in)) == NULL) 378 return -1; 379 if ((val = htoi(*in++)) == -1) 380 return -1; 381 *out = val << 4; 382 383 if ((in = skipspace(in)) == NULL) 384 return -1; 385 if ((val = htoi(*in++)) == -1) 386 return -1; 387 *out++ |= val; 388 } 389 return 0; 390 } 391 392 /* Convert 8-byte binary array to hex-ascii string */ 393 int btoa8(char *out, const char *in) 394 { 395 int i; 396 397 if (in == NULL || out == NULL) 398 return -1; 399 400 for (i=0;i<8;i++) { 401 sprintf(out, "%02x", *in++ & 0xff); 402 out += 2; 403 } 404 return 0; 405 } 406 407 408 /* Convert hex digit to binary integer */ 409 int htoi(int c) 410 { 411 if ('0' <= c && c <= '9') 412 return c - '0'; 413 if ('a' <= c && c <= 'f') 414 return 10 + c - 'a'; 415 if ('A' <= c && c <= 'F') 416 return 10 + c - 'A'; 417 return -1; 418 } 419 420 /* Skip leading spaces from the string */ 421 const char *skipspace(const char *cp) 422 { 423 while (*cp == ' ' || *cp == '\t') 424 cp++; 425 426 if (*cp == '\0') 427 return NULL; 428 else 429 return cp; 430 } 431 432 /* Remove backspaced over charaters from the string */ 433 void backspace(char *buf) 434 { 435 char bs = 0x8; 436 char *cp = buf; 437 char *out = buf; 438 439 while (*cp) { 440 if (*cp == bs) { 441 if (out == buf) { 442 cp++; 443 continue; 444 } else { 445 cp++; 446 out--; 447 } 448 } else { 449 *out++ = *cp++; 450 } 451 452 } 453 *out = '\0'; 454 } 455 456 /* Make sure line is all seven bits */ 457 void sevenbit(char *s) 458 { 459 while (*s) 460 *s++ &= 0x7f; 461 } 462 463 /* Set hash algorithm type */ 464 const char *skey_set_algorithm(const char *new) 465 { 466 int i; 467 468 for (i = 0; skey_algorithm_table[i].name; i++) { 469 if (strcmp(new, skey_algorithm_table[i].name) == 0) { 470 skey_hash_type = i; 471 return(new); 472 } 473 } 474 475 return(NULL); 476 } 477 478 /* Get current hash type */ 479 const char *skey_get_algorithm() 480 { 481 return(skey_algorithm_table[skey_hash_type].name); 482 } 483 484 /* Turn echo on/off */ 485 static void skey_echo(int action) 486 { 487 static struct termios term; 488 static int echo = 0; 489 490 if (action == 0) { 491 /* Turn echo off */ 492 (void) tcgetattr(fileno(stdin), &term); 493 if ((echo = (term.c_lflag & ECHO))) { 494 term.c_lflag &= ~ECHO; 495 (void) tcsetattr(fileno(stdin), TCSAFLUSH|TCSASOFT, &term); 496 } 497 } else if (action && echo) { 498 /* Turn echo on */ 499 term.c_lflag |= ECHO; 500 (void) tcsetattr(fileno(stdin), TCSAFLUSH|TCSASOFT, &term); 501 echo = 0; 502 } 503 } 504 505 /* Convert string to lower case */ 506 static void lowcase(char *s) 507 { 508 u_char *p; 509 510 for (p = (u_char *) s; *p; p++) 511 if (isupper(*p)) 512 *p = tolower(*p); 513 } 514