xref: /onnv-gate/usr/src/lib/crypt_modules/sha256/crypt_sha.c (revision 9557:e292b8371405)
16532Swyllys /*
26532Swyllys  * CDDL HEADER START
36532Swyllys  *
46532Swyllys  * The contents of this file are subject to the terms of the
56532Swyllys  * Common Development and Distribution License (the "License").
66532Swyllys  * You may not use this file except in compliance with the License.
76532Swyllys  *
86532Swyllys  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96532Swyllys  * or http://www.opensolaris.org/os/licensing.
106532Swyllys  * See the License for the specific language governing permissions
116532Swyllys  * and limitations under the License.
126532Swyllys  *
136532Swyllys  * When distributing Covered Code, include this CDDL HEADER in each
146532Swyllys  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156532Swyllys  * If applicable, add the following below this CDDL HEADER, with the
166532Swyllys  * fields enclosed by brackets "[]" replaced with your own identifying
176532Swyllys  * information: Portions Copyright [yyyy] [name of copyright owner]
186532Swyllys  *
196532Swyllys  * CDDL HEADER END
206532Swyllys  */
216532Swyllys /*
22*9557SWyllys.Ingersoll@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
236532Swyllys  * Use is subject to license terms.
246532Swyllys  */
256532Swyllys 
266532Swyllys /*
276532Swyllys  * Portions of this code from crypt_bsdmd5.so (bsdmd5.c) :
286532Swyllys  * ----------------------------------------------------------------------------
296532Swyllys  * "THE BEER-WARE LICENSE" (Revision 42):
306532Swyllys  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
316532Swyllys  * can do whatever you want with this stuff. If we meet some day, and you think
326532Swyllys  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
336532Swyllys  * ----------------------------------------------------------------------------
346532Swyllys  *
356532Swyllys  * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $
366532Swyllys  *
376532Swyllys  */
386532Swyllys 
396532Swyllys /*
406532Swyllys  * Implements the specification from:
416532Swyllys  *
426532Swyllys  * From http://people.redhat.com/drepper/SHA-crypt.txt
436532Swyllys  *
446532Swyllys  * Portions of the code taken from inspired by or verified against the
456532Swyllys  * source in the above document which is licensed as:
466532Swyllys  *
476532Swyllys  * "Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>."
486532Swyllys  */
496532Swyllys 
506532Swyllys 
516532Swyllys #include <sys/types.h>
526532Swyllys #include <sys/stat.h>
536532Swyllys #include <sys/sysmacros.h>
546532Swyllys #include <fcntl.h>
556532Swyllys #include <unistd.h>
566532Swyllys #include <string.h>
576532Swyllys #include <stdio.h>
586532Swyllys #include <errno.h>
596532Swyllys #include <stdlib.h>
606532Swyllys #include <alloca.h>
616532Swyllys 
626532Swyllys #include <sha2.h>
636532Swyllys #include <crypt.h>
646532Swyllys 
656532Swyllys #define	MAX_SALT_LEN	16
666532Swyllys #define	ROUNDS_DEFAULT	5000
676532Swyllys #define	ROUNDS_MIN	1000
686532Swyllys #define	ROUNDS_MAX	999999999
696532Swyllys 
706532Swyllys #ifdef CRYPT_SHA256
716532Swyllys 
726532Swyllys #define	DIGEST_CTX	SHA256_CTX
736532Swyllys #define	DIGESTInit	SHA256Init
746532Swyllys #define	DIGESTUpdate	SHA256Update
756532Swyllys #define	DIGESTFinal	SHA256Final
766532Swyllys #define	DIGEST_LEN	SHA256_DIGEST_LENGTH
776532Swyllys #define	MIXCHARS	32
78*9557SWyllys.Ingersoll@Sun.COM static const char crypt_alg_magic[] = "$5";
796532Swyllys 
806532Swyllys #elif CRYPT_SHA512
816532Swyllys 
826532Swyllys #define	DIGEST_CTX	SHA512_CTX
836532Swyllys #define	DIGESTInit	SHA512Init
846532Swyllys #define	DIGESTUpdate	SHA512Update
856532Swyllys #define	DIGESTFinal	SHA512Final
866532Swyllys #define	DIGEST_LEN	SHA512_DIGEST_LENGTH
876532Swyllys #define	MIXCHARS	64
88*9557SWyllys.Ingersoll@Sun.COM static const char crypt_alg_magic[] = "$6";
896532Swyllys 
906532Swyllys #else
916532Swyllys #error	"One of CRYPT_256 or CRYPT_512 must be defined"
926532Swyllys #endif
936532Swyllys 
946532Swyllys static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1;
956532Swyllys 
966532Swyllys 
976532Swyllys static uchar_t b64t[] =		/* 0 ... 63 => ascii - 64 */
986532Swyllys 	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
996532Swyllys 
1006532Swyllys #define	b64_from_24bit(B2, B1, B0, N) \
1016532Swyllys { \
1026532Swyllys 	uint_t w = ((B2) << 16) | ((B1) << 8) | (B0); \
1036532Swyllys 	int n = (N); \
1046532Swyllys 	while (--n >= 0 && ctbufflen > 0) { \
1056532Swyllys 		*p++ = b64t[w & 0x3f]; \
1066532Swyllys 		w >>= 6; \
1076532Swyllys 		ctbufflen--; \
1086532Swyllys 	} \
1096532Swyllys }
1106532Swyllys 
1116532Swyllys static void
1126532Swyllys to64(char *s, uint64_t v, int n)
1136532Swyllys {
1146532Swyllys 	while (--n >= 0) {
1156532Swyllys 		*s++ = b64t[v&0x3f];
1166532Swyllys 		v >>= 6;
1176532Swyllys 	}
1186532Swyllys }
1196532Swyllys 
120*9557SWyllys.Ingersoll@Sun.COM #define	ROUNDS		"rounds="
121*9557SWyllys.Ingersoll@Sun.COM #define	ROUNDSLEN	(sizeof (ROUNDS) - 1)
122*9557SWyllys.Ingersoll@Sun.COM 
123*9557SWyllys.Ingersoll@Sun.COM /*
124*9557SWyllys.Ingersoll@Sun.COM  * get the integer value after rounds= where ever it occurs in the string.
125*9557SWyllys.Ingersoll@Sun.COM  * if the last char after the int is a , or $ that is fine anything else is an
126*9557SWyllys.Ingersoll@Sun.COM  * error.
127*9557SWyllys.Ingersoll@Sun.COM  */
128*9557SWyllys.Ingersoll@Sun.COM static uint32_t
129*9557SWyllys.Ingersoll@Sun.COM getrounds(const char *s)
130*9557SWyllys.Ingersoll@Sun.COM {
131*9557SWyllys.Ingersoll@Sun.COM 	char *r, *p, *e;
132*9557SWyllys.Ingersoll@Sun.COM 	long val;
133*9557SWyllys.Ingersoll@Sun.COM 
134*9557SWyllys.Ingersoll@Sun.COM 	if (s == NULL)
135*9557SWyllys.Ingersoll@Sun.COM 		return (0);
136*9557SWyllys.Ingersoll@Sun.COM 
137*9557SWyllys.Ingersoll@Sun.COM 	if ((r = strstr(s, ROUNDS)) == NULL) {
138*9557SWyllys.Ingersoll@Sun.COM 		return (0);
139*9557SWyllys.Ingersoll@Sun.COM 	}
140*9557SWyllys.Ingersoll@Sun.COM 
141*9557SWyllys.Ingersoll@Sun.COM 	if (strncmp(r, ROUNDS, ROUNDSLEN) != 0) {
142*9557SWyllys.Ingersoll@Sun.COM 		return (0);
143*9557SWyllys.Ingersoll@Sun.COM 	}
144*9557SWyllys.Ingersoll@Sun.COM 
145*9557SWyllys.Ingersoll@Sun.COM 	p = r + ROUNDSLEN;
146*9557SWyllys.Ingersoll@Sun.COM 	errno = 0;
147*9557SWyllys.Ingersoll@Sun.COM 	val = strtol(p, &e, 10);
148*9557SWyllys.Ingersoll@Sun.COM 	/*
149*9557SWyllys.Ingersoll@Sun.COM 	 * An error occured or there is non-numeric stuff at the end
150*9557SWyllys.Ingersoll@Sun.COM 	 * which isn't one of the crypt(3c) special chars ',' or '$'
151*9557SWyllys.Ingersoll@Sun.COM 	 */
152*9557SWyllys.Ingersoll@Sun.COM 	if (errno != 0 || val < 0 ||
153*9557SWyllys.Ingersoll@Sun.COM 	    !(*e == '\0' || *e == ',' || *e == '$')) {
154*9557SWyllys.Ingersoll@Sun.COM 		return (0);
155*9557SWyllys.Ingersoll@Sun.COM 	}
156*9557SWyllys.Ingersoll@Sun.COM 
157*9557SWyllys.Ingersoll@Sun.COM 	return ((uint32_t)val);
158*9557SWyllys.Ingersoll@Sun.COM }
159*9557SWyllys.Ingersoll@Sun.COM 
160*9557SWyllys.Ingersoll@Sun.COM 
1616532Swyllys char *
1626532Swyllys crypt_genhash_impl(char *ctbuffer,
1636532Swyllys 	    size_t ctbufflen,
1646532Swyllys 	    const char *plaintext,
1656532Swyllys 	    const char *switchsalt,
1666532Swyllys 	    const char **params)
1676532Swyllys {
1686532Swyllys 	int salt_len, plaintext_len, i;
1696532Swyllys 	char *salt;
1706532Swyllys 	uchar_t A[DIGEST_LEN];
1716532Swyllys 	uchar_t B[DIGEST_LEN];
1726532Swyllys 	uchar_t DP[DIGEST_LEN];
1736532Swyllys 	uchar_t DS[DIGEST_LEN];
1746532Swyllys 	DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS;
1756532Swyllys 	int rounds = ROUNDS_DEFAULT;
176*9557SWyllys.Ingersoll@Sun.COM 	int srounds = 0;
1776532Swyllys 	boolean_t custom_rounds = B_FALSE;
1786532Swyllys 	char *p;
1796532Swyllys 	char *P, *Pp;
1806532Swyllys 	char *S, *Sp;
1816532Swyllys 
1826532Swyllys 	/* Refine the salt */
1836532Swyllys 	salt = (char *)switchsalt;
1846532Swyllys 
1856532Swyllys 	/* skip our magic string */
1866532Swyllys 	if (strncmp((char *)salt, crypt_alg_magic, crypt_alg_magic_len) == 0) {
187*9557SWyllys.Ingersoll@Sun.COM 		salt += crypt_alg_magic_len + 1;
1886532Swyllys 	}
1896532Swyllys 
190*9557SWyllys.Ingersoll@Sun.COM 	srounds = getrounds(salt);
191*9557SWyllys.Ingersoll@Sun.COM 	if (srounds != 0) {
192*9557SWyllys.Ingersoll@Sun.COM 		rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
193*9557SWyllys.Ingersoll@Sun.COM 		custom_rounds = B_TRUE;
194*9557SWyllys.Ingersoll@Sun.COM 		p = strchr(salt, '$');
195*9557SWyllys.Ingersoll@Sun.COM 		if (p != NULL)
196*9557SWyllys.Ingersoll@Sun.COM 			salt = p + 1;
1976532Swyllys 	}
1986532Swyllys 
1996532Swyllys 	salt_len = MIN(strcspn(salt, "$"), MAX_SALT_LEN);
2006532Swyllys 	plaintext_len = strlen(plaintext);
2016532Swyllys 
2026532Swyllys 	/* 1. */
2036532Swyllys 	DIGESTInit(&ctxA);
2046532Swyllys 
2056532Swyllys 	/* 2. The password first, since that is what is most unknown */
2066532Swyllys 	DIGESTUpdate(&ctxA, plaintext, plaintext_len);
2076532Swyllys 
2086532Swyllys 	/* 3. Then the raw salt */
2096532Swyllys 	DIGESTUpdate(&ctxA, salt, salt_len);
2106532Swyllys 
2116532Swyllys 	/* 4. - 8. */
2126532Swyllys 	DIGESTInit(&ctxB);
2136532Swyllys 	DIGESTUpdate(&ctxB, plaintext, plaintext_len);
2146532Swyllys 	DIGESTUpdate(&ctxB, salt, salt_len);
2156532Swyllys 	DIGESTUpdate(&ctxB, plaintext, plaintext_len);
2166532Swyllys 	DIGESTFinal(B, &ctxB);
2176532Swyllys 
2186532Swyllys 	/* 9. - 10. */
2196532Swyllys 	for (i = plaintext_len; i > MIXCHARS; i -= MIXCHARS)
2206532Swyllys 		DIGESTUpdate(&ctxA, B, MIXCHARS);
2216532Swyllys 	DIGESTUpdate(&ctxA, B, i);
2226532Swyllys 
2236532Swyllys 	/* 11. */
2246532Swyllys 	for (i = plaintext_len; i > 0; i >>= 1) {
2256532Swyllys 		if ((i & 1) != 0) {
2266532Swyllys 			DIGESTUpdate(&ctxA, B, MIXCHARS);
2276532Swyllys 		} else {
2286532Swyllys 			DIGESTUpdate(&ctxA, plaintext, plaintext_len);
2296532Swyllys 		}
2306532Swyllys 	}
2316532Swyllys 
2326532Swyllys 	/* 12. */
2336532Swyllys 	DIGESTFinal(A, &ctxA);
2346532Swyllys 
2356532Swyllys 	/* 13. - 15. */
2366532Swyllys 	DIGESTInit(&ctxDP);
2376532Swyllys 	for (i = 0; i < plaintext_len; i++)
2386532Swyllys 		DIGESTUpdate(&ctxDP, plaintext, plaintext_len);
2396532Swyllys 	DIGESTFinal(DP, &ctxDP);
2406532Swyllys 
2416532Swyllys 	/* 16. */
2426532Swyllys 	Pp = P = alloca(plaintext_len);
2436532Swyllys 	for (i = plaintext_len; i >= MIXCHARS; i -= MIXCHARS) {
2446532Swyllys 		Pp = (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS;
2456532Swyllys 	}
2466532Swyllys 	memcpy(Pp, DP, i);
2476532Swyllys 
2486532Swyllys 	/* 17. - 19. */
2496532Swyllys 	DIGESTInit(&ctxDS);
2506532Swyllys 	for (i = 0; i < 16 + (uint8_t)A[0]; i++)
2516532Swyllys 		DIGESTUpdate(&ctxDS, salt, salt_len);
2526532Swyllys 	DIGESTFinal(DS, &ctxDS);
2536532Swyllys 
2546532Swyllys 	/* 20. */
2556532Swyllys 	Sp = S = alloca(salt_len);
2566532Swyllys 	for (i = salt_len; i >= MIXCHARS; i -= MIXCHARS) {
2576532Swyllys 		Sp = (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS;
2586532Swyllys 	}
2596532Swyllys 	memcpy(Sp, DS, i);
2606532Swyllys 
2616532Swyllys 	/*  21. */
2626532Swyllys 	for (i = 0; i < rounds; i++) {
2636532Swyllys 		DIGESTInit(&ctxC);
2646532Swyllys 
2656532Swyllys 		if ((i & 1) != 0) {
2666532Swyllys 			DIGESTUpdate(&ctxC, P, plaintext_len);
2676532Swyllys 		} else {
2686532Swyllys 			if (i == 0)
2696532Swyllys 				DIGESTUpdate(&ctxC, A, MIXCHARS);
2706532Swyllys 			else
2716532Swyllys 				DIGESTUpdate(&ctxC, DP, MIXCHARS);
2726532Swyllys 		}
2736532Swyllys 
2746532Swyllys 		if (i % 3 != 0) {
2756532Swyllys 			DIGESTUpdate(&ctxC, S, salt_len);
2766532Swyllys 		}
2776532Swyllys 
2786532Swyllys 		if (i % 7 != 0) {
2796532Swyllys 			DIGESTUpdate(&ctxC, P, plaintext_len);
2806532Swyllys 		}
2816532Swyllys 
2826532Swyllys 		if ((i & 1) != 0) {
2836532Swyllys 			if (i == 0)
2846532Swyllys 				DIGESTUpdate(&ctxC, A, MIXCHARS);
2856532Swyllys 			else
2866532Swyllys 				DIGESTUpdate(&ctxC, DP, MIXCHARS);
2876532Swyllys 		} else {
2886532Swyllys 			DIGESTUpdate(&ctxC, P, plaintext_len);
2896532Swyllys 		}
2906532Swyllys 		DIGESTFinal(DP, &ctxC);
2916532Swyllys 	}
2926532Swyllys 
2936532Swyllys 	/* 22. Now make the output string */
2946532Swyllys 	if (custom_rounds) {
2956532Swyllys 		(void) snprintf(ctbuffer, ctbufflen,
296*9557SWyllys.Ingersoll@Sun.COM 		    "%s$rounds=%zu$", crypt_alg_magic, rounds);
297*9557SWyllys.Ingersoll@Sun.COM 	} else {
298*9557SWyllys.Ingersoll@Sun.COM 		(void) snprintf(ctbuffer, ctbufflen,
299*9557SWyllys.Ingersoll@Sun.COM 		    "%s$", crypt_alg_magic);
3006532Swyllys 	}
3017314SWyllys.Ingersoll@Sun.COM 	(void) strncat(ctbuffer, (const char *)salt, salt_len);
3026532Swyllys 	(void) strlcat(ctbuffer, "$", ctbufflen);
303*9557SWyllys.Ingersoll@Sun.COM 
3046532Swyllys 	p = ctbuffer + strlen(ctbuffer);
3056532Swyllys 	ctbufflen -= strlen(ctbuffer);
3066532Swyllys 
3076532Swyllys #ifdef CRYPT_SHA256
3086532Swyllys 	b64_from_24bit(DP[ 0], DP[10], DP[20], 4);
3096532Swyllys 	b64_from_24bit(DP[21], DP[ 1], DP[11], 4);
3106532Swyllys 	b64_from_24bit(DP[12], DP[22], DP[ 2], 4);
3116532Swyllys 	b64_from_24bit(DP[ 3], DP[13], DP[23], 4);
3126532Swyllys 	b64_from_24bit(DP[24], DP[ 4], DP[14], 4);
3136532Swyllys 	b64_from_24bit(DP[15], DP[25], DP[ 5], 4);
3146532Swyllys 	b64_from_24bit(DP[ 6], DP[16], DP[26], 4);
3156532Swyllys 	b64_from_24bit(DP[27], DP[ 7], DP[17], 4);
3166532Swyllys 	b64_from_24bit(DP[18], DP[28], DP[ 8], 4);
3176532Swyllys 	b64_from_24bit(DP[ 9], DP[19], DP[29], 4);
3186532Swyllys 	b64_from_24bit(0, DP[31], DP[30], 3);
3196532Swyllys #elif CRYPT_SHA512
3206532Swyllys 	b64_from_24bit(DP[ 0], DP[21], DP[42], 4);
3216532Swyllys 	b64_from_24bit(DP[22], DP[43], DP[ 1], 4);
3226532Swyllys 	b64_from_24bit(DP[44], DP[ 2], DP[23], 4);
3236532Swyllys 	b64_from_24bit(DP[ 3], DP[24], DP[45], 4);
3246532Swyllys 	b64_from_24bit(DP[25], DP[46], DP[ 4], 4);
3256532Swyllys 	b64_from_24bit(DP[47], DP[ 5], DP[26], 4);
3266532Swyllys 	b64_from_24bit(DP[ 6], DP[27], DP[48], 4);
3276532Swyllys 	b64_from_24bit(DP[28], DP[49], DP[ 7], 4);
3286532Swyllys 	b64_from_24bit(DP[50], DP[ 8], DP[29], 4);
3296532Swyllys 	b64_from_24bit(DP[ 9], DP[30], DP[51], 4);
3306532Swyllys 	b64_from_24bit(DP[31], DP[52], DP[10], 4);
3316532Swyllys 	b64_from_24bit(DP[53], DP[11], DP[32], 4);
3326532Swyllys 	b64_from_24bit(DP[12], DP[33], DP[54], 4);
3336532Swyllys 	b64_from_24bit(DP[34], DP[55], DP[13], 4);
3346532Swyllys 	b64_from_24bit(DP[56], DP[14], DP[35], 4);
3356532Swyllys 	b64_from_24bit(DP[15], DP[36], DP[57], 4);
3366532Swyllys 	b64_from_24bit(DP[37], DP[58], DP[16], 4);
3376532Swyllys 	b64_from_24bit(DP[59], DP[17], DP[38], 4);
3386532Swyllys 	b64_from_24bit(DP[18], DP[39], DP[60], 4);
3396532Swyllys 	b64_from_24bit(DP[40], DP[61], DP[19], 4);
3406532Swyllys 	b64_from_24bit(DP[62], DP[20], DP[41], 4);
3416532Swyllys 	b64_from_24bit(0, 0, DP[63], 2);
3426532Swyllys #endif
3436532Swyllys 	*p = '\0';
3446532Swyllys 
3456532Swyllys 	(void) memset(A, 0, sizeof (A));
3466532Swyllys 	(void) memset(B, 0, sizeof (B));
3476532Swyllys 	(void) memset(DP, 0, sizeof (DP));
3486532Swyllys 	(void) memset(DS, 0, sizeof (DS));
3496532Swyllys 
3506532Swyllys 	return (ctbuffer);
3516532Swyllys }
3526532Swyllys 
3536532Swyllys char *
3546532Swyllys crypt_gensalt_impl(char *gsbuffer,
3556532Swyllys 	    size_t gsbufflen,
3566532Swyllys 	    const char *oldsalt,
3576532Swyllys 	    const struct passwd *userinfo,
3586532Swyllys 	    const char **params)
3596532Swyllys {
3606532Swyllys 	int fd;
3616532Swyllys 	int err;
3626532Swyllys 	ssize_t got;
3636532Swyllys 	uint64_t rndval;
364*9557SWyllys.Ingersoll@Sun.COM 	uint32_t confrounds = 0;
365*9557SWyllys.Ingersoll@Sun.COM 	uint32_t saltrounds;
366*9557SWyllys.Ingersoll@Sun.COM 	char rndstr[sizeof (rndval) + 1];
367*9557SWyllys.Ingersoll@Sun.COM 	int i;
368*9557SWyllys.Ingersoll@Sun.COM 
369*9557SWyllys.Ingersoll@Sun.COM 	for (i = 0; params != NULL && params[i] != NULL; i++) {
370*9557SWyllys.Ingersoll@Sun.COM 		if (strncmp(params[i], ROUNDS, ROUNDSLEN) == 0) {
371*9557SWyllys.Ingersoll@Sun.COM 			confrounds = getrounds(params[i]);
372*9557SWyllys.Ingersoll@Sun.COM 		} else {
373*9557SWyllys.Ingersoll@Sun.COM 			errno = EINVAL;
374*9557SWyllys.Ingersoll@Sun.COM 			return (NULL);
375*9557SWyllys.Ingersoll@Sun.COM 		}
376*9557SWyllys.Ingersoll@Sun.COM 	}
377*9557SWyllys.Ingersoll@Sun.COM 
378*9557SWyllys.Ingersoll@Sun.COM 	/*
379*9557SWyllys.Ingersoll@Sun.COM 	 * If the config file has a higher value for rounds= than what
380*9557SWyllys.Ingersoll@Sun.COM 	 * was in the old salt use that, otherwise keep what was in the
381*9557SWyllys.Ingersoll@Sun.COM 	 * old salt.
382*9557SWyllys.Ingersoll@Sun.COM 	 */
383*9557SWyllys.Ingersoll@Sun.COM 	saltrounds = getrounds(oldsalt);
384*9557SWyllys.Ingersoll@Sun.COM 	if (confrounds > saltrounds) {
385*9557SWyllys.Ingersoll@Sun.COM 		saltrounds = confrounds;
386*9557SWyllys.Ingersoll@Sun.COM 	}
3876532Swyllys 
3886532Swyllys 	if ((fd = open("/dev/urandom", O_RDONLY)) == -1) {
3896532Swyllys 		return (NULL);
3906532Swyllys 	}
3916532Swyllys 
3926532Swyllys 	got = read(fd, &rndval, sizeof (rndval));
3936532Swyllys 	if (got < sizeof (rndval)) {
3946532Swyllys 		err = errno;
3956532Swyllys 		(void) close(fd);
3966532Swyllys 		errno = err;
3976532Swyllys 		return (NULL);
3986532Swyllys 	}
3996532Swyllys 	(void) close(fd);
4006532Swyllys 
401*9557SWyllys.Ingersoll@Sun.COM 	to64((char *)&rndstr, rndval, sizeof (rndval));
402*9557SWyllys.Ingersoll@Sun.COM 	rndstr[sizeof (rndstr) - 1] = 0;
403*9557SWyllys.Ingersoll@Sun.COM 
404*9557SWyllys.Ingersoll@Sun.COM 	if (saltrounds > 0) {
405*9557SWyllys.Ingersoll@Sun.COM 		if (snprintf(gsbuffer, gsbufflen,
406*9557SWyllys.Ingersoll@Sun.COM 		    "%s$rounds=%d$",
407*9557SWyllys.Ingersoll@Sun.COM 		    crypt_alg_magic, saltrounds) >= gsbufflen)
408*9557SWyllys.Ingersoll@Sun.COM 			goto fail;
409*9557SWyllys.Ingersoll@Sun.COM 	} else {
410*9557SWyllys.Ingersoll@Sun.COM 		if (snprintf(gsbuffer, gsbufflen,
411*9557SWyllys.Ingersoll@Sun.COM 		    "%s$", crypt_alg_magic) >= gsbufflen)
412*9557SWyllys.Ingersoll@Sun.COM 			goto fail;
413*9557SWyllys.Ingersoll@Sun.COM 	}
414*9557SWyllys.Ingersoll@Sun.COM 	if (strlcat(gsbuffer, rndstr, gsbufflen) >= gsbufflen)
415*9557SWyllys.Ingersoll@Sun.COM 		goto fail;
416*9557SWyllys.Ingersoll@Sun.COM 	if (strlcat(gsbuffer, "$", gsbufflen) >= gsbufflen)
417*9557SWyllys.Ingersoll@Sun.COM 		goto fail;
418*9557SWyllys.Ingersoll@Sun.COM 
419*9557SWyllys.Ingersoll@Sun.COM 	return (gsbuffer);
420*9557SWyllys.Ingersoll@Sun.COM 
421*9557SWyllys.Ingersoll@Sun.COM fail:
422*9557SWyllys.Ingersoll@Sun.COM 	(void) memset(gsbuffer, 0, gsbufflen);
4236532Swyllys 	return (gsbuffer);
4246532Swyllys }
425