diff options
Diffstat (limited to 'core/tee/tee_cryp_pbkdf2.c')
-rw-r--r-- | core/tee/tee_cryp_pbkdf2.c | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/core/tee/tee_cryp_pbkdf2.c b/core/tee/tee_cryp_pbkdf2.c new file mode 100644 index 0000000..5e6abc1 --- /dev/null +++ b/core/tee/tee_cryp_pbkdf2.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <tee/tee_cryp_pbkdf2.h> +#include <tee/tee_cryp_provider.h> +#include <tee/tee_cryp_utl.h> +#include <utee_defines.h> +#include <stdlib.h> +#include <string.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; + const struct mac_ops *mac = &crypto_ops.mac; + + memset(out, 0, len); + for (i = 1; i <= p->iteration_count; i++) { + res = 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 = 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 = mac->update(h->ctx, h->algo, + (uint8_t *)&be_index, + sizeof(be_index)); + if (res != TEE_SUCCESS) + return res; + } else { + res = mac->update(h->ctx, h->algo, u, h->hash_len); + if (res != TEE_SUCCESS) + return res; + } + + res = 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 ctx_size, i, l, r; + uint8_t *out = derived_key; + struct pbkdf2_parms pbkdf2_parms; + struct hmac_parms hmac_parms = {0, }; + const struct mac_ops *mac = &crypto_ops.mac; + + if (!mac->get_ctx_size || !mac->init || !mac->update || + !mac->final) + return TEE_ERROR_NOT_IMPLEMENTED; + + 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 = mac->get_ctx_size(hmac_parms.algo, &ctx_size); + if (res != TEE_SUCCESS) + return res; + + hmac_parms.ctx = malloc(ctx_size); + if (!hmac_parms.ctx) + return TEE_ERROR_OUT_OF_MEMORY; + + 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: + free(hmac_parms.ctx); + return res; +} |