git ssb

0+

dangerousbeans / %aPBe2k3ugtjBr4rrsU1…



Tree: 9905c5d171ad8b457e160ee2b5ba98dd1cbf4d12

Files: 9905c5d171ad8b457e160ee2b5ba98dd1cbf4d12 / ext / mri / bcrypt.c

8321 bytesRaw
1/* $OpenBSD: bcrypt.c,v 1.22 2007/02/20 01:44:16 ray Exp $ */
2
3/*
4 * Modified by <coda.hale@gmail.com> on 2009-09-16:
5 *
6 * - Standardized on stdint.h's numerical types and removed some debug cruft.
7 *
8 * Modified by <hongli@phusion.nl> on 2009-08-05:
9 *
10 * - Got rid of the global variables; they're not thread-safe.
11 * Modified the functions to accept local buffers instead.
12 *
13 * Modified by <coda.hale@gmail.com> on 2007-02-27:
14 *
15 * - Changed bcrypt_gensalt to accept a random seed as a parameter,
16 * to remove the code's dependency on arc4random(), which isn't
17 * available on Linux.
18 */
19
20/*
21 * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
22 * All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 * 3. All advertising materials mentioning features or use of this software
33 * must display the following acknowledgement:
34 * This product includes software developed by Niels Provos.
35 * 4. The name of the author may not be used to endorse or promote products
36 * derived from this software without specific prior written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
39 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
42 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
47 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 */
49
50/* This password hashing algorithm was designed by David Mazieres
51 * <dm@lcs.mit.edu> and works as follows:
52 *
53 * 1. state := InitState ()
54 * 2. state := ExpandKey (state, salt, password) 3.
55 * REPEAT rounds:
56 * state := ExpandKey (state, 0, salt)
57 * state := ExpandKey(state, 0, password)
58 * 4. ctext := "OrpheanBeholderScryDoubt"
59 * 5. REPEAT 64:
60 * ctext := Encrypt_ECB (state, ctext);
61 * 6. RETURN Concatenate (salt, ctext);
62 *
63 */
64
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include "blf.h"
69#include "bcrypt.h"
70
71/* This implementation is adaptable to current computing power.
72 * You can have up to 2^31 rounds which should be enough for some
73 * time to come.
74 */
75
76static void encode_salt(char *, uint8_t *, uint16_t, uint8_t);
77static void encode_base64(uint8_t *, uint8_t *, uint16_t);
78static void decode_base64(uint8_t *, uint16_t, uint8_t *);
79
80static const uint8_t Base64Code[] =
81"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
82
83static const uint8_t index_64[128] = {
84 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
85 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
86 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
87 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
88 255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
89 56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
90 255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
91 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
92 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
93 255, 255, 255, 255, 255, 255, 28, 29, 30,
94 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
95 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
96 51, 52, 53, 255, 255, 255, 255, 255
97};
98#define CHAR64(c) ( (c) > 127 ? 255 : index_64[(c)])
99
100static void
101decode_base64(uint8_t *buffer, uint16_t len, uint8_t *data)
102{
103 uint8_t *bp = buffer;
104 uint8_t *p = data;
105 uint8_t c1, c2, c3, c4;
106 while (bp < buffer + len) {
107 c1 = CHAR64(*p);
108 c2 = CHAR64(*(p + 1));
109
110 /* Invalid data */
111 if (c1 == 255 || c2 == 255)
112 break;
113
114 *bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);
115 if (bp >= buffer + len)
116 break;
117
118 c3 = CHAR64(*(p + 2));
119 if (c3 == 255)
120 break;
121
122 *bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
123 if (bp >= buffer + len)
124 break;
125
126 c4 = CHAR64(*(p + 3));
127 if (c4 == 255)
128 break;
129 *bp++ = ((c3 & 0x03) << 6) | c4;
130
131 p += 4;
132 }
133}
134
135static void
136encode_salt(char *salt, uint8_t *csalt, uint16_t clen, uint8_t logr)
137{
138 salt[0] = '$';
139 salt[1] = BCRYPT_VERSION;
140 salt[2] = 'a';
141 salt[3] = '$';
142
143 snprintf(salt + 4, 4, "%2.2u$", logr);
144
145 encode_base64((uint8_t *) salt + 7, csalt, clen);
146}
147/* Generates a salt for this version of crypt.
148 Since versions may change. Keeping this here
149 seems sensible.
150 */
151
152char *
153ruby_bcrypt_gensalt(char *output, uint8_t log_rounds, uint8_t *rseed)
154{
155 if (log_rounds < 4)
156 log_rounds = 4;
157 else if (log_rounds > 31)
158 log_rounds = 31;
159
160 encode_salt(output, rseed, BCRYPT_MAXSALT, log_rounds);
161 return output;
162}
163/* We handle $Vers$log2(NumRounds)$salt+passwd$
164 i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
165
166char *
167ruby_bcrypt(char *output, const char *key, const char *salt)
168{
169 blf_ctx state;
170 uint32_t rounds, i, k;
171 uint16_t j;
172 uint8_t key_len, salt_len, logr, minor;
173 uint8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt";
174 uint8_t csalt[BCRYPT_MAXSALT];
175 uint32_t cdata[BCRYPT_BLOCKS];
176 int n;
177
178 /* Discard "$" identifier */
179 salt++;
180
181 if (*salt > BCRYPT_VERSION) {
182 return NULL;
183 }
184
185 /* Check for minor versions */
186 if (salt[1] != '$') {
187 switch (salt[1]) {
188 case 'a':
189 /* 'ab' should not yield the same as 'abab' */
190 minor = salt[1];
191 salt++;
192 break;
193 default:
194 return NULL;
195 }
196 } else
197 minor = 0;
198
199 /* Discard version + "$" identifier */
200 salt += 2;
201
202 if (salt[2] != '$')
203 /* Out of sync with passwd entry */
204 return NULL;
205
206 /* Computer power doesn't increase linear, 2^x should be fine */
207 n = atoi(salt);
208 if (n > 31 || n < 0)
209 return NULL;
210 logr = (uint8_t)n;
211 if ((rounds = (uint32_t) 1 << logr) < BCRYPT_MINROUNDS)
212 return NULL;
213
214 /* Discard num rounds + "$" identifier */
215 salt += 3;
216
217 if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)
218 return NULL;
219
220 /* We dont want the base64 salt but the raw data */
221 decode_base64(csalt, BCRYPT_MAXSALT, (uint8_t *) salt);
222 salt_len = BCRYPT_MAXSALT;
223 key_len = strlen(key) + (minor >= 'a' ? 1 : 0);
224
225 /* Setting up S-Boxes and Subkeys */
226 Blowfish_initstate(&state);
227 Blowfish_expandstate(&state, csalt, salt_len,
228 (uint8_t *) key, key_len);
229 for (k = 0; k < rounds; k++) {
230 Blowfish_expand0state(&state, (uint8_t *) key, key_len);
231 Blowfish_expand0state(&state, csalt, salt_len);
232 }
233
234 /* This can be precomputed later */
235 j = 0;
236 for (i = 0; i < BCRYPT_BLOCKS; i++)
237 cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_BLOCKS, &j);
238
239 /* Now do the encryption */
240 for (k = 0; k < 64; k++)
241 blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
242
243 for (i = 0; i < BCRYPT_BLOCKS; i++) {
244 ciphertext[4 * i + 3] = cdata[i] & 0xff;
245 cdata[i] = cdata[i] >> 8;
246 ciphertext[4 * i + 2] = cdata[i] & 0xff;
247 cdata[i] = cdata[i] >> 8;
248 ciphertext[4 * i + 1] = cdata[i] & 0xff;
249 cdata[i] = cdata[i] >> 8;
250 ciphertext[4 * i + 0] = cdata[i] & 0xff;
251 }
252
253
254 i = 0;
255 output[i++] = '$';
256 output[i++] = BCRYPT_VERSION;
257 if (minor)
258 output[i++] = minor;
259 output[i++] = '$';
260
261 snprintf(output + i, 4, "%2.2u$", logr);
262
263 encode_base64((uint8_t *) output + i + 3, csalt, BCRYPT_MAXSALT);
264 encode_base64((uint8_t *) output + strlen(output), ciphertext,
265 4 * BCRYPT_BLOCKS - 1);
266 return output;
267}
268
269static void
270encode_base64(uint8_t *buffer, uint8_t *data, uint16_t len)
271{
272 uint8_t *bp = buffer;
273 uint8_t *p = data;
274 uint8_t c1, c2;
275 while (p < data + len) {
276 c1 = *p++;
277 *bp++ = Base64Code[(c1 >> 2)];
278 c1 = (c1 & 0x03) << 4;
279 if (p >= data + len) {
280 *bp++ = Base64Code[c1];
281 break;
282 }
283 c2 = *p++;
284 c1 |= (c2 >> 4) & 0x0f;
285 *bp++ = Base64Code[c1];
286 c1 = (c2 & 0x0f) << 2;
287 if (p >= data + len) {
288 *bp++ = Base64Code[c1];
289 break;
290 }
291 c2 = *p++;
292 c1 |= (c2 >> 6) & 0x03;
293 *bp++ = Base64Code[c1];
294 *bp++ = Base64Code[c2 & 0x3f];
295 }
296 *bp = '\0';
297}
298

Built with git-ssb-web