Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/secure/lib/libcrypt/crypt-blowfish.c
39507 views
1
/* $OpenBSD: bcrypt.c,v 1.29 2014/02/24 19:45:43 tedu Exp $ */
2
3
/*
4
* Copyright 1997 Niels Provos <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. All advertising materials mentioning features or use of this software
16
* must display the following acknowledgement:
17
* This product includes software developed by Niels Provos.
18
* 4. The name of the author may not be used to endorse or promote products
19
* derived from this software without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
#include <sys/cdefs.h>
34
/* This password hashing algorithm was designed by David Mazieres
35
* <[email protected]> and works as follows:
36
*
37
* 1. state := InitState ()
38
* 2. state := ExpandKey (state, salt, password)
39
* 3. REPEAT rounds:
40
* state := ExpandKey (state, 0, password)
41
* state := ExpandKey (state, 0, salt)
42
* 4. ctext := "OrpheanBeholderScryDoubt"
43
* 5. REPEAT 64:
44
* ctext := Encrypt_ECB (state, ctext);
45
* 6. RETURN Concatenate (salt, ctext);
46
*
47
*/
48
49
/*
50
* FreeBSD implementation by Paul Herman <[email protected]>
51
* and updated by Xin Li <[email protected]>
52
*/
53
54
#include <stdio.h>
55
#include <stdlib.h>
56
#include <sys/types.h>
57
#include <string.h>
58
#include <pwd.h>
59
#include "blowfish.h"
60
#include "crypt.h"
61
62
/* This implementation is adaptable to current computing power.
63
* You can have up to 2^31 rounds which should be enough for some
64
* time to come.
65
*/
66
67
#define BCRYPT_VERSION '2'
68
#define BCRYPT_MAXSALT 16 /* Precomputation is just so nice */
69
#define BCRYPT_BLOCKS 6 /* Ciphertext blocks */
70
#define BCRYPT_MINLOGROUNDS 4 /* we have log2(rounds) in salt */
71
72
73
static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t);
74
static void decode_base64(u_int8_t *, u_int16_t, const u_int8_t *);
75
76
const static u_int8_t Base64Code[] =
77
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
78
79
const static u_int8_t index_64[128] = {
80
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
81
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
82
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
83
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
84
255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
85
56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
86
255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
87
7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
88
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
89
255, 255, 255, 255, 255, 255, 28, 29, 30,
90
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
91
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
92
51, 52, 53, 255, 255, 255, 255, 255
93
};
94
#define CHAR64(c) ( (c) > 127 ? 255 : index_64[(c)])
95
96
static void
97
decode_base64(u_int8_t *buffer, u_int16_t len, const u_int8_t *data)
98
{
99
u_int8_t *bp = buffer;
100
const u_int8_t *p = data;
101
u_int8_t c1, c2, c3, c4;
102
while (bp < buffer + len) {
103
c1 = CHAR64(*p);
104
c2 = CHAR64(*(p + 1));
105
106
/* Invalid data */
107
if (c1 == 255 || c2 == 255)
108
break;
109
110
*bp++ = (c1 << 2) | ((c2 & 0x30) >> 4);
111
if (bp >= buffer + len)
112
break;
113
114
c3 = CHAR64(*(p + 2));
115
if (c3 == 255)
116
break;
117
118
*bp++ = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2);
119
if (bp >= buffer + len)
120
break;
121
122
c4 = CHAR64(*(p + 3));
123
if (c4 == 255)
124
break;
125
*bp++ = ((c3 & 0x03) << 6) | c4;
126
127
p += 4;
128
}
129
}
130
131
/* We handle $Vers$log2(NumRounds)$salt+passwd$
132
i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
133
134
int
135
crypt_blowfish(const char *key, const char *salt, char *buffer)
136
{
137
blf_ctx state;
138
u_int32_t rounds, i, k;
139
u_int16_t j;
140
size_t key_len;
141
u_int8_t salt_len, logr, minr;
142
u_int8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt";
143
u_int8_t csalt[BCRYPT_MAXSALT];
144
u_int32_t cdata[BCRYPT_BLOCKS];
145
char arounds[3];
146
147
/* Defaults */
148
minr = 'b';
149
logr = BCRYPT_MINLOGROUNDS;
150
rounds = 1U << logr;
151
152
if (*salt == '$') {
153
/* Discard "$" identifier */
154
salt++;
155
156
if (*salt > BCRYPT_VERSION)
157
return (-1);
158
159
/* Check for minor versions */
160
if (salt[1] != '$') {
161
switch (salt[1]) {
162
case 'a': /* 'ab' should not yield the same as 'abab' */
163
case 'b': /* cap input length at 72 bytes */
164
case 'y': /* same as 'b', for compatibility
165
* with openwall crypt_blowfish
166
*/
167
minr = salt[1];
168
salt++;
169
break;
170
default:
171
return (-1);
172
}
173
} else
174
minr = 0;
175
176
/* Discard version + "$" identifier */
177
salt += 2;
178
179
if (salt[2] != '$')
180
/* Out of sync with passwd entry */
181
return (-1);
182
183
memcpy(arounds, salt, sizeof(arounds));
184
if (arounds[sizeof(arounds) - 1] != '$')
185
return (-1);
186
arounds[sizeof(arounds) - 1] = 0;
187
logr = strtonum(arounds, BCRYPT_MINLOGROUNDS, 31, NULL);
188
if (logr == 0)
189
return (-1);
190
/* Computer power doesn't increase linearly, 2^x should be fine */
191
rounds = 1U << logr;
192
193
/* Discard num rounds + "$" identifier */
194
salt += 3;
195
}
196
197
if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)
198
return (-1);
199
200
/* We dont want the base64 salt but the raw data */
201
decode_base64(csalt, BCRYPT_MAXSALT, (const u_int8_t *) salt);
202
salt_len = BCRYPT_MAXSALT;
203
if (minr <= 'a')
204
key_len = (u_int8_t)(strlen(key) + (minr >= 'a' ? 1 : 0));
205
else {
206
/* strlen() returns a size_t, but the function calls
207
* below result in implicit casts to a narrower integer
208
* type, so cap key_len at the actual maximum supported
209
* length here to avoid integer wraparound */
210
key_len = strlen(key);
211
if (key_len > 72)
212
key_len = 72;
213
key_len++; /* include the NUL */
214
}
215
216
/* Setting up S-Boxes and Subkeys */
217
Blowfish_initstate(&state);
218
Blowfish_expandstate(&state, csalt, salt_len,
219
(const u_int8_t *) key, key_len);
220
for (k = 0; k < rounds; k++) {
221
Blowfish_expand0state(&state, (const u_int8_t *) key, key_len);
222
Blowfish_expand0state(&state, csalt, salt_len);
223
}
224
225
/* This can be precomputed later */
226
j = 0;
227
for (i = 0; i < BCRYPT_BLOCKS; i++)
228
cdata[i] = Blowfish_stream2word(ciphertext, 4 * BCRYPT_BLOCKS, &j);
229
230
/* Now do the encryption */
231
for (k = 0; k < 64; k++)
232
blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
233
234
for (i = 0; i < BCRYPT_BLOCKS; i++) {
235
ciphertext[4 * i + 3] = cdata[i] & 0xff;
236
cdata[i] = cdata[i] >> 8;
237
ciphertext[4 * i + 2] = cdata[i] & 0xff;
238
cdata[i] = cdata[i] >> 8;
239
ciphertext[4 * i + 1] = cdata[i] & 0xff;
240
cdata[i] = cdata[i] >> 8;
241
ciphertext[4 * i + 0] = cdata[i] & 0xff;
242
}
243
244
245
*buffer++ = '$';
246
*buffer++ = BCRYPT_VERSION;
247
if (minr)
248
*buffer++ = minr;
249
*buffer++ = '$';
250
251
snprintf(buffer, 4, "%2.2u$", logr);
252
buffer += 3;
253
254
encode_base64((u_int8_t *)buffer, csalt, BCRYPT_MAXSALT);
255
buffer += strlen(buffer);
256
encode_base64((u_int8_t *)buffer, ciphertext, 4 * BCRYPT_BLOCKS - 1);
257
memset(&state, 0, sizeof(state));
258
memset(ciphertext, 0, sizeof(ciphertext));
259
memset(csalt, 0, sizeof(csalt));
260
memset(cdata, 0, sizeof(cdata));
261
return (0);
262
}
263
264
static void
265
encode_base64(u_int8_t *buffer, u_int8_t *data, u_int16_t len)
266
{
267
u_int8_t *bp = buffer;
268
u_int8_t *p = data;
269
u_int8_t c1, c2;
270
while (p < data + len) {
271
c1 = *p++;
272
*bp++ = Base64Code[(c1 >> 2)];
273
c1 = (c1 & 0x03) << 4;
274
if (p >= data + len) {
275
*bp++ = Base64Code[c1];
276
break;
277
}
278
c2 = *p++;
279
c1 |= (c2 >> 4) & 0x0f;
280
*bp++ = Base64Code[c1];
281
c1 = (c2 & 0x0f) << 2;
282
if (p >= data + len) {
283
*bp++ = Base64Code[c1];
284
break;
285
}
286
c2 = *p++;
287
c1 |= (c2 >> 6) & 0x03;
288
*bp++ = Base64Code[c1];
289
*bp++ = Base64Code[c2 & 0x3f];
290
}
291
*bp = '\0';
292
}
293
#if 0
294
void
295
main()
296
{
297
char blubber[73];
298
char salt[100];
299
char *p;
300
salt[0] = '$';
301
salt[1] = BCRYPT_VERSION;
302
salt[2] = '$';
303
304
snprintf(salt + 3, 4, "%2.2u$", 5);
305
306
printf("24 bytes of salt: ");
307
fgets(salt + 6, sizeof(salt) - 6, stdin);
308
salt[99] = 0;
309
printf("72 bytes of password: ");
310
fpurge(stdin);
311
fgets(blubber, sizeof(blubber), stdin);
312
blubber[72] = 0;
313
314
p = crypt(blubber, salt);
315
printf("Passwd entry: %s\n\n", p);
316
317
p = bcrypt_gensalt(5);
318
printf("Generated salt: %s\n", p);
319
p = crypt(blubber, p);
320
printf("Passwd entry: %s\n", p);
321
}
322
#endif
323
324