1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Portions of this code:
31*0Sstevel@tonic-gate  * ----------------------------------------------------------------------------
32*0Sstevel@tonic-gate  * "THE BEER-WARE LICENSE" (Revision 42):
33*0Sstevel@tonic-gate  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
34*0Sstevel@tonic-gate  * can do whatever you want with this stuff. If we meet some day, and you think
35*0Sstevel@tonic-gate  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
36*0Sstevel@tonic-gate  * ----------------------------------------------------------------------------
37*0Sstevel@tonic-gate  *
38*0Sstevel@tonic-gate  * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $
39*0Sstevel@tonic-gate  *
40*0Sstevel@tonic-gate  */
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #include <sys/types.h>
43*0Sstevel@tonic-gate #include <sys/stat.h>
44*0Sstevel@tonic-gate #include <fcntl.h>
45*0Sstevel@tonic-gate #include <unistd.h>
46*0Sstevel@tonic-gate #include <string.h>
47*0Sstevel@tonic-gate #include <strings.h>
48*0Sstevel@tonic-gate #include <stdio.h>
49*0Sstevel@tonic-gate #include <errno.h>
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate #include <md5.h>
52*0Sstevel@tonic-gate #include <crypt.h>
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate static const char crypt_alg_magic[] = "$1$";
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate #define	SALT_LEN	8
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate static uchar_t itoa64[] =		/* 0 ... 63 => ascii - 64 */
59*0Sstevel@tonic-gate 	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate static void
62*0Sstevel@tonic-gate to64(char *s, uint64_t v, int n)
63*0Sstevel@tonic-gate {
64*0Sstevel@tonic-gate 	while (--n >= 0) {
65*0Sstevel@tonic-gate 		*s++ = itoa64[v&0x3f];
66*0Sstevel@tonic-gate 		v >>= 6;
67*0Sstevel@tonic-gate 	}
68*0Sstevel@tonic-gate }
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate char *
72*0Sstevel@tonic-gate crypt_genhash_impl(char *ctbuffer,
73*0Sstevel@tonic-gate 	    size_t ctbufflen,
74*0Sstevel@tonic-gate 	    const char *plaintext,
75*0Sstevel@tonic-gate 	    const char *switchsalt,
76*0Sstevel@tonic-gate 	    const char **params)
77*0Sstevel@tonic-gate {
78*0Sstevel@tonic-gate 	char *p;
79*0Sstevel@tonic-gate 	int sl, l, pl, i;
80*0Sstevel@tonic-gate 	uchar_t *sp, *ep;
81*0Sstevel@tonic-gate 	uchar_t final[16]; /* XXX: 16 is some number from the orig source */
82*0Sstevel@tonic-gate 	MD5_CTX ctx, ctx1;
83*0Sstevel@tonic-gate 	const int crypt_alg_magic_len = strlen(crypt_alg_magic);
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	/* Refine the salt */
86*0Sstevel@tonic-gate 	sp = (uchar_t *)switchsalt;
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 	/* skip our magic string */
89*0Sstevel@tonic-gate 	if (strncmp((char *)sp, crypt_alg_magic, crypt_alg_magic_len) == 0) {
90*0Sstevel@tonic-gate 		sp += crypt_alg_magic_len;
91*0Sstevel@tonic-gate 	}
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	/* Salt stops at the first $, max SALT_LEN chars */
94*0Sstevel@tonic-gate 	for (ep = sp; *ep && *ep != '$' && ep < (sp + SALT_LEN); ep++)
95*0Sstevel@tonic-gate 		continue;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	sl = ep - sp;
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	MD5Init(&ctx);
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	/* The password first, since that is what is most unknown */
102*0Sstevel@tonic-gate 	MD5Update(&ctx, (uchar_t *)plaintext, strlen(plaintext));
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	/* Then our magic string */
105*0Sstevel@tonic-gate 	MD5Update(&ctx, (uchar_t *)crypt_alg_magic, strlen(crypt_alg_magic));
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	/* Then the raw salt */
108*0Sstevel@tonic-gate 	MD5Update(&ctx, (uchar_t *)sp, sl);
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	/* Then just as many characters of the MD5(plaintext,salt,plaintext) */
111*0Sstevel@tonic-gate 	MD5Init(&ctx1);
112*0Sstevel@tonic-gate 	MD5Update(&ctx1, (uchar_t *)plaintext, strlen(plaintext));
113*0Sstevel@tonic-gate 	MD5Update(&ctx1, sp, sl);
114*0Sstevel@tonic-gate 	MD5Update(&ctx1, (uchar_t *)plaintext, strlen(plaintext));
115*0Sstevel@tonic-gate 	MD5Final(final, &ctx1);
116*0Sstevel@tonic-gate 	for (pl = strlen(plaintext); pl > 0; pl -= 16)
117*0Sstevel@tonic-gate 		MD5Update(&ctx, final, pl > 16 ? 16 : pl);
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 	/* Don't leave anything around in vm they could use. */
120*0Sstevel@tonic-gate 	memset(final, 0, sizeof (final));
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	/* Then something really weird... */
123*0Sstevel@tonic-gate 	for (i = strlen(plaintext); i; i >>= 1) {
124*0Sstevel@tonic-gate 		if (i & 1) {
125*0Sstevel@tonic-gate 			MD5Update(&ctx, final, 1);
126*0Sstevel@tonic-gate 		} else {
127*0Sstevel@tonic-gate 			MD5Update(&ctx, (uchar_t *)plaintext, 1);
128*0Sstevel@tonic-gate 		}
129*0Sstevel@tonic-gate 	}
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	/* Now make the output string */
132*0Sstevel@tonic-gate 	(void) strlcpy(ctbuffer, crypt_alg_magic, ctbufflen);
133*0Sstevel@tonic-gate 	(void) strncat(ctbuffer, (const char *)sp, sl);
134*0Sstevel@tonic-gate 	(void) strlcat(ctbuffer, "$", ctbufflen);
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	MD5Final(final, &ctx);
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 	/*
139*0Sstevel@tonic-gate 	 * and now, just to make sure things don't run too fast
140*0Sstevel@tonic-gate 	 * On a 60 Mhz Pentium this takes 34 msec, so you would
141*0Sstevel@tonic-gate 	 * need 30 seconds to build a 1000 entry dictionary...
142*0Sstevel@tonic-gate 	 */
143*0Sstevel@tonic-gate 	for (i = 0; i < 1000; i++) {
144*0Sstevel@tonic-gate 		MD5Init(&ctx1);
145*0Sstevel@tonic-gate 		if (i & 1)
146*0Sstevel@tonic-gate 			MD5Update(&ctx1, (uchar_t *)plaintext,
147*0Sstevel@tonic-gate 			    strlen(plaintext));
148*0Sstevel@tonic-gate 		else
149*0Sstevel@tonic-gate 			MD5Update(&ctx1, final, 16);
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 		if (i % 3)
152*0Sstevel@tonic-gate 			MD5Update(&ctx1, sp, sl);
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 		if (i % 7)
155*0Sstevel@tonic-gate 			MD5Update(&ctx1, (uchar_t *)plaintext,
156*0Sstevel@tonic-gate 			    strlen(plaintext));
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 		if (i & 1)
159*0Sstevel@tonic-gate 			MD5Update(&ctx1, final, 16);
160*0Sstevel@tonic-gate 		else
161*0Sstevel@tonic-gate 			MD5Update(&ctx1, (uchar_t *)plaintext,
162*0Sstevel@tonic-gate 			    strlen(plaintext));
163*0Sstevel@tonic-gate 		MD5Final(final, &ctx1);
164*0Sstevel@tonic-gate 	}
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	p = ctbuffer + strlen(ctbuffer);
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
169*0Sstevel@tonic-gate 	l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
170*0Sstevel@tonic-gate 	l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
171*0Sstevel@tonic-gate 	l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
172*0Sstevel@tonic-gate 	l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
173*0Sstevel@tonic-gate 	l = final[11]; to64(p, l, 2); p += 2;
174*0Sstevel@tonic-gate 	*p = '\0';
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	/* Don't leave anything around in vm they could use. */
177*0Sstevel@tonic-gate 	memset(final, 0, sizeof (final));
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 	return (ctbuffer);
180*0Sstevel@tonic-gate }
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate char *
184*0Sstevel@tonic-gate crypt_gensalt_impl(char *gsbuffer,
185*0Sstevel@tonic-gate 	    size_t gsbufflen,
186*0Sstevel@tonic-gate 	    const char *oldsalt,
187*0Sstevel@tonic-gate 	    const struct passwd *userinfo,
188*0Sstevel@tonic-gate 	    const char **params)
189*0Sstevel@tonic-gate {
190*0Sstevel@tonic-gate 	int fd;
191*0Sstevel@tonic-gate 	int err;
192*0Sstevel@tonic-gate 	ssize_t got;
193*0Sstevel@tonic-gate 	uint64_t rndval;
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	if ((fd = open("/dev/urandom", O_RDONLY)) == -1) {
196*0Sstevel@tonic-gate 		return (NULL);
197*0Sstevel@tonic-gate 	}
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	(void) strlcpy(gsbuffer, crypt_alg_magic, gsbufflen);
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	got = read(fd, &rndval, sizeof (rndval));
202*0Sstevel@tonic-gate 	if (got < sizeof (rndval)) {
203*0Sstevel@tonic-gate 		err = errno;
204*0Sstevel@tonic-gate 		(void) close(fd);
205*0Sstevel@tonic-gate 		errno = err;
206*0Sstevel@tonic-gate 		return (NULL);
207*0Sstevel@tonic-gate 	}
208*0Sstevel@tonic-gate 	to64(&gsbuffer[strlen(crypt_alg_magic)], rndval, sizeof (rndval));
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	(void) close(fd);
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	return (gsbuffer);
213*0Sstevel@tonic-gate }
214