1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <strings.h> 35 #include <pwd.h> 36 #include <errno.h> 37 #include <stdlib.h> 38 #include <syslog.h> 39 40 #include <crypt.h> 41 #include <md5.h> 42 43 #define CRYPT_ALGNAME "md5" 44 45 46 /* minimum number of rounds we do, not including the per-user ones */ 47 48 #define BASIC_ROUND_COUNT 4096 /* enough to make things interesting */ 49 #define DIGEST_LEN 16 50 #define ROUND_BUFFER_LEN 64 51 52 /* 53 * Public domain quotation courtesy of Project Gutenberg. 54 * ftp://metalab.unc.edu/pub/docs/books/gutenberg/etext98/2ws2610.txt 55 * Hamlet III.ii - 1517 bytes, including trailing NUL 56 * ANSI-C string constant concatenation is a requirement here. 57 */ 58 59 static const char constant_phrase[] = 60 "To be, or not to be,--that is the question:--\n" 61 "Whether 'tis nobler in the mind to suffer\n" 62 "The slings and arrows of outrageous fortune\n" 63 "Or to take arms against a sea of troubles,\n" 64 "And by opposing end them?--To die,--to sleep,--\n" 65 "No more; and by a sleep to say we end\n" 66 "The heartache, and the thousand natural shocks\n" 67 "That flesh is heir to,--'tis a consummation\n" 68 "Devoutly to be wish'd. To die,--to sleep;--\n" 69 "To sleep! perchance to dream:--ay, there's the rub;\n" 70 "For in that sleep of death what dreams may come,\n" 71 "When we have shuffled off this mortal coil,\n" 72 "Must give us pause: there's the respect\n" 73 "That makes calamity of so long life;\n" 74 "For who would bear the whips and scorns of time,\n" 75 "The oppressor's wrong, the proud man's contumely,\n" 76 "The pangs of despis'd love, the law's delay,\n" 77 "The insolence of office, and the spurns\n" 78 "That patient merit of the unworthy takes,\n" 79 "When he himself might his quietus make\n" 80 "With a bare bodkin? who would these fardels bear,\n" 81 "To grunt and sweat under a weary life,\n" 82 "But that the dread of something after death,--\n" 83 "The undiscover'd country, from whose bourn\n" 84 "No traveller returns,--puzzles the will,\n" 85 "And makes us rather bear those ills we have\n" 86 "Than fly to others that we know not of?\n" 87 "Thus conscience does make cowards of us all;\n" 88 "And thus the native hue of resolution\n" 89 "Is sicklied o'er with the pale cast of thought;\n" 90 "And enterprises of great pith and moment,\n" 91 "With this regard, their currents turn awry,\n" 92 "And lose the name of action.--Soft you now!\n" 93 "The fair Ophelia!--Nymph, in thy orisons\n" 94 "Be all my sins remember'd.\n"; 95 96 /* ------------------------------------------------------------------ */ 97 98 static int 99 md5bit(uint8_t *digest, int bit_num) 100 { 101 int byte_off; 102 int bit_off; 103 104 bit_num %= 128; /* keep this bounded for convenience */ 105 byte_off = bit_num / 8; 106 bit_off = bit_num % 8; 107 108 /* return the value of bit N from the digest */ 109 return ((digest[byte_off] & (0x01 << bit_off)) ? 1 : 0); 110 } 111 112 static uchar_t itoa64[] = /* 0 ... 63 => ascii - 64 */ 113 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 114 115 static void 116 to64(char *s, uint64_t v, int n) 117 { 118 while (--n >= 0) { 119 *s++ = itoa64[v&0x3f]; 120 v >>= 6; 121 } 122 } 123 124 #define ROUNDS "rounds=" 125 #define ROUNDSLEN (sizeof (ROUNDS) - 1) 126 127 /* 128 * get the integer value after rounds= where ever it occurs in the string. 129 * if the last char after the int is a , or $ that is fine anything else is an 130 * error. 131 */ 132 static uint32_t 133 getrounds(const char *s) 134 { 135 char *r, *p, *e; 136 long val; 137 138 if (s == NULL) 139 return (0); 140 141 if ((r = strstr(s, ROUNDS)) == NULL) { 142 return (0); 143 } 144 145 if (strncmp(r, ROUNDS, ROUNDSLEN) != 0) { 146 return (0); 147 } 148 149 p = r + ROUNDSLEN; 150 errno = 0; 151 val = strtol(p, &e, 10); 152 /* 153 * An error occured or there is non-numeric stuff at the end 154 * which isn't one of the crypt(3c) special chars ',' or '$' 155 */ 156 if (errno != 0 || val < 0 || 157 !(*e == '\0' || *e == ',' || *e == '$')) { 158 syslog(LOG_WARNING, 159 "crypt_sunmd5: invalid rounds specification \"%s\"", s); 160 return (0); 161 } 162 163 return ((uint32_t)val); 164 } 165 166 /*ARGSUSED*/ 167 char * 168 crypt_gensalt_impl(char *gsbuffer, 169 size_t gsbufflen, 170 const char *oldsalt, 171 const struct passwd *userinfo, 172 const char **params) 173 { 174 uint32_t confrounds = 0; 175 uint32_t saltrounds; 176 int i; 177 int fd; 178 ssize_t got; 179 uint64_t rndval; 180 char rndstr[sizeof (rndval) + 1]; /* rndval as a base64 string */ 181 182 for (i = 0; params != NULL && params[i] != NULL; i++) { 183 if (strncmp(params[i], ROUNDS, ROUNDSLEN) == 0) { 184 confrounds = getrounds(params[i]); 185 } else { 186 syslog(LOG_WARNING, 187 "crypt_sunmd5: invalid parameter %s", params[i]); 188 errno = EINVAL; 189 return (NULL); 190 } 191 } 192 193 /* 194 * If the config file has a higher value for rounds= than what 195 * was in the old salt use that, otherwise keep what was in the 196 * old salt. 197 */ 198 saltrounds = getrounds(oldsalt); 199 if (confrounds > saltrounds) { 200 saltrounds = confrounds; 201 } 202 203 if ((fd = open("/dev/random", O_RDONLY)) == -1) { 204 goto fail; 205 } 206 207 got = read(fd, &rndval, sizeof (rndval)); 208 if (got < sizeof (rndval)) { 209 int err = errno; 210 211 (void) close(fd); 212 errno = err; 213 goto fail; 214 } 215 (void) close(fd); 216 217 to64((char *)&rndstr, rndval, sizeof (rndval)); 218 rndstr[sizeof (rndstr) - 1] = '\0'; 219 220 if (saltrounds > 0) { 221 if (snprintf(gsbuffer, gsbufflen, 222 "$" CRYPT_ALGNAME "," ROUNDS "%d$", 223 saltrounds) >= gsbufflen) 224 goto fail; 225 } else { 226 if (snprintf(gsbuffer, gsbufflen, 227 "$" CRYPT_ALGNAME "$") >= gsbufflen) 228 goto fail; 229 } 230 231 if (strlcat(gsbuffer, rndstr, gsbufflen) >= gsbufflen) 232 goto fail; 233 if (strlcat(gsbuffer, "$", gsbufflen) >= gsbufflen) 234 goto fail; 235 236 return (gsbuffer); 237 238 fail: 239 bzero(gsbuffer, gsbufflen); 240 return (NULL); 241 } 242 243 244 /*ARGSUSED4*/ 245 char * 246 crypt_genhash_impl(char *ctbuffer, 247 size_t ctbufflen, 248 const char *plaintext, 249 const char *salt, 250 const char **params) 251 { 252 int i; 253 int round; 254 int maxrounds = BASIC_ROUND_COUNT; 255 uint32_t l; 256 char *puresalt; 257 char *saltend; 258 char *p; 259 260 /* put all the sensitive data in a struct */ 261 struct { 262 MD5_CTX context; /* working buffer for MD5 algorithm */ 263 uint8_t digest[DIGEST_LEN]; /* where the MD5 digest is stored */ 264 265 int indirect_4[16]; /* extracted array of 4bit values */ 266 int shift_4[16]; /* shift schedule, vals 0..4 */ 267 268 int s7shift; /* shift for shift_7 creation, vals 0..7 */ 269 int indirect_7[16]; /* extracted array of 7bit values */ 270 int shift_7[16]; /* shift schedule, vals 0..1 */ 271 272 int indirect_a; /* 7bit index into digest */ 273 int shift_a; /* shift schedule, vals 0..1 */ 274 275 int indirect_b; /* 7bit index into digest */ 276 int shift_b; /* shift schedule, vals 0..1 */ 277 278 int bit_a; /* single bit for cointoss */ 279 int bit_b; /* single bit for cointoss */ 280 281 char roundascii[ROUND_BUFFER_LEN]; /* ascii rep of roundcount */ 282 } data; 283 284 285 /* 286 * Extract the puresalt (if it exists) from the existing salt string 287 * $md5[,rounds=%d]$<puresalt>$<optional existing encoding> 288 */ 289 saltend = strrchr(salt, '$'); 290 if (saltend == NULL || saltend == salt) { 291 return (NULL); 292 } 293 if (saltend[1] != '\0') { 294 size_t len = saltend - salt + 1; 295 if ((puresalt = malloc(len)) == NULL) { 296 return (NULL); 297 } 298 (void) strlcpy(puresalt, salt, len); 299 } else { 300 puresalt = strdup(salt); 301 if (puresalt == NULL) { 302 return (NULL); 303 } 304 } 305 306 maxrounds += getrounds(salt); 307 308 /* initialise the context */ 309 310 MD5Init(&data.context); 311 312 /* update with the (hopefully entropic) plaintext */ 313 314 MD5Update(&data.context, (uchar_t *)plaintext, strlen(plaintext)); 315 316 /* update with the (publically known) salt */ 317 318 MD5Update(&data.context, (uchar_t *)puresalt, strlen(puresalt)); 319 320 321 /* compute the digest */ 322 323 MD5Final(data.digest, &data.context); 324 325 /* 326 * now to delay high-speed md5 implementations that have stuff 327 * like code inlining, loops unrolled and table lookup 328 */ 329 330 for (round = 0; round < maxrounds; round++) { 331 /* re-initialise the context */ 332 333 MD5Init(&data.context); 334 335 /* update with the previous digest */ 336 337 MD5Update(&data.context, data.digest, sizeof (data.digest)); 338 339 /* populate the shift schedules for use later */ 340 341 for (i = 0; i < 16; i++) { 342 int j; 343 344 /* offset 3 -> occasionally span more than 1 int32 fetch */ 345 j = (i + 3) % 16; 346 data.s7shift = data.digest[i] % 8; 347 data.shift_4[i] = data.digest[j] % 5; 348 data.shift_7[i] = (data.digest[j] >> data.s7shift) 349 & 0x01; 350 } 351 352 data.shift_a = md5bit(data.digest, round); 353 data.shift_b = md5bit(data.digest, round + 64); 354 355 /* populate indirect_4 with 4bit values extracted from digest */ 356 357 for (i = 0; i < 16; i++) { 358 /* shift the digest byte and extract four bits */ 359 data.indirect_4[i] = 360 (data.digest[i] >> data.shift_4[i]) & 0x0f; 361 } 362 363 /* 364 * populate indirect_7 with 7bit values from digest 365 * indexed via indirect_4 366 */ 367 368 for (i = 0; i < 16; i++) { 369 /* shift the digest byte and extract seven bits */ 370 data.indirect_7[i] = (data.digest[data.indirect_4[i]] 371 >> data.shift_7[i]) & 0x7f; 372 } 373 374 /* 375 * use the 7bit values to indirect into digest, 376 * and create two 8bit values from the results. 377 */ 378 379 data.indirect_a = data.indirect_b = 0; 380 381 for (i = 0; i < 8; i++) { 382 data.indirect_a |= (md5bit(data.digest, 383 data.indirect_7[i]) << i); 384 385 data.indirect_b |= (md5bit(data.digest, 386 data.indirect_7[i + 8]) << i); 387 } 388 389 390 /* shall we utilise the top or bottom 7 bits? */ 391 392 data.indirect_a = (data.indirect_a >> data.shift_a) & 0x7f; 393 data.indirect_b = (data.indirect_b >> data.shift_b) & 0x7f; 394 395 396 /* extract two data.digest bits */ 397 398 data.bit_a = md5bit(data.digest, data.indirect_a); 399 data.bit_b = md5bit(data.digest, data.indirect_b); 400 401 402 #if ALGDEBUG 403 for (i = 0; i < 15; i++) { 404 printf("%1x-", data.indirect_4[i]); 405 } 406 printf("%1x ", data.indirect_4[15]); 407 for (i = 0; i < 15; i++) { 408 printf("%02x-", data.indirect_7[i]); 409 } 410 printf("%02x ", data.indirect_7[15]); 411 printf("%02x/%02x ", data.indirect_a, data.indirect_b); 412 printf("%d^%d\n", data.bit_a, data.bit_b); 413 #endif 414 415 416 /* xor a coin-toss; if true, mix-in the constant phrase */ 417 418 if (data.bit_a ^ data.bit_b) { 419 MD5Update(&data.context, 420 (unsigned char *) constant_phrase, 421 sizeof (constant_phrase)); 422 #if ALGDEBUG 423 printf("mixing constant_phrase\n"); 424 #endif 425 } 426 427 428 /* digest a decimal sprintf of the current roundcount */ 429 430 snprintf(data.roundascii, ROUND_BUFFER_LEN, "%d", round); 431 MD5Update(&data.context, 432 (unsigned char *) data.roundascii, strlen(data.roundascii)); 433 434 /* compute/flush the digest, and loop */ 435 436 MD5Final(data.digest, &data.context); 437 } 438 439 440 #if ALGDEBUG 441 /* print the digest */ 442 for (i = 0; i < 16; i++) { 443 printf("%02x", data.digest[i]); 444 } 445 printf("\n"); 446 #endif 447 448 (void) snprintf(ctbuffer, ctbufflen, "%s$", puresalt); 449 p = ctbuffer + strlen(ctbuffer); 450 451 l = (data.digest[ 0]<<16) | (data.digest[ 6]<<8) | data.digest[12]; 452 to64(p, l, 4); p += 4; 453 l = (data.digest[ 1]<<16) | (data.digest[ 7]<<8) | data.digest[13]; 454 to64(p, l, 4); p += 4; 455 l = (data.digest[ 2]<<16) | (data.digest[ 8]<<8) | data.digest[14]; 456 to64(p, l, 4); p += 4; 457 l = (data.digest[ 3]<<16) | (data.digest[ 9]<<8) | data.digest[15]; 458 to64(p, l, 4); p += 4; 459 l = (data.digest[ 4]<<16) | (data.digest[10]<<8) | data.digest[ 5]; 460 to64(p, l, 4); p += 4; 461 l = data.digest[11]; to64(p, l, 2); p += 2; 462 *p = '\0'; 463 464 /* tidy up after ourselves */ 465 bzero(&data, sizeof (data)); 466 467 return (ctbuffer); 468 } 469