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