diff options
Diffstat (limited to 'openbsd-compat/bcrypt_pbkdf.c')
-rw-r--r-- | openbsd-compat/bcrypt_pbkdf.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/openbsd-compat/bcrypt_pbkdf.c b/openbsd-compat/bcrypt_pbkdf.c new file mode 100644 index 000000000..91b6ba07b --- /dev/null +++ b/openbsd-compat/bcrypt_pbkdf.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* $OpenBSD: bcrypt_pbkdf.c,v 1.4 2013/07/29 00:55:53 tedu Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2013 Ted Unangst <tedu@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include "includes.h" | ||
19 | |||
20 | #ifndef HAVE_BCRYPT_PBKDF | ||
21 | |||
22 | #include <sys/types.h> | ||
23 | #include <sys/param.h> | ||
24 | |||
25 | #ifdef HAVE_STDLIB_H | ||
26 | # include <stdlib.h> | ||
27 | #endif | ||
28 | #include <string.h> | ||
29 | |||
30 | #ifdef HAVE_BLF_H | ||
31 | # include <blf.h> | ||
32 | #endif | ||
33 | |||
34 | #include "crypto_api.h" | ||
35 | #define SHA512_DIGEST_LENGTH crypto_hash_sha512_BYTES | ||
36 | |||
37 | /* | ||
38 | * pkcs #5 pbkdf2 implementation using the "bcrypt" hash | ||
39 | * | ||
40 | * The bcrypt hash function is derived from the bcrypt password hashing | ||
41 | * function with the following modifications: | ||
42 | * 1. The input password and salt are preprocessed with SHA512. | ||
43 | * 2. The output length is expanded to 256 bits. | ||
44 | * 3. Subsequently the magic string to be encrypted is lengthened and modifed | ||
45 | * to "OxychromaticBlowfishSwatDynamite" | ||
46 | * 4. The hash function is defined to perform 64 rounds of initial state | ||
47 | * expansion. (More rounds are performed by iterating the hash.) | ||
48 | * | ||
49 | * Note that this implementation pulls the SHA512 operations into the caller | ||
50 | * as a performance optimization. | ||
51 | * | ||
52 | * One modification from official pbkdf2. Instead of outputting key material | ||
53 | * linearly, we mix it. pbkdf2 has a known weakness where if one uses it to | ||
54 | * generate (i.e.) 512 bits of key material for use as two 256 bit keys, an | ||
55 | * attacker can merely run once through the outer loop below, but the user | ||
56 | * always runs it twice. Shuffling output bytes requires computing the | ||
57 | * entirety of the key material to assemble any subkey. This is something a | ||
58 | * wise caller could do; we just do it for you. | ||
59 | */ | ||
60 | |||
61 | #define BCRYPT_BLOCKS 8 | ||
62 | #define BCRYPT_HASHSIZE (BCRYPT_BLOCKS * 4) | ||
63 | |||
64 | static void | ||
65 | bcrypt_hash(u_int8_t *sha2pass, u_int8_t *sha2salt, u_int8_t *out) | ||
66 | { | ||
67 | blf_ctx state; | ||
68 | u_int8_t ciphertext[BCRYPT_HASHSIZE] = | ||
69 | "OxychromaticBlowfishSwatDynamite"; | ||
70 | uint32_t cdata[BCRYPT_BLOCKS]; | ||
71 | int i; | ||
72 | uint16_t j; | ||
73 | size_t shalen = SHA512_DIGEST_LENGTH; | ||
74 | |||
75 | /* key expansion */ | ||
76 | Blowfish_initstate(&state); | ||
77 | Blowfish_expandstate(&state, sha2salt, shalen, sha2pass, shalen); | ||
78 | for (i = 0; i < 64; i++) { | ||
79 | Blowfish_expand0state(&state, sha2salt, shalen); | ||
80 | Blowfish_expand0state(&state, sha2pass, shalen); | ||
81 | } | ||
82 | |||
83 | /* encryption */ | ||
84 | j = 0; | ||
85 | for (i = 0; i < BCRYPT_BLOCKS; i++) | ||
86 | cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext), | ||
87 | &j); | ||
88 | for (i = 0; i < 64; i++) | ||
89 | blf_enc(&state, cdata, sizeof(cdata) / sizeof(uint64_t)); | ||
90 | |||
91 | /* copy out */ | ||
92 | for (i = 0; i < BCRYPT_BLOCKS; i++) { | ||
93 | out[4 * i + 3] = (cdata[i] >> 24) & 0xff; | ||
94 | out[4 * i + 2] = (cdata[i] >> 16) & 0xff; | ||
95 | out[4 * i + 1] = (cdata[i] >> 8) & 0xff; | ||
96 | out[4 * i + 0] = cdata[i] & 0xff; | ||
97 | } | ||
98 | |||
99 | /* zap */ | ||
100 | memset(ciphertext, 0, sizeof(ciphertext)); | ||
101 | memset(cdata, 0, sizeof(cdata)); | ||
102 | memset(&state, 0, sizeof(state)); | ||
103 | } | ||
104 | |||
105 | int | ||
106 | bcrypt_pbkdf(const char *pass, size_t passlen, const u_int8_t *salt, size_t saltlen, | ||
107 | u_int8_t *key, size_t keylen, unsigned int rounds) | ||
108 | { | ||
109 | u_int8_t sha2pass[SHA512_DIGEST_LENGTH]; | ||
110 | u_int8_t sha2salt[SHA512_DIGEST_LENGTH]; | ||
111 | u_int8_t out[BCRYPT_HASHSIZE]; | ||
112 | u_int8_t tmpout[BCRYPT_HASHSIZE]; | ||
113 | u_int8_t *countsalt; | ||
114 | size_t i, j, amt, stride; | ||
115 | uint32_t count; | ||
116 | |||
117 | /* nothing crazy */ | ||
118 | if (rounds < 1) | ||
119 | return -1; | ||
120 | if (passlen == 0 || saltlen == 0 || keylen == 0 || | ||
121 | keylen > sizeof(out) * sizeof(out) || saltlen > 1<<20) | ||
122 | return -1; | ||
123 | if ((countsalt = calloc(1, saltlen + 4)) == NULL) | ||
124 | return -1; | ||
125 | stride = (keylen + sizeof(out) - 1) / sizeof(out); | ||
126 | amt = (keylen + stride - 1) / stride; | ||
127 | |||
128 | memcpy(countsalt, salt, saltlen); | ||
129 | |||
130 | /* collapse password */ | ||
131 | crypto_hash_sha512(sha2pass, pass, passlen); | ||
132 | |||
133 | /* generate key, sizeof(out) at a time */ | ||
134 | for (count = 1; keylen > 0; count++) { | ||
135 | countsalt[saltlen + 0] = (count >> 24) & 0xff; | ||
136 | countsalt[saltlen + 1] = (count >> 16) & 0xff; | ||
137 | countsalt[saltlen + 2] = (count >> 8) & 0xff; | ||
138 | countsalt[saltlen + 3] = count & 0xff; | ||
139 | |||
140 | /* first round, salt is salt */ | ||
141 | crypto_hash_sha512(sha2salt, countsalt, saltlen + 4); | ||
142 | |||
143 | bcrypt_hash(sha2pass, sha2salt, tmpout); | ||
144 | memcpy(out, tmpout, sizeof(out)); | ||
145 | |||
146 | for (i = 1; i < rounds; i++) { | ||
147 | /* subsequent rounds, salt is previous output */ | ||
148 | crypto_hash_sha512(sha2salt, tmpout, sizeof(tmpout)); | ||
149 | bcrypt_hash(sha2pass, sha2salt, tmpout); | ||
150 | for (j = 0; j < sizeof(out); j++) | ||
151 | out[j] ^= tmpout[j]; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * pbkdf2 deviation: ouput the key material non-linearly. | ||
156 | */ | ||
157 | amt = MIN(amt, keylen); | ||
158 | for (i = 0; i < amt; i++) | ||
159 | key[i * stride + (count - 1)] = out[i]; | ||
160 | keylen -= amt; | ||
161 | } | ||
162 | |||
163 | /* zap */ | ||
164 | memset(out, 0, sizeof(out)); | ||
165 | memset(countsalt, 0, saltlen + 4); | ||
166 | free(countsalt); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | #endif /* HAVE_BCRYPT_PBKDF */ | ||