1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, Linaro Limited
4  */
5 
6 #include <crypto/crypto.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <tee/tee_cryp_pbkdf2.h>
10 #include <tee/tee_cryp_utl.h>
11 #include <utee_defines.h>
12 
13 struct hmac_parms {
14 	uint32_t algo;
15 	size_t hash_len;
16 	void *ctx;
17 };
18 
19 struct pbkdf2_parms {
20 	const uint8_t *password;
21 	size_t password_len;
22 	const uint8_t *salt;
23 	size_t salt_len;
24 	uint32_t iteration_count;
25 };
26 
pbkdf2_f(uint8_t * out,size_t len,uint32_t idx,struct hmac_parms * h,struct pbkdf2_parms * p)27 static TEE_Result pbkdf2_f(uint8_t *out, size_t len, uint32_t idx,
28 			   struct hmac_parms *h, struct pbkdf2_parms *p)
29 {
30 	TEE_Result res;
31 	uint8_t u[TEE_MAX_HASH_SIZE];
32 	uint32_t be_index;
33 	size_t i, j;
34 
35 	memset(out, 0, len);
36 	for (i = 1; i <= p->iteration_count; i++) {
37 		res = crypto_mac_init(h->ctx, p->password, p->password_len);
38 		if (res != TEE_SUCCESS)
39 			return res;
40 
41 		if (i == 1) {
42 			if (p->salt && p->salt_len) {
43 				res = crypto_mac_update(h->ctx, p->salt,
44 							p->salt_len);
45 				if (res != TEE_SUCCESS)
46 					return res;
47 			}
48 
49 			be_index = TEE_U32_TO_BIG_ENDIAN(idx);
50 
51 			res = crypto_mac_update(h->ctx, (uint8_t *)&be_index,
52 						sizeof(be_index));
53 			if (res != TEE_SUCCESS)
54 				return res;
55 		} else {
56 			res = crypto_mac_update(h->ctx, u, h->hash_len);
57 			if (res != TEE_SUCCESS)
58 				return res;
59 		}
60 
61 		res = crypto_mac_final(h->ctx, u, sizeof(u));
62 		if (res != TEE_SUCCESS)
63 			return res;
64 
65 		for (j = 0; j < len; j++)
66 			out[j] ^= u[j];
67 	}
68 	return TEE_SUCCESS;
69 }
70 
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)71 TEE_Result tee_cryp_pbkdf2(uint32_t hash_id, const uint8_t *password,
72 			   size_t password_len, const uint8_t *salt,
73 			   size_t salt_len, uint32_t iteration_count,
74 			   uint8_t *derived_key, size_t derived_key_len)
75 {
76 	TEE_Result res;
77 	size_t i, l, r;
78 	uint8_t *out = derived_key;
79 	struct pbkdf2_parms pbkdf2_parms;
80 	struct hmac_parms hmac_parms = {0, };
81 
82 	hmac_parms.algo = TEE_ALG_HMAC_ALGO(hash_id);
83 
84 	res = tee_alg_get_digest_size(hmac_parms.algo, &hmac_parms.hash_len);
85 	if (res != TEE_SUCCESS)
86 		return res;
87 
88 	res = crypto_mac_alloc_ctx(&hmac_parms.ctx, hmac_parms.algo);
89 	if (res != TEE_SUCCESS)
90 		return res;
91 
92 	pbkdf2_parms.password = password;
93 	pbkdf2_parms.password_len = password_len;
94 	pbkdf2_parms.salt = salt;
95 	pbkdf2_parms.salt_len = salt_len;
96 	pbkdf2_parms.iteration_count = iteration_count;
97 
98 	l = derived_key_len / hmac_parms.hash_len;
99 	r = derived_key_len % hmac_parms.hash_len;
100 
101 	for (i = 1; i <= l; i++) {
102 		res = pbkdf2_f(out, hmac_parms.hash_len, i, &hmac_parms,
103 			       &pbkdf2_parms);
104 		if (res != TEE_SUCCESS)
105 			goto out;
106 		out += hmac_parms.hash_len;
107 	}
108 	if (r)
109 		res = pbkdf2_f(out, r, i, &hmac_parms, &pbkdf2_parms);
110 
111 out:
112 	crypto_mac_free_ctx(hmac_parms.ctx);
113 	return res;
114 }
115