UNPKG

8.18 kBtext/x-cView Raw
1/* $OpenBSD: bcrypt.c,v 1.31 2014/03/22 23:02:03 tedu Exp $ */
2
3/*
4 * Copyright (c) 1997 Niels Provos <provos@umich.edu>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/* This password hashing algorithm was designed by David Mazieres
20 * <dm@lcs.mit.edu> and works as follows:
21 *
22 * 1. state := InitState ()
23 * 2. state := ExpandKey (state, salt, password)
24 * 3. REPEAT rounds:
25 * state := ExpandKey (state, 0, password)
26 * state := ExpandKey (state, 0, salt)
27 * 4. ctext := "OrpheanBeholderScryDoubt"
28 * 5. REPEAT 64:
29 * ctext := Encrypt_ECB (state, ctext);
30 * 6. RETURN Concatenate (salt, ctext);
31 *
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <sys/types.h>
37#include <string.h>
38#include "node_blf.h"
39
40#ifdef _WIN32
41#define snprintf _snprintf
42#endif
43
44//#if !defined(__APPLE__) && !defined(__MACH__)
45//#include "bsd/stdlib.h"
46//#endif
47
48/* This implementation is adaptable to current computing power.
49 * You can have up to 2^31 rounds which should be enough for some
50 * time to come.
51 */
52
53static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t);
54static void decode_base64(u_int8_t *, u_int16_t, u_int8_t *);
55
56const static char* error = ":";
57
58const static u_int8_t Base64Code[] =
59"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
60
61const static u_int8_t index_64[128] = {
62 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
63 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
64 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
65 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
66 255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
67 56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
68 255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
69 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
70 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
71 255, 255, 255, 255, 255, 255, 28, 29, 30,
72 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
73 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
74 51, 52, 53, 255, 255, 255, 255, 255
75};
76#define CHAR64(c) ( (c) > 127 ? 255 : index_64[(c)])
77
78static void
79decode_base64(u_int8_t *buffer, u_int16_t len, u_int8_t *data)
80{
81 u_int8_t *bp = buffer;
82 u_int8_t *p = data;
83 u_int8_t c1, c2, c3, c4;
84 while (bp < buffer + len) {
85 c1 = CHAR64(*p);
86 c2 = CHAR64(*(p + 1));
87
88 /* Invalid data */
89 if (c1 == 255 || c2 == 255)
90 break;
91
92 *bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);
93 if (bp >= buffer + len)
94 break;
95
96 c3 = CHAR64(*(p + 2));
97 if (c3 == 255)
98 break;
99
100 *bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
101 if (bp >= buffer + len)
102 break;
103
104 c4 = CHAR64(*(p + 3));
105 if (c4 == 255)
106 break;
107 *bp++ = ((c3 & 0x03) << 6) | c4;
108
109 p += 4;
110 }
111}
112
113void
114encode_salt(char *salt, u_int8_t *csalt, char minor, u_int16_t clen, u_int8_t logr)
115{
116 salt[0] = '$';
117 salt[1] = BCRYPT_VERSION;
118 salt[2] = minor;
119 salt[3] = '$';
120
121 // Max rounds are 31
122 snprintf(salt + 4, 4, "%2.2u$", logr & 0x001F);
123
124 encode_base64((u_int8_t *) salt + 7, csalt, clen);
125}
126
127
128/* Generates a salt for this version of crypt.
129 Since versions may change. Keeping this here
130 seems sensible.
131 from: http://mail-index.netbsd.org/tech-crypto/2002/05/24/msg000204.html
132*/
133void
134bcrypt_gensalt(char minor, u_int8_t log_rounds, u_int8_t *seed, char *gsalt)
135{
136 if (log_rounds < 4)
137 log_rounds = 4;
138 else if (log_rounds > 31)
139 log_rounds = 31;
140
141 encode_salt(gsalt, seed, minor, BCRYPT_MAXSALT, log_rounds);
142}
143
144/* We handle $Vers$log2(NumRounds)$salt+passwd$
145 i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
146
147void
148bcrypt(const char *key, const char *salt, char *encrypted)
149{
150 blf_ctx state;
151 u_int32_t rounds, i, k;
152 u_int16_t j;
153 u_int8_t key_len, salt_len, logr, minor;
154 u_int8_t ciphertext[4 * BCRYPT_BLOCKS+1] = "OrpheanBeholderScryDoubt";
155 u_int8_t csalt[BCRYPT_MAXSALT];
156 u_int32_t cdata[BCRYPT_BLOCKS];
157 int n;
158
159 /* Discard "$" identifier */
160 salt++;
161
162 if (*salt > BCRYPT_VERSION) {
163 /* How do I handle errors ? Return ':' */
164 strcpy(encrypted, error);
165 return;
166 }
167
168 /* Check for minor versions */
169 if (salt[1] != '$') {
170 switch (salt[1]) {
171 case 'a': /* 'ab' should not yield the same as 'abab' */
172 case 'b': /* cap input length at 72 bytes */
173 minor = salt[1];
174 salt++;
175 break;
176 default:
177 strcpy(encrypted, error);
178 return;
179 }
180 } else
181 minor = 0;
182
183 /* Discard version + "$" identifier */
184 salt += 2;
185
186 if (salt[2] != '$') {
187 /* Out of sync with passwd entry */
188 strcpy(encrypted, error);
189 return;
190 }
191
192 /* Computer power doesn't increase linear, 2^x should be fine */
193 n = atoi(salt);
194 if (n > 31 || n < 0) {
195 strcpy(encrypted, error);
196 return;
197 }
198 logr = (u_int8_t)n;
199 if ((rounds = (u_int32_t) 1 << logr) < BCRYPT_MINROUNDS) {
200 strcpy(encrypted, error);
201 return;
202 }
203
204 /* Discard num rounds + "$" identifier */
205 salt += 3;
206
207 if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) {
208 strcpy(encrypted, error);
209 return;
210 }
211
212 /* We dont want the base64 salt but the raw data */
213 decode_base64(csalt, BCRYPT_MAXSALT, (u_int8_t *) salt);
214 salt_len = BCRYPT_MAXSALT;
215 if (minor <= 'a')
216 key_len = (u_int8_t)(strlen(key) + (minor >= 'a' ? 1 : 0));
217 else
218 {
219 /* strlen() returns a size_t, but the function calls
220 * below result in implicit casts to a narrower integer
221 * type, so cap key_len at the actual maximum supported
222 * length here to avoid integer wraparound */
223 key_len = strlen(key);
224 if (key_len > 72)
225 key_len = 72;
226 key_len++; /* include the NUL */
227 }
228
229
230 /* Setting up S-Boxes and Subkeys */
231 Blowfish_initstate(&state);
232 Blowfish_expandstate(&state, csalt, salt_len,
233 (u_int8_t *) key, key_len);
234 for (k = 0; k < rounds; k++) {
235 Blowfish_expand0state(&state, (u_int8_t *) key, key_len);
236 Blowfish_expand0state(&state, csalt, salt_len);
237 }
238
239 /* This can be precomputed later */
240 j = 0;
241 for (i = 0; i < BCRYPT_BLOCKS; i++)
242 cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_BLOCKS, &j);
243
244 /* Now do the encryption */
245 for (k = 0; k < 64; k++)
246 blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
247
248 for (i = 0; i < BCRYPT_BLOCKS; i++) {
249 ciphertext[4 * i + 3] = cdata[i] & 0xff;
250 cdata[i] = cdata[i] >> 8;
251 ciphertext[4 * i + 2] = cdata[i] & 0xff;
252 cdata[i] = cdata[i] >> 8;
253 ciphertext[4 * i + 1] = cdata[i] & 0xff;
254 cdata[i] = cdata[i] >> 8;
255 ciphertext[4 * i + 0] = cdata[i] & 0xff;
256 }
257
258 i = 0;
259 encrypted[i++] = '$';
260 encrypted[i++] = BCRYPT_VERSION;
261 if (minor)
262 encrypted[i++] = minor;
263 encrypted[i++] = '$';
264
265 snprintf(encrypted + i, 4, "%2.2u$", logr & 0x001F);
266
267 encode_base64((u_int8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT);
268 encode_base64((u_int8_t *) encrypted + strlen(encrypted), ciphertext,
269 4 * BCRYPT_BLOCKS - 1);
270 memset(&state, 0, sizeof(state));
271 memset(ciphertext, 0, sizeof(ciphertext));
272 memset(csalt, 0, sizeof(csalt));
273 memset(cdata, 0, sizeof(cdata));
274}
275
276u_int32_t bcrypt_get_rounds(const char * hash)
277{
278 /* skip past the leading "$" */
279 if (!hash || *(hash++) != '$') return 0;
280
281 /* skip past version */
282 if (0 == (*hash++)) return 0;
283 if (*hash && *hash != '$') hash++;
284 if (*hash++ != '$') return 0;
285
286 return atoi(hash);
287}
288
289static void
290encode_base64(u_int8_t *buffer, u_int8_t *data, u_int16_t len)
291{
292 u_int8_t *bp = buffer;
293 u_int8_t *p = data;
294 u_int8_t c1, c2;
295 while (p < data + len) {
296 c1 = *p++;
297 *bp++ = Base64Code[(c1 >> 2)];
298 c1 = (c1 & 0x03) << 4;
299 if (p >= data + len) {
300 *bp++ = Base64Code[c1];
301 break;
302 }
303 c2 = *p++;
304 c1 |= (c2 >> 4) & 0x0f;
305 *bp++ = Base64Code[c1];
306 c1 = (c2 & 0x0f) << 2;
307 if (p >= data + len) {
308 *bp++ = Base64Code[c1];
309 break;
310 }
311 c2 = *p++;
312 c1 |= (c2 >> 6) & 0x03;
313 *bp++ = Base64Code[c1];
314 *bp++ = Base64Code[c2 & 0x3f];
315 }
316 *bp = '\0';
317}