aboutsummaryrefslogtreecommitdiff
path: root/core/tee/tee_cryp_pbkdf2.c
blob: 6c526bdace91e2e4d40e0db7ae7e0b552d375ba1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// SPDX-License-Identifier: BSD-2-Clause
/*
 * Copyright (c) 2014, Linaro Limited
 * All rights reserved.
 */

#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, 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 ctx_size, 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_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;
}