1/**
2 * \file pkcs5.c
3 *
4 * \brief PKCS#5 functions
5 *
6 * \author Mathias Olsson <mathias@kompetensum.com>
7 *
8 * Copyright The Mbed TLS Contributors
9 * SPDX-License-Identifier: Apache-2.0
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License"); you may
12 * not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
19 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23/*
24 * PKCS#5 includes PBKDF2 and more
25 *
26 * http://tools.ietf.org/html/rfc2898 (Specification)
27 * http://tools.ietf.org/html/rfc6070 (Test vectors)
28 */
29
30#include "common.h"
31
32#if defined(MBEDTLS_PKCS5_C)
33
34#include "mbedtls/pkcs5.h"
35#include "mbedtls/error.h"
36
37#if defined(MBEDTLS_ASN1_PARSE_C)
38#include "mbedtls/asn1.h"
39#include "mbedtls/cipher.h"
40#include "mbedtls/oid.h"
41#endif /* MBEDTLS_ASN1_PARSE_C */
42
43#include <string.h>
44
45#include "mbedtls/platform.h"
46
47#if defined(MBEDTLS_ASN1_PARSE_C)
48static int pkcs5_parse_pbkdf2_params(const mbedtls_asn1_buf *params,
49 mbedtls_asn1_buf *salt, int *iterations,
50 int *keylen, mbedtls_md_type_t *md_type)
51{
52 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
53 mbedtls_asn1_buf prf_alg_oid;
54 unsigned char *p = params->p;
55 const unsigned char *end = params->p + params->len;
56
57 if (params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
58 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
59 MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
60 }
61 /*
62 * PBKDF2-params ::= SEQUENCE {
63 * salt OCTET STRING,
64 * iterationCount INTEGER,
65 * keyLength INTEGER OPTIONAL
66 * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1
67 * }
68 *
69 */
70 if ((ret = mbedtls_asn1_get_tag(&p, end, &salt->len,
71 MBEDTLS_ASN1_OCTET_STRING)) != 0) {
72 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
73 }
74
75 salt->p = p;
76 p += salt->len;
77
78 if ((ret = mbedtls_asn1_get_int(&p, end, iterations)) != 0) {
79 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
80 }
81
82 if (p == end) {
83 return 0;
84 }
85
86 if ((ret = mbedtls_asn1_get_int(&p, end, keylen)) != 0) {
87 if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
88 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
89 }
90 }
91
92 if (p == end) {
93 return 0;
94 }
95
96 if ((ret = mbedtls_asn1_get_alg_null(&p, end, &prf_alg_oid)) != 0) {
97 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
98 }
99
100 if (mbedtls_oid_get_md_hmac(&prf_alg_oid, md_type) != 0) {
101 return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
102 }
103
104 if (p != end) {
105 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
106 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
107 }
108
109 return 0;
110}
111
112int mbedtls_pkcs5_pbes2(const mbedtls_asn1_buf *pbe_params, int mode,
113 const unsigned char *pwd, size_t pwdlen,
114 const unsigned char *data, size_t datalen,
115 unsigned char *output)
116{
117 int ret, iterations = 0, keylen = 0;
118 unsigned char *p, *end;
119 mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
120 mbedtls_asn1_buf salt;
121 mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1;
122 unsigned char key[32], iv[32];
123 size_t olen = 0;
124 const mbedtls_md_info_t *md_info;
125 const mbedtls_cipher_info_t *cipher_info;
126 mbedtls_md_context_t md_ctx;
127 mbedtls_cipher_type_t cipher_alg;
128 mbedtls_cipher_context_t cipher_ctx;
129
130 p = pbe_params->p;
131 end = p + pbe_params->len;
132
133 /*
134 * PBES2-params ::= SEQUENCE {
135 * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
136 * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
137 * }
138 */
139 if (pbe_params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
140 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
141 MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
142 }
143
144 if ((ret = mbedtls_asn1_get_alg(&p, end, &kdf_alg_oid,
145 &kdf_alg_params)) != 0) {
146 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
147 }
148
149 // Only PBKDF2 supported at the moment
150 //
151 if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid) != 0) {
152 return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
153 }
154
155 if ((ret = pkcs5_parse_pbkdf2_params(&kdf_alg_params,
156 &salt, &iterations, &keylen,
157 &md_type)) != 0) {
158 return ret;
159 }
160
161 md_info = mbedtls_md_info_from_type(md_type);
162 if (md_info == NULL) {
163 return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
164 }
165
166 if ((ret = mbedtls_asn1_get_alg(&p, end, &enc_scheme_oid,
167 &enc_scheme_params)) != 0) {
168 return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
169 }
170
171 if (mbedtls_oid_get_cipher_alg(&enc_scheme_oid, &cipher_alg) != 0) {
172 return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
173 }
174
175 cipher_info = mbedtls_cipher_info_from_type(cipher_alg);
176 if (cipher_info == NULL) {
177 return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
178 }
179
180 /*
181 * The value of keylen from pkcs5_parse_pbkdf2_params() is ignored
182 * since it is optional and we don't know if it was set or not
183 */
184 keylen = cipher_info->key_bitlen / 8;
185
186 if (enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING ||
187 enc_scheme_params.len != cipher_info->iv_size) {
188 return MBEDTLS_ERR_PKCS5_INVALID_FORMAT;
189 }
190
191 mbedtls_md_init(&md_ctx);
192 mbedtls_cipher_init(&cipher_ctx);
193
194 memcpy(iv, enc_scheme_params.p, enc_scheme_params.len);
195
196 if ((ret = mbedtls_md_setup(&md_ctx, md_info, 1)) != 0) {
197 goto exit;
198 }
199
200 if ((ret = mbedtls_pkcs5_pbkdf2_hmac(&md_ctx, pwd, pwdlen, salt.p, salt.len,
201 iterations, keylen, key)) != 0) {
202 goto exit;
203 }
204
205 if ((ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info)) != 0) {
206 goto exit;
207 }
208
209 if ((ret = mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen,
210 (mbedtls_operation_t) mode)) != 0) {
211 goto exit;
212 }
213
214 if ((ret = mbedtls_cipher_crypt(&cipher_ctx, iv, enc_scheme_params.len,
215 data, datalen, output, &olen)) != 0) {
216 ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH;
217 }
218
219exit:
220 mbedtls_md_free(&md_ctx);
221 mbedtls_cipher_free(&cipher_ctx);
222
223 return ret;
224}
225#endif /* MBEDTLS_ASN1_PARSE_C */
226
227int mbedtls_pkcs5_pbkdf2_hmac(mbedtls_md_context_t *ctx,
228 const unsigned char *password,
229 size_t plen, const unsigned char *salt, size_t slen,
230 unsigned int iteration_count,
231 uint32_t key_length, unsigned char *output)
232{
233 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
234 int j;
235 unsigned int i;
236 unsigned char md1[MBEDTLS_MD_MAX_SIZE];
237 unsigned char work[MBEDTLS_MD_MAX_SIZE];
238 unsigned char md_size = mbedtls_md_get_size(ctx->md_info);
239 size_t use_len;
240 unsigned char *out_p = output;
241 unsigned char counter[4];
242
243 memset(counter, 0, 4);
244 counter[3] = 1;
245
246#if UINT_MAX > 0xFFFFFFFF
247 if (iteration_count > 0xFFFFFFFF) {
248 return MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA;
249 }
250#endif
251
252 if ((ret = mbedtls_md_hmac_starts(ctx, password, plen)) != 0) {
253 return ret;
254 }
255 while (key_length) {
256 // U1 ends up in work
257 //
258 if ((ret = mbedtls_md_hmac_update(ctx, salt, slen)) != 0) {
259 goto cleanup;
260 }
261
262 if ((ret = mbedtls_md_hmac_update(ctx, counter, 4)) != 0) {
263 goto cleanup;
264 }
265
266 if ((ret = mbedtls_md_hmac_finish(ctx, work)) != 0) {
267 goto cleanup;
268 }
269
270 if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) {
271 goto cleanup;
272 }
273
274 memcpy(md1, work, md_size);
275
276 for (i = 1; i < iteration_count; i++) {
277 // U2 ends up in md1
278 //
279 if ((ret = mbedtls_md_hmac_update(ctx, md1, md_size)) != 0) {
280 goto cleanup;
281 }
282
283 if ((ret = mbedtls_md_hmac_finish(ctx, md1)) != 0) {
284 goto cleanup;
285 }
286
287 if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) {
288 goto cleanup;
289 }
290
291 // U1 xor U2
292 //
293 for (j = 0; j < md_size; j++) {
294 work[j] ^= md1[j];
295 }
296 }
297
298 use_len = (key_length < md_size) ? key_length : md_size;
299 memcpy(out_p, work, use_len);
300
301 key_length -= (uint32_t) use_len;
302 out_p += use_len;
303
304 for (i = 4; i > 0; i--) {
305 if (++counter[i - 1] != 0) {
306 break;
307 }
308 }
309 }
310
311cleanup:
312 /* Zeroise buffers to clear sensitive data from memory. */
313 mbedtls_platform_zeroize(work, MBEDTLS_MD_MAX_SIZE);
314 mbedtls_platform_zeroize(md1, MBEDTLS_MD_MAX_SIZE);
315
316 return ret;
317}
318
319#if defined(MBEDTLS_SELF_TEST)
320
321#if !defined(MBEDTLS_SHA1_C)
322int mbedtls_pkcs5_self_test(int verbose)
323{
324 if (verbose != 0) {
325 mbedtls_printf(" PBKDF2 (SHA1): skipped\n\n");
326 }
327
328 return 0;
329}
330#else
331
332#define MAX_TESTS 6
333
334static const size_t plen_test_data[MAX_TESTS] =
335{ 8, 8, 8, 24, 9 };
336
337static const unsigned char password_test_data[MAX_TESTS][32] =
338{
339 "password",
340 "password",
341 "password",
342 "passwordPASSWORDpassword",
343 "pass\0word",
344};
345
346static const size_t slen_test_data[MAX_TESTS] =
347{ 4, 4, 4, 36, 5 };
348
349static const unsigned char salt_test_data[MAX_TESTS][40] =
350{
351 "salt",
352 "salt",
353 "salt",
354 "saltSALTsaltSALTsaltSALTsaltSALTsalt",
355 "sa\0lt",
356};
357
358static const uint32_t it_cnt_test_data[MAX_TESTS] =
359{ 1, 2, 4096, 4096, 4096 };
360
361static const uint32_t key_len_test_data[MAX_TESTS] =
362{ 20, 20, 20, 25, 16 };
363
364static const unsigned char result_key_test_data[MAX_TESTS][32] =
365{
366 { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
367 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
368 0x2f, 0xe0, 0x37, 0xa6 },
369 { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
370 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
371 0xd8, 0xde, 0x89, 0x57 },
372 { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
373 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
374 0x65, 0xa4, 0x29, 0xc1 },
375 { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
376 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
377 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
378 0x38 },
379 { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
380 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 },
381};
382
383int mbedtls_pkcs5_self_test(int verbose)
384{
385 mbedtls_md_context_t sha1_ctx;
386 const mbedtls_md_info_t *info_sha1;
387 int ret, i;
388 unsigned char key[64];
389
390 mbedtls_md_init(&sha1_ctx);
391
392 info_sha1 = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
393 if (info_sha1 == NULL) {
394 ret = 1;
395 goto exit;
396 }
397
398 if ((ret = mbedtls_md_setup(&sha1_ctx, info_sha1, 1)) != 0) {
399 ret = 1;
400 goto exit;
401 }
402
403 for (i = 0; i < MAX_TESTS; i++) {
404 if (verbose != 0) {
405 mbedtls_printf(" PBKDF2 (SHA1) #%d: ", i);
406 }
407
408 ret = mbedtls_pkcs5_pbkdf2_hmac(&sha1_ctx, password_test_data[i],
409 plen_test_data[i], salt_test_data[i],
410 slen_test_data[i], it_cnt_test_data[i],
411 key_len_test_data[i], key);
412 if (ret != 0 ||
413 memcmp(result_key_test_data[i], key, key_len_test_data[i]) != 0) {
414 if (verbose != 0) {
415 mbedtls_printf("failed\n");
416 }
417
418 ret = 1;
419 goto exit;
420 }
421
422 if (verbose != 0) {
423 mbedtls_printf("passed\n");
424 }
425 }
426
427 if (verbose != 0) {
428 mbedtls_printf("\n");
429 }
430
431exit:
432 mbedtls_md_free(&sha1_ctx);
433
434 return ret;
435}
436#endif /* MBEDTLS_SHA1_C */
437
438#endif /* MBEDTLS_SELF_TEST */
439
440#endif /* MBEDTLS_PKCS5_C */
441