xref: /dflybsd-src/lib/libcrypt/crypt-blowfish.c (revision e0369600668aca82fea4c3901659ea23bc610fc0)
10fe46dc6SMatthew Dillon /*
20fe46dc6SMatthew Dillon  * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
30fe46dc6SMatthew Dillon  * All rights reserved.
40fe46dc6SMatthew Dillon  *
50fe46dc6SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
60fe46dc6SMatthew Dillon  * modification, are permitted provided that the following conditions
70fe46dc6SMatthew Dillon  * are met:
80fe46dc6SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
90fe46dc6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
100fe46dc6SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
110fe46dc6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
120fe46dc6SMatthew Dillon  *    documentation and/or other materials provided with the distribution.
130fe46dc6SMatthew Dillon  * 3. All advertising materials mentioning features or use of this software
140fe46dc6SMatthew Dillon  *    must display the following acknowledgement:
150fe46dc6SMatthew Dillon  *      This product includes software developed by Niels Provos.
160fe46dc6SMatthew Dillon  * 4. The name of the author may not be used to endorse or promote products
170fe46dc6SMatthew Dillon  *    derived from this software without specific prior written permission.
180fe46dc6SMatthew Dillon  *
190fe46dc6SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
200fe46dc6SMatthew Dillon  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
210fe46dc6SMatthew Dillon  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
220fe46dc6SMatthew Dillon  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
230fe46dc6SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
240fe46dc6SMatthew Dillon  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
250fe46dc6SMatthew Dillon  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
260fe46dc6SMatthew Dillon  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
270fe46dc6SMatthew Dillon  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
280fe46dc6SMatthew Dillon  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
290fe46dc6SMatthew Dillon  *
300fe46dc6SMatthew Dillon  * $FreeBSD: src/secure/lib/libcrypt/crypt-blowfish.c,v 1.1.2.1 2001/05/24 12:20:03 markm Exp $
310fe46dc6SMatthew Dillon  */
320fe46dc6SMatthew Dillon 
330fe46dc6SMatthew Dillon /* This password hashing algorithm was designed by David Mazieres
340fe46dc6SMatthew Dillon  * <dm@lcs.mit.edu> and works as follows:
350fe46dc6SMatthew Dillon  *
360fe46dc6SMatthew Dillon  * 1. state := InitState ()
370fe46dc6SMatthew Dillon  * 2. state := ExpandKey (state, salt, password) 3.
380fe46dc6SMatthew Dillon  * REPEAT rounds:
390fe46dc6SMatthew Dillon  *	state := ExpandKey (state, 0, salt)
400fe46dc6SMatthew Dillon  *      state := ExpandKey(state, 0, password)
410fe46dc6SMatthew Dillon  * 4. ctext := "OrpheanBeholderScryDoubt"
420fe46dc6SMatthew Dillon  * 5. REPEAT 64:
430fe46dc6SMatthew Dillon  * 	ctext := Encrypt_ECB (state, ctext);
440fe46dc6SMatthew Dillon  * 6. RETURN Concatenate (salt, ctext);
450fe46dc6SMatthew Dillon  *
460fe46dc6SMatthew Dillon  */
470fe46dc6SMatthew Dillon 
480fe46dc6SMatthew Dillon /*
490fe46dc6SMatthew Dillon  * FreeBSD implementation by Paul Herman <pherman@frenchfries.net>
500fe46dc6SMatthew Dillon  */
510fe46dc6SMatthew Dillon 
520fe46dc6SMatthew Dillon #if 0
530fe46dc6SMatthew Dillon #include <stdio.h>
540fe46dc6SMatthew Dillon #endif
550fe46dc6SMatthew Dillon 
560fe46dc6SMatthew Dillon #include <stdio.h>
570fe46dc6SMatthew Dillon #include <stdlib.h>
580fe46dc6SMatthew Dillon #include <sys/types.h>
590fe46dc6SMatthew Dillon #include <string.h>
600fe46dc6SMatthew Dillon #include <pwd.h>
610fe46dc6SMatthew Dillon #include "blowfish.h"
62*e0369600Szrj #include "crypt.h"
630fe46dc6SMatthew Dillon 
640fe46dc6SMatthew Dillon /* This implementation is adaptable to current computing power.
650fe46dc6SMatthew Dillon  * You can have up to 2^31 rounds which should be enough for some
660fe46dc6SMatthew Dillon  * time to come.
670fe46dc6SMatthew Dillon  */
680fe46dc6SMatthew Dillon 
690fe46dc6SMatthew Dillon #define BCRYPT_VERSION '2'
700fe46dc6SMatthew Dillon #define BCRYPT_MAXSALT 16	/* Precomputation is just so nice */
710fe46dc6SMatthew Dillon #define BCRYPT_BLOCKS 6		/* Ciphertext blocks */
720fe46dc6SMatthew Dillon #define BCRYPT_MINROUNDS 16	/* we have log2(rounds) in salt */
730fe46dc6SMatthew Dillon 
740fe46dc6SMatthew Dillon char   *bcrypt_gensalt (u_int8_t);
750fe46dc6SMatthew Dillon 
760fe46dc6SMatthew Dillon static void encode_salt (char *, u_int8_t *, u_int16_t, u_int8_t);
770fe46dc6SMatthew Dillon static void encode_base64 (u_int8_t *, u_int8_t *, u_int16_t);
780fe46dc6SMatthew Dillon static void decode_base64 (u_int8_t *, u_int16_t, u_int8_t *);
790fe46dc6SMatthew Dillon 
800fe46dc6SMatthew Dillon static char    encrypted[_PASSWORD_LEN];
810fe46dc6SMatthew Dillon static char    gsalt[BCRYPT_MAXSALT * 4 / 3 + 1];
820fe46dc6SMatthew Dillon 
830fe46dc6SMatthew Dillon static const u_int8_t Base64Code[] =
840fe46dc6SMatthew Dillon "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
850fe46dc6SMatthew Dillon 
860fe46dc6SMatthew Dillon static const u_int8_t index_64[128] =
870fe46dc6SMatthew Dillon {
880fe46dc6SMatthew Dillon 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
890fe46dc6SMatthew Dillon 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
900fe46dc6SMatthew Dillon 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
910fe46dc6SMatthew Dillon 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
920fe46dc6SMatthew Dillon 	255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
930fe46dc6SMatthew Dillon 	56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
940fe46dc6SMatthew Dillon 	255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
950fe46dc6SMatthew Dillon 	7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
960fe46dc6SMatthew Dillon 	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
970fe46dc6SMatthew Dillon 	255, 255, 255, 255, 255, 255, 28, 29, 30,
980fe46dc6SMatthew Dillon 	31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
990fe46dc6SMatthew Dillon 	41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
1000fe46dc6SMatthew Dillon 	51, 52, 53, 255, 255, 255, 255, 255
1010fe46dc6SMatthew Dillon };
1020fe46dc6SMatthew Dillon #define CHAR64(c)  ( (c) > 127 ? 255 : index_64[(c)])
1030fe46dc6SMatthew Dillon 
1040fe46dc6SMatthew Dillon static void
decode_base64(u_int8_t * buffer,u_int16_t len,u_int8_t * data)1050fe46dc6SMatthew Dillon decode_base64(u_int8_t *buffer, u_int16_t len, u_int8_t *data)
1060fe46dc6SMatthew Dillon {
1070fe46dc6SMatthew Dillon 	u_int8_t *bp = buffer;
1080fe46dc6SMatthew Dillon 	u_int8_t *p = data;
1090fe46dc6SMatthew Dillon 	u_int8_t c1, c2, c3, c4;
1100fe46dc6SMatthew Dillon 	while (bp < buffer + len) {
1110fe46dc6SMatthew Dillon 		c1 = CHAR64(*p);
1120fe46dc6SMatthew Dillon 		c2 = CHAR64(*(p + 1));
1130fe46dc6SMatthew Dillon 
1140fe46dc6SMatthew Dillon 		/* Invalid data */
1150fe46dc6SMatthew Dillon 		if (c1 == 255 || c2 == 255)
1160fe46dc6SMatthew Dillon 			break;
1170fe46dc6SMatthew Dillon 
1180fe46dc6SMatthew Dillon 		*bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);
1190fe46dc6SMatthew Dillon 		if (bp >= buffer + len)
1200fe46dc6SMatthew Dillon 			break;
1210fe46dc6SMatthew Dillon 
1220fe46dc6SMatthew Dillon 		c3 = CHAR64(*(p + 2));
1230fe46dc6SMatthew Dillon 		if (c3 == 255)
1240fe46dc6SMatthew Dillon 			break;
1250fe46dc6SMatthew Dillon 
1260fe46dc6SMatthew Dillon 		*bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
1270fe46dc6SMatthew Dillon 		if (bp >= buffer + len)
1280fe46dc6SMatthew Dillon 			break;
1290fe46dc6SMatthew Dillon 
1300fe46dc6SMatthew Dillon 		c4 = CHAR64(*(p + 3));
1310fe46dc6SMatthew Dillon 		if (c4 == 255)
1320fe46dc6SMatthew Dillon 			break;
1330fe46dc6SMatthew Dillon 		*bp++ = ((c3 & 0x03) << 6) | c4;
1340fe46dc6SMatthew Dillon 
1350fe46dc6SMatthew Dillon 		p += 4;
1360fe46dc6SMatthew Dillon 	}
1370fe46dc6SMatthew Dillon }
1380fe46dc6SMatthew Dillon 
1390fe46dc6SMatthew Dillon static void
encode_salt(char * salt,u_int8_t * csalt,u_int16_t clen,u_int8_t logr)1400fe46dc6SMatthew Dillon encode_salt(char *salt, u_int8_t *csalt, u_int16_t clen, u_int8_t logr)
1410fe46dc6SMatthew Dillon {
1420fe46dc6SMatthew Dillon 	salt[0] = '$';
1430fe46dc6SMatthew Dillon 	salt[1] = BCRYPT_VERSION;
1440fe46dc6SMatthew Dillon 	salt[2] = 'a';
1450fe46dc6SMatthew Dillon 	salt[3] = '$';
1460fe46dc6SMatthew Dillon 
1470fe46dc6SMatthew Dillon 	snprintf(salt + 4, 4, "%2.2u$", logr);
1480fe46dc6SMatthew Dillon 
1490fe46dc6SMatthew Dillon 	encode_base64((u_int8_t *) salt + 7, csalt, clen);
1500fe46dc6SMatthew Dillon }
1510fe46dc6SMatthew Dillon /* Generates a salt for this version of crypt.
1520fe46dc6SMatthew Dillon    Since versions may change. Keeping this here
1530fe46dc6SMatthew Dillon    seems sensible.
1540fe46dc6SMatthew Dillon  */
1550fe46dc6SMatthew Dillon 
1560fe46dc6SMatthew Dillon char *
bcrypt_gensalt(u_int8_t log_rounds)1570fe46dc6SMatthew Dillon bcrypt_gensalt(u_int8_t log_rounds)
1580fe46dc6SMatthew Dillon {
1590fe46dc6SMatthew Dillon 	u_int8_t csalt[BCRYPT_MAXSALT];
1600fe46dc6SMatthew Dillon 	u_int16_t i;
1610fe46dc6SMatthew Dillon 	u_int32_t seed = 0;
1620fe46dc6SMatthew Dillon 
1630fe46dc6SMatthew Dillon 	for (i = 0; i < BCRYPT_MAXSALT; i++) {
1640fe46dc6SMatthew Dillon 		if (i % 4 == 0)
1650fe46dc6SMatthew Dillon 			seed = arc4random();
1660fe46dc6SMatthew Dillon 		csalt[i] = seed & 0xff;
1670fe46dc6SMatthew Dillon 		seed = seed >> 8;
1680fe46dc6SMatthew Dillon 	}
1690fe46dc6SMatthew Dillon 
1700fe46dc6SMatthew Dillon 	if (log_rounds < 4)
1710fe46dc6SMatthew Dillon 		log_rounds = 4;
1720fe46dc6SMatthew Dillon 
1730fe46dc6SMatthew Dillon 	encode_salt(gsalt, csalt, BCRYPT_MAXSALT, log_rounds);
1740fe46dc6SMatthew Dillon 	return gsalt;
1750fe46dc6SMatthew Dillon }
1760fe46dc6SMatthew Dillon /* We handle $Vers$log2(NumRounds)$salt+passwd$
1770fe46dc6SMatthew Dillon    i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
1780fe46dc6SMatthew Dillon 
1790fe46dc6SMatthew Dillon char   *
crypt_blowfish(const char * key,const char * salt)1802ae2c6edSSascha Wildner crypt_blowfish(const char *key, const char *salt)
1810fe46dc6SMatthew Dillon {
1820fe46dc6SMatthew Dillon 	blf_ctx state;
1830fe46dc6SMatthew Dillon 	u_int32_t rounds, i, k;
1840fe46dc6SMatthew Dillon 	u_int16_t j;
1850fe46dc6SMatthew Dillon 	u_int8_t key_len, salt_len, logr, minor;
1860fe46dc6SMatthew Dillon 	u_int8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt";
1870fe46dc6SMatthew Dillon 	u_int8_t csalt[BCRYPT_MAXSALT];
1880fe46dc6SMatthew Dillon 	u_int32_t cdata[BCRYPT_BLOCKS];
189*e0369600Szrj 	static const char *magic = "$2a$04$";
1900fe46dc6SMatthew Dillon 
1910fe46dc6SMatthew Dillon 		/* Defaults */
1920fe46dc6SMatthew Dillon 	minor = 'a';
1930fe46dc6SMatthew Dillon 	logr = 4;
1940fe46dc6SMatthew Dillon 	rounds = 1 << logr;
1950fe46dc6SMatthew Dillon 
1960fe46dc6SMatthew Dillon         /* If it starts with the magic string, then skip that */
1970fe46dc6SMatthew Dillon 	if(!strncmp(salt, magic, strlen(magic))) {
1980fe46dc6SMatthew Dillon 		salt += strlen(magic);
1990fe46dc6SMatthew Dillon 	}
2000fe46dc6SMatthew Dillon 	else if (*salt == '$') {
2010fe46dc6SMatthew Dillon 
2020fe46dc6SMatthew Dillon 		/* Discard "$" identifier */
2030fe46dc6SMatthew Dillon 		salt++;
2040fe46dc6SMatthew Dillon 
2050fe46dc6SMatthew Dillon 		if (*salt > BCRYPT_VERSION) {
2060fe46dc6SMatthew Dillon 			/* How do I handle errors ? Return NULL according to
2070fe46dc6SMatthew Dillon 			   crypt(3) */
2080fe46dc6SMatthew Dillon 			return NULL;
2090fe46dc6SMatthew Dillon 		}
2100fe46dc6SMatthew Dillon 
2110fe46dc6SMatthew Dillon 		/* Check for minor versions */
2120fe46dc6SMatthew Dillon 		if (salt[1] != '$') {
2130fe46dc6SMatthew Dillon 			 switch (salt[1]) {
2140fe46dc6SMatthew Dillon 			 case 'a':
2150fe46dc6SMatthew Dillon 				 /* 'ab' should not yield the same as 'abab' */
2160fe46dc6SMatthew Dillon 				 minor = salt[1];
2170fe46dc6SMatthew Dillon 				 salt++;
2180fe46dc6SMatthew Dillon 				 break;
2190fe46dc6SMatthew Dillon 			 default:
2200fe46dc6SMatthew Dillon 				 return NULL;
2210fe46dc6SMatthew Dillon 			 }
2220fe46dc6SMatthew Dillon 		} else
2230fe46dc6SMatthew Dillon 			 minor = 0;
2240fe46dc6SMatthew Dillon 
2250fe46dc6SMatthew Dillon 		/* Discard version + "$" identifier */
2260fe46dc6SMatthew Dillon 		salt += 2;
2270fe46dc6SMatthew Dillon 
2280fe46dc6SMatthew Dillon 		if (salt[2] != '$')
2290fe46dc6SMatthew Dillon 			/* Out of sync with passwd entry */
2300fe46dc6SMatthew Dillon 			return NULL;
2310fe46dc6SMatthew Dillon 
2320fe46dc6SMatthew Dillon 		/* Computer power doesnt increase linear, 2^x should be fine */
2330fe46dc6SMatthew Dillon 		if ((rounds = (u_int32_t) 1 << (logr = atoi(salt))) < BCRYPT_MINROUNDS)
2340fe46dc6SMatthew Dillon 			return NULL;
2350fe46dc6SMatthew Dillon 
2360fe46dc6SMatthew Dillon 		/* Discard num rounds + "$" identifier */
2370fe46dc6SMatthew Dillon 		salt += 3;
2380fe46dc6SMatthew Dillon 	}
2390fe46dc6SMatthew Dillon 
2400fe46dc6SMatthew Dillon 
2410fe46dc6SMatthew Dillon 	/* We dont want the base64 salt but the raw data */
2420fe46dc6SMatthew Dillon 	decode_base64(csalt, BCRYPT_MAXSALT, (u_int8_t *) salt);
2430fe46dc6SMatthew Dillon 	salt_len = BCRYPT_MAXSALT;
2440fe46dc6SMatthew Dillon 	key_len = strlen(key) + (minor >= 'a' ? 1 : 0);
2450fe46dc6SMatthew Dillon 
2460fe46dc6SMatthew Dillon 	/* Setting up S-Boxes and Subkeys */
2470fe46dc6SMatthew Dillon 	Blowfish_initstate(&state);
2480fe46dc6SMatthew Dillon 	Blowfish_expandstate(&state, csalt, salt_len,
2490fe46dc6SMatthew Dillon 	    (u_int8_t *) key, key_len);
2500fe46dc6SMatthew Dillon 	for (k = 0; k < rounds; k++) {
2510fe46dc6SMatthew Dillon 		Blowfish_expand0state(&state, (u_int8_t *) key, key_len);
2520fe46dc6SMatthew Dillon 		Blowfish_expand0state(&state, csalt, salt_len);
2530fe46dc6SMatthew Dillon 	}
2540fe46dc6SMatthew Dillon 
2550fe46dc6SMatthew Dillon 	/* This can be precomputed later */
2560fe46dc6SMatthew Dillon 	j = 0;
2570fe46dc6SMatthew Dillon 	for (i = 0; i < BCRYPT_BLOCKS; i++)
2580fe46dc6SMatthew Dillon 		cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_BLOCKS, &j);
2590fe46dc6SMatthew Dillon 
2600fe46dc6SMatthew Dillon 	/* Now do the encryption */
2610fe46dc6SMatthew Dillon 	for (k = 0; k < 64; k++)
2620fe46dc6SMatthew Dillon 		blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
2630fe46dc6SMatthew Dillon 
2640fe46dc6SMatthew Dillon 	for (i = 0; i < BCRYPT_BLOCKS; i++) {
2650fe46dc6SMatthew Dillon 		ciphertext[4 * i + 3] = cdata[i] & 0xff;
2660fe46dc6SMatthew Dillon 		cdata[i] = cdata[i] >> 8;
2670fe46dc6SMatthew Dillon 		ciphertext[4 * i + 2] = cdata[i] & 0xff;
2680fe46dc6SMatthew Dillon 		cdata[i] = cdata[i] >> 8;
2690fe46dc6SMatthew Dillon 		ciphertext[4 * i + 1] = cdata[i] & 0xff;
2700fe46dc6SMatthew Dillon 		cdata[i] = cdata[i] >> 8;
2710fe46dc6SMatthew Dillon 		ciphertext[4 * i + 0] = cdata[i] & 0xff;
2720fe46dc6SMatthew Dillon 	}
2730fe46dc6SMatthew Dillon 
2740fe46dc6SMatthew Dillon 
2750fe46dc6SMatthew Dillon 	i = 0;
2760fe46dc6SMatthew Dillon 	encrypted[i++] = '$';
2770fe46dc6SMatthew Dillon 	encrypted[i++] = BCRYPT_VERSION;
2780fe46dc6SMatthew Dillon 	if (minor)
2790fe46dc6SMatthew Dillon 		encrypted[i++] = minor;
2800fe46dc6SMatthew Dillon 	encrypted[i++] = '$';
2810fe46dc6SMatthew Dillon 
2820fe46dc6SMatthew Dillon 	snprintf(encrypted + i, 4, "%2.2u$", logr);
2830fe46dc6SMatthew Dillon 
2840fe46dc6SMatthew Dillon 	encode_base64((u_int8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT);
2850fe46dc6SMatthew Dillon 	encode_base64((u_int8_t *) encrypted + strlen(encrypted), ciphertext,
2860fe46dc6SMatthew Dillon 	    4 * BCRYPT_BLOCKS - 1);
2870fe46dc6SMatthew Dillon 	return encrypted;
2880fe46dc6SMatthew Dillon }
2890fe46dc6SMatthew Dillon 
2900fe46dc6SMatthew Dillon static void
encode_base64(u_int8_t * buffer,u_int8_t * data,u_int16_t len)2910fe46dc6SMatthew Dillon encode_base64(u_int8_t *buffer, u_int8_t *data, u_int16_t len)
2920fe46dc6SMatthew Dillon {
2930fe46dc6SMatthew Dillon 	u_int8_t *bp = buffer;
2940fe46dc6SMatthew Dillon 	u_int8_t *p = data;
2950fe46dc6SMatthew Dillon 	u_int8_t c1, c2;
2960fe46dc6SMatthew Dillon 	while (p < data + len) {
2970fe46dc6SMatthew Dillon 		c1 = *p++;
2980fe46dc6SMatthew Dillon 		*bp++ = Base64Code[(c1 >> 2)];
2990fe46dc6SMatthew Dillon 		c1 = (c1 & 0x03) << 4;
3000fe46dc6SMatthew Dillon 		if (p >= data + len) {
3010fe46dc6SMatthew Dillon 			*bp++ = Base64Code[c1];
3020fe46dc6SMatthew Dillon 			break;
3030fe46dc6SMatthew Dillon 		}
3040fe46dc6SMatthew Dillon 		c2 = *p++;
3050fe46dc6SMatthew Dillon 		c1 |= (c2 >> 4) & 0x0f;
3060fe46dc6SMatthew Dillon 		*bp++ = Base64Code[c1];
3070fe46dc6SMatthew Dillon 		c1 = (c2 & 0x0f) << 2;
3080fe46dc6SMatthew Dillon 		if (p >= data + len) {
3090fe46dc6SMatthew Dillon 			*bp++ = Base64Code[c1];
3100fe46dc6SMatthew Dillon 			break;
3110fe46dc6SMatthew Dillon 		}
3120fe46dc6SMatthew Dillon 		c2 = *p++;
3130fe46dc6SMatthew Dillon 		c1 |= (c2 >> 6) & 0x03;
3140fe46dc6SMatthew Dillon 		*bp++ = Base64Code[c1];
3150fe46dc6SMatthew Dillon 		*bp++ = Base64Code[c2 & 0x3f];
3160fe46dc6SMatthew Dillon 	}
3170fe46dc6SMatthew Dillon 	*bp = '\0';
3180fe46dc6SMatthew Dillon }
3190fe46dc6SMatthew Dillon #if 0
3200fe46dc6SMatthew Dillon void
3210fe46dc6SMatthew Dillon main()
3220fe46dc6SMatthew Dillon {
3230fe46dc6SMatthew Dillon 	char    blubber[73];
3240fe46dc6SMatthew Dillon 	char    salt[100];
3250fe46dc6SMatthew Dillon 	char   *p;
3260fe46dc6SMatthew Dillon 	salt[0] = '$';
3270fe46dc6SMatthew Dillon 	salt[1] = BCRYPT_VERSION;
3280fe46dc6SMatthew Dillon 	salt[2] = '$';
3290fe46dc6SMatthew Dillon 
3300fe46dc6SMatthew Dillon 	snprintf(salt + 3, 4, "%2.2u$", 5);
3310fe46dc6SMatthew Dillon 
3320fe46dc6SMatthew Dillon 	printf("24 bytes of salt: ");
3330fe46dc6SMatthew Dillon 	fgets(salt + 6, 94, stdin);
3340fe46dc6SMatthew Dillon 	salt[99] = 0;
3350fe46dc6SMatthew Dillon 	printf("72 bytes of password: ");
3360fe46dc6SMatthew Dillon 	fpurge(stdin);
3370fe46dc6SMatthew Dillon 	fgets(blubber, 73, stdin);
3380fe46dc6SMatthew Dillon 	blubber[72] = 0;
3390fe46dc6SMatthew Dillon 
3400fe46dc6SMatthew Dillon 	p = crypt(blubber, salt);
3410fe46dc6SMatthew Dillon 	printf("Passwd entry: %s\n\n", p);
3420fe46dc6SMatthew Dillon 
3430fe46dc6SMatthew Dillon 	p = bcrypt_gensalt(5);
3440fe46dc6SMatthew Dillon 	printf("Generated salt: %s\n", p);
3450fe46dc6SMatthew Dillon 	p = crypt(blubber, p);
3460fe46dc6SMatthew Dillon 	printf("Passwd entry: %s\n", p);
3470fe46dc6SMatthew Dillon }
3480fe46dc6SMatthew Dillon #endif
349