// SPDX-License-Identifier: BSD-2-Clause /* * Copyright (c) 2014, Linaro Limited */ #include #include #include #include #include #include struct hmac_parms { uint32_t algo; size_t hash_len; void *ctx; }; struct pbkdf2_parms { const uint8_t *password; size_t password_len; const uint8_t *salt; size_t salt_len; uint32_t iteration_count; }; static TEE_Result pbkdf2_f(uint8_t *out, size_t len, uint32_t idx, struct hmac_parms *h, struct pbkdf2_parms *p) { TEE_Result res; uint8_t u[TEE_MAX_HASH_SIZE]; uint32_t be_index; size_t i, j; memset(out, 0, len); for (i = 1; i <= p->iteration_count; i++) { res = crypto_mac_init(h->ctx, h->algo, p->password, p->password_len); if (res != TEE_SUCCESS) return res; if (i == 1) { if (p->salt && p->salt_len) { res = crypto_mac_update(h->ctx, h->algo, p->salt, p->salt_len); if (res != TEE_SUCCESS) return res; } be_index = TEE_U32_TO_BIG_ENDIAN(idx); res = crypto_mac_update(h->ctx, h->algo, (uint8_t *)&be_index, sizeof(be_index)); if (res != TEE_SUCCESS) return res; } else { res = crypto_mac_update(h->ctx, h->algo, u, h->hash_len); if (res != TEE_SUCCESS) return res; } res = crypto_mac_final(h->ctx, h->algo, u, sizeof(u)); if (res != TEE_SUCCESS) return res; for (j = 0; j < len; j++) out[j] ^= u[j]; } return TEE_SUCCESS; } TEE_Result tee_cryp_pbkdf2(uint32_t hash_id, const uint8_t *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint32_t iteration_count, uint8_t *derived_key, size_t derived_key_len) { TEE_Result res; size_t i, l, r; uint8_t *out = derived_key; struct pbkdf2_parms pbkdf2_parms; struct hmac_parms hmac_parms = {0, }; hmac_parms.algo = TEE_ALG_HMAC_ALGO(hash_id); res = tee_mac_get_digest_size(hmac_parms.algo, &hmac_parms.hash_len); if (res != TEE_SUCCESS) return res; res = crypto_mac_alloc_ctx(&hmac_parms.ctx, hmac_parms.algo); if (res != TEE_SUCCESS) return res; pbkdf2_parms.password = password; pbkdf2_parms.password_len = password_len; pbkdf2_parms.salt = salt; pbkdf2_parms.salt_len = salt_len; pbkdf2_parms.iteration_count = iteration_count; l = derived_key_len / hmac_parms.hash_len; r = derived_key_len % hmac_parms.hash_len; for (i = 1; i <= l; i++) { res = pbkdf2_f(out, hmac_parms.hash_len, i, &hmac_parms, &pbkdf2_parms); if (res != TEE_SUCCESS) goto out; out += hmac_parms.hash_len; } if (r) res = pbkdf2_f(out, r, i, &hmac_parms, &pbkdf2_parms); out: crypto_mac_free_ctx(hmac_parms.ctx, hmac_parms.algo); return res; }