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 /*	$OpenBSD: bcrypt.c,v 1.16 2002/02/19 19:39:36 millert Exp $	*/
23*0Sstevel@tonic-gate 
24*0Sstevel@tonic-gate /*
25*0Sstevel@tonic-gate  * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
26*0Sstevel@tonic-gate  * All rights reserved.
27*0Sstevel@tonic-gate  *
28*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
29*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
30*0Sstevel@tonic-gate  * are met:
31*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
32*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
33*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
34*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
35*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
36*0Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
37*0Sstevel@tonic-gate  *    must display the following acknowledgement:
38*0Sstevel@tonic-gate  *      This product includes software developed by Niels Provos.
39*0Sstevel@tonic-gate  * 4. The name of the author may not be used to endorse or promote products
40*0Sstevel@tonic-gate  *    derived from this software without specific prior written permission.
41*0Sstevel@tonic-gate  *
42*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
43*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45*0Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
46*0Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48*0Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49*0Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50*0Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
51*0Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52*0Sstevel@tonic-gate  */
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /*
55*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
56*0Sstevel@tonic-gate  * Use is subject to license terms.
57*0Sstevel@tonic-gate  */
58*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /* This password hashing algorithm was designed by David Mazieres
61*0Sstevel@tonic-gate  * <dm@lcs.mit.edu> and works as follows:
62*0Sstevel@tonic-gate  *
63*0Sstevel@tonic-gate  * 1. state := InitState ()
64*0Sstevel@tonic-gate  * 2. state := ExpandKey (state, salt, password) 3.
65*0Sstevel@tonic-gate  * REPEAT rounds:
66*0Sstevel@tonic-gate  *	state := ExpandKey (state, 0, salt)
67*0Sstevel@tonic-gate  *      state := ExpandKey(state, 0, password)
68*0Sstevel@tonic-gate  * 4. ctext := "OrpheanBeholderScryDoubt"
69*0Sstevel@tonic-gate  * 5. REPEAT 64:
70*0Sstevel@tonic-gate  * 	ctext := Encrypt_ECB (state, ctext);
71*0Sstevel@tonic-gate  * 6. RETURN Concatenate (salt, ctext);
72*0Sstevel@tonic-gate  *
73*0Sstevel@tonic-gate  */
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate #if 0
76*0Sstevel@tonic-gate #include <stdio.h>
77*0Sstevel@tonic-gate #endif
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate #include <stdio.h>
80*0Sstevel@tonic-gate #include <stdlib.h>
81*0Sstevel@tonic-gate #include <sys/types.h>
82*0Sstevel@tonic-gate #include <string.h>
83*0Sstevel@tonic-gate #include <pwd.h>
84*0Sstevel@tonic-gate #include <blf.h>
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate extern uint32_t arc4random();
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate /* This implementation is adaptable to current computing power.
89*0Sstevel@tonic-gate  * You can have up to 2^31 rounds which should be enough for some
90*0Sstevel@tonic-gate  * time to come.
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate #define BCRYPT_VERSION '2'
94*0Sstevel@tonic-gate #define BCRYPT_MAXSALT 16	/* Precomputation is just so nice */
95*0Sstevel@tonic-gate #define BCRYPT_BLOCKS 6		/* Ciphertext blocks */
96*0Sstevel@tonic-gate #define BCRYPT_MINROUNDS 16	/* we have log2(rounds) in salt */
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate char   *bcrypt_gensalt(uint8_t);
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate static void encode_salt(char *, uint8_t *, uint16_t, uint8_t);
101*0Sstevel@tonic-gate static void encode_base64(uint8_t *, uint8_t *, uint16_t);
102*0Sstevel@tonic-gate static void decode_base64(uint8_t *, uint16_t, uint8_t *);
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate static char    encrypted[128]; /* _PASSWORD_LEN in <pwd.h> on OpenBSD */
105*0Sstevel@tonic-gate static char    gsalt[BCRYPT_MAXSALT * 4 / 3 + 1];
106*0Sstevel@tonic-gate static char    error[] = ":";
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate static uint8_t Base64Code[] =
109*0Sstevel@tonic-gate "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate static uint8_t index_64[128] =
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
114*0Sstevel@tonic-gate 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
115*0Sstevel@tonic-gate 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
116*0Sstevel@tonic-gate 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
117*0Sstevel@tonic-gate 	255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
118*0Sstevel@tonic-gate 	56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
119*0Sstevel@tonic-gate 	255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
120*0Sstevel@tonic-gate 	7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
121*0Sstevel@tonic-gate 	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
122*0Sstevel@tonic-gate 	255, 255, 255, 255, 255, 255, 28, 29, 30,
123*0Sstevel@tonic-gate 	31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
124*0Sstevel@tonic-gate 	41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
125*0Sstevel@tonic-gate 	51, 52, 53, 255, 255, 255, 255, 255
126*0Sstevel@tonic-gate };
127*0Sstevel@tonic-gate #define CHAR64(c)  ( (c) > 127 ? 255 : index_64[(c)])
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate static void
130*0Sstevel@tonic-gate decode_base64(uint8_t *buffer, uint16_t len, uint8_t *data)
131*0Sstevel@tonic-gate {
132*0Sstevel@tonic-gate 	uint8_t *bp = buffer;
133*0Sstevel@tonic-gate 	uint8_t *p = data;
134*0Sstevel@tonic-gate 	uint8_t c1, c2, c3, c4;
135*0Sstevel@tonic-gate 	while (bp < buffer + len) {
136*0Sstevel@tonic-gate 		c1 = CHAR64(*p);
137*0Sstevel@tonic-gate 		c2 = CHAR64(*(p + 1));
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 		/* Invalid data */
140*0Sstevel@tonic-gate 		if (c1 == 255 || c2 == 255)
141*0Sstevel@tonic-gate 			break;
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 		*bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);
144*0Sstevel@tonic-gate 		if (bp >= buffer + len)
145*0Sstevel@tonic-gate 			break;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 		c3 = CHAR64(*(p + 2));
148*0Sstevel@tonic-gate 		if (c3 == 255)
149*0Sstevel@tonic-gate 			break;
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 		*bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
152*0Sstevel@tonic-gate 		if (bp >= buffer + len)
153*0Sstevel@tonic-gate 			break;
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 		c4 = CHAR64(*(p + 3));
156*0Sstevel@tonic-gate 		if (c4 == 255)
157*0Sstevel@tonic-gate 			break;
158*0Sstevel@tonic-gate 		*bp++ = ((c3 & 0x03) << 6) | c4;
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 		p += 4;
161*0Sstevel@tonic-gate 	}
162*0Sstevel@tonic-gate }
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate static void
165*0Sstevel@tonic-gate encode_salt(char *salt, uint8_t *csalt, uint16_t clen, uint8_t logr)
166*0Sstevel@tonic-gate {
167*0Sstevel@tonic-gate 	salt[0] = '$';
168*0Sstevel@tonic-gate 	salt[1] = BCRYPT_VERSION;
169*0Sstevel@tonic-gate 	salt[2] = 'a';
170*0Sstevel@tonic-gate 	salt[3] = '$';
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	(void) snprintf(salt + 4, 4, "%2.2u$", logr);
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	encode_base64((uint8_t *) salt + 7, csalt, clen);
175*0Sstevel@tonic-gate }
176*0Sstevel@tonic-gate /* Generates a salt for this version of crypt.
177*0Sstevel@tonic-gate    Since versions may change. Keeping this here
178*0Sstevel@tonic-gate    seems sensible.
179*0Sstevel@tonic-gate  */
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate char *
182*0Sstevel@tonic-gate bcrypt_gensalt(uint8_t log_rounds)
183*0Sstevel@tonic-gate {
184*0Sstevel@tonic-gate 	uint8_t csalt[BCRYPT_MAXSALT];
185*0Sstevel@tonic-gate 	uint16_t i;
186*0Sstevel@tonic-gate 	uint32_t seed = 0;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	for (i = 0; i < BCRYPT_MAXSALT; i++) {
189*0Sstevel@tonic-gate 		if (i % 4 == 0)
190*0Sstevel@tonic-gate 			seed = arc4random();
191*0Sstevel@tonic-gate 		csalt[i] = seed & 0xff;
192*0Sstevel@tonic-gate 		seed = seed >> 8;
193*0Sstevel@tonic-gate 	}
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	if (log_rounds < 4)
196*0Sstevel@tonic-gate 		log_rounds = 4;
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 	encode_salt(gsalt, csalt, BCRYPT_MAXSALT, log_rounds);
199*0Sstevel@tonic-gate 	return gsalt;
200*0Sstevel@tonic-gate }
201*0Sstevel@tonic-gate /* We handle $Vers$log2(NumRounds)$salt+passwd$
202*0Sstevel@tonic-gate    i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate char   *
205*0Sstevel@tonic-gate bcrypt(key, salt)
206*0Sstevel@tonic-gate 	const char   *key;
207*0Sstevel@tonic-gate 	const char   *salt;
208*0Sstevel@tonic-gate {
209*0Sstevel@tonic-gate 	blf_ctx state;
210*0Sstevel@tonic-gate 	uint32_t rounds, i, k;
211*0Sstevel@tonic-gate 	uint16_t j;
212*0Sstevel@tonic-gate 	uint8_t key_len, salt_len, logr, minor;
213*0Sstevel@tonic-gate 	uint8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt";
214*0Sstevel@tonic-gate 	uint8_t csalt[BCRYPT_MAXSALT];
215*0Sstevel@tonic-gate 	uint32_t cdata[BCRYPT_BLOCKS];
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	/* Discard "$" identifier */
218*0Sstevel@tonic-gate 	salt++;
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	if (*salt > BCRYPT_VERSION) {
221*0Sstevel@tonic-gate 		/* How do I handle errors ? Return ':' */
222*0Sstevel@tonic-gate 		return error;
223*0Sstevel@tonic-gate 	}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	/* Check for minor versions */
226*0Sstevel@tonic-gate 	if (salt[1] != '$') {
227*0Sstevel@tonic-gate 		 switch (salt[1]) {
228*0Sstevel@tonic-gate 		 case 'a':
229*0Sstevel@tonic-gate 			 /* 'ab' should not yield the same as 'abab' */
230*0Sstevel@tonic-gate 			 minor = salt[1];
231*0Sstevel@tonic-gate 			 salt++;
232*0Sstevel@tonic-gate 			 break;
233*0Sstevel@tonic-gate 		 default:
234*0Sstevel@tonic-gate 			 return error;
235*0Sstevel@tonic-gate 		 }
236*0Sstevel@tonic-gate 	} else
237*0Sstevel@tonic-gate 		 minor = 0;
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	/* Discard version + "$" identifier */
240*0Sstevel@tonic-gate 	salt += 2;
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	if (salt[2] != '$')
243*0Sstevel@tonic-gate 		/* Out of sync with passwd entry */
244*0Sstevel@tonic-gate 		return error;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	/* Computer power doesn't increase linear, 2^x should be fine */
247*0Sstevel@tonic-gate 	if ((rounds = (uint32_t) 1 << (logr = atoi(salt))) < BCRYPT_MINROUNDS)
248*0Sstevel@tonic-gate 		return error;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	/* Discard num rounds + "$" identifier */
251*0Sstevel@tonic-gate 	salt += 3;
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)
254*0Sstevel@tonic-gate 		return error;
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	/* We dont want the base64 salt but the raw data */
257*0Sstevel@tonic-gate 	decode_base64(csalt, BCRYPT_MAXSALT, (uint8_t *) salt);
258*0Sstevel@tonic-gate 	salt_len = BCRYPT_MAXSALT;
259*0Sstevel@tonic-gate 	key_len = strlen(key) + (minor >= 'a' ? 1 : 0);
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	/* Setting up S-Boxes and Subkeys */
262*0Sstevel@tonic-gate 	Blowfish_initstate(&state);
263*0Sstevel@tonic-gate 	Blowfish_expandstate(&state, csalt, salt_len,
264*0Sstevel@tonic-gate 	    (uint8_t *) key, key_len);
265*0Sstevel@tonic-gate 	for (k = 0; k < rounds; k++) {
266*0Sstevel@tonic-gate 		Blowfish_expand0state(&state, (uint8_t *) key, key_len);
267*0Sstevel@tonic-gate 		Blowfish_expand0state(&state, csalt, salt_len);
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	/* This can be precomputed later */
271*0Sstevel@tonic-gate 	j = 0;
272*0Sstevel@tonic-gate 	for (i = 0; i < BCRYPT_BLOCKS; i++)
273*0Sstevel@tonic-gate 		cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_BLOCKS, &j);
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	/* Now do the encryption */
276*0Sstevel@tonic-gate 	for (k = 0; k < 64; k++)
277*0Sstevel@tonic-gate 		blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	for (i = 0; i < BCRYPT_BLOCKS; i++) {
280*0Sstevel@tonic-gate 		ciphertext[4 * i + 3] = cdata[i] & 0xff;
281*0Sstevel@tonic-gate 		cdata[i] = cdata[i] >> 8;
282*0Sstevel@tonic-gate 		ciphertext[4 * i + 2] = cdata[i] & 0xff;
283*0Sstevel@tonic-gate 		cdata[i] = cdata[i] >> 8;
284*0Sstevel@tonic-gate 		ciphertext[4 * i + 1] = cdata[i] & 0xff;
285*0Sstevel@tonic-gate 		cdata[i] = cdata[i] >> 8;
286*0Sstevel@tonic-gate 		ciphertext[4 * i + 0] = cdata[i] & 0xff;
287*0Sstevel@tonic-gate 	}
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	i = 0;
291*0Sstevel@tonic-gate 	encrypted[i++] = '$';
292*0Sstevel@tonic-gate 	encrypted[i++] = BCRYPT_VERSION;
293*0Sstevel@tonic-gate 	if (minor)
294*0Sstevel@tonic-gate 		encrypted[i++] = minor;
295*0Sstevel@tonic-gate 	encrypted[i++] = '$';
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	(void) snprintf(encrypted + i, 4, "%2.2u$", logr);
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	encode_base64((uint8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT);
300*0Sstevel@tonic-gate 	encode_base64((uint8_t *) encrypted + strlen(encrypted), ciphertext,
301*0Sstevel@tonic-gate 	    4 * BCRYPT_BLOCKS - 1);
302*0Sstevel@tonic-gate 	return encrypted;
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate static void
306*0Sstevel@tonic-gate encode_base64(uint8_t *buffer, uint8_t *data, uint16_t len)
307*0Sstevel@tonic-gate {
308*0Sstevel@tonic-gate 	uint8_t *bp = buffer;
309*0Sstevel@tonic-gate 	uint8_t *p = data;
310*0Sstevel@tonic-gate 	uint8_t c1, c2;
311*0Sstevel@tonic-gate 	while (p < data + len) {
312*0Sstevel@tonic-gate 		c1 = *p++;
313*0Sstevel@tonic-gate 		*bp++ = Base64Code[(c1 >> 2)];
314*0Sstevel@tonic-gate 		c1 = (c1 & 0x03) << 4;
315*0Sstevel@tonic-gate 		if (p >= data + len) {
316*0Sstevel@tonic-gate 			*bp++ = Base64Code[c1];
317*0Sstevel@tonic-gate 			break;
318*0Sstevel@tonic-gate 		}
319*0Sstevel@tonic-gate 		c2 = *p++;
320*0Sstevel@tonic-gate 		c1 |= (c2 >> 4) & 0x0f;
321*0Sstevel@tonic-gate 		*bp++ = Base64Code[c1];
322*0Sstevel@tonic-gate 		c1 = (c2 & 0x0f) << 2;
323*0Sstevel@tonic-gate 		if (p >= data + len) {
324*0Sstevel@tonic-gate 			*bp++ = Base64Code[c1];
325*0Sstevel@tonic-gate 			break;
326*0Sstevel@tonic-gate 		}
327*0Sstevel@tonic-gate 		c2 = *p++;
328*0Sstevel@tonic-gate 		c1 |= (c2 >> 6) & 0x03;
329*0Sstevel@tonic-gate 		*bp++ = Base64Code[c1];
330*0Sstevel@tonic-gate 		*bp++ = Base64Code[c2 & 0x3f];
331*0Sstevel@tonic-gate 	}
332*0Sstevel@tonic-gate 	*bp = '\0';
333*0Sstevel@tonic-gate }
334*0Sstevel@tonic-gate #if 0
335*0Sstevel@tonic-gate void
336*0Sstevel@tonic-gate main()
337*0Sstevel@tonic-gate {
338*0Sstevel@tonic-gate 	char    blubber[73];
339*0Sstevel@tonic-gate 	char    salt[100];
340*0Sstevel@tonic-gate 	char   *p;
341*0Sstevel@tonic-gate 	salt[0] = '$';
342*0Sstevel@tonic-gate 	salt[1] = BCRYPT_VERSION;
343*0Sstevel@tonic-gate 	salt[2] = '$';
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	snprintf(salt + 3, 4, "%2.2u$", 5);
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	printf("24 bytes of salt: ");
348*0Sstevel@tonic-gate 	fgets(salt + 6, 94, stdin);
349*0Sstevel@tonic-gate 	salt[99] = 0;
350*0Sstevel@tonic-gate 	printf("72 bytes of password: ");
351*0Sstevel@tonic-gate 	fpurge(stdin);
352*0Sstevel@tonic-gate 	fgets(blubber, 73, stdin);
353*0Sstevel@tonic-gate 	blubber[72] = 0;
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	p = crypt(blubber, salt);
356*0Sstevel@tonic-gate 	printf("Passwd entry: %s\n\n", p);
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	p = bcrypt_gensalt(5);
359*0Sstevel@tonic-gate 	printf("Generated salt: %s\n", p);
360*0Sstevel@tonic-gate 	p = crypt(blubber, p);
361*0Sstevel@tonic-gate 	printf("Passwd entry: %s\n", p);
362*0Sstevel@tonic-gate }
363*0Sstevel@tonic-gate #endif
364