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