1
11
17
18
19
20
21
22
23
24
25
26
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
50
59
63
64
65
66
67
70
71
74
75
80
81
84
85
88
89
92
93
97
98
99
100
101
102
107
108
109
110
111
112
113
114
115
116
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
152
156
157
161
162
163
164
167
168
173
174
175
178
179
183
184
187
188
189
192
193
197
198
199
203
204
209
210
216
217
218
219
220
221
222
223
226
227
231
232
235
236
240
241
263
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
300
301
304
305
306
307
310
311
314
315
318
319
322
323
324
325
326
327
328
331
332
335
336
339
340
341
342
345
346
347
348
349
350
351
352
353
358
359
360
361
362
363
364
365
366
367
368
369
370
371
380
381
382
383
384
385
386
387
394
395
396
397
398
399
406
407
408
409
410
411
412
413
414
431
432
433
434
435
436
437
438
439
440
441
442
446
447
451
452
453
456
457
458
459
460
461
470
471
474
475
476
479
480
481
482
483
484
485
486
487
488
489
/* ... */
/* ... */
#include "common.h"
#if defined(MBEDTLS_PKCS5_C)
#include "mbedtls/pkcs5.h"
#include "mbedtls/error.h"
#if defined(MBEDTLS_ASN1_PARSE_C)
#include "mbedtls/asn1.h"
#include "mbedtls/cipher.h"
#include "mbedtls/oid.h"
/* ... */#endif
#include <string.h>
#include "mbedtls/platform.h"
#if defined(MBEDTLS_ASN1_PARSE_C)
static int pkcs5_parse_pbkdf2_params(const mbedtls_asn1_buf *params,
mbedtls_asn1_buf *salt, int *iterations,
int *keylen, mbedtls_md_type_t *md_type)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_asn1_buf prf_alg_oid;
unsigned char *p = params->p;
const unsigned char *end = params->p + params->len;
if (params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
}if (params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) { ... }
/* ... */
if ((ret = mbedtls_asn1_get_tag(&p, end, &salt->len,
MBEDTLS_ASN1_OCTET_STRING)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
}if ((ret = mbedtls_asn1_get_tag(&p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING)) != 0) { ... }
salt->p = p;
p += salt->len;
if ((ret = mbedtls_asn1_get_int(&p, end, iterations)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
}if ((ret = mbedtls_asn1_get_int(&p, end, iterations)) != 0) { ... }
if (p == end) {
return 0;
}if (p == end) { ... }
if ((ret = mbedtls_asn1_get_int(&p, end, keylen)) != 0) {
if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
}if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { ... }
}if ((ret = mbedtls_asn1_get_int(&p, end, keylen)) != 0) { ... }
if (p == end) {
return 0;
}if (p == end) { ... }
if ((ret = mbedtls_asn1_get_alg_null(&p, end, &prf_alg_oid)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
}if ((ret = mbedtls_asn1_get_alg_null(&p, end, &prf_alg_oid)) != 0) { ... }
if (mbedtls_oid_get_md_hmac(&prf_alg_oid, md_type) != 0) {
return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
}if (mbedtls_oid_get_md_hmac(&prf_alg_oid, md_type) != 0) { ... }
if (p != end) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
}if (p != end) { ... }
return 0;
}{ ... }
#if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
int mbedtls_pkcs5_pbes2_ext(const mbedtls_asn1_buf *pbe_params, int mode,
const unsigned char *pwd, size_t pwdlen,
const unsigned char *data, size_t datalen,
unsigned char *output, size_t output_size,
size_t *output_len);/* ... */
#endif
int mbedtls_pkcs5_pbes2(const mbedtls_asn1_buf *pbe_params, int mode,
const unsigned char *pwd, size_t pwdlen,
const unsigned char *data, size_t datalen,
unsigned char *output)
{
size_t output_len = 0;
/* ... */
return mbedtls_pkcs5_pbes2_ext(pbe_params, mode, pwd, pwdlen, data,
datalen, output, SIZE_MAX, &output_len);
}{ ... }
int mbedtls_pkcs5_pbes2_ext(const mbedtls_asn1_buf *pbe_params, int mode,
const unsigned char *pwd, size_t pwdlen,
const unsigned char *data, size_t datalen,
unsigned char *output, size_t output_size,
size_t *output_len)
{
int ret, iterations = 0, keylen = 0;
unsigned char *p, *end;
mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
mbedtls_asn1_buf salt;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1;
unsigned char key[32], iv[32];
const mbedtls_md_info_t *md_info;
const mbedtls_cipher_info_t *cipher_info;
mbedtls_md_context_t md_ctx;
mbedtls_cipher_type_t cipher_alg;
mbedtls_cipher_context_t cipher_ctx;
unsigned int padlen = 0;
p = pbe_params->p;
end = p + pbe_params->len;
/* ... */
if (pbe_params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT,
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
}if (pbe_params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) { ... }
if ((ret = mbedtls_asn1_get_alg(&p, end, &kdf_alg_oid,
&kdf_alg_params)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
}if ((ret = mbedtls_asn1_get_alg(&p, end, &kdf_alg_oid, &kdf_alg_params)) != 0) { ... }
if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid) != 0) {
return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
}if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid) != 0) { ... }
if ((ret = pkcs5_parse_pbkdf2_params(&kdf_alg_params,
&salt, &iterations, &keylen,
&md_type)) != 0) {
return ret;
}if ((ret = pkcs5_parse_pbkdf2_params(&kdf_alg_params, &salt, &iterations, &keylen, &md_type)) != 0) { ... }
md_info = mbedtls_md_info_from_type(md_type);
if (md_info == NULL) {
return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
}if (md_info == NULL) { ... }
if ((ret = mbedtls_asn1_get_alg(&p, end, &enc_scheme_oid,
&enc_scheme_params)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret);
}if ((ret = mbedtls_asn1_get_alg(&p, end, &enc_scheme_oid, &enc_scheme_params)) != 0) { ... }
if (mbedtls_oid_get_cipher_alg(&enc_scheme_oid, &cipher_alg) != 0) {
return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
}if (mbedtls_oid_get_cipher_alg(&enc_scheme_oid, &cipher_alg) != 0) { ... }
cipher_info = mbedtls_cipher_info_from_type(cipher_alg);
if (cipher_info == NULL) {
return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE;
}if (cipher_info == NULL) { ... }
/* ... */
keylen = cipher_info->key_bitlen / 8;
if (enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING ||
enc_scheme_params.len != cipher_info->iv_size) {
return MBEDTLS_ERR_PKCS5_INVALID_FORMAT;
}if (enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING || enc_scheme_params.len != cipher_info->iv_size) { ... }
if (mode == MBEDTLS_PKCS5_DECRYPT) {
if (output_size < datalen) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
}if (output_size < datalen) { ... }
}if (mode == MBEDTLS_PKCS5_DECRYPT) { ... }
if (mode == MBEDTLS_PKCS5_ENCRYPT) {
padlen = cipher_info->block_size - (datalen % cipher_info->block_size);
if (output_size < (datalen + padlen)) {
return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
}if (output_size < (datalen + padlen)) { ... }
}if (mode == MBEDTLS_PKCS5_ENCRYPT) { ... }
mbedtls_md_init(&md_ctx);
mbedtls_cipher_init(&cipher_ctx);
memcpy(iv, enc_scheme_params.p, enc_scheme_params.len);
if ((ret = mbedtls_md_setup(&md_ctx, md_info, 1)) != 0) {
goto exit;
}if ((ret = mbedtls_md_setup(&md_ctx, md_info, 1)) != 0) { ... }
if ((ret = mbedtls_pkcs5_pbkdf2_hmac(&md_ctx, pwd, pwdlen, salt.p, salt.len,
iterations, keylen, key)) != 0) {
goto exit;
}if ((ret = mbedtls_pkcs5_pbkdf2_hmac(&md_ctx, pwd, pwdlen, salt.p, salt.len, iterations, keylen, key)) != 0) { ... }
if ((ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info)) != 0) {
goto exit;
}if ((ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info)) != 0) { ... }
if ((ret = mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen,
(mbedtls_operation_t) mode)) != 0) {
goto exit;
}if ((ret = mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode)) != 0) { ... }
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
{
/* ... */
mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_PKCS7;
#if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
/* ... */
if (mode == MBEDTLS_DECRYPT) {
padding = MBEDTLS_PADDING_NONE;
}if (mode == MBEDTLS_DECRYPT) { ... }
/* ... */#endif
if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) {
goto exit;
}if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) { ... }
}/* ... */
defined (MBEDTLS_CIPHER_MODE_WITH_PADDING) { ... }#endif
if ((ret = mbedtls_cipher_crypt(&cipher_ctx, iv, enc_scheme_params.len,
data, datalen, output, output_len)) != 0) {
ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH;
}if ((ret = mbedtls_cipher_crypt(&cipher_ctx, iv, enc_scheme_params.len, data, datalen, output, output_len)) != 0) { ... }
exit:
mbedtls_md_free(&md_ctx);
mbedtls_cipher_free(&cipher_ctx);
return ret;
}{ ... }
#endif/* ... */
int mbedtls_pkcs5_pbkdf2_hmac(mbedtls_md_context_t *ctx,
const unsigned char *password,
size_t plen, const unsigned char *salt, size_t slen,
unsigned int iteration_count,
uint32_t key_length, unsigned char *output)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int j;
unsigned int i;
unsigned char md1[MBEDTLS_MD_MAX_SIZE];
unsigned char work[MBEDTLS_MD_MAX_SIZE];
unsigned char md_size = mbedtls_md_get_size(ctx->md_info);
size_t use_len;
unsigned char *out_p = output;
unsigned char counter[4];
memset(counter, 0, 4);
counter[3] = 1;
#if UINT_MAX > 0xFFFFFFFF
if (iteration_count > 0xFFFFFFFF) {
return MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA;
}if (iteration_count > 0xFFFFFFFF) { ... }
/* ... */#endif
if ((ret = mbedtls_md_hmac_starts(ctx, password, plen)) != 0) {
return ret;
}if ((ret = mbedtls_md_hmac_starts(ctx, password, plen)) != 0) { ... }
while (key_length) {
if ((ret = mbedtls_md_hmac_update(ctx, salt, slen)) != 0) {
goto cleanup;
}if ((ret = mbedtls_md_hmac_update(ctx, salt, slen)) != 0) { ... }
if ((ret = mbedtls_md_hmac_update(ctx, counter, 4)) != 0) {
goto cleanup;
}if ((ret = mbedtls_md_hmac_update(ctx, counter, 4)) != 0) { ... }
if ((ret = mbedtls_md_hmac_finish(ctx, work)) != 0) {
goto cleanup;
}if ((ret = mbedtls_md_hmac_finish(ctx, work)) != 0) { ... }
if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) {
goto cleanup;
}if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) { ... }
memcpy(md1, work, md_size);
for (i = 1; i < iteration_count; i++) {
if ((ret = mbedtls_md_hmac_update(ctx, md1, md_size)) != 0) {
goto cleanup;
}if ((ret = mbedtls_md_hmac_update(ctx, md1, md_size)) != 0) { ... }
if ((ret = mbedtls_md_hmac_finish(ctx, md1)) != 0) {
goto cleanup;
}if ((ret = mbedtls_md_hmac_finish(ctx, md1)) != 0) { ... }
if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) {
goto cleanup;
}if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) { ... }
for (j = 0; j < md_size; j++) {
work[j] ^= md1[j];
}for (j = 0; j < md_size; j++) { ... }
}for (i = 1; i < iteration_count; i++) { ... }
use_len = (key_length < md_size) ? key_length : md_size;
memcpy(out_p, work, use_len);
key_length -= (uint32_t) use_len;
out_p += use_len;
for (i = 4; i > 0; i--) {
if (++counter[i - 1] != 0) {
break;
}if (++counter[i - 1] != 0) { ... }
}for (i = 4; i > 0; i--) { ... }
}while (key_length) { ... }
cleanup:
mbedtls_platform_zeroize(work, MBEDTLS_MD_MAX_SIZE);
mbedtls_platform_zeroize(md1, MBEDTLS_MD_MAX_SIZE);
return ret;
}{ ... }
#if defined(MBEDTLS_SELF_TEST)
#if !defined(MBEDTLS_SHA1_C)
int mbedtls_pkcs5_self_test(int verbose)
{
if (verbose != 0) {
mbedtls_printf(" PBKDF2 (SHA1): skipped\n\n");
}if (verbose != 0) { ... }
return 0;
}mbedtls_pkcs5_self_test (int verbose) { ... }
/* ... */#else
#define MAX_TESTS 6
static const size_t plen_test_data[MAX_TESTS] =
{ 8, 8, 8, 24, 9 };
static const unsigned char password_test_data[MAX_TESTS][32] =
{
"password",
"password",
"password",
"passwordPASSWORDpassword",
"pass\0word",
...};
static const size_t slen_test_data[MAX_TESTS] =
{ 4, 4, 4, 36, 5 };
static const unsigned char salt_test_data[MAX_TESTS][40] =
{
"salt",
"salt",
"salt",
"saltSALTsaltSALTsaltSALTsaltSALTsalt",
"sa\0lt",
...};
static const uint32_t it_cnt_test_data[MAX_TESTS] =
{ 1, 2, 4096, 4096, 4096 };
static const uint32_t key_len_test_data[MAX_TESTS] =
{ 20, 20, 20, 25, 16 };
static const unsigned char result_key_test_data[MAX_TESTS][32] =
{
{ 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
0x2f, 0xe0, 0x37, 0xa6 ...},
{ 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
0xd8, 0xde, 0x89, 0x57 ...},
{ 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
0x65, 0xa4, 0x29, 0xc1 ...},
{ 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
0x38 ...},
{ 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 ...},
...};
int mbedtls_pkcs5_self_test(int verbose)
{
mbedtls_md_context_t sha1_ctx;
const mbedtls_md_info_t *info_sha1;
int ret, i;
unsigned char key[64];
mbedtls_md_init(&sha1_ctx);
info_sha1 = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
if (info_sha1 == NULL) {
ret = 1;
goto exit;
}if (info_sha1 == NULL) { ... }
if ((ret = mbedtls_md_setup(&sha1_ctx, info_sha1, 1)) != 0) {
ret = 1;
goto exit;
}if ((ret = mbedtls_md_setup(&sha1_ctx, info_sha1, 1)) != 0) { ... }
for (i = 0; i < MAX_TESTS; i++) {
if (verbose != 0) {
mbedtls_printf(" PBKDF2 (SHA1) #%d: ", i);
}if (verbose != 0) { ... }
ret = mbedtls_pkcs5_pbkdf2_hmac(&sha1_ctx, password_test_data[i],
plen_test_data[i], salt_test_data[i],
slen_test_data[i], it_cnt_test_data[i],
key_len_test_data[i], key);
if (ret != 0 ||
memcmp(result_key_test_data[i], key, key_len_test_data[i]) != 0) {
if (verbose != 0) {
mbedtls_printf("failed\n");
}if (verbose != 0) { ... }
ret = 1;
goto exit;
}if (ret != 0 || memcmp(result_key_test_data[i], key, key_len_test_data[i]) != 0) { ... }
if (verbose != 0) {
mbedtls_printf("passed\n");
}if (verbose != 0) { ... }
}for (i = 0; i < MAX_TESTS; i++) { ... }
if (verbose != 0) {
mbedtls_printf("\n");
}if (verbose != 0) { ... }
exit:
mbedtls_md_free(&sha1_ctx);
return ret;
}mbedtls_pkcs5_self_test (int verbose) { ... }
/* ... */#endif
/* ... */
#endif
/* ... */
#endif