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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Portions of this code from crypt_bsdmd5.so (bsdmd5.c) : 28 * ---------------------------------------------------------------------------- 29 * "THE BEER-WARE LICENSE" (Revision 42): 30 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 31 * can do whatever you want with this stuff. If we meet some day, and you think 32 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 33 * ---------------------------------------------------------------------------- 34 * 35 * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $ 36 * 37 */ 38 39 /* 40 * Implements the specification from: 41 * 42 * From http://people.redhat.com/drepper/SHA-crypt.txt 43 * 44 * Portions of the code taken from inspired by or verified against the 45 * source in the above document which is licensed as: 46 * 47 * "Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>." 48 */ 49 50 51 #include <sys/types.h> 52 #include <sys/stat.h> 53 #include <sys/sysmacros.h> 54 #include <fcntl.h> 55 #include <unistd.h> 56 #include <string.h> 57 #include <stdio.h> 58 #include <errno.h> 59 #include <stdlib.h> 60 #include <alloca.h> 61 62 #include <sha2.h> 63 #include <crypt.h> 64 65 #define MAX_SALT_LEN 16 66 #define ROUNDS_DEFAULT 5000 67 #define ROUNDS_MIN 1000 68 #define ROUNDS_MAX 999999999 69 70 #ifdef CRYPT_SHA256 71 72 #define DIGEST_CTX SHA256_CTX 73 #define DIGESTInit SHA256Init 74 #define DIGESTUpdate SHA256Update 75 #define DIGESTFinal SHA256Final 76 #define DIGEST_LEN SHA256_DIGEST_LENGTH 77 #define MIXCHARS 32 78 static const char crypt_alg_magic[] = "$5"; 79 80 #elif CRYPT_SHA512 81 82 #define DIGEST_CTX SHA512_CTX 83 #define DIGESTInit SHA512Init 84 #define DIGESTUpdate SHA512Update 85 #define DIGESTFinal SHA512Final 86 #define DIGEST_LEN SHA512_DIGEST_LENGTH 87 #define MIXCHARS 64 88 static const char crypt_alg_magic[] = "$6"; 89 90 #else 91 #error "One of CRYPT_256 or CRYPT_512 must be defined" 92 #endif 93 94 static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1; 95 96 97 static uchar_t b64t[] = /* 0 ... 63 => ascii - 64 */ 98 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 99 100 #define b64_from_24bit(B2, B1, B0, N) \ 101 { \ 102 uint_t w = ((B2) << 16) | ((B1) << 8) | (B0); \ 103 int n = (N); \ 104 while (--n >= 0 && ctbufflen > 0) { \ 105 *p++ = b64t[w & 0x3f]; \ 106 w >>= 6; \ 107 ctbufflen--; \ 108 } \ 109 } 110 111 static void 112 to64(char *s, uint64_t v, int n) 113 { 114 while (--n >= 0) { 115 *s++ = b64t[v & 0x3f]; 116 v >>= 6; 117 } 118 } 119 120 #define ROUNDS "rounds=" 121 #define ROUNDSLEN (sizeof (ROUNDS) - 1) 122 123 /* 124 * get the integer value after rounds= where ever it occurs in the string. 125 * if the last char after the int is a , or $ that is fine anything else is an 126 * error. 127 */ 128 static uint32_t 129 getrounds(const char *s) 130 { 131 char *r, *p, *e; 132 long val; 133 134 if (s == NULL) 135 return (0); 136 137 if ((r = strstr(s, ROUNDS)) == NULL) { 138 return (0); 139 } 140 141 if (strncmp(r, ROUNDS, ROUNDSLEN) != 0) { 142 return (0); 143 } 144 145 p = r + ROUNDSLEN; 146 errno = 0; 147 val = strtol(p, &e, 10); 148 /* 149 * An error occurred or there is non-numeric stuff at the end 150 * which isn't one of the crypt(3c) special chars ',' or '$' 151 */ 152 if (errno != 0 || val < 0 || 153 !(*e == '\0' || *e == ',' || *e == '$')) { 154 return (0); 155 } 156 157 return ((uint32_t)val); 158 } 159 160 161 /* ARGSUSED4 */ 162 char * 163 crypt_genhash_impl(char *ctbuffer, 164 size_t ctbufflen, 165 const char *plaintext, 166 const char *switchsalt, 167 const char **params) 168 { 169 int salt_len, plaintext_len, i; 170 char *salt; 171 uchar_t A[DIGEST_LEN]; 172 uchar_t B[DIGEST_LEN]; 173 uchar_t DP[DIGEST_LEN]; 174 uchar_t DS[DIGEST_LEN]; 175 DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS; 176 int rounds = ROUNDS_DEFAULT; 177 int srounds = 0; 178 boolean_t custom_rounds = B_FALSE; 179 char *p; 180 char *P, *Pp; 181 char *S, *Sp; 182 183 /* Refine the salt */ 184 salt = (char *)switchsalt; 185 186 /* skip our magic string */ 187 if (strncmp((char *)salt, crypt_alg_magic, crypt_alg_magic_len) == 0) { 188 salt += crypt_alg_magic_len + 1; 189 } 190 191 srounds = getrounds(salt); 192 if (srounds != 0) { 193 rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX)); 194 custom_rounds = B_TRUE; 195 p = strchr(salt, '$'); 196 if (p != NULL) 197 salt = p + 1; 198 } 199 200 salt_len = MIN(strcspn(salt, "$"), MAX_SALT_LEN); 201 plaintext_len = strlen(plaintext); 202 203 /* 1. */ 204 DIGESTInit(&ctxA); 205 206 /* 2. The password first, since that is what is most unknown */ 207 DIGESTUpdate(&ctxA, plaintext, plaintext_len); 208 209 /* 3. Then the raw salt */ 210 DIGESTUpdate(&ctxA, salt, salt_len); 211 212 /* 4. - 8. */ 213 DIGESTInit(&ctxB); 214 DIGESTUpdate(&ctxB, plaintext, plaintext_len); 215 DIGESTUpdate(&ctxB, salt, salt_len); 216 DIGESTUpdate(&ctxB, plaintext, plaintext_len); 217 DIGESTFinal(B, &ctxB); 218 219 /* 9. - 10. */ 220 for (i = plaintext_len; i > MIXCHARS; i -= MIXCHARS) 221 DIGESTUpdate(&ctxA, B, MIXCHARS); 222 DIGESTUpdate(&ctxA, B, i); 223 224 /* 11. */ 225 for (i = plaintext_len; i > 0; i >>= 1) { 226 if ((i & 1) != 0) { 227 DIGESTUpdate(&ctxA, B, MIXCHARS); 228 } else { 229 DIGESTUpdate(&ctxA, plaintext, plaintext_len); 230 } 231 } 232 233 /* 12. */ 234 DIGESTFinal(A, &ctxA); 235 236 /* 13. - 15. */ 237 DIGESTInit(&ctxDP); 238 for (i = 0; i < plaintext_len; i++) 239 DIGESTUpdate(&ctxDP, plaintext, plaintext_len); 240 DIGESTFinal(DP, &ctxDP); 241 242 /* 16. */ 243 Pp = P = alloca(plaintext_len); 244 for (i = plaintext_len; i >= MIXCHARS; i -= MIXCHARS) { 245 Pp = (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS; 246 } 247 (void) memcpy(Pp, DP, i); 248 249 /* 17. - 19. */ 250 DIGESTInit(&ctxDS); 251 for (i = 0; i < 16 + (uint8_t)A[0]; i++) 252 DIGESTUpdate(&ctxDS, salt, salt_len); 253 DIGESTFinal(DS, &ctxDS); 254 255 /* 20. */ 256 Sp = S = alloca(salt_len); 257 for (i = salt_len; i >= MIXCHARS; i -= MIXCHARS) { 258 Sp = (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS; 259 } 260 (void) memcpy(Sp, DS, i); 261 262 /* 21. */ 263 for (i = 0; i < rounds; i++) { 264 DIGESTInit(&ctxC); 265 266 if ((i & 1) != 0) { 267 DIGESTUpdate(&ctxC, P, plaintext_len); 268 } else { 269 if (i == 0) 270 DIGESTUpdate(&ctxC, A, MIXCHARS); 271 else 272 DIGESTUpdate(&ctxC, DP, MIXCHARS); 273 } 274 275 if (i % 3 != 0) { 276 DIGESTUpdate(&ctxC, S, salt_len); 277 } 278 279 if (i % 7 != 0) { 280 DIGESTUpdate(&ctxC, P, plaintext_len); 281 } 282 283 if ((i & 1) != 0) { 284 if (i == 0) 285 DIGESTUpdate(&ctxC, A, MIXCHARS); 286 else 287 DIGESTUpdate(&ctxC, DP, MIXCHARS); 288 } else { 289 DIGESTUpdate(&ctxC, P, plaintext_len); 290 } 291 DIGESTFinal(DP, &ctxC); 292 } 293 294 /* 22. Now make the output string */ 295 if (custom_rounds) { 296 (void) snprintf(ctbuffer, ctbufflen, 297 "%s$rounds=%zu$", crypt_alg_magic, rounds); 298 } else { 299 (void) snprintf(ctbuffer, ctbufflen, 300 "%s$", crypt_alg_magic); 301 } 302 (void) strncat(ctbuffer, (const char *)salt, salt_len); 303 (void) strlcat(ctbuffer, "$", ctbufflen); 304 305 p = ctbuffer + strlen(ctbuffer); 306 ctbufflen -= strlen(ctbuffer); 307 308 #ifdef CRYPT_SHA256 309 b64_from_24bit(DP[ 0], DP[10], DP[20], 4); 310 b64_from_24bit(DP[21], DP[ 1], DP[11], 4); 311 b64_from_24bit(DP[12], DP[22], DP[ 2], 4); 312 b64_from_24bit(DP[ 3], DP[13], DP[23], 4); 313 b64_from_24bit(DP[24], DP[ 4], DP[14], 4); 314 b64_from_24bit(DP[15], DP[25], DP[ 5], 4); 315 b64_from_24bit(DP[ 6], DP[16], DP[26], 4); 316 b64_from_24bit(DP[27], DP[ 7], DP[17], 4); 317 b64_from_24bit(DP[18], DP[28], DP[ 8], 4); 318 b64_from_24bit(DP[ 9], DP[19], DP[29], 4); 319 b64_from_24bit(0, DP[31], DP[30], 3); 320 #elif CRYPT_SHA512 321 b64_from_24bit(DP[ 0], DP[21], DP[42], 4); 322 b64_from_24bit(DP[22], DP[43], DP[ 1], 4); 323 b64_from_24bit(DP[44], DP[ 2], DP[23], 4); 324 b64_from_24bit(DP[ 3], DP[24], DP[45], 4); 325 b64_from_24bit(DP[25], DP[46], DP[ 4], 4); 326 b64_from_24bit(DP[47], DP[ 5], DP[26], 4); 327 b64_from_24bit(DP[ 6], DP[27], DP[48], 4); 328 b64_from_24bit(DP[28], DP[49], DP[ 7], 4); 329 b64_from_24bit(DP[50], DP[ 8], DP[29], 4); 330 b64_from_24bit(DP[ 9], DP[30], DP[51], 4); 331 b64_from_24bit(DP[31], DP[52], DP[10], 4); 332 b64_from_24bit(DP[53], DP[11], DP[32], 4); 333 b64_from_24bit(DP[12], DP[33], DP[54], 4); 334 b64_from_24bit(DP[34], DP[55], DP[13], 4); 335 b64_from_24bit(DP[56], DP[14], DP[35], 4); 336 b64_from_24bit(DP[15], DP[36], DP[57], 4); 337 b64_from_24bit(DP[37], DP[58], DP[16], 4); 338 b64_from_24bit(DP[59], DP[17], DP[38], 4); 339 b64_from_24bit(DP[18], DP[39], DP[60], 4); 340 b64_from_24bit(DP[40], DP[61], DP[19], 4); 341 b64_from_24bit(DP[62], DP[20], DP[41], 4); 342 b64_from_24bit(0, 0, DP[63], 2); 343 #endif 344 *p = '\0'; 345 346 (void) memset(A, 0, sizeof (A)); 347 (void) memset(B, 0, sizeof (B)); 348 (void) memset(DP, 0, sizeof (DP)); 349 (void) memset(DS, 0, sizeof (DS)); 350 351 return (ctbuffer); 352 } 353 354 355 /* ARGSUSED3 */ 356 char * 357 crypt_gensalt_impl(char *gsbuffer, 358 size_t gsbufflen, 359 const char *oldsalt, 360 const struct passwd *userinfo, 361 const char **params) 362 { 363 int fd; 364 int err; 365 ssize_t got; 366 uint64_t rndval; 367 uint32_t confrounds = 0; 368 uint32_t saltrounds; 369 char rndstr[sizeof (rndval) + 1]; 370 int i; 371 372 for (i = 0; params != NULL && params[i] != NULL; i++) { 373 if (strncmp(params[i], ROUNDS, ROUNDSLEN) == 0) { 374 confrounds = getrounds(params[i]); 375 } else { 376 errno = EINVAL; 377 return (NULL); 378 } 379 } 380 381 /* 382 * If the config file has a higher value for rounds= than what 383 * was in the old salt use that, otherwise keep what was in the 384 * old salt. 385 */ 386 saltrounds = getrounds(oldsalt); 387 if (confrounds > saltrounds) { 388 saltrounds = confrounds; 389 } 390 391 if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { 392 return (NULL); 393 } 394 395 got = read(fd, &rndval, sizeof (rndval)); 396 if (got < sizeof (rndval)) { 397 err = errno; 398 (void) close(fd); 399 errno = err; 400 return (NULL); 401 } 402 (void) close(fd); 403 404 to64((char *)&rndstr, rndval, sizeof (rndval)); 405 rndstr[sizeof (rndstr) - 1] = 0; 406 407 if (saltrounds > 0) { 408 if (snprintf(gsbuffer, gsbufflen, 409 "%s$rounds=%d$", 410 crypt_alg_magic, saltrounds) >= gsbufflen) 411 goto fail; 412 } else { 413 if (snprintf(gsbuffer, gsbufflen, 414 "%s$", crypt_alg_magic) >= gsbufflen) 415 goto fail; 416 } 417 if (strlcat(gsbuffer, rndstr, gsbufflen) >= gsbufflen) 418 goto fail; 419 if (strlcat(gsbuffer, "$", gsbufflen) >= gsbufflen) 420 goto fail; 421 422 return (gsbuffer); 423 424 fail: 425 (void) memset(gsbuffer, 0, gsbufflen); 426 return (gsbuffer); 427 } 428