]>
Commit | Line | Data |
---|---|---|
5a285add DM |
1 | /* |
2 | * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * | |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | #include <stdlib.h> | |
11 | #include <stdarg.h> | |
12 | #include <string.h> | |
13 | #include <openssl/hmac.h> | |
14 | #include <openssl/evp.h> | |
15 | #include <openssl/kdf.h> | |
16 | #include "internal/cryptlib.h" | |
17 | #include "internal/evp_int.h" | |
18 | #include "kdf_local.h" | |
19 | ||
20 | static void kdf_pbkdf2_reset(EVP_KDF_IMPL *impl); | |
21 | static void kdf_pbkdf2_init(EVP_KDF_IMPL *impl); | |
22 | static int pkcs5_pbkdf2_alg(const char *pass, size_t passlen, | |
23 | const unsigned char *salt, int saltlen, int iter, | |
24 | const EVP_MD *digest, unsigned char *key, | |
25 | size_t keylen); | |
26 | ||
27 | struct evp_kdf_impl_st { | |
28 | unsigned char *pass; | |
29 | size_t pass_len; | |
30 | unsigned char *salt; | |
31 | size_t salt_len; | |
32 | int iter; | |
33 | const EVP_MD *md; | |
34 | }; | |
35 | ||
36 | static EVP_KDF_IMPL *kdf_pbkdf2_new(void) | |
37 | { | |
38 | EVP_KDF_IMPL *impl; | |
39 | ||
40 | impl = OPENSSL_zalloc(sizeof(*impl)); | |
41 | if (impl == NULL) { | |
42 | KDFerr(KDF_F_KDF_PBKDF2_NEW, ERR_R_MALLOC_FAILURE); | |
43 | return NULL; | |
44 | } | |
45 | kdf_pbkdf2_init(impl); | |
46 | return impl; | |
47 | } | |
48 | ||
49 | static void kdf_pbkdf2_free(EVP_KDF_IMPL *impl) | |
50 | { | |
51 | kdf_pbkdf2_reset(impl); | |
52 | OPENSSL_free(impl); | |
53 | } | |
54 | ||
55 | static void kdf_pbkdf2_reset(EVP_KDF_IMPL *impl) | |
56 | { | |
57 | OPENSSL_free(impl->salt); | |
58 | OPENSSL_clear_free(impl->pass, impl->pass_len); | |
59 | memset(impl, 0, sizeof(*impl)); | |
60 | kdf_pbkdf2_init(impl); | |
61 | } | |
62 | ||
63 | static void kdf_pbkdf2_init(EVP_KDF_IMPL *impl) | |
64 | { | |
65 | impl->iter = PKCS5_DEFAULT_ITER; | |
66 | impl->md = EVP_sha1(); | |
67 | } | |
68 | ||
69 | static int pbkdf2_set_membuf(unsigned char **buffer, size_t *buflen, | |
70 | const unsigned char *new_buffer, | |
71 | size_t new_buflen) | |
72 | { | |
73 | if (new_buffer == NULL) | |
74 | return 1; | |
75 | ||
76 | OPENSSL_clear_free(*buffer, *buflen); | |
77 | ||
78 | if (new_buflen > 0) { | |
79 | *buffer = OPENSSL_memdup(new_buffer, new_buflen); | |
80 | } else { | |
81 | *buffer = OPENSSL_malloc(1); | |
82 | } | |
83 | if (*buffer == NULL) { | |
84 | KDFerr(KDF_F_PBKDF2_SET_MEMBUF, ERR_R_MALLOC_FAILURE); | |
85 | return 0; | |
86 | } | |
87 | ||
88 | *buflen = new_buflen; | |
89 | return 1; | |
90 | } | |
91 | ||
92 | static int kdf_pbkdf2_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args) | |
93 | { | |
94 | int iter; | |
95 | const unsigned char *p; | |
96 | size_t len; | |
97 | const EVP_MD *md; | |
98 | ||
99 | switch (cmd) { | |
100 | case EVP_KDF_CTRL_SET_PASS: | |
101 | p = va_arg(args, const unsigned char *); | |
102 | len = va_arg(args, size_t); | |
103 | return pbkdf2_set_membuf(&impl->pass, &impl->pass_len, p, len); | |
104 | ||
105 | case EVP_KDF_CTRL_SET_SALT: | |
106 | p = va_arg(args, const unsigned char *); | |
107 | len = va_arg(args, size_t); | |
108 | return pbkdf2_set_membuf(&impl->salt, &impl->salt_len, p, len); | |
109 | ||
110 | case EVP_KDF_CTRL_SET_ITER: | |
111 | iter = va_arg(args, int); | |
112 | if (iter < 1) | |
113 | return 0; | |
114 | ||
115 | impl->iter = iter; | |
116 | return 1; | |
117 | ||
118 | case EVP_KDF_CTRL_SET_MD: | |
119 | md = va_arg(args, const EVP_MD *); | |
120 | if (md == NULL) | |
121 | return 0; | |
122 | ||
123 | impl->md = md; | |
124 | return 1; | |
125 | ||
126 | default: | |
127 | return -2; | |
128 | } | |
129 | } | |
130 | ||
131 | static int kdf_pbkdf2_ctrl_str(EVP_KDF_IMPL *impl, const char *type, | |
132 | const char *value) | |
133 | { | |
134 | if (value == NULL) { | |
135 | KDFerr(KDF_F_KDF_PBKDF2_CTRL_STR, KDF_R_VALUE_MISSING); | |
136 | return 0; | |
137 | } | |
138 | ||
139 | if (strcmp(type, "pass") == 0) | |
140 | return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_PASS, | |
141 | value); | |
142 | ||
143 | if (strcmp(type, "hexpass") == 0) | |
144 | return kdf_hex2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_PASS, | |
145 | value); | |
146 | ||
147 | if (strcmp(type, "salt") == 0) | |
148 | return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_SALT, | |
149 | value); | |
150 | ||
151 | if (strcmp(type, "hexsalt") == 0) | |
152 | return kdf_hex2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_SALT, | |
153 | value); | |
154 | ||
155 | if (strcmp(type, "iter") == 0) | |
156 | return call_ctrl(kdf_pbkdf2_ctrl, impl, EVP_KDF_CTRL_SET_ITER, | |
157 | atoi(value)); | |
158 | ||
159 | if (strcmp(type, "digest") == 0) | |
160 | return kdf_md2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_MD, value); | |
161 | ||
162 | return -2; | |
163 | } | |
164 | ||
165 | static int kdf_pbkdf2_derive(EVP_KDF_IMPL *impl, unsigned char *key, | |
166 | size_t keylen) | |
167 | { | |
168 | if (impl->pass == NULL) { | |
169 | KDFerr(KDF_F_KDF_PBKDF2_DERIVE, KDF_R_MISSING_PASS); | |
170 | return 0; | |
171 | } | |
172 | ||
173 | if (impl->salt == NULL) { | |
174 | KDFerr(KDF_F_KDF_PBKDF2_DERIVE, KDF_R_MISSING_SALT); | |
175 | return 0; | |
176 | } | |
177 | ||
178 | return pkcs5_pbkdf2_alg((char *)impl->pass, impl->pass_len, | |
179 | impl->salt, impl->salt_len, impl->iter, | |
180 | impl->md, key, keylen); | |
181 | } | |
182 | ||
d2ba8123 | 183 | const EVP_KDF pbkdf2_kdf_meth = { |
5a285add DM |
184 | EVP_KDF_PBKDF2, |
185 | kdf_pbkdf2_new, | |
186 | kdf_pbkdf2_free, | |
187 | kdf_pbkdf2_reset, | |
188 | kdf_pbkdf2_ctrl, | |
189 | kdf_pbkdf2_ctrl_str, | |
190 | NULL, | |
191 | kdf_pbkdf2_derive | |
192 | }; | |
193 | ||
194 | /* | |
195 | * This is an implementation of PKCS#5 v2.0 password based encryption key | |
196 | * derivation function PBKDF2. SHA1 version verified against test vectors | |
197 | * posted by Peter Gutmann to the PKCS-TNG mailing list. | |
198 | */ | |
199 | ||
200 | static int pkcs5_pbkdf2_alg(const char *pass, size_t passlen, | |
201 | const unsigned char *salt, int saltlen, int iter, | |
202 | const EVP_MD *digest, unsigned char *key, | |
203 | size_t keylen) | |
204 | { | |
205 | int ret = 0; | |
206 | unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4]; | |
207 | int cplen, j, k, tkeylen, mdlen; | |
208 | unsigned long i = 1; | |
209 | HMAC_CTX *hctx_tpl = NULL, *hctx = NULL; | |
210 | ||
211 | mdlen = EVP_MD_size(digest); | |
212 | if (mdlen < 0) | |
213 | return 0; | |
214 | ||
215 | hctx_tpl = HMAC_CTX_new(); | |
216 | if (hctx_tpl == NULL) | |
217 | return 0; | |
218 | p = key; | |
219 | tkeylen = keylen; | |
220 | if (!HMAC_Init_ex(hctx_tpl, pass, passlen, digest, NULL)) | |
221 | goto err; | |
222 | hctx = HMAC_CTX_new(); | |
223 | if (hctx == NULL) | |
224 | goto err; | |
225 | while (tkeylen) { | |
226 | if (tkeylen > mdlen) | |
227 | cplen = mdlen; | |
228 | else | |
229 | cplen = tkeylen; | |
230 | /* | |
231 | * We are unlikely to ever use more than 256 blocks (5120 bits!) but | |
232 | * just in case... | |
233 | */ | |
234 | itmp[0] = (unsigned char)((i >> 24) & 0xff); | |
235 | itmp[1] = (unsigned char)((i >> 16) & 0xff); | |
236 | itmp[2] = (unsigned char)((i >> 8) & 0xff); | |
237 | itmp[3] = (unsigned char)(i & 0xff); | |
238 | if (!HMAC_CTX_copy(hctx, hctx_tpl)) | |
239 | goto err; | |
240 | if (!HMAC_Update(hctx, salt, saltlen) | |
241 | || !HMAC_Update(hctx, itmp, 4) | |
242 | || !HMAC_Final(hctx, digtmp, NULL)) | |
243 | goto err; | |
244 | memcpy(p, digtmp, cplen); | |
245 | for (j = 1; j < iter; j++) { | |
246 | if (!HMAC_CTX_copy(hctx, hctx_tpl)) | |
247 | goto err; | |
248 | if (!HMAC_Update(hctx, digtmp, mdlen) | |
249 | || !HMAC_Final(hctx, digtmp, NULL)) | |
250 | goto err; | |
251 | for (k = 0; k < cplen; k++) | |
252 | p[k] ^= digtmp[k]; | |
253 | } | |
254 | tkeylen -= cplen; | |
255 | i++; | |
256 | p += cplen; | |
257 | } | |
258 | ret = 1; | |
259 | ||
260 | err: | |
261 | HMAC_CTX_free(hctx); | |
262 | HMAC_CTX_free(hctx_tpl); | |
263 | return ret; | |
264 | } |