Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
cx_hmac.c
Go to the documentation of this file.
1
2/*******************************************************************************
3 * Ledger Nano S - Secure firmware
4 * (c) 2022 Ledger
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 ********************************************************************************/
18
19#ifdef HAVE_HMAC
20
21#include "cx_hmac.h"
22#include "cx_hash.h"
23#include "cx_ram.h"
24#include "errors.h"
25#include "exceptions.h"
26#include "lcx_common.h"
27
28#include <string.h>
29
30#define IPAD 0x36u
31#define OPAD 0x5cu
32
33static size_t cx_get_block_size(cx_md_t md)
34{
35 const cx_hash_info_t *info = cx_hash_get_info(md);
36 if (info == NULL) {
37 return 0;
38 }
39 return info->block_size;
40}
41
42static cx_md_t cx_get_algorithm(cx_hmac_t *ctx)
43{
44 return ctx->hash_ctx.info->md_type;
45}
46
47static bool cx_is_allowed_digest(cx_md_t md_type)
48{
49 const cx_md_t allowed_algorithms[] = {
50#ifdef HAVE_SHA224
51 CX_SHA224,
52#endif
53#ifdef HAVE_SHA256
54 CX_SHA256,
55#endif
56#ifdef HAVE_SHA384
57 CX_SHA384,
58#endif
59#ifdef HAVE_SHA512
60 CX_SHA512,
61#endif
62#ifdef HAVE_RIPEMD160
63 CX_RIPEMD160,
64#endif
65 };
66 for (unsigned int i = 0; i < sizeof(allowed_algorithms) / sizeof(allowed_algorithms[0]); i++) {
67 if (allowed_algorithms[i] == md_type) {
68 return true;
69 }
70 }
71 return false;
72}
73
74cx_err_t cx_hmac_init(cx_hmac_t *ctx, cx_md_t hash_id, const uint8_t *key, size_t key_len)
75{
76 cx_hash_t *hash_ctx;
77 cx_err_t error;
78
79 if ((ctx == NULL) || (!cx_is_allowed_digest(hash_id)) || (key == NULL && key_len != 0)) {
80 return CX_INVALID_PARAMETER;
81 }
82
83 hash_ctx = &ctx->hash_ctx;
84 memset(ctx, 0, sizeof(cx_hmac_t));
85 size_t block_size = cx_get_block_size(hash_id);
86
87 if (key) {
88 if (key_len > block_size) {
89 CX_CHECK(cx_hash_init(hash_ctx, hash_id));
90 CX_CHECK(cx_hash_update(hash_ctx, key, key_len));
91 CX_CHECK(cx_hash_final(hash_ctx, ctx->key));
92 }
93 else {
94 memcpy(ctx->key, key, key_len);
95 }
96
97 for (unsigned int i = 0; i < block_size; i++) {
98 ctx->key[i] ^= IPAD;
99 }
100 }
101
102 CX_CHECK(cx_hash_init(hash_ctx, hash_id));
103 CX_CHECK(cx_hash_update(hash_ctx, ctx->key, block_size));
104end:
105 return error;
106}
107
108cx_err_t cx_hmac_update(cx_hmac_t *ctx, const uint8_t *data, size_t data_len)
109{
110 if (data_len == 0) {
111 return CX_OK;
112 }
113 return cx_hash_update(&ctx->hash_ctx, data, data_len);
114}
115
116cx_err_t cx_hmac_final(cx_hmac_t *ctx, uint8_t *out, size_t *out_len)
117{
118 cx_err_t error;
119
120 uint8_t inner_hash[MAX_HASH_SIZE];
121 uint8_t hkey[MAX_HASH_BLOCK_SIZE];
122
123 cx_hash_t *hash_ctx = &ctx->hash_ctx;
124
125 cx_md_t hash_algorithm = cx_get_algorithm(ctx);
126 size_t block_size = cx_get_block_size(hash_algorithm);
127 size_t hash_output_size = cx_hash_get_size(hash_ctx);
128
129 CX_CHECK(cx_hash_final(hash_ctx, inner_hash));
130
131 // hash key xor 5c (and 36 to remove prepadding at init)
132 memcpy(hkey, ctx->key, block_size);
133 for (unsigned int i = 0; i < block_size; i++) {
134 hkey[i] ^= OPAD ^ IPAD;
135 }
136
137 CX_CHECK(cx_hash_init(hash_ctx, hash_algorithm));
138 CX_CHECK(cx_hash_update(hash_ctx, hkey, block_size));
139 CX_CHECK(cx_hash_update(hash_ctx, inner_hash, hash_output_size));
140 CX_CHECK(cx_hash_final(hash_ctx, hkey));
141
142 // length result
143 if (*out_len >= hash_output_size) {
144 *out_len = hash_output_size;
145 }
146 memcpy(out, hkey, *out_len);
147end:
148 return error;
149}
150
151#ifdef HAVE_SHA224
152cx_err_t cx_hmac_sha224_init(cx_hmac_sha256_t *hmac, const uint8_t *key, unsigned int key_len)
153{
154 return cx_hmac_init((cx_hmac_t *) hmac, CX_SHA224, key, key_len);
155}
156#endif
157#ifdef HAVE_SHA256
158cx_err_t cx_hmac_sha256_init_no_throw(cx_hmac_sha256_t *hmac, const uint8_t *key, size_t key_len)
159{
160 return cx_hmac_init((cx_hmac_t *) hmac, CX_SHA256, key, key_len);
161}
162#endif
163
164#ifdef HAVE_SHA384
165cx_err_t cx_hmac_sha384_init(cx_hmac_sha512_t *hmac, const uint8_t *key, unsigned int key_len)
166{
167 return cx_hmac_init((cx_hmac_t *) hmac, CX_SHA384, key, key_len);
168}
169#endif
170#ifdef HAVE_SHA512
171cx_err_t cx_hmac_sha512_init_no_throw(cx_hmac_sha512_t *hmac, const uint8_t *key, size_t key_len)
172{
173 return cx_hmac_init((cx_hmac_t *) hmac, CX_SHA512, key, key_len);
174}
175#endif
176
177#ifdef HAVE_RIPEMD160
178cx_err_t cx_hmac_ripemd160_init_no_throw(cx_hmac_ripemd160_t *hmac,
179 const uint8_t *key,
180 size_t key_len)
181{
182 return cx_hmac_init((cx_hmac_t *) hmac, CX_RIPEMD160, key, key_len);
183}
184#endif
185
186cx_err_t cx_hmac_no_throw(cx_hmac_t *hmac,
187 uint32_t mode,
188 const uint8_t *in,
189 size_t len,
190 uint8_t *out,
191 size_t out_len)
192{
193 size_t output_size = 0;
194 cx_err_t error = CX_OK;
195
196 if (in == NULL && len != 0) {
197 return CX_INVALID_PARAMETER;
198 }
199 if (out == NULL && out_len != 0) {
200 return CX_INVALID_PARAMETER;
201 }
202
203 if (in != NULL) {
204 CX_CHECK(cx_hmac_update(hmac, in, len));
205 }
206
207 if (mode & CX_LAST) {
208 output_size = out_len;
209 CX_CHECK(cx_hmac_final(hmac, out, &output_size));
210
211 if (!(mode & CX_NO_REINIT)) {
212 CX_CHECK(cx_hmac_init(hmac, cx_get_algorithm(hmac), NULL, 0));
213 }
214 }
215
216end:
217 return error;
218}
219
220#ifdef HAVE_SHA256
221size_t cx_hmac_sha256(const uint8_t *key,
222 size_t key_len,
223 const uint8_t *in,
224 size_t len,
225 uint8_t *out,
226 size_t out_len)
227{
228 size_t mac_len = out_len;
229 if (cx_hmac_init(&G_cx.hmac, CX_SHA256, key, key_len) != CX_OK
230 || cx_hmac_update(&G_cx.hmac, in, len) != CX_OK
231 || cx_hmac_final(&G_cx.hmac, out, &mac_len) != CX_OK) {
232 mac_len = 0;
233 }
234 explicit_bzero(&G_cx.hmac, sizeof(cx_hmac_sha256_t));
235 return mac_len;
236}
237#endif
238
239#ifdef HAVE_SHA512
240size_t cx_hmac_sha512(const uint8_t *key,
241 size_t key_len,
242 const uint8_t *in,
243 size_t len,
244 uint8_t *out,
245 size_t out_len)
246{
247 size_t mac_len = out_len;
248 if (cx_hmac_init(&G_cx.hmac, CX_SHA512, key, key_len) != CX_OK
249 || cx_hmac_update(&G_cx.hmac, in, len) != CX_OK
250 || cx_hmac_final(&G_cx.hmac, out, &mac_len) != CX_OK) {
251 mac_len = 0;
252 }
253 explicit_bzero(&G_cx.hmac, sizeof(cx_hmac_sha512_t));
254 return mac_len;
255}
256#endif
257
258#endif // HAVE_HMAC
union cx_u G_cx
Definition cx_ram.c:21
Cryptography flags.
#define CX_NO_REINIT
Definition lcx_common.h:183
#define CX_LAST
Definition lcx_common.h:115
unsigned char uint8_t
Definition usbd_conf.h:53