blob: f6ab74a4b997678bf45b93fc89d6c3026c11f1eb [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2014, Linaro Limited
*/
#include <crypto/crypto.h>
#include <stdlib.h>
#include <string.h>
#include <tee/tee_cryp_pbkdf2.h>
#include <tee/tee_cryp_utl.h>
#include <utee_defines.h>
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, 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, 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, (uint8_t *)&be_index,
sizeof(be_index));
if (res != TEE_SUCCESS)
return res;
} else {
res = crypto_mac_update(h->ctx, u, h->hash_len);
if (res != TEE_SUCCESS)
return res;
}
res = crypto_mac_final(h->ctx, 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);
return res;
}