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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Portions of this code:
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 * ----------------------------------------------------------------------------
35 * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $
39 #include <sys/types.h>
51 static const char crypt_alg_magic
[] = "$1$";
55 static uchar_t itoa64
[] = /* 0 ... 63 => ascii - 64 */
56 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
59 to64(char *s
, uint64_t v
, int n
)
62 *s
++ = itoa64
[v
& 0x3f];
70 crypt_genhash_impl(char *ctbuffer
,
72 const char *plaintext
,
73 const char *switchsalt
,
79 uchar_t final
[16]; /* XXX: 16 is some number from the orig source */
81 const int crypt_alg_magic_len
= strlen(crypt_alg_magic
);
84 sp
= (uchar_t
*)switchsalt
;
86 /* skip our magic string */
87 if (strncmp((char *)sp
, crypt_alg_magic
, crypt_alg_magic_len
) == 0) {
88 sp
+= crypt_alg_magic_len
;
91 /* Salt stops at the first $, max SALT_LEN chars */
92 for (ep
= sp
; *ep
&& *ep
!= '$' && ep
< (sp
+ SALT_LEN
); ep
++)
99 /* The password first, since that is what is most unknown */
100 MD5Update(&ctx
, (uchar_t
*)plaintext
, strlen(plaintext
));
102 /* Then our magic string */
103 MD5Update(&ctx
, (uchar_t
*)crypt_alg_magic
, strlen(crypt_alg_magic
));
105 /* Then the raw salt */
106 MD5Update(&ctx
, (uchar_t
*)sp
, sl
);
108 /* Then just as many characters of the MD5(plaintext,salt,plaintext) */
110 MD5Update(&ctx1
, (uchar_t
*)plaintext
, strlen(plaintext
));
111 MD5Update(&ctx1
, sp
, sl
);
112 MD5Update(&ctx1
, (uchar_t
*)plaintext
, strlen(plaintext
));
113 MD5Final(final
, &ctx1
);
114 for (pl
= strlen(plaintext
); pl
> 0; pl
-= 16)
115 MD5Update(&ctx
, final
, pl
> 16 ? 16 : pl
);
117 /* Don't leave anything around in vm they could use. */
118 (void) memset(final
, 0, sizeof (final
));
120 /* Then something really weird... */
121 for (i
= strlen(plaintext
); i
; i
>>= 1) {
123 MD5Update(&ctx
, final
, 1);
125 MD5Update(&ctx
, (uchar_t
*)plaintext
, 1);
129 /* Now make the output string */
130 (void) strlcpy(ctbuffer
, crypt_alg_magic
, ctbufflen
);
131 (void) strncat(ctbuffer
, (const char *)sp
, sl
);
132 (void) strlcat(ctbuffer
, "$", ctbufflen
);
134 MD5Final(final
, &ctx
);
137 * and now, just to make sure things don't run too fast
138 * On a 60 Mhz Pentium this takes 34 msec, so you would
139 * need 30 seconds to build a 1000 entry dictionary...
141 for (i
= 0; i
< 1000; i
++) {
144 MD5Update(&ctx1
, (uchar_t
*)plaintext
,
147 MD5Update(&ctx1
, final
, 16);
150 MD5Update(&ctx1
, sp
, sl
);
153 MD5Update(&ctx1
, (uchar_t
*)plaintext
,
157 MD5Update(&ctx1
, final
, 16);
159 MD5Update(&ctx1
, (uchar_t
*)plaintext
,
161 MD5Final(final
, &ctx1
);
164 p
= ctbuffer
+ strlen(ctbuffer
);
166 l
= (final
[ 0]<<16) | (final
[ 6]<<8) | final
[12]; to64(p
, l
, 4); p
+= 4;
167 l
= (final
[ 1]<<16) | (final
[ 7]<<8) | final
[13]; to64(p
, l
, 4); p
+= 4;
168 l
= (final
[ 2]<<16) | (final
[ 8]<<8) | final
[14]; to64(p
, l
, 4); p
+= 4;
169 l
= (final
[ 3]<<16) | (final
[ 9]<<8) | final
[15]; to64(p
, l
, 4); p
+= 4;
170 l
= (final
[ 4]<<16) | (final
[10]<<8) | final
[ 5]; to64(p
, l
, 4); p
+= 4;
171 l
= final
[11]; to64(p
, l
, 2); p
+= 2;
174 /* Don't leave anything around in vm they could use. */
175 (void) memset(final
, 0, sizeof (final
));
183 crypt_gensalt_impl(char *gsbuffer
,
186 const struct passwd
*userinfo
,
194 if ((fd
= open("/dev/urandom", O_RDONLY
)) == -1) {
198 (void) strlcpy(gsbuffer
, crypt_alg_magic
, gsbufflen
);
200 got
= read(fd
, &rndval
, sizeof (rndval
));
201 if (got
< sizeof (rndval
)) {
207 to64(&gsbuffer
[strlen(crypt_alg_magic
)], rndval
, sizeof (rndval
));