1817466cbSJens Wiklander /** 2817466cbSJens Wiklander * \file pkcs5.c 3817466cbSJens Wiklander * 4817466cbSJens Wiklander * \brief PKCS#5 functions 5817466cbSJens Wiklander * 6817466cbSJens Wiklander * \author Mathias Olsson <mathias@kompetensum.com> 7817466cbSJens Wiklander * 87901324dSJerome Forissier * Copyright The Mbed TLS Contributors 97901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 12817466cbSJens Wiklander * not use this file except in compliance with the License. 13817466cbSJens Wiklander * You may obtain a copy of the License at 14817466cbSJens Wiklander * 15817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 16817466cbSJens Wiklander * 17817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 18817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 19817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20817466cbSJens Wiklander * See the License for the specific language governing permissions and 21817466cbSJens Wiklander * limitations under the License. 22817466cbSJens Wiklander */ 23817466cbSJens Wiklander /* 24817466cbSJens Wiklander * PKCS#5 includes PBKDF2 and more 25817466cbSJens Wiklander * 26817466cbSJens Wiklander * http://tools.ietf.org/html/rfc2898 (Specification) 27817466cbSJens Wiklander * http://tools.ietf.org/html/rfc6070 (Test vectors) 28817466cbSJens Wiklander */ 29817466cbSJens Wiklander 307901324dSJerome Forissier #include "common.h" 31817466cbSJens Wiklander 32817466cbSJens Wiklander #if defined(MBEDTLS_PKCS5_C) 33817466cbSJens Wiklander 34817466cbSJens Wiklander #include "mbedtls/pkcs5.h" 3511fa71b9SJerome Forissier #include "mbedtls/error.h" 363d3b0591SJens Wiklander 373d3b0591SJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C) 38817466cbSJens Wiklander #include "mbedtls/asn1.h" 39817466cbSJens Wiklander #include "mbedtls/cipher.h" 40817466cbSJens Wiklander #include "mbedtls/oid.h" 413d3b0591SJens Wiklander #endif /* MBEDTLS_ASN1_PARSE_C */ 42817466cbSJens Wiklander 43817466cbSJens Wiklander #include <string.h> 44817466cbSJens Wiklander 45817466cbSJens Wiklander #include "mbedtls/platform.h" 46*32b31808SJens Wiklander 47*32b31808SJens Wiklander #include "hash_info.h" 48*32b31808SJens Wiklander #include "mbedtls/psa_util.h" 49*32b31808SJens Wiklander 50*32b31808SJens Wiklander #if !defined(MBEDTLS_MD_C) 51*32b31808SJens Wiklander #define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status, \ 52*32b31808SJens Wiklander psa_to_md_errors, \ 53*32b31808SJens Wiklander psa_generic_status_to_mbedtls) 54817466cbSJens Wiklander #endif 55817466cbSJens Wiklander 563d3b0591SJens Wiklander #if defined(MBEDTLS_ASN1_PARSE_C) 57817466cbSJens Wiklander static int pkcs5_parse_pbkdf2_params(const mbedtls_asn1_buf *params, 58817466cbSJens Wiklander mbedtls_asn1_buf *salt, int *iterations, 59817466cbSJens Wiklander int *keylen, mbedtls_md_type_t *md_type) 60817466cbSJens Wiklander { 6111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 62817466cbSJens Wiklander mbedtls_asn1_buf prf_alg_oid; 63817466cbSJens Wiklander unsigned char *p = params->p; 64817466cbSJens Wiklander const unsigned char *end = params->p + params->len; 65817466cbSJens Wiklander 66*32b31808SJens Wiklander if (params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) { 67*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, 68*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); 69*32b31808SJens Wiklander } 70817466cbSJens Wiklander /* 71817466cbSJens Wiklander * PBKDF2-params ::= SEQUENCE { 72817466cbSJens Wiklander * salt OCTET STRING, 73817466cbSJens Wiklander * iterationCount INTEGER, 74817466cbSJens Wiklander * keyLength INTEGER OPTIONAL 75817466cbSJens Wiklander * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1 76817466cbSJens Wiklander * } 77817466cbSJens Wiklander * 78817466cbSJens Wiklander */ 7911fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_tag(&p, end, &salt->len, 80*32b31808SJens Wiklander MBEDTLS_ASN1_OCTET_STRING)) != 0) { 81*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret); 82*32b31808SJens Wiklander } 83817466cbSJens Wiklander 84817466cbSJens Wiklander salt->p = p; 85817466cbSJens Wiklander p += salt->len; 86817466cbSJens Wiklander 87*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(&p, end, iterations)) != 0) { 88*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret); 89817466cbSJens Wiklander } 90817466cbSJens Wiklander 91*32b31808SJens Wiklander if (p == end) { 92*32b31808SJens Wiklander return 0; 93*32b31808SJens Wiklander } 94817466cbSJens Wiklander 95*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(&p, end, keylen)) != 0) { 96*32b31808SJens Wiklander if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 97*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret); 98*32b31808SJens Wiklander } 99*32b31808SJens Wiklander } 100817466cbSJens Wiklander 101*32b31808SJens Wiklander if (p == end) { 102*32b31808SJens Wiklander return 0; 103*32b31808SJens Wiklander } 104817466cbSJens Wiklander 105*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_alg_null(&p, end, &prf_alg_oid)) != 0) { 106*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret); 107*32b31808SJens Wiklander } 108817466cbSJens Wiklander 109*32b31808SJens Wiklander if (mbedtls_oid_get_md_hmac(&prf_alg_oid, md_type) != 0) { 110*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE; 111*32b31808SJens Wiklander } 112*32b31808SJens Wiklander 113*32b31808SJens Wiklander if (p != end) { 114*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, 115*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 116*32b31808SJens Wiklander } 117*32b31808SJens Wiklander 118*32b31808SJens Wiklander return 0; 119817466cbSJens Wiklander } 120817466cbSJens Wiklander 121817466cbSJens Wiklander int mbedtls_pkcs5_pbes2(const mbedtls_asn1_buf *pbe_params, int mode, 122817466cbSJens Wiklander const unsigned char *pwd, size_t pwdlen, 123817466cbSJens Wiklander const unsigned char *data, size_t datalen, 124817466cbSJens Wiklander unsigned char *output) 125817466cbSJens Wiklander { 126817466cbSJens Wiklander int ret, iterations = 0, keylen = 0; 127817466cbSJens Wiklander unsigned char *p, *end; 128817466cbSJens Wiklander mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params; 129817466cbSJens Wiklander mbedtls_asn1_buf salt; 130817466cbSJens Wiklander mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1; 131817466cbSJens Wiklander unsigned char key[32], iv[32]; 132817466cbSJens Wiklander size_t olen = 0; 133817466cbSJens Wiklander const mbedtls_cipher_info_t *cipher_info; 134817466cbSJens Wiklander mbedtls_cipher_type_t cipher_alg; 135817466cbSJens Wiklander mbedtls_cipher_context_t cipher_ctx; 136817466cbSJens Wiklander 137817466cbSJens Wiklander p = pbe_params->p; 138817466cbSJens Wiklander end = p + pbe_params->len; 139817466cbSJens Wiklander 140817466cbSJens Wiklander /* 141817466cbSJens Wiklander * PBES2-params ::= SEQUENCE { 142817466cbSJens Wiklander * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, 143817466cbSJens Wiklander * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} 144817466cbSJens Wiklander * } 145817466cbSJens Wiklander */ 146*32b31808SJens Wiklander if (pbe_params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) { 147*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, 148*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); 149*32b31808SJens Wiklander } 150817466cbSJens Wiklander 15111fa71b9SJerome Forissier if ((ret = mbedtls_asn1_get_alg(&p, end, &kdf_alg_oid, 152*32b31808SJens Wiklander &kdf_alg_params)) != 0) { 153*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret); 154*32b31808SJens Wiklander } 155817466cbSJens Wiklander 156817466cbSJens Wiklander // Only PBKDF2 supported at the moment 157817466cbSJens Wiklander // 158*32b31808SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid) != 0) { 159*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE; 160*32b31808SJens Wiklander } 161817466cbSJens Wiklander 162817466cbSJens Wiklander if ((ret = pkcs5_parse_pbkdf2_params(&kdf_alg_params, 163817466cbSJens Wiklander &salt, &iterations, &keylen, 164*32b31808SJens Wiklander &md_type)) != 0) { 165*32b31808SJens Wiklander return ret; 166817466cbSJens Wiklander } 167817466cbSJens Wiklander 168817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_alg(&p, end, &enc_scheme_oid, 169*32b31808SJens Wiklander &enc_scheme_params)) != 0) { 170*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS5_INVALID_FORMAT, ret); 171817466cbSJens Wiklander } 172817466cbSJens Wiklander 173*32b31808SJens Wiklander if (mbedtls_oid_get_cipher_alg(&enc_scheme_oid, &cipher_alg) != 0) { 174*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE; 175*32b31808SJens Wiklander } 176817466cbSJens Wiklander 177817466cbSJens Wiklander cipher_info = mbedtls_cipher_info_from_type(cipher_alg); 178*32b31808SJens Wiklander if (cipher_info == NULL) { 179*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE; 180*32b31808SJens Wiklander } 181817466cbSJens Wiklander 182817466cbSJens Wiklander /* 183817466cbSJens Wiklander * The value of keylen from pkcs5_parse_pbkdf2_params() is ignored 184817466cbSJens Wiklander * since it is optional and we don't know if it was set or not 185817466cbSJens Wiklander */ 186817466cbSJens Wiklander keylen = cipher_info->key_bitlen / 8; 187817466cbSJens Wiklander 188817466cbSJens Wiklander if (enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING || 189*32b31808SJens Wiklander enc_scheme_params.len != cipher_info->iv_size) { 190*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS5_INVALID_FORMAT; 191817466cbSJens Wiklander } 192817466cbSJens Wiklander 193817466cbSJens Wiklander mbedtls_cipher_init(&cipher_ctx); 194817466cbSJens Wiklander 195817466cbSJens Wiklander memcpy(iv, enc_scheme_params.p, enc_scheme_params.len); 196817466cbSJens Wiklander 197*32b31808SJens Wiklander if ((ret = mbedtls_pkcs5_pbkdf2_hmac_ext(md_type, pwd, pwdlen, salt.p, 198*32b31808SJens Wiklander salt.len, iterations, keylen, 199*32b31808SJens Wiklander key)) != 0) { 200817466cbSJens Wiklander goto exit; 201817466cbSJens Wiklander } 202817466cbSJens Wiklander 203*32b31808SJens Wiklander if ((ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info)) != 0) { 204817466cbSJens Wiklander goto exit; 205*32b31808SJens Wiklander } 206817466cbSJens Wiklander 20711fa71b9SJerome Forissier if ((ret = mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen, 208*32b31808SJens Wiklander (mbedtls_operation_t) mode)) != 0) { 209817466cbSJens Wiklander goto exit; 210*32b31808SJens Wiklander } 211817466cbSJens Wiklander 212817466cbSJens Wiklander if ((ret = mbedtls_cipher_crypt(&cipher_ctx, iv, enc_scheme_params.len, 213*32b31808SJens Wiklander data, datalen, output, &olen)) != 0) { 214817466cbSJens Wiklander ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH; 215*32b31808SJens Wiklander } 216817466cbSJens Wiklander 217817466cbSJens Wiklander exit: 218817466cbSJens Wiklander mbedtls_cipher_free(&cipher_ctx); 219817466cbSJens Wiklander 220*32b31808SJens Wiklander return ret; 221817466cbSJens Wiklander } 2223d3b0591SJens Wiklander #endif /* MBEDTLS_ASN1_PARSE_C */ 223817466cbSJens Wiklander 224*32b31808SJens Wiklander #if defined(MBEDTLS_MD_C) 225*32b31808SJens Wiklander static int pkcs5_pbkdf2_hmac(mbedtls_md_context_t *ctx, 22611fa71b9SJerome Forissier const unsigned char *password, 227817466cbSJens Wiklander size_t plen, const unsigned char *salt, size_t slen, 228817466cbSJens Wiklander unsigned int iteration_count, 229817466cbSJens Wiklander uint32_t key_length, unsigned char *output) 230817466cbSJens Wiklander { 2317901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 232817466cbSJens Wiklander unsigned int i; 233817466cbSJens Wiklander unsigned char md1[MBEDTLS_MD_MAX_SIZE]; 234817466cbSJens Wiklander unsigned char work[MBEDTLS_MD_MAX_SIZE]; 235817466cbSJens Wiklander unsigned char md_size = mbedtls_md_get_size(ctx->md_info); 236817466cbSJens Wiklander size_t use_len; 237817466cbSJens Wiklander unsigned char *out_p = output; 238817466cbSJens Wiklander unsigned char counter[4]; 239817466cbSJens Wiklander 240817466cbSJens Wiklander memset(counter, 0, 4); 241817466cbSJens Wiklander counter[3] = 1; 242817466cbSJens Wiklander 2433d3b0591SJens Wiklander #if UINT_MAX > 0xFFFFFFFF 244*32b31808SJens Wiklander if (iteration_count > 0xFFFFFFFF) { 245*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA; 246*32b31808SJens Wiklander } 2473d3b0591SJens Wiklander #endif 248817466cbSJens Wiklander 249*32b31808SJens Wiklander if ((ret = mbedtls_md_hmac_starts(ctx, password, plen)) != 0) { 250*32b31808SJens Wiklander return ret; 251*32b31808SJens Wiklander } 252*32b31808SJens Wiklander while (key_length) { 253817466cbSJens Wiklander // U1 ends up in work 254817466cbSJens Wiklander // 255*32b31808SJens Wiklander if ((ret = mbedtls_md_hmac_update(ctx, salt, slen)) != 0) { 2567901324dSJerome Forissier goto cleanup; 257*32b31808SJens Wiklander } 258817466cbSJens Wiklander 259*32b31808SJens Wiklander if ((ret = mbedtls_md_hmac_update(ctx, counter, 4)) != 0) { 2607901324dSJerome Forissier goto cleanup; 261*32b31808SJens Wiklander } 262817466cbSJens Wiklander 263*32b31808SJens Wiklander if ((ret = mbedtls_md_hmac_finish(ctx, work)) != 0) { 2647901324dSJerome Forissier goto cleanup; 265*32b31808SJens Wiklander } 266817466cbSJens Wiklander 267*32b31808SJens Wiklander if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) { 2687901324dSJerome Forissier goto cleanup; 269*32b31808SJens Wiklander } 27011fa71b9SJerome Forissier 271817466cbSJens Wiklander memcpy(md1, work, md_size); 272817466cbSJens Wiklander 273*32b31808SJens Wiklander for (i = 1; i < iteration_count; i++) { 274817466cbSJens Wiklander // U2 ends up in md1 275817466cbSJens Wiklander // 276*32b31808SJens Wiklander if ((ret = mbedtls_md_hmac_update(ctx, md1, md_size)) != 0) { 2777901324dSJerome Forissier goto cleanup; 278*32b31808SJens Wiklander } 279817466cbSJens Wiklander 280*32b31808SJens Wiklander if ((ret = mbedtls_md_hmac_finish(ctx, md1)) != 0) { 2817901324dSJerome Forissier goto cleanup; 282*32b31808SJens Wiklander } 283817466cbSJens Wiklander 284*32b31808SJens Wiklander if ((ret = mbedtls_md_hmac_reset(ctx)) != 0) { 2857901324dSJerome Forissier goto cleanup; 286*32b31808SJens Wiklander } 28711fa71b9SJerome Forissier 288817466cbSJens Wiklander // U1 xor U2 289817466cbSJens Wiklander // 290*32b31808SJens Wiklander mbedtls_xor(work, work, md1, md_size); 291817466cbSJens Wiklander } 292817466cbSJens Wiklander 293817466cbSJens Wiklander use_len = (key_length < md_size) ? key_length : md_size; 294817466cbSJens Wiklander memcpy(out_p, work, use_len); 295817466cbSJens Wiklander 296817466cbSJens Wiklander key_length -= (uint32_t) use_len; 297817466cbSJens Wiklander out_p += use_len; 298817466cbSJens Wiklander 299*32b31808SJens Wiklander for (i = 4; i > 0; i--) { 300*32b31808SJens Wiklander if (++counter[i - 1] != 0) { 301817466cbSJens Wiklander break; 302817466cbSJens Wiklander } 303*32b31808SJens Wiklander } 304*32b31808SJens Wiklander } 305817466cbSJens Wiklander 3067901324dSJerome Forissier cleanup: 3077901324dSJerome Forissier /* Zeroise buffers to clear sensitive data from memory. */ 3087901324dSJerome Forissier mbedtls_platform_zeroize(work, MBEDTLS_MD_MAX_SIZE); 3097901324dSJerome Forissier mbedtls_platform_zeroize(md1, MBEDTLS_MD_MAX_SIZE); 3107901324dSJerome Forissier 311*32b31808SJens Wiklander return ret; 312*32b31808SJens Wiklander } 313*32b31808SJens Wiklander 314*32b31808SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED) 315*32b31808SJens Wiklander int mbedtls_pkcs5_pbkdf2_hmac(mbedtls_md_context_t *ctx, 316*32b31808SJens Wiklander const unsigned char *password, 317*32b31808SJens Wiklander size_t plen, const unsigned char *salt, size_t slen, 318*32b31808SJens Wiklander unsigned int iteration_count, 319*32b31808SJens Wiklander uint32_t key_length, unsigned char *output) 320*32b31808SJens Wiklander { 321*32b31808SJens Wiklander return pkcs5_pbkdf2_hmac(ctx, password, plen, salt, slen, iteration_count, 322*32b31808SJens Wiklander key_length, output); 323*32b31808SJens Wiklander } 324*32b31808SJens Wiklander #endif 325*32b31808SJens Wiklander #endif /* MBEDTLS_MD_C */ 326*32b31808SJens Wiklander 327*32b31808SJens Wiklander int mbedtls_pkcs5_pbkdf2_hmac_ext(mbedtls_md_type_t md_alg, 328*32b31808SJens Wiklander const unsigned char *password, 329*32b31808SJens Wiklander size_t plen, const unsigned char *salt, size_t slen, 330*32b31808SJens Wiklander unsigned int iteration_count, 331*32b31808SJens Wiklander uint32_t key_length, unsigned char *output) 332*32b31808SJens Wiklander { 333*32b31808SJens Wiklander #if defined(MBEDTLS_MD_C) 334*32b31808SJens Wiklander mbedtls_md_context_t md_ctx; 335*32b31808SJens Wiklander const mbedtls_md_info_t *md_info = NULL; 336*32b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 337*32b31808SJens Wiklander 338*32b31808SJens Wiklander md_info = mbedtls_md_info_from_type(md_alg); 339*32b31808SJens Wiklander if (md_info == NULL) { 340*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE; 341*32b31808SJens Wiklander } 342*32b31808SJens Wiklander 343*32b31808SJens Wiklander mbedtls_md_init(&md_ctx); 344*32b31808SJens Wiklander 345*32b31808SJens Wiklander if ((ret = mbedtls_md_setup(&md_ctx, md_info, 1)) != 0) { 346*32b31808SJens Wiklander goto exit; 347*32b31808SJens Wiklander } 348*32b31808SJens Wiklander ret = pkcs5_pbkdf2_hmac(&md_ctx, password, plen, salt, slen, 349*32b31808SJens Wiklander iteration_count, key_length, output); 350*32b31808SJens Wiklander exit: 351*32b31808SJens Wiklander mbedtls_md_free(&md_ctx); 352*32b31808SJens Wiklander return ret; 353*32b31808SJens Wiklander #else 354*32b31808SJens Wiklander unsigned int i; 355*32b31808SJens Wiklander unsigned char md1[PSA_HASH_MAX_SIZE]; 356*32b31808SJens Wiklander unsigned char work[PSA_HASH_MAX_SIZE]; 357*32b31808SJens Wiklander const unsigned char md_size = mbedtls_hash_info_get_size(md_alg); 358*32b31808SJens Wiklander psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; 359*32b31808SJens Wiklander 360*32b31808SJens Wiklander psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; 361*32b31808SJens Wiklander psa_status_t status_destruction = PSA_ERROR_CORRUPTION_DETECTED; 362*32b31808SJens Wiklander size_t use_len, out_len; 363*32b31808SJens Wiklander unsigned char *out_p = output; 364*32b31808SJens Wiklander unsigned char counter[4]; 365*32b31808SJens Wiklander mbedtls_svc_key_id_t psa_hmac_key = MBEDTLS_SVC_KEY_ID_INIT; 366*32b31808SJens Wiklander psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; 367*32b31808SJens Wiklander const psa_algorithm_t alg = PSA_ALG_HMAC(mbedtls_hash_info_psa_from_md(md_alg)); 368*32b31808SJens Wiklander const size_t out_size = PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, 0, alg); 369*32b31808SJens Wiklander 370*32b31808SJens Wiklander memset(counter, 0, sizeof(counter)); 371*32b31808SJens Wiklander counter[3] = 1; 372*32b31808SJens Wiklander 373*32b31808SJens Wiklander psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE); 374*32b31808SJens Wiklander psa_set_key_algorithm(&attributes, alg); 375*32b31808SJens Wiklander psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC); 376*32b31808SJens Wiklander 377*32b31808SJens Wiklander if (key_length == 0) { 378*32b31808SJens Wiklander return 0; 379*32b31808SJens Wiklander } 380*32b31808SJens Wiklander if ((status = psa_import_key(&attributes, 381*32b31808SJens Wiklander password, plen, 382*32b31808SJens Wiklander &psa_hmac_key)) != PSA_SUCCESS) { 383*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA; 384*32b31808SJens Wiklander } 385*32b31808SJens Wiklander 386*32b31808SJens Wiklander #if UINT_MAX > 0xFFFFFFFF 387*32b31808SJens Wiklander if (iteration_count > 0xFFFFFFFF) { 388*32b31808SJens Wiklander return MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA; 389*32b31808SJens Wiklander } 390*32b31808SJens Wiklander #endif 391*32b31808SJens Wiklander 392*32b31808SJens Wiklander while (key_length) { 393*32b31808SJens Wiklander status = psa_mac_sign_setup(&operation, psa_hmac_key, 394*32b31808SJens Wiklander PSA_ALG_HMAC(alg)); 395*32b31808SJens Wiklander if (status != PSA_SUCCESS) { 396*32b31808SJens Wiklander goto cleanup; 397*32b31808SJens Wiklander } 398*32b31808SJens Wiklander // U1 ends up in work 399*32b31808SJens Wiklander if ((status = psa_mac_update(&operation, salt, slen)) != PSA_SUCCESS) { 400*32b31808SJens Wiklander goto cleanup; 401*32b31808SJens Wiklander } 402*32b31808SJens Wiklander 403*32b31808SJens Wiklander if ((status = psa_mac_update(&operation, counter, sizeof(counter))) != PSA_SUCCESS) { 404*32b31808SJens Wiklander goto cleanup; 405*32b31808SJens Wiklander } 406*32b31808SJens Wiklander 407*32b31808SJens Wiklander if ((status = psa_mac_sign_finish(&operation, work, out_size, &out_len)) 408*32b31808SJens Wiklander != PSA_SUCCESS) { 409*32b31808SJens Wiklander goto cleanup; 410*32b31808SJens Wiklander } 411*32b31808SJens Wiklander 412*32b31808SJens Wiklander memcpy(md1, work, out_len); 413*32b31808SJens Wiklander 414*32b31808SJens Wiklander for (i = 1; i < iteration_count; i++) { 415*32b31808SJens Wiklander // U2 ends up in md1 416*32b31808SJens Wiklander // 417*32b31808SJens Wiklander status = psa_mac_sign_setup(&operation, psa_hmac_key, 418*32b31808SJens Wiklander PSA_ALG_HMAC(alg)); 419*32b31808SJens Wiklander if (status != PSA_SUCCESS) { 420*32b31808SJens Wiklander goto cleanup; 421*32b31808SJens Wiklander } 422*32b31808SJens Wiklander if ((status = psa_mac_update(&operation, md1, md_size)) != PSA_SUCCESS) { 423*32b31808SJens Wiklander goto cleanup; 424*32b31808SJens Wiklander } 425*32b31808SJens Wiklander if ((status = 426*32b31808SJens Wiklander psa_mac_sign_finish(&operation, md1, out_size, &out_len)) != PSA_SUCCESS) { 427*32b31808SJens Wiklander goto cleanup; 428*32b31808SJens Wiklander } 429*32b31808SJens Wiklander 430*32b31808SJens Wiklander // U1 xor U2 431*32b31808SJens Wiklander // 432*32b31808SJens Wiklander mbedtls_xor(work, work, md1, md_size); 433*32b31808SJens Wiklander } 434*32b31808SJens Wiklander 435*32b31808SJens Wiklander use_len = (key_length < md_size) ? key_length : md_size; 436*32b31808SJens Wiklander memcpy(out_p, work, use_len); 437*32b31808SJens Wiklander 438*32b31808SJens Wiklander key_length -= (uint32_t) use_len; 439*32b31808SJens Wiklander out_p += use_len; 440*32b31808SJens Wiklander 441*32b31808SJens Wiklander for (i = 4; i > 0; i--) { 442*32b31808SJens Wiklander if (++counter[i - 1] != 0) { 443*32b31808SJens Wiklander break; 444*32b31808SJens Wiklander } 445*32b31808SJens Wiklander } 446*32b31808SJens Wiklander } 447*32b31808SJens Wiklander 448*32b31808SJens Wiklander cleanup: 449*32b31808SJens Wiklander /* Zeroise buffers to clear sensitive data from memory. */ 450*32b31808SJens Wiklander mbedtls_platform_zeroize(work, PSA_HASH_MAX_SIZE); 451*32b31808SJens Wiklander mbedtls_platform_zeroize(md1, PSA_HASH_MAX_SIZE); 452*32b31808SJens Wiklander status_destruction = psa_destroy_key(psa_hmac_key); 453*32b31808SJens Wiklander if (status == PSA_SUCCESS && status_destruction != PSA_SUCCESS) { 454*32b31808SJens Wiklander status = status_destruction; 455*32b31808SJens Wiklander } 456*32b31808SJens Wiklander status_destruction = psa_mac_abort(&operation); 457*32b31808SJens Wiklander if (status == PSA_SUCCESS && status_destruction != PSA_SUCCESS) { 458*32b31808SJens Wiklander status = status_destruction; 459*32b31808SJens Wiklander } 460*32b31808SJens Wiklander 461*32b31808SJens Wiklander return PSA_TO_MBEDTLS_ERR(status); 462*32b31808SJens Wiklander #endif /* !MBEDTLS_MD_C */ 463817466cbSJens Wiklander } 464817466cbSJens Wiklander 465817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 466817466cbSJens Wiklander 467*32b31808SJens Wiklander #if !defined(MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA) 468817466cbSJens Wiklander int mbedtls_pkcs5_self_test(int verbose) 469817466cbSJens Wiklander { 470*32b31808SJens Wiklander if (verbose != 0) { 471817466cbSJens Wiklander mbedtls_printf(" PBKDF2 (SHA1): skipped\n\n"); 472*32b31808SJens Wiklander } 473817466cbSJens Wiklander 474*32b31808SJens Wiklander return 0; 475817466cbSJens Wiklander } 476817466cbSJens Wiklander #else 477817466cbSJens Wiklander 478817466cbSJens Wiklander #define MAX_TESTS 6 479817466cbSJens Wiklander 48011fa71b9SJerome Forissier static const size_t plen_test_data[MAX_TESTS] = 481817466cbSJens Wiklander { 8, 8, 8, 24, 9 }; 482817466cbSJens Wiklander 48311fa71b9SJerome Forissier static const unsigned char password_test_data[MAX_TESTS][32] = 484817466cbSJens Wiklander { 485817466cbSJens Wiklander "password", 486817466cbSJens Wiklander "password", 487817466cbSJens Wiklander "password", 488817466cbSJens Wiklander "passwordPASSWORDpassword", 489817466cbSJens Wiklander "pass\0word", 490817466cbSJens Wiklander }; 491817466cbSJens Wiklander 49211fa71b9SJerome Forissier static const size_t slen_test_data[MAX_TESTS] = 493817466cbSJens Wiklander { 4, 4, 4, 36, 5 }; 494817466cbSJens Wiklander 49511fa71b9SJerome Forissier static const unsigned char salt_test_data[MAX_TESTS][40] = 496817466cbSJens Wiklander { 497817466cbSJens Wiklander "salt", 498817466cbSJens Wiklander "salt", 499817466cbSJens Wiklander "salt", 500817466cbSJens Wiklander "saltSALTsaltSALTsaltSALTsaltSALTsalt", 501817466cbSJens Wiklander "sa\0lt", 502817466cbSJens Wiklander }; 503817466cbSJens Wiklander 50411fa71b9SJerome Forissier static const uint32_t it_cnt_test_data[MAX_TESTS] = 505817466cbSJens Wiklander { 1, 2, 4096, 4096, 4096 }; 506817466cbSJens Wiklander 50711fa71b9SJerome Forissier static const uint32_t key_len_test_data[MAX_TESTS] = 508817466cbSJens Wiklander { 20, 20, 20, 25, 16 }; 509817466cbSJens Wiklander 51011fa71b9SJerome Forissier static const unsigned char result_key_test_data[MAX_TESTS][32] = 511817466cbSJens Wiklander { 512817466cbSJens Wiklander { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, 513817466cbSJens Wiklander 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, 514817466cbSJens Wiklander 0x2f, 0xe0, 0x37, 0xa6 }, 515817466cbSJens Wiklander { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, 516817466cbSJens Wiklander 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, 517817466cbSJens Wiklander 0xd8, 0xde, 0x89, 0x57 }, 518817466cbSJens Wiklander { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, 519817466cbSJens Wiklander 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, 520817466cbSJens Wiklander 0x65, 0xa4, 0x29, 0xc1 }, 521817466cbSJens Wiklander { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, 522817466cbSJens Wiklander 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, 523817466cbSJens Wiklander 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, 524817466cbSJens Wiklander 0x38 }, 525817466cbSJens Wiklander { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, 526817466cbSJens Wiklander 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 }, 527817466cbSJens Wiklander }; 528817466cbSJens Wiklander 529817466cbSJens Wiklander int mbedtls_pkcs5_self_test(int verbose) 530817466cbSJens Wiklander { 531817466cbSJens Wiklander int ret, i; 532817466cbSJens Wiklander unsigned char key[64]; 533817466cbSJens Wiklander 534*32b31808SJens Wiklander for (i = 0; i < MAX_TESTS; i++) { 535*32b31808SJens Wiklander if (verbose != 0) { 536817466cbSJens Wiklander mbedtls_printf(" PBKDF2 (SHA1) #%d: ", i); 537*32b31808SJens Wiklander } 538817466cbSJens Wiklander 539*32b31808SJens Wiklander ret = mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA1, password_test_data[i], 54011fa71b9SJerome Forissier plen_test_data[i], salt_test_data[i], 54111fa71b9SJerome Forissier slen_test_data[i], it_cnt_test_data[i], 54211fa71b9SJerome Forissier key_len_test_data[i], key); 543817466cbSJens Wiklander if (ret != 0 || 544*32b31808SJens Wiklander memcmp(result_key_test_data[i], key, key_len_test_data[i]) != 0) { 545*32b31808SJens Wiklander if (verbose != 0) { 546817466cbSJens Wiklander mbedtls_printf("failed\n"); 547*32b31808SJens Wiklander } 548817466cbSJens Wiklander 549817466cbSJens Wiklander ret = 1; 550817466cbSJens Wiklander goto exit; 551817466cbSJens Wiklander } 552817466cbSJens Wiklander 553*32b31808SJens Wiklander if (verbose != 0) { 554817466cbSJens Wiklander mbedtls_printf("passed\n"); 555817466cbSJens Wiklander } 556*32b31808SJens Wiklander } 557817466cbSJens Wiklander 558*32b31808SJens Wiklander if (verbose != 0) { 559817466cbSJens Wiklander mbedtls_printf("\n"); 560*32b31808SJens Wiklander } 561817466cbSJens Wiklander 562817466cbSJens Wiklander exit: 563*32b31808SJens Wiklander return ret; 564817466cbSJens Wiklander } 565*32b31808SJens Wiklander #endif /* MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA */ 566817466cbSJens Wiklander 567817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 568817466cbSJens Wiklander 569817466cbSJens Wiklander #endif /* MBEDTLS_PKCS5_C */ 570