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