xref: /openbsd-src/lib/libc/crypt/bcrypt.c (revision d82e6535c6efd8305182f77041b2246ccfae1196)
1*d82e6535Spirofti /*	$OpenBSD: bcrypt.c,v 1.58 2020/07/06 13:33:05 pirofti Exp $	*/
258720cefSmillert 
36d84a8a1Sprovos /*
49573d548Stedu  * Copyright (c) 2014 Ted Unangst <tedu@openbsd.org>
5be33bfdfStedu  * Copyright (c) 1997 Niels Provos <provos@umich.edu>
66d84a8a1Sprovos  *
7be33bfdfStedu  * Permission to use, copy, modify, and distribute this software for any
8be33bfdfStedu  * purpose with or without fee is hereby granted, provided that the above
9be33bfdfStedu  * copyright notice and this permission notice appear in all copies.
10d5b08a54Sprovos  *
11be33bfdfStedu  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12be33bfdfStedu  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13be33bfdfStedu  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14be33bfdfStedu  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15be33bfdfStedu  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16be33bfdfStedu  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17be33bfdfStedu  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
186d84a8a1Sprovos  */
196d84a8a1Sprovos /* This password hashing algorithm was designed by David Mazieres
206d84a8a1Sprovos  * <dm@lcs.mit.edu> and works as follows:
216d84a8a1Sprovos  *
226d84a8a1Sprovos  * 1. state := InitState ()
2351141693Sderaadt  * 2. state := ExpandKey (state, salt, password)
2451141693Sderaadt  * 3. REPEAT rounds:
256d84a8a1Sprovos  *      state := ExpandKey (state, 0, password)
2651141693Sderaadt  *	state := ExpandKey (state, 0, salt)
27473a5892Sprovos  * 4. ctext := "OrpheanBeholderScryDoubt"
286d84a8a1Sprovos  * 5. REPEAT 64:
296d84a8a1Sprovos  * 	ctext := Encrypt_ECB (state, ctext);
306d84a8a1Sprovos  * 6. RETURN Concatenate (salt, ctext);
316d84a8a1Sprovos  *
326d84a8a1Sprovos  */
336d84a8a1Sprovos 
34d0288240Schl #include <sys/types.h>
35d0288240Schl #include <blf.h>
36d0288240Schl #include <ctype.h>
3777fd6317Stedu #include <errno.h>
38d0288240Schl #include <pwd.h>
3958720cefSmillert #include <stdio.h>
406d84a8a1Sprovos #include <stdlib.h>
416d84a8a1Sprovos #include <string.h>
420ccb1e69Sguenther #include <time.h>
436d84a8a1Sprovos 
446d84a8a1Sprovos /* This implementation is adaptable to current computing power.
456d84a8a1Sprovos  * You can have up to 2^31 rounds which should be enough for some
466d84a8a1Sprovos  * time to come.
476d84a8a1Sprovos  */
486d84a8a1Sprovos 
496d84a8a1Sprovos #define BCRYPT_VERSION '2'
506d84a8a1Sprovos #define BCRYPT_MAXSALT 16	/* Precomputation is just so nice */
51c6555c4fStedu #define BCRYPT_WORDS 6		/* Ciphertext words */
520e59d8e3Stedu #define BCRYPT_MINLOGROUNDS 4	/* we have log2(rounds) in salt */
536d84a8a1Sprovos 
549573d548Stedu #define	BCRYPT_SALTSPACE	(7 + (BCRYPT_MAXSALT * 4 + 2) / 3 + 1)
555105d936Stedu #define	BCRYPT_HASHSPACE	61
569573d548Stedu 
57c72b5b24Smillert char   *bcrypt_gensalt(u_int8_t);
586d84a8a1Sprovos 
59ad45bbcfStedu static int encode_base64(char *, const u_int8_t *, size_t);
60ad45bbcfStedu static int decode_base64(u_int8_t *, size_t, const char *);
616d84a8a1Sprovos 
629573d548Stedu /*
639573d548Stedu  * Generates a salt for this version of crypt.
646d84a8a1Sprovos  */
6560bc2a0fStedu static int
bcrypt_initsalt(int log_rounds,uint8_t * salt,size_t saltbuflen)669573d548Stedu bcrypt_initsalt(int log_rounds, uint8_t *salt, size_t saltbuflen)
676d84a8a1Sprovos {
689573d548Stedu 	uint8_t csalt[BCRYPT_MAXSALT];
699573d548Stedu 
702ae21647Stedu 	if (saltbuflen < BCRYPT_SALTSPACE) {
712ae21647Stedu 		errno = EINVAL;
729573d548Stedu 		return -1;
732ae21647Stedu 	}
74d937c54eSprovos 
75769d2f2fStedu 	arc4random_buf(csalt, sizeof(csalt));
766d84a8a1Sprovos 
776d84a8a1Sprovos 	if (log_rounds < 4)
786d84a8a1Sprovos 		log_rounds = 4;
79e0c55b37Sotto 	else if (log_rounds > 31)
80e0c55b37Sotto 		log_rounds = 31;
816d84a8a1Sprovos 
826b630d86Stedu 	snprintf(salt, saltbuflen, "$2b$%2.2u$", log_rounds);
83ad45bbcfStedu 	encode_base64(salt + 7, csalt, sizeof(csalt));
846d84a8a1Sprovos 
859573d548Stedu 	return 0;
869573d548Stedu }
879573d548Stedu 
889573d548Stedu /*
899573d548Stedu  * the core bcrypt function
909573d548Stedu  */
9160bc2a0fStedu static int
bcrypt_hashpass(const char * key,const char * salt,char * encrypted,size_t encryptedlen)929573d548Stedu bcrypt_hashpass(const char *key, const char *salt, char *encrypted,
939573d548Stedu     size_t encryptedlen)
946d84a8a1Sprovos {
956d84a8a1Sprovos 	blf_ctx state;
966d84a8a1Sprovos 	u_int32_t rounds, i, k;
976d84a8a1Sprovos 	u_int16_t j;
984ffb3abbStedu 	size_t key_len;
994ffb3abbStedu 	u_int8_t salt_len, logr, minor;
100c6555c4fStedu 	u_int8_t ciphertext[4 * BCRYPT_WORDS] = "OrpheanBeholderScryDoubt";
1016d84a8a1Sprovos 	u_int8_t csalt[BCRYPT_MAXSALT];
102c6555c4fStedu 	u_int32_t cdata[BCRYPT_WORDS];
1032b2cf4b1Sprovos 
1045105d936Stedu 	if (encryptedlen < BCRYPT_HASHSPACE)
1052ae21647Stedu 		goto inval;
1065105d936Stedu 
1072c4c53c9Stedu 	/* Check and discard "$" identifier */
1082c4c53c9Stedu 	if (salt[0] != '$')
1092ae21647Stedu 		goto inval;
1102c4c53c9Stedu 	salt += 1;
1116d84a8a1Sprovos 
1122c4c53c9Stedu 	if (salt[0] != BCRYPT_VERSION)
1132ae21647Stedu 		goto inval;
1142b2cf4b1Sprovos 
1152b2cf4b1Sprovos 	/* Check for minor versions */
1162c4c53c9Stedu 	switch ((minor = salt[1])) {
1172c4c53c9Stedu 	case 'a':
1182c4c53c9Stedu 		key_len = (u_int8_t)(strlen(key) + 1);
1192c4c53c9Stedu 		break;
1202c4c53c9Stedu 	case 'b':
1212c4c53c9Stedu 		/* strlen() returns a size_t, but the function calls
1222c4c53c9Stedu 		 * below result in implicit casts to a narrower integer
1232c4c53c9Stedu 		 * type, so cap key_len at the actual maximum supported
1242c4c53c9Stedu 		 * length here to avoid integer wraparound */
1252c4c53c9Stedu 		key_len = strlen(key);
1262c4c53c9Stedu 		if (key_len > 72)
1272c4c53c9Stedu 			key_len = 72;
1282c4c53c9Stedu 		key_len++; /* include the NUL */
1292b2cf4b1Sprovos 		break;
1302b2cf4b1Sprovos 	default:
1312ae21647Stedu 		 goto inval;
1322b2cf4b1Sprovos 	}
1332b2cf4b1Sprovos 	if (salt[2] != '$')
1342ae21647Stedu 		goto inval;
1352c4c53c9Stedu 	/* Discard version + "$" identifier */
1362c4c53c9Stedu 	salt += 3;
1376d84a8a1Sprovos 
1382c4c53c9Stedu 	/* Check and parse num rounds */
1392c4c53c9Stedu 	if (!isdigit((unsigned char)salt[0]) ||
1402c4c53c9Stedu 	    !isdigit((unsigned char)salt[1]) || salt[2] != '$')
1412ae21647Stedu 		goto inval;
142df22808aSmillert 	logr = (salt[1] - '0') + ((salt[0] - '0') * 10);
1432c4c53c9Stedu 	if (logr < BCRYPT_MINLOGROUNDS || logr > 31)
1442ae21647Stedu 		goto inval;
1450e59d8e3Stedu 	/* Computer power doesn't increase linearly, 2^x should be fine */
1460e59d8e3Stedu 	rounds = 1U << logr;
1476d84a8a1Sprovos 
1486d84a8a1Sprovos 	/* Discard num rounds + "$" identifier */
1496d84a8a1Sprovos 	salt += 3;
1506d84a8a1Sprovos 
151296b7048Sprovos 	if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)
1522ae21647Stedu 		goto inval;
153296b7048Sprovos 
1546d84a8a1Sprovos 	/* We dont want the base64 salt but the raw data */
1557708e05bStedu 	if (decode_base64(csalt, BCRYPT_MAXSALT, salt))
1562ae21647Stedu 		goto inval;
1576d84a8a1Sprovos 	salt_len = BCRYPT_MAXSALT;
1586d84a8a1Sprovos 
1596d84a8a1Sprovos 	/* Setting up S-Boxes and Subkeys */
1606d84a8a1Sprovos 	Blowfish_initstate(&state);
1616d84a8a1Sprovos 	Blowfish_expandstate(&state, csalt, salt_len,
1626d84a8a1Sprovos 	    (u_int8_t *) key, key_len);
1636d84a8a1Sprovos 	for (k = 0; k < rounds; k++) {
1646d84a8a1Sprovos 		Blowfish_expand0state(&state, (u_int8_t *) key, key_len);
1656d84a8a1Sprovos 		Blowfish_expand0state(&state, csalt, salt_len);
1666d84a8a1Sprovos 	}
1676d84a8a1Sprovos 
1686d84a8a1Sprovos 	/* This can be precomputed later */
1696d84a8a1Sprovos 	j = 0;
170c6555c4fStedu 	for (i = 0; i < BCRYPT_WORDS; i++)
171c6555c4fStedu 		cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_WORDS, &j);
1726d84a8a1Sprovos 
1736d84a8a1Sprovos 	/* Now do the encryption */
1746d84a8a1Sprovos 	for (k = 0; k < 64; k++)
175c6555c4fStedu 		blf_enc(&state, cdata, BCRYPT_WORDS / 2);
1766d84a8a1Sprovos 
177c6555c4fStedu 	for (i = 0; i < BCRYPT_WORDS; i++) {
1786d84a8a1Sprovos 		ciphertext[4 * i + 3] = cdata[i] & 0xff;
1796d84a8a1Sprovos 		cdata[i] = cdata[i] >> 8;
1806d84a8a1Sprovos 		ciphertext[4 * i + 2] = cdata[i] & 0xff;
1816d84a8a1Sprovos 		cdata[i] = cdata[i] >> 8;
1826d84a8a1Sprovos 		ciphertext[4 * i + 1] = cdata[i] & 0xff;
1836d84a8a1Sprovos 		cdata[i] = cdata[i] >> 8;
1846d84a8a1Sprovos 		ciphertext[4 * i + 0] = cdata[i] & 0xff;
1856d84a8a1Sprovos 	}
1866d84a8a1Sprovos 
1876d84a8a1Sprovos 
1885105d936Stedu 	snprintf(encrypted, 8, "$2%c$%2.2u$", minor, logr);
1895105d936Stedu 	encode_base64(encrypted + 7, csalt, BCRYPT_MAXSALT);
190c6555c4fStedu 	encode_base64(encrypted + 7 + 22, ciphertext, 4 * BCRYPT_WORDS - 1);
1912d36debaStedu 	explicit_bzero(&state, sizeof(state));
1922d36debaStedu 	explicit_bzero(ciphertext, sizeof(ciphertext));
1932d36debaStedu 	explicit_bzero(csalt, sizeof(csalt));
1942d36debaStedu 	explicit_bzero(cdata, sizeof(cdata));
1959573d548Stedu 	return 0;
1962ae21647Stedu 
1972ae21647Stedu inval:
1982ae21647Stedu 	errno = EINVAL;
1992ae21647Stedu 	return -1;
2006d84a8a1Sprovos }
2016d84a8a1Sprovos 
2029573d548Stedu /*
2039573d548Stedu  * user friendly functions
2049573d548Stedu  */
2059573d548Stedu int
bcrypt_newhash(const char * pass,int log_rounds,char * hash,size_t hashlen)2069573d548Stedu bcrypt_newhash(const char *pass, int log_rounds, char *hash, size_t hashlen)
2079573d548Stedu {
2089573d548Stedu 	char salt[BCRYPT_SALTSPACE];
2099573d548Stedu 
2109573d548Stedu 	if (bcrypt_initsalt(log_rounds, salt, sizeof(salt)) != 0)
2119573d548Stedu 		return -1;
2129573d548Stedu 
2139573d548Stedu 	if (bcrypt_hashpass(pass, salt, hash, hashlen) != 0)
2149573d548Stedu 		return -1;
2159573d548Stedu 
21690e74185Stedu 	explicit_bzero(salt, sizeof(salt));
2179573d548Stedu 	return 0;
2189573d548Stedu }
219f3415991Sguenther DEF_WEAK(bcrypt_newhash);
2209573d548Stedu 
2219573d548Stedu int
bcrypt_checkpass(const char * pass,const char * goodhash)2229573d548Stedu bcrypt_checkpass(const char *pass, const char *goodhash)
2239573d548Stedu {
2245105d936Stedu 	char hash[BCRYPT_HASHSPACE];
2259573d548Stedu 
2269573d548Stedu 	if (bcrypt_hashpass(pass, goodhash, hash, sizeof(hash)) != 0)
2279573d548Stedu 		return -1;
2288391e028Stedu 	if (strlen(hash) != strlen(goodhash) ||
2292ae21647Stedu 	    timingsafe_bcmp(hash, goodhash, strlen(goodhash)) != 0) {
2302ae21647Stedu 		errno = EACCES;
2319573d548Stedu 		return -1;
2322ae21647Stedu 	}
23390e74185Stedu 
23490e74185Stedu 	explicit_bzero(hash, sizeof(hash));
2359573d548Stedu 	return 0;
2369573d548Stedu }
237f3415991Sguenther DEF_WEAK(bcrypt_checkpass);
2389573d548Stedu 
2399573d548Stedu /*
240e08a42f8Stedu  * Measure this system's performance by measuring the time for 8 rounds.
2416c34c853Stedu  * We are aiming for something that takes around 0.1s, but not too much over.
242e08a42f8Stedu  */
243e08a42f8Stedu int
_bcrypt_autorounds(void)244f3415991Sguenther _bcrypt_autorounds(void)
245e08a42f8Stedu {
24687c89173Stedu 	struct timespec before, after;
247e08a42f8Stedu 	int r = 8;
248e08a42f8Stedu 	char buf[_PASSWORD_LEN];
249e08a42f8Stedu 	int duration;
250e08a42f8Stedu 
251*d82e6535Spirofti 	WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &before);
252e08a42f8Stedu 	bcrypt_newhash("testpassword", r, buf, sizeof(buf));
253*d82e6535Spirofti 	WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &after);
254e08a42f8Stedu 
25587c89173Stedu 	duration = after.tv_sec - before.tv_sec;
25687c89173Stedu 	duration *= 1000000;
25787c89173Stedu 	duration += (after.tv_nsec - before.tv_nsec) / 1000;
258e08a42f8Stedu 
259e08a42f8Stedu 	/* too quick? slow it down. */
2606c34c853Stedu 	while (r < 16 && duration <= 60000) {
261e08a42f8Stedu 		r += 1;
262e08a42f8Stedu 		duration *= 2;
263e08a42f8Stedu 	}
264e08a42f8Stedu 	/* too slow? speed it up. */
2650d28cf8dStedu 	while (r > 6 && duration > 120000) {
266e08a42f8Stedu 		r -= 1;
267e08a42f8Stedu 		duration /= 2;
268e08a42f8Stedu 	}
269e08a42f8Stedu 
270e08a42f8Stedu 	return r;
271e08a42f8Stedu }
272e08a42f8Stedu 
273e08a42f8Stedu /*
2749573d548Stedu  * internal utilities
2759573d548Stedu  */
2761a0ab620Sguenther static const u_int8_t Base64Code[] =
277419393fbStedu "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
278419393fbStedu 
2791a0ab620Sguenther static const u_int8_t index_64[128] = {
280419393fbStedu 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
281419393fbStedu 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
282419393fbStedu 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
283419393fbStedu 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
284419393fbStedu 	255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
285419393fbStedu 	56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
286419393fbStedu 	255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
287419393fbStedu 	7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
288419393fbStedu 	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
289419393fbStedu 	255, 255, 255, 255, 255, 255, 28, 29, 30,
290419393fbStedu 	31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
291419393fbStedu 	41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
292419393fbStedu 	51, 52, 53, 255, 255, 255, 255, 255
293419393fbStedu };
294419393fbStedu #define CHAR64(c)  ( (c) > 127 ? 255 : index_64[(c)])
295419393fbStedu 
296ad45bbcfStedu /*
297ad45bbcfStedu  * read buflen (after decoding) bytes of data from b64data
298ad45bbcfStedu  */
299ad45bbcfStedu static int
decode_base64(u_int8_t * buffer,size_t len,const char * b64data)300ad45bbcfStedu decode_base64(u_int8_t *buffer, size_t len, const char *b64data)
301419393fbStedu {
302419393fbStedu 	u_int8_t *bp = buffer;
303ad45bbcfStedu 	const u_int8_t *p = b64data;
304419393fbStedu 	u_int8_t c1, c2, c3, c4;
305ad45bbcfStedu 
306419393fbStedu 	while (bp < buffer + len) {
307419393fbStedu 		c1 = CHAR64(*p);
308419393fbStedu 		/* Invalid data */
3097b5a7360Stedu 		if (c1 == 255)
3107b5a7360Stedu 			return -1;
3117b5a7360Stedu 
3127b5a7360Stedu 		c2 = CHAR64(*(p + 1));
3137b5a7360Stedu 		if (c2 == 255)
314ad45bbcfStedu 			return -1;
315419393fbStedu 
316419393fbStedu 		*bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);
317419393fbStedu 		if (bp >= buffer + len)
318419393fbStedu 			break;
319419393fbStedu 
320419393fbStedu 		c3 = CHAR64(*(p + 2));
321419393fbStedu 		if (c3 == 255)
3227708e05bStedu 			return -1;
323419393fbStedu 
324419393fbStedu 		*bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
325419393fbStedu 		if (bp >= buffer + len)
326419393fbStedu 			break;
327419393fbStedu 
328419393fbStedu 		c4 = CHAR64(*(p + 3));
329419393fbStedu 		if (c4 == 255)
3307708e05bStedu 			return -1;
331419393fbStedu 		*bp++ = ((c3 & 0x03) << 6) | c4;
332419393fbStedu 
333419393fbStedu 		p += 4;
334419393fbStedu 	}
335ad45bbcfStedu 	return 0;
336419393fbStedu }
337419393fbStedu 
338ad45bbcfStedu /*
339ad45bbcfStedu  * Turn len bytes of data into base64 encoded data.
340ad45bbcfStedu  * This works without = padding.
341ad45bbcfStedu  */
342ad45bbcfStedu static int
encode_base64(char * b64buffer,const u_int8_t * data,size_t len)343ad45bbcfStedu encode_base64(char *b64buffer, const u_int8_t *data, size_t len)
3446d84a8a1Sprovos {
345ad45bbcfStedu 	u_int8_t *bp = b64buffer;
346ad45bbcfStedu 	const u_int8_t *p = data;
3476d84a8a1Sprovos 	u_int8_t c1, c2;
348ad45bbcfStedu 
3496d84a8a1Sprovos 	while (p < data + len) {
3506d84a8a1Sprovos 		c1 = *p++;
3516d84a8a1Sprovos 		*bp++ = Base64Code[(c1 >> 2)];
3526d84a8a1Sprovos 		c1 = (c1 & 0x03) << 4;
3536d84a8a1Sprovos 		if (p >= data + len) {
3546d84a8a1Sprovos 			*bp++ = Base64Code[c1];
3556d84a8a1Sprovos 			break;
3566d84a8a1Sprovos 		}
35727ad40b1Sprovos 		c2 = *p++;
3586d84a8a1Sprovos 		c1 |= (c2 >> 4) & 0x0f;
3596d84a8a1Sprovos 		*bp++ = Base64Code[c1];
3606d84a8a1Sprovos 		c1 = (c2 & 0x0f) << 2;
3616d84a8a1Sprovos 		if (p >= data + len) {
3626d84a8a1Sprovos 			*bp++ = Base64Code[c1];
3636d84a8a1Sprovos 			break;
3646d84a8a1Sprovos 		}
36527ad40b1Sprovos 		c2 = *p++;
3666d84a8a1Sprovos 		c1 |= (c2 >> 6) & 0x03;
3676d84a8a1Sprovos 		*bp++ = Base64Code[c1];
3686d84a8a1Sprovos 		*bp++ = Base64Code[c2 & 0x3f];
3696d84a8a1Sprovos 	}
3706d84a8a1Sprovos 	*bp = '\0';
371ad45bbcfStedu 	return 0;
3726d84a8a1Sprovos }
3739573d548Stedu 
3749573d548Stedu /*
3759573d548Stedu  * classic interface
3769573d548Stedu  */
3779573d548Stedu char *
bcrypt_gensalt(u_int8_t log_rounds)3789573d548Stedu bcrypt_gensalt(u_int8_t log_rounds)
3799573d548Stedu {
3808391e028Stedu 	static char    gsalt[BCRYPT_SALTSPACE];
3819573d548Stedu 
3829573d548Stedu 	bcrypt_initsalt(log_rounds, gsalt, sizeof(gsalt));
3839573d548Stedu 
3849573d548Stedu 	return gsalt;
3859573d548Stedu }
3869573d548Stedu 
3879573d548Stedu char *
bcrypt(const char * pass,const char * salt)3889573d548Stedu bcrypt(const char *pass, const char *salt)
3899573d548Stedu {
3905105d936Stedu 	static char    gencrypted[BCRYPT_HASHSPACE];
3919573d548Stedu 
3929573d548Stedu 	if (bcrypt_hashpass(pass, salt, gencrypted, sizeof(gencrypted)) != 0)
3938d29ece6Stedu 		return NULL;
3949573d548Stedu 
3959573d548Stedu 	return gencrypted;
3969573d548Stedu }
397f3415991Sguenther DEF_WEAK(bcrypt);
398