1 /*
2 * Copyright (c) 2023, The TrustedFirmware-M Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include <assert.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include "cc3xx_hash.h"
11 #include "cc3xx_hmac.h"
12 #include "cc3xx_stdlib.h"
13
cc3xx_lowlevel_hmac_compute(size_t tag_len,const uint8_t * key,size_t key_size,cc3xx_hash_alg_t alg,const uint8_t * data,size_t data_length,uint32_t * tag,size_t tag_size,size_t * tag_length)14 cc3xx_err_t cc3xx_lowlevel_hmac_compute(
15 size_t tag_len,
16 const uint8_t *key,
17 size_t key_size,
18 cc3xx_hash_alg_t alg,
19 const uint8_t *data,
20 size_t data_length,
21 uint32_t *tag,
22 size_t tag_size,
23 size_t *tag_length)
24 {
25 const uint8_t ipad = 0x36;
26 cc3xx_err_t err;
27 size_t idx;
28 /* In case the key is higher than B, it must be hashed first */
29 uint32_t hash_key_output[CC3XX_HASH_LENGTH(alg) / sizeof(uint32_t)];
30 const uint8_t *p_key = key;
31 size_t key_length = key_size;
32 const uint8_t ixopad = 0x6a; /* 0x36 ^ 0x5c == ipad ^ opad */
33 uint8_t block[CC3XX_HMAC_BLOCK_SIZE];
34
35 memset(block, ipad, sizeof(block));
36 *tag_length = 0;
37
38 assert(tag_size >= tag_len);
39
40 err = cc3xx_lowlevel_hash_init(alg);
41 if (err != CC3XX_ERR_SUCCESS) {
42 return err;
43 }
44
45 if (key_size > CC3XX_HMAC_BLOCK_SIZE) {
46 /* hash the key to L bytes */
47 err = cc3xx_lowlevel_hash_update(key, key_size);
48 if (err != CC3XX_ERR_SUCCESS) {
49 goto out;
50 }
51 p_key = (const uint8_t *)hash_key_output;
52 key_length = CC3XX_HASH_LENGTH(alg);
53 }
54
55 cc3xx_lowlevel_hash_finish(hash_key_output, sizeof(hash_key_output));
56
57 /* K ^ ipad */
58 for (idx = 0; idx < key_length; idx++) {
59 block[idx] ^= p_key[idx];
60 }
61
62 /* H(K ^ ipad) */
63 err = cc3xx_lowlevel_hash_init(alg);
64 if (err != CC3XX_ERR_SUCCESS) {
65 goto out;
66 }
67
68 err = cc3xx_lowlevel_hash_update((uint8_t *)block, CC3XX_HMAC_BLOCK_SIZE);
69 if (err != CC3XX_ERR_SUCCESS) {
70 goto out;
71 }
72
73 /* H(K ^ ipad | data)*/
74 if (data_length > 0) {
75 err = cc3xx_lowlevel_hash_update(data, data_length);
76 if (err != CC3XX_ERR_SUCCESS) {
77 goto out;
78 }
79 }
80
81 /* Produce H(K ^ ipad | data) */
82 cc3xx_lowlevel_hash_finish(hash_key_output, sizeof(hash_key_output));
83
84 /* K ^ opad */
85 for (idx = 0; idx < CC3XX_HMAC_BLOCK_SIZE; idx++) {
86 block[idx] ^= ixopad;
87 }
88
89 /* H( K ^ opad | H(K ^ ipad | data)) */
90 err = cc3xx_lowlevel_hash_init(alg);
91 if (err != CC3XX_ERR_SUCCESS) {
92 return err;
93 }
94
95 err = cc3xx_lowlevel_hash_update((uint8_t *)block, CC3XX_HMAC_BLOCK_SIZE);
96 if (err != CC3XX_ERR_SUCCESS) {
97 goto out;
98 }
99
100 err = cc3xx_lowlevel_hash_update((uint8_t *)hash_key_output, sizeof(hash_key_output));
101 if (err != CC3XX_ERR_SUCCESS) {
102 goto out;
103 }
104
105 cc3xx_lowlevel_hash_finish(hash_key_output, sizeof(hash_key_output));
106
107 out:
108 if (err == CC3XX_ERR_SUCCESS) {
109 memcpy(tag, hash_key_output, tag_len);
110 *tag_length = tag_len;
111 }
112 cc3xx_lowlevel_hash_uninit();
113 cc3xx_secure_erase_buffer((uint32_t *)block, sizeof(block) / sizeof(uint32_t));
114 return err;
115 }
116
cc3xx_lowlevel_hmac_set_key(struct cc3xx_hmac_state_t * state,const uint8_t * key,size_t key_size,cc3xx_hash_alg_t alg)117 cc3xx_err_t cc3xx_lowlevel_hmac_set_key(
118 struct cc3xx_hmac_state_t *state,
119 const uint8_t *key,
120 size_t key_size,
121 cc3xx_hash_alg_t alg)
122 {
123 const uint8_t ipad = 0x36;
124 cc3xx_err_t err;
125 size_t idx;
126 /* In case the key is higher than B, it must be hashed first */
127 uint32_t hash_key_output[CC3XX_HMAC_BLOCK_SIZE / sizeof(uint32_t)];
128 const uint8_t *p_key = key;
129 size_t key_length = key_size;
130
131 if (key_size > CC3XX_HMAC_BLOCK_SIZE) {
132 err = cc3xx_lowlevel_hash_init(alg);
133 if (err != CC3XX_ERR_SUCCESS) {
134 return err;
135 }
136
137 /* hash the key to L bytes */
138 err = cc3xx_lowlevel_hash_update(key, key_size);
139 if (err != CC3XX_ERR_SUCCESS) {
140 goto out;
141 }
142 p_key = (const uint8_t *)hash_key_output;
143 key_length = CC3XX_HASH_LENGTH(alg);
144
145 cc3xx_lowlevel_hash_finish(hash_key_output, sizeof(hash_key_output));
146 }
147
148 /* K ^ ipad */
149 for (idx = 0; idx < key_length; idx++) {
150 state->key[idx] = p_key[idx] ^ ipad;
151 }
152
153 memset(&state->key[key_length], ipad, CC3XX_HMAC_BLOCK_SIZE - key_length);
154
155 /* H(K ^ ipad) */
156 err = cc3xx_lowlevel_hash_init(alg);
157 if (err != CC3XX_ERR_SUCCESS) {
158 goto out;
159 }
160
161 err = cc3xx_lowlevel_hash_update(state->key, CC3XX_HMAC_BLOCK_SIZE);
162
163 out:
164 if (err == CC3XX_ERR_SUCCESS) {
165 cc3xx_lowlevel_hash_get_state(&state->hash);
166 state->alg = alg;
167 state->tag_len = CC3XX_HASH_LENGTH(alg);
168 }
169 cc3xx_lowlevel_hash_uninit();
170 return err;
171 }
172
cc3xx_lowlevel_hmac_set_tag_length(struct cc3xx_hmac_state_t * state,size_t tag_len)173 void cc3xx_lowlevel_hmac_set_tag_length(
174 struct cc3xx_hmac_state_t *state,
175 size_t tag_len)
176 {
177 state->tag_len = tag_len;
178 }
179
cc3xx_lowlevel_hmac_update(struct cc3xx_hmac_state_t * state,const uint8_t * data,size_t data_length)180 cc3xx_err_t cc3xx_lowlevel_hmac_update(
181 struct cc3xx_hmac_state_t *state,
182 const uint8_t *data,
183 size_t data_length)
184 {
185 cc3xx_err_t err;
186
187 cc3xx_lowlevel_hash_set_state(&state->hash);
188
189 /* H(K ^ ipad | data)*/
190 err = cc3xx_lowlevel_hash_update(data, data_length);
191
192 if (err == CC3XX_ERR_SUCCESS) {
193 cc3xx_lowlevel_hash_get_state(&state->hash);
194 }
195 cc3xx_lowlevel_hash_uninit();
196 return err;
197 }
198
cc3xx_lowlevel_hmac_finish(struct cc3xx_hmac_state_t * state,uint32_t * tag,size_t tag_size,size_t * tag_len)199 cc3xx_err_t cc3xx_lowlevel_hmac_finish(
200 struct cc3xx_hmac_state_t *state,
201 uint32_t *tag,
202 size_t tag_size,
203 size_t *tag_len)
204 {
205 uint32_t scratch[CC3XX_HASH_LENGTH(state->alg) / sizeof(uint32_t)];
206 const uint8_t ixopad = 0x36 ^ 0x5c; /* ipad ^ opad */
207 cc3xx_err_t err;
208 size_t idx;
209
210 assert(tag_size >= state->tag_len);
211
212 cc3xx_lowlevel_hash_set_state(&state->hash);
213
214 /* Produce H(K ^ ipad | data) */
215 cc3xx_lowlevel_hash_finish(scratch, sizeof(scratch));
216
217 /* K ^ opad */
218 for (idx = 0; idx < CC3XX_HMAC_BLOCK_SIZE; idx++) {
219 state->key[idx] ^= ixopad;
220 }
221
222 /* H( K ^ opad | H(K ^ ipad | data)) */
223 err = cc3xx_lowlevel_hash_init(state->alg);
224 if (err != CC3XX_ERR_SUCCESS) {
225 goto out;
226 }
227
228 err = cc3xx_lowlevel_hash_update(state->key, CC3XX_HMAC_BLOCK_SIZE);
229 if (err != CC3XX_ERR_SUCCESS) {
230 goto out;
231 }
232
233 err = cc3xx_lowlevel_hash_update((const uint8_t *)scratch, sizeof(scratch));
234 if (err != CC3XX_ERR_SUCCESS) {
235 goto out;
236 }
237
238 cc3xx_lowlevel_hash_finish(scratch, sizeof(scratch));
239
240 if (tag_len != NULL) {
241 *tag_len = state->tag_len;
242 }
243
244 out:
245 if (err == CC3XX_ERR_SUCCESS) {
246 memcpy(tag, scratch, state->tag_len);
247 cc3xx_lowlevel_hash_get_state(&state->hash);
248 }
249 cc3xx_lowlevel_hash_uninit();
250 return err;
251 }
252