17c478bd9Sstevel@tonic-gate /* 2a0b85df4Sstevel * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3a0b85df4Sstevel * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 5a0b85df4Sstevel 67c478bd9Sstevel@tonic-gate /* $OpenBSD: bcrypt.c,v 1.16 2002/02/19 19:39:36 millert Exp $ */ 77c478bd9Sstevel@tonic-gate 87c478bd9Sstevel@tonic-gate /* 97c478bd9Sstevel@tonic-gate * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> 107c478bd9Sstevel@tonic-gate * All rights reserved. 117c478bd9Sstevel@tonic-gate * 127c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 137c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 147c478bd9Sstevel@tonic-gate * are met: 157c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 167c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 177c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 187c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 197c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 207c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 217c478bd9Sstevel@tonic-gate * must display the following acknowledgement: 227c478bd9Sstevel@tonic-gate * This product includes software developed by Niels Provos. 237c478bd9Sstevel@tonic-gate * 4. The name of the author may not be used to endorse or promote products 247c478bd9Sstevel@tonic-gate * derived from this software without specific prior written permission. 257c478bd9Sstevel@tonic-gate * 267c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 277c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 287c478bd9Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 297c478bd9Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 307c478bd9Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 317c478bd9Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327c478bd9Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337c478bd9Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347c478bd9Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 357c478bd9Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 38*00d0b46cSPatrick Domack /* 39*00d0b46cSPatrick Domack * This password hashing algorithm was designed by David Mazieres 407c478bd9Sstevel@tonic-gate * <dm@lcs.mit.edu> and works as follows: 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * 1. state := InitState () 437c478bd9Sstevel@tonic-gate * 2. state := ExpandKey (state, salt, password) 3. 447c478bd9Sstevel@tonic-gate * REPEAT rounds: 457c478bd9Sstevel@tonic-gate * state := ExpandKey (state, 0, salt) 467c478bd9Sstevel@tonic-gate * state := ExpandKey(state, 0, password) 477c478bd9Sstevel@tonic-gate * 4. ctext := "OrpheanBeholderScryDoubt" 487c478bd9Sstevel@tonic-gate * 5. REPEAT 64: 497c478bd9Sstevel@tonic-gate * ctext := Encrypt_ECB (state, ctext); 507c478bd9Sstevel@tonic-gate * 6. RETURN Concatenate (salt, ctext); 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #if 0 557c478bd9Sstevel@tonic-gate #include <stdio.h> 567c478bd9Sstevel@tonic-gate #endif 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #include <stdio.h> 597c478bd9Sstevel@tonic-gate #include <stdlib.h> 607c478bd9Sstevel@tonic-gate #include <sys/types.h> 617c478bd9Sstevel@tonic-gate #include <string.h> 627c478bd9Sstevel@tonic-gate #include <pwd.h> 637c478bd9Sstevel@tonic-gate #include <blf.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate extern uint32_t arc4random(); 667c478bd9Sstevel@tonic-gate 67*00d0b46cSPatrick Domack /* 68*00d0b46cSPatrick Domack * This implementation is adaptable to current computing power. 697c478bd9Sstevel@tonic-gate * You can have up to 2^31 rounds which should be enough for some 707c478bd9Sstevel@tonic-gate * time to come. 717c478bd9Sstevel@tonic-gate */ 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #define BCRYPT_VERSION '2' 747c478bd9Sstevel@tonic-gate #define BCRYPT_MAXSALT 16 /* Precomputation is just so nice */ 757c478bd9Sstevel@tonic-gate #define BCRYPT_BLOCKS 6 /* Ciphertext blocks */ 76*00d0b46cSPatrick Domack #define BCRYPT_MINLOGROUNDS 4 /* we have log2(rounds) in salt */ 77*00d0b46cSPatrick Domack #define BCRYPT_MAXLOGROUNDS 31 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate char *bcrypt_gensalt(uint8_t); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate static void encode_salt(char *, uint8_t *, uint16_t, uint8_t); 827c478bd9Sstevel@tonic-gate static void encode_base64(uint8_t *, uint8_t *, uint16_t); 837c478bd9Sstevel@tonic-gate static void decode_base64(uint8_t *, uint16_t, uint8_t *); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate static char encrypted[128]; /* _PASSWORD_LEN in <pwd.h> on OpenBSD */ 867c478bd9Sstevel@tonic-gate static char gsalt[BCRYPT_MAXSALT * 4 / 3 + 1]; 877c478bd9Sstevel@tonic-gate static char error[] = ":"; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate static uint8_t Base64Code[] = 907c478bd9Sstevel@tonic-gate "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate static uint8_t index_64[128] = 937c478bd9Sstevel@tonic-gate { 947c478bd9Sstevel@tonic-gate 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 957c478bd9Sstevel@tonic-gate 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 967c478bd9Sstevel@tonic-gate 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 977c478bd9Sstevel@tonic-gate 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 987c478bd9Sstevel@tonic-gate 255, 255, 255, 255, 255, 255, 0, 1, 54, 55, 997c478bd9Sstevel@tonic-gate 56, 57, 58, 59, 60, 61, 62, 63, 255, 255, 1007c478bd9Sstevel@tonic-gate 255, 255, 255, 255, 255, 2, 3, 4, 5, 6, 1017c478bd9Sstevel@tonic-gate 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1027c478bd9Sstevel@tonic-gate 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 1037c478bd9Sstevel@tonic-gate 255, 255, 255, 255, 255, 255, 28, 29, 30, 1047c478bd9Sstevel@tonic-gate 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 1057c478bd9Sstevel@tonic-gate 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 1067c478bd9Sstevel@tonic-gate 51, 52, 53, 255, 255, 255, 255, 255 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate #define CHAR64(c) ((c) > 127 ? 255 : index_64[(c)]) 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static void 1117c478bd9Sstevel@tonic-gate decode_base64(uint8_t *buffer, uint16_t len, uint8_t *data) 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate uint8_t *bp = buffer; 1147c478bd9Sstevel@tonic-gate uint8_t *p = data; 1157c478bd9Sstevel@tonic-gate uint8_t c1, c2, c3, c4; 1167c478bd9Sstevel@tonic-gate while (bp < buffer + len) { 1177c478bd9Sstevel@tonic-gate c1 = CHAR64(*p); 1187c478bd9Sstevel@tonic-gate c2 = CHAR64(*(p + 1)); 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* Invalid data */ 1217c478bd9Sstevel@tonic-gate if (c1 == 255 || c2 == 255) 1227c478bd9Sstevel@tonic-gate break; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate *bp++ = (c1 << 2) | ((c2 & 0x30) >> 4); 1257c478bd9Sstevel@tonic-gate if (bp >= buffer + len) 1267c478bd9Sstevel@tonic-gate break; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate c3 = CHAR64(*(p + 2)); 1297c478bd9Sstevel@tonic-gate if (c3 == 255) 1307c478bd9Sstevel@tonic-gate break; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate *bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); 1337c478bd9Sstevel@tonic-gate if (bp >= buffer + len) 1347c478bd9Sstevel@tonic-gate break; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate c4 = CHAR64(*(p + 3)); 1377c478bd9Sstevel@tonic-gate if (c4 == 255) 1387c478bd9Sstevel@tonic-gate break; 1397c478bd9Sstevel@tonic-gate *bp++ = ((c3 & 0x03) << 6) | c4; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate p += 4; 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate static void 1467c478bd9Sstevel@tonic-gate encode_salt(char *salt, uint8_t *csalt, uint16_t clen, uint8_t logr) 1477c478bd9Sstevel@tonic-gate { 1487c478bd9Sstevel@tonic-gate salt[0] = '$'; 1497c478bd9Sstevel@tonic-gate salt[1] = BCRYPT_VERSION; 1507c478bd9Sstevel@tonic-gate salt[2] = 'a'; 1517c478bd9Sstevel@tonic-gate salt[3] = '$'; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate (void) snprintf(salt + 4, 4, "%2.2u$", logr); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate encode_base64((uint8_t *)salt + 7, csalt, clen); 1567c478bd9Sstevel@tonic-gate } 157*00d0b46cSPatrick Domack /* 158*00d0b46cSPatrick Domack * Generates a salt for this version of crypt. 159*00d0b46cSPatrick Domack * Since versions may change. Keeping this here 160*00d0b46cSPatrick Domack * seems sensible. 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate char * 1647c478bd9Sstevel@tonic-gate bcrypt_gensalt(uint8_t log_rounds) 1657c478bd9Sstevel@tonic-gate { 1667c478bd9Sstevel@tonic-gate uint8_t csalt[BCRYPT_MAXSALT]; 1677c478bd9Sstevel@tonic-gate uint16_t i; 1687c478bd9Sstevel@tonic-gate uint32_t seed = 0; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate for (i = 0; i < BCRYPT_MAXSALT; i++) { 1717c478bd9Sstevel@tonic-gate if (i % 4 == 0) 1727c478bd9Sstevel@tonic-gate seed = arc4random(); 1737c478bd9Sstevel@tonic-gate csalt[i] = seed & 0xff; 1747c478bd9Sstevel@tonic-gate seed = seed >> 8; 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 177*00d0b46cSPatrick Domack if (log_rounds < BCRYPT_MINLOGROUNDS) 178*00d0b46cSPatrick Domack log_rounds = BCRYPT_MINLOGROUNDS; 179*00d0b46cSPatrick Domack else if (log_rounds > BCRYPT_MAXLOGROUNDS) 180*00d0b46cSPatrick Domack log_rounds = BCRYPT_MAXLOGROUNDS; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate encode_salt(gsalt, csalt, BCRYPT_MAXSALT, log_rounds); 183*00d0b46cSPatrick Domack return (gsalt); 1847c478bd9Sstevel@tonic-gate } 185*00d0b46cSPatrick Domack /* 186*00d0b46cSPatrick Domack * We handle $Vers$log2(NumRounds)$salt+passwd$ 187*00d0b46cSPatrick Domack * i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou 188*00d0b46cSPatrick Domack */ 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate char * 1917c478bd9Sstevel@tonic-gate bcrypt(key, salt) 1927c478bd9Sstevel@tonic-gate const char *key; 1937c478bd9Sstevel@tonic-gate const char *salt; 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate blf_ctx state; 1967c478bd9Sstevel@tonic-gate uint32_t rounds, i, k; 1977c478bd9Sstevel@tonic-gate uint16_t j; 198*00d0b46cSPatrick Domack size_t key_len; 199*00d0b46cSPatrick Domack uint8_t salt_len, logr, minor; 2007c478bd9Sstevel@tonic-gate uint8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt"; 2017c478bd9Sstevel@tonic-gate uint8_t csalt[BCRYPT_MAXSALT]; 2027c478bd9Sstevel@tonic-gate uint32_t cdata[BCRYPT_BLOCKS]; 203*00d0b46cSPatrick Domack char arounds[3]; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* Discard "$" identifier */ 2067c478bd9Sstevel@tonic-gate salt++; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate if (*salt > BCRYPT_VERSION) { 2097c478bd9Sstevel@tonic-gate /* How do I handle errors ? Return ':' */ 210*00d0b46cSPatrick Domack return (error); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* Check for minor versions */ 2147c478bd9Sstevel@tonic-gate if (salt[1] != '$') { 2157c478bd9Sstevel@tonic-gate switch (salt[1]) { 216*00d0b46cSPatrick Domack case 'a': /* 'ab' should not yield the same as 'abab' */ 217*00d0b46cSPatrick Domack case 'b': /* cap input length at 72 bytes */ 2187c478bd9Sstevel@tonic-gate minor = salt[1]; 2197c478bd9Sstevel@tonic-gate salt++; 2207c478bd9Sstevel@tonic-gate break; 2217c478bd9Sstevel@tonic-gate default: 222*00d0b46cSPatrick Domack return (error); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate } else 2257c478bd9Sstevel@tonic-gate minor = 0; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* Discard version + "$" identifier */ 2287c478bd9Sstevel@tonic-gate salt += 2; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate if (salt[2] != '$') 2317c478bd9Sstevel@tonic-gate /* Out of sync with passwd entry */ 232*00d0b46cSPatrick Domack return (error); 2337c478bd9Sstevel@tonic-gate 234*00d0b46cSPatrick Domack (void) memcpy(arounds, salt, sizeof (arounds)); 235*00d0b46cSPatrick Domack if (arounds[sizeof (arounds) - 1] != '$') 236*00d0b46cSPatrick Domack return (error); 237*00d0b46cSPatrick Domack if ((logr = atoi(arounds)) < BCRYPT_MINLOGROUNDS || 238*00d0b46cSPatrick Domack logr > BCRYPT_MAXLOGROUNDS) 239*00d0b46cSPatrick Domack return (error); 2407c478bd9Sstevel@tonic-gate /* Computer power doesn't increase linear, 2^x should be fine */ 241*00d0b46cSPatrick Domack rounds = 1U << logr; 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate /* Discard num rounds + "$" identifier */ 2447c478bd9Sstevel@tonic-gate salt += 3; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) 247*00d0b46cSPatrick Domack return (error); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* We dont want the base64 salt but the raw data */ 2507c478bd9Sstevel@tonic-gate decode_base64(csalt, BCRYPT_MAXSALT, (uint8_t *)salt); 2517c478bd9Sstevel@tonic-gate salt_len = BCRYPT_MAXSALT; 252*00d0b46cSPatrick Domack if (minor <= 'a') 253*00d0b46cSPatrick Domack key_len = (uint8_t)(strlen(key) + (minor >= 'a' ? 1 : 0)); 254*00d0b46cSPatrick Domack else { 255*00d0b46cSPatrick Domack /* 256*00d0b46cSPatrick Domack * strlen() returns a size_t, but the function calls 257*00d0b46cSPatrick Domack * below result in implicit casts to a narrower integer 258*00d0b46cSPatrick Domack * type, so cap key_len at the actual maximum supported 259*00d0b46cSPatrick Domack * length here to avoid integer wraparound 260*00d0b46cSPatrick Domack */ 261*00d0b46cSPatrick Domack key_len = strlen(key); 262*00d0b46cSPatrick Domack if (key_len > 72) 263*00d0b46cSPatrick Domack key_len = 72; 264*00d0b46cSPatrick Domack key_len++; /* include the NUL */ 265*00d0b46cSPatrick Domack } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /* Setting up S-Boxes and Subkeys */ 2687c478bd9Sstevel@tonic-gate Blowfish_initstate(&state); 2697c478bd9Sstevel@tonic-gate Blowfish_expandstate(&state, csalt, salt_len, 2707c478bd9Sstevel@tonic-gate (uint8_t *)key, key_len); 2717c478bd9Sstevel@tonic-gate for (k = 0; k < rounds; k++) { 2727c478bd9Sstevel@tonic-gate Blowfish_expand0state(&state, (uint8_t *)key, key_len); 2737c478bd9Sstevel@tonic-gate Blowfish_expand0state(&state, csalt, salt_len); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate /* This can be precomputed later */ 2777c478bd9Sstevel@tonic-gate j = 0; 2787c478bd9Sstevel@tonic-gate for (i = 0; i < BCRYPT_BLOCKS; i++) 279*00d0b46cSPatrick Domack cdata[i] = Blowfish_stream2word(ciphertext, 280*00d0b46cSPatrick Domack 4 * BCRYPT_BLOCKS, &j); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /* Now do the encryption */ 2837c478bd9Sstevel@tonic-gate for (k = 0; k < 64; k++) 2847c478bd9Sstevel@tonic-gate blf_enc(&state, cdata, BCRYPT_BLOCKS / 2); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate for (i = 0; i < BCRYPT_BLOCKS; i++) { 2877c478bd9Sstevel@tonic-gate ciphertext[4 * i + 3] = cdata[i] & 0xff; 2887c478bd9Sstevel@tonic-gate cdata[i] = cdata[i] >> 8; 2897c478bd9Sstevel@tonic-gate ciphertext[4 * i + 2] = cdata[i] & 0xff; 2907c478bd9Sstevel@tonic-gate cdata[i] = cdata[i] >> 8; 2917c478bd9Sstevel@tonic-gate ciphertext[4 * i + 1] = cdata[i] & 0xff; 2927c478bd9Sstevel@tonic-gate cdata[i] = cdata[i] >> 8; 2937c478bd9Sstevel@tonic-gate ciphertext[4 * i + 0] = cdata[i] & 0xff; 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate i = 0; 2987c478bd9Sstevel@tonic-gate encrypted[i++] = '$'; 2997c478bd9Sstevel@tonic-gate encrypted[i++] = BCRYPT_VERSION; 3007c478bd9Sstevel@tonic-gate if (minor) 3017c478bd9Sstevel@tonic-gate encrypted[i++] = minor; 3027c478bd9Sstevel@tonic-gate encrypted[i++] = '$'; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate (void) snprintf(encrypted + i, 4, "%2.2u$", logr); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate encode_base64((uint8_t *)encrypted + i + 3, csalt, BCRYPT_MAXSALT); 3077c478bd9Sstevel@tonic-gate encode_base64((uint8_t *)encrypted + strlen(encrypted), ciphertext, 3087c478bd9Sstevel@tonic-gate 4 * BCRYPT_BLOCKS - 1); 309*00d0b46cSPatrick Domack return (encrypted); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate static void 3137c478bd9Sstevel@tonic-gate encode_base64(uint8_t *buffer, uint8_t *data, uint16_t len) 3147c478bd9Sstevel@tonic-gate { 3157c478bd9Sstevel@tonic-gate uint8_t *bp = buffer; 3167c478bd9Sstevel@tonic-gate uint8_t *p = data; 3177c478bd9Sstevel@tonic-gate uint8_t c1, c2; 3187c478bd9Sstevel@tonic-gate while (p < data + len) { 3197c478bd9Sstevel@tonic-gate c1 = *p++; 3207c478bd9Sstevel@tonic-gate *bp++ = Base64Code[(c1 >> 2)]; 3217c478bd9Sstevel@tonic-gate c1 = (c1 & 0x03) << 4; 3227c478bd9Sstevel@tonic-gate if (p >= data + len) { 3237c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c1]; 3247c478bd9Sstevel@tonic-gate break; 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate c2 = *p++; 3277c478bd9Sstevel@tonic-gate c1 |= (c2 >> 4) & 0x0f; 3287c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c1]; 3297c478bd9Sstevel@tonic-gate c1 = (c2 & 0x0f) << 2; 3307c478bd9Sstevel@tonic-gate if (p >= data + len) { 3317c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c1]; 3327c478bd9Sstevel@tonic-gate break; 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate c2 = *p++; 3357c478bd9Sstevel@tonic-gate c1 |= (c2 >> 6) & 0x03; 3367c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c1]; 3377c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c2 & 0x3f]; 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate *bp = '\0'; 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate #if 0 3427c478bd9Sstevel@tonic-gate void 3437c478bd9Sstevel@tonic-gate main() 3447c478bd9Sstevel@tonic-gate { 3457c478bd9Sstevel@tonic-gate char blubber[73]; 3467c478bd9Sstevel@tonic-gate char salt[100]; 3477c478bd9Sstevel@tonic-gate char *p; 3487c478bd9Sstevel@tonic-gate salt[0] = '$'; 3497c478bd9Sstevel@tonic-gate salt[1] = BCRYPT_VERSION; 3507c478bd9Sstevel@tonic-gate salt[2] = '$'; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate snprintf(salt + 3, 4, "%2.2u$", 5); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate printf("24 bytes of salt: "); 3557c478bd9Sstevel@tonic-gate fgets(salt + 6, 94, stdin); 3567c478bd9Sstevel@tonic-gate salt[99] = 0; 3577c478bd9Sstevel@tonic-gate printf("72 bytes of password: "); 3587c478bd9Sstevel@tonic-gate fpurge(stdin); 3597c478bd9Sstevel@tonic-gate fgets(blubber, 73, stdin); 3607c478bd9Sstevel@tonic-gate blubber[72] = 0; 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate p = crypt(blubber, salt); 3637c478bd9Sstevel@tonic-gate printf("Passwd entry: %s\n\n", p); 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate p = bcrypt_gensalt(5); 3667c478bd9Sstevel@tonic-gate printf("Generated salt: %s\n", p); 3677c478bd9Sstevel@tonic-gate p = crypt(blubber, p); 3687c478bd9Sstevel@tonic-gate printf("Passwd entry: %s\n", p); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate #endif 371