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