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