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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Portions of this code from crypt_bsdmd5.so (bsdmd5.c) : 30 * ---------------------------------------------------------------------------- 31 * "THE BEER-WARE LICENSE" (Revision 42): 32 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 33 * can do whatever you want with this stuff. If we meet some day, and you think 34 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 35 * ---------------------------------------------------------------------------- 36 * 37 * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $ 38 * 39 */ 40 41 /* 42 * Implements the specification from: 43 * 44 * From http://people.redhat.com/drepper/SHA-crypt.txt 45 * 46 * Portions of the code taken from inspired by or verified against the 47 * source in the above document which is licensed as: 48 * 49 * "Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>." 50 */ 51 52 53 #include <sys/types.h> 54 #include <sys/stat.h> 55 #include <sys/sysmacros.h> 56 #include <fcntl.h> 57 #include <unistd.h> 58 #include <string.h> 59 #include <stdio.h> 60 #include <errno.h> 61 #include <stdlib.h> 62 #include <alloca.h> 63 64 #include <sha2.h> 65 #include <crypt.h> 66 67 #define MAX_SALT_LEN 16 68 #define ROUNDS_DEFAULT 5000 69 #define ROUNDS_MIN 1000 70 #define ROUNDS_MAX 999999999 71 72 #ifdef CRYPT_SHA256 73 74 #define DIGEST_CTX SHA256_CTX 75 #define DIGESTInit SHA256Init 76 #define DIGESTUpdate SHA256Update 77 #define DIGESTFinal SHA256Final 78 #define DIGEST_LEN SHA256_DIGEST_LENGTH 79 #define MIXCHARS 32 80 static const char crypt_alg_magic[] = "$5$"; 81 82 #elif CRYPT_SHA512 83 84 #define DIGEST_CTX SHA512_CTX 85 #define DIGESTInit SHA512Init 86 #define DIGESTUpdate SHA512Update 87 #define DIGESTFinal SHA512Final 88 #define DIGEST_LEN SHA512_DIGEST_LENGTH 89 #define MIXCHARS 64 90 static const char crypt_alg_magic[] = "$6$"; 91 92 #else 93 #error "One of CRYPT_256 or CRYPT_512 must be defined" 94 #endif 95 96 static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1; 97 static const char rounds_prefix[] = "rounds="; 98 99 100 static uchar_t b64t[] = /* 0 ... 63 => ascii - 64 */ 101 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 102 103 #define b64_from_24bit(B2, B1, B0, N) \ 104 { \ 105 uint_t w = ((B2) << 16) | ((B1) << 8) | (B0); \ 106 int n = (N); \ 107 while (--n >= 0 && ctbufflen > 0) { \ 108 *p++ = b64t[w & 0x3f]; \ 109 w >>= 6; \ 110 ctbufflen--; \ 111 } \ 112 } 113 114 static void 115 to64(char *s, uint64_t v, int n) 116 { 117 while (--n >= 0) { 118 *s++ = b64t[v&0x3f]; 119 v >>= 6; 120 } 121 } 122 123 char * 124 crypt_genhash_impl(char *ctbuffer, 125 size_t ctbufflen, 126 const char *plaintext, 127 const char *switchsalt, 128 const char **params) 129 { 130 int salt_len, plaintext_len, i; 131 char *salt; 132 uchar_t A[DIGEST_LEN]; 133 uchar_t B[DIGEST_LEN]; 134 uchar_t DP[DIGEST_LEN]; 135 uchar_t DS[DIGEST_LEN]; 136 DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS; 137 int rounds = ROUNDS_DEFAULT; 138 boolean_t custom_rounds = B_FALSE; 139 char *p; 140 char *P, *Pp; 141 char *S, *Sp; 142 143 /* Refine the salt */ 144 salt = (char *)switchsalt; 145 146 /* skip our magic string */ 147 if (strncmp((char *)salt, crypt_alg_magic, crypt_alg_magic_len) == 0) { 148 salt += crypt_alg_magic_len; 149 } 150 151 if (strncmp(salt, rounds_prefix, sizeof (rounds_prefix) - 1) == 0) { 152 char *num = salt + sizeof (rounds_prefix) - 1; 153 char *endp; 154 ulong_t srounds = strtoul(num, &endp, 10); 155 if (*endp == '$') { 156 salt = endp + 1; 157 rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX)); 158 custom_rounds = B_TRUE; 159 } 160 } 161 162 salt_len = MIN(strcspn(salt, "$"), MAX_SALT_LEN); 163 plaintext_len = strlen(plaintext); 164 165 /* 1. */ 166 DIGESTInit(&ctxA); 167 168 /* 2. The password first, since that is what is most unknown */ 169 DIGESTUpdate(&ctxA, plaintext, plaintext_len); 170 171 /* 3. Then the raw salt */ 172 DIGESTUpdate(&ctxA, salt, salt_len); 173 174 /* 4. - 8. */ 175 DIGESTInit(&ctxB); 176 DIGESTUpdate(&ctxB, plaintext, plaintext_len); 177 DIGESTUpdate(&ctxB, salt, salt_len); 178 DIGESTUpdate(&ctxB, plaintext, plaintext_len); 179 DIGESTFinal(B, &ctxB); 180 181 /* 9. - 10. */ 182 for (i = plaintext_len; i > MIXCHARS; i -= MIXCHARS) 183 DIGESTUpdate(&ctxA, B, MIXCHARS); 184 DIGESTUpdate(&ctxA, B, i); 185 186 /* 11. */ 187 for (i = plaintext_len; i > 0; i >>= 1) { 188 if ((i & 1) != 0) { 189 DIGESTUpdate(&ctxA, B, MIXCHARS); 190 } else { 191 DIGESTUpdate(&ctxA, plaintext, plaintext_len); 192 } 193 } 194 195 /* 12. */ 196 DIGESTFinal(A, &ctxA); 197 198 /* 13. - 15. */ 199 DIGESTInit(&ctxDP); 200 for (i = 0; i < plaintext_len; i++) 201 DIGESTUpdate(&ctxDP, plaintext, plaintext_len); 202 DIGESTFinal(DP, &ctxDP); 203 204 /* 16. */ 205 Pp = P = alloca(plaintext_len); 206 for (i = plaintext_len; i >= MIXCHARS; i -= MIXCHARS) { 207 Pp = (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS; 208 } 209 memcpy(Pp, DP, i); 210 211 /* 17. - 19. */ 212 DIGESTInit(&ctxDS); 213 for (i = 0; i < 16 + (uint8_t)A[0]; i++) 214 DIGESTUpdate(&ctxDS, salt, salt_len); 215 DIGESTFinal(DS, &ctxDS); 216 217 /* 20. */ 218 Sp = S = alloca(salt_len); 219 for (i = salt_len; i >= MIXCHARS; i -= MIXCHARS) { 220 Sp = (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS; 221 } 222 memcpy(Sp, DS, i); 223 224 /* 21. */ 225 for (i = 0; i < rounds; i++) { 226 DIGESTInit(&ctxC); 227 228 if ((i & 1) != 0) { 229 DIGESTUpdate(&ctxC, P, plaintext_len); 230 } else { 231 if (i == 0) 232 DIGESTUpdate(&ctxC, A, MIXCHARS); 233 else 234 DIGESTUpdate(&ctxC, DP, MIXCHARS); 235 } 236 237 if (i % 3 != 0) { 238 DIGESTUpdate(&ctxC, S, salt_len); 239 } 240 241 if (i % 7 != 0) { 242 DIGESTUpdate(&ctxC, P, plaintext_len); 243 } 244 245 if ((i & 1) != 0) { 246 if (i == 0) 247 DIGESTUpdate(&ctxC, A, MIXCHARS); 248 else 249 DIGESTUpdate(&ctxC, DP, MIXCHARS); 250 } else { 251 DIGESTUpdate(&ctxC, P, plaintext_len); 252 } 253 DIGESTFinal(DP, &ctxC); 254 } 255 256 /* 22. Now make the output string */ 257 (void) strlcpy(ctbuffer, crypt_alg_magic, ctbufflen); 258 if (custom_rounds) { 259 (void) snprintf(ctbuffer, ctbufflen, 260 "%srounds=%zu$", ctbuffer, rounds); 261 } 262 263 (void) strncat(ctbuffer, (const char *)salt, MAX_SALT_LEN); 264 (void) strlcat(ctbuffer, "$", ctbufflen); 265 p = ctbuffer + strlen(ctbuffer); 266 ctbufflen -= strlen(ctbuffer); 267 268 #ifdef CRYPT_SHA256 269 b64_from_24bit(DP[ 0], DP[10], DP[20], 4); 270 b64_from_24bit(DP[21], DP[ 1], DP[11], 4); 271 b64_from_24bit(DP[12], DP[22], DP[ 2], 4); 272 b64_from_24bit(DP[ 3], DP[13], DP[23], 4); 273 b64_from_24bit(DP[24], DP[ 4], DP[14], 4); 274 b64_from_24bit(DP[15], DP[25], DP[ 5], 4); 275 b64_from_24bit(DP[ 6], DP[16], DP[26], 4); 276 b64_from_24bit(DP[27], DP[ 7], DP[17], 4); 277 b64_from_24bit(DP[18], DP[28], DP[ 8], 4); 278 b64_from_24bit(DP[ 9], DP[19], DP[29], 4); 279 b64_from_24bit(0, DP[31], DP[30], 3); 280 #elif CRYPT_SHA512 281 b64_from_24bit(DP[ 0], DP[21], DP[42], 4); 282 b64_from_24bit(DP[22], DP[43], DP[ 1], 4); 283 b64_from_24bit(DP[44], DP[ 2], DP[23], 4); 284 b64_from_24bit(DP[ 3], DP[24], DP[45], 4); 285 b64_from_24bit(DP[25], DP[46], DP[ 4], 4); 286 b64_from_24bit(DP[47], DP[ 5], DP[26], 4); 287 b64_from_24bit(DP[ 6], DP[27], DP[48], 4); 288 b64_from_24bit(DP[28], DP[49], DP[ 7], 4); 289 b64_from_24bit(DP[50], DP[ 8], DP[29], 4); 290 b64_from_24bit(DP[ 9], DP[30], DP[51], 4); 291 b64_from_24bit(DP[31], DP[52], DP[10], 4); 292 b64_from_24bit(DP[53], DP[11], DP[32], 4); 293 b64_from_24bit(DP[12], DP[33], DP[54], 4); 294 b64_from_24bit(DP[34], DP[55], DP[13], 4); 295 b64_from_24bit(DP[56], DP[14], DP[35], 4); 296 b64_from_24bit(DP[15], DP[36], DP[57], 4); 297 b64_from_24bit(DP[37], DP[58], DP[16], 4); 298 b64_from_24bit(DP[59], DP[17], DP[38], 4); 299 b64_from_24bit(DP[18], DP[39], DP[60], 4); 300 b64_from_24bit(DP[40], DP[61], DP[19], 4); 301 b64_from_24bit(DP[62], DP[20], DP[41], 4); 302 b64_from_24bit(0, 0, DP[63], 2); 303 #endif 304 *p = '\0'; 305 306 (void) memset(A, 0, sizeof (A)); 307 (void) memset(B, 0, sizeof (B)); 308 (void) memset(DP, 0, sizeof (DP)); 309 (void) memset(DS, 0, sizeof (DS)); 310 311 return (ctbuffer); 312 } 313 314 char * 315 crypt_gensalt_impl(char *gsbuffer, 316 size_t gsbufflen, 317 const char *oldsalt, 318 const struct passwd *userinfo, 319 const char **params) 320 { 321 int fd; 322 int err; 323 ssize_t got; 324 uint64_t rndval; 325 326 if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { 327 return (NULL); 328 } 329 330 (void) strlcpy(gsbuffer, crypt_alg_magic, gsbufflen); 331 332 got = read(fd, &rndval, sizeof (rndval)); 333 if (got < sizeof (rndval)) { 334 err = errno; 335 (void) close(fd); 336 errno = err; 337 return (NULL); 338 } 339 340 to64(&gsbuffer[strlen(crypt_alg_magic)], rndval, sizeof (rndval)); 341 342 (void) close(fd); 343 344 return (gsbuffer); 345 } 346