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 | |
66 | |
67 | |
68 | |
69 | |
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 | |
76 | static void encode_salt(char *, uint8_t *, uint16_t, uint8_t); |
77 | static void encode_base64(uint8_t *, uint8_t *, uint16_t); |
78 | static void decode_base64(uint8_t *, uint16_t, uint8_t *); |
79 | |
80 | static const uint8_t Base64Code[] = |
81 | "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; |
82 | |
83 | static 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 | |
99 | |
100 | static void |
101 | decode_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 | |
135 | static void |
136 | encode_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 | |
152 | char * |
153 | ruby_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 | |
166 | char * |
167 | ruby_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 | |
269 | static void |
270 | encode_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