Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
cx_sha3.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_SHA3
20
21#include "cx_sha3.h"
22#include "cx_errors.h"
23#include "cx_utils.h"
24#include "errors.h"
25#include <stdbool.h>
26#include <string.h>
27
28#ifndef ARCH_LITTLE_ENDIAN
29#error "Big endian architectures are not supported. Please abort your project"
30#endif
31
32#ifndef NATIVE_64BITS // NO 64BITS natively supported by the compiler
33#error sha3 require 64 bits support at compiler level (NATIVE_64BITS option)
34#endif
35
36const cx_hash_info_t cx_sha3_info
37 = {CX_SHA3,
38 0,
39 0,
40 sizeof(cx_sha3_t),
41 NULL,
42 (cx_err_t(*)(cx_hash_t * ctx, const uint8_t *data, size_t len)) cx_sha3_update,
43 (cx_err_t(*)(cx_hash_t * ctx, uint8_t *digest)) cx_sha3_final,
44 (cx_err_t(*)(cx_hash_t * ctx, size_t output_size)) cx_sha3_init_no_throw,
45 (size_t(*)(const cx_hash_t *ctx)) cx_sha3_get_output_size};
46
47const cx_hash_info_t cx_keccak_info
48 = {CX_KECCAK,
49 0,
50 0,
51 sizeof(cx_sha3_t),
52 NULL,
53 (cx_err_t(*)(cx_hash_t * ctx, const uint8_t *data, size_t len)) cx_sha3_update,
54 (cx_err_t(*)(cx_hash_t * ctx, uint8_t *digest)) cx_sha3_final,
55 (cx_err_t(*)(cx_hash_t * ctx, size_t output_size)) cx_keccak_init_no_throw,
56 (size_t(*)(const cx_hash_t *ctx)) cx_sha3_get_output_size};
57
58const cx_hash_info_t cx_shake128_info
59 = {CX_SHAKE128,
60 0,
61 0,
62 sizeof(cx_sha3_t),
63 NULL,
64 (cx_err_t(*)(cx_hash_t * ctx, const uint8_t *data, size_t len)) cx_sha3_update,
65 (cx_err_t(*)(cx_hash_t * ctx, uint8_t *digest)) cx_sha3_final,
66 (cx_err_t(*)(cx_hash_t * ctx, size_t output_size)) cx_shake128_init_no_throw,
67 (size_t(*)(const cx_hash_t *ctx)) cx_sha3_get_output_size};
68
69const cx_hash_info_t cx_shake256_info
70 = {CX_SHAKE256,
71 0,
72 0,
73 sizeof(cx_sha3_t),
74 NULL,
75 (cx_err_t(*)(cx_hash_t * ctx, const uint8_t *data, size_t len)) cx_sha3_update,
76 (cx_err_t(*)(cx_hash_t * ctx, uint8_t *digest)) cx_sha3_final,
77 (cx_err_t(*)(cx_hash_t * ctx, size_t output_size)) cx_shake256_init_no_throw,
78 (size_t(*)(const cx_hash_t *ctx)) cx_sha3_get_output_size};
79
80// Assume state is a uint64_t array
81#define S64(x, y) state[x + 5 * y]
82#define ROTL64(x, n) cx_rotl64(x, n)
83
84static void cx_sha3_theta(uint64bits_t state[])
85{
86 uint64bits_t C[5];
87 uint64bits_t D[5];
88 int i, j;
89
90 for (i = 0; i < 5; i++) {
91 C[i] = S64(i, 0) ^ S64(i, 1) ^ S64(i, 2) ^ S64(i, 3) ^ S64(i, 4);
92 }
93 for (i = 0; i < 5; i++) {
94 D[i] = C[(i + 4) % 5] ^ ROTL64(C[(i + 1) % 5], 1);
95 for (j = 0; j < 5; j++) {
96 S64(i, j) ^= D[i];
97 }
98 }
99}
100
101static const uint8_t C_cx_pi_table[]
102 = {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1};
103
104static const uint8_t C_cx_rho_table[]
105 = {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44};
106
107static void cx_sha3_rho_pi(uint64bits_t state[])
108{
109 int i, j;
110 uint64bits_t A;
111 uint64bits_t tmp;
112
113 A = state[1];
114 for (i = 0; i < 24; i++) {
115 j = C_cx_pi_table[i];
116 tmp = state[j];
117 state[j] = ROTL64(A, C_cx_rho_table[i]);
118 A = tmp;
119 }
120}
121
122static void cx_sha3_chi(uint64bits_t state[])
123{
124 uint64bits_t C[5];
125
126 int i, j;
127 for (j = 0; j < 5; j++) {
128 for (i = 0; i < 5; i++) {
129 C[i] = S64(i, j);
130 }
131 for (i = 0; i < 5; i++) {
132 S64(i, j) ^= (~C[(i + 1) % 5]) & C[(i + 2) % 5];
133 }
134 }
135}
136
137static const uint64bits_t C_cx_iota_RC[24]
138 = {_64BITS(0x00000000, 0x00000001), _64BITS(0x00000000, 0x00008082),
139 _64BITS(0x80000000, 0x0000808A), _64BITS(0x80000000, 0x80008000),
140 _64BITS(0x00000000, 0x0000808B), _64BITS(0x00000000, 0x80000001),
141 _64BITS(0x80000000, 0x80008081), _64BITS(0x80000000, 0x00008009),
142 _64BITS(0x00000000, 0x0000008A), _64BITS(0x00000000, 0x00000088),
143 _64BITS(0x00000000, 0x80008009), _64BITS(0x00000000, 0x8000000A),
144 _64BITS(0x00000000, 0x8000808B), _64BITS(0x80000000, 0x0000008B),
145 _64BITS(0x80000000, 0x00008089), _64BITS(0x80000000, 0x00008003),
146 _64BITS(0x80000000, 0x00008002), _64BITS(0x80000000, 0x00000080),
147 _64BITS(0x00000000, 0x0000800A), _64BITS(0x80000000, 0x8000000A),
148 _64BITS(0x80000000, 0x80008081), _64BITS(0x80000000, 0x00008080),
149 _64BITS(0x00000000, 0x80000001), _64BITS(0x80000000, 0x80008008)};
150
151static void cx_sha3_iota(uint64bits_t state[], int round)
152{
153 S64(0, 0) ^= C_cx_iota_RC[round];
154}
155
156static bool check_hash_out_size(size_t size)
157{
158 switch (size) {
159 case 128:
160 case 224:
161 case 256:
162 case 384:
163 case 512:
164 return true;
165 default:
166 return false;
167 }
168}
169
170cx_err_t cx_sha3_init_no_throw(cx_sha3_t *hash PLENGTH(sizeof(cx_sha3_t)), size_t size)
171{
172 if (!check_hash_out_size(size)) {
173 return CX_INVALID_PARAMETER;
174 }
175 memset(hash, 0, sizeof(cx_sha3_t));
176 hash->header.info = &cx_sha3_info;
177 hash->output_size = size >> 3;
178 hash->block_size = (1600 - 2 * size) >> 3;
179 return CX_OK;
180}
181
182cx_err_t cx_keccak_init_no_throw(cx_sha3_t *hash PLENGTH(sizeof(cx_sha3_t)), size_t size)
183{
184 if (!check_hash_out_size(size) || cx_sha3_init_no_throw(hash, size) != CX_OK) {
185 return CX_INVALID_PARAMETER;
186 }
187 hash->header.info = &cx_keccak_info;
188 return CX_OK;
189}
190
191cx_err_t cx_shake128_init_no_throw(cx_sha3_t *hash, size_t size)
192{
193 memset(hash, 0, sizeof(cx_sha3_t));
194 if (size % 8 != 0) {
195 return CX_INVALID_PARAMETER;
196 }
197 hash->header.info = &cx_shake128_info;
198 hash->output_size = size / 8;
199 hash->block_size = (1600 - 2 * 128) >> 3;
200 return CX_OK;
201}
202
203cx_err_t cx_shake256_init_no_throw(cx_sha3_t *hash, size_t size)
204{
205 memset(hash, 0, sizeof(cx_sha3_t));
206 if (size % 8 != 0) {
207 return CX_INVALID_PARAMETER;
208 }
209 hash->header.info = &cx_shake256_info;
210 hash->output_size = size / 8;
211 hash->block_size = (1600 - 2 * 256) >> 3;
212 return CX_OK;
213}
214
215cx_err_t cx_sha3_xof_init_no_throw(cx_sha3_t *hash PLENGTH(sizeof(cx_sha3_t)),
216 size_t size,
217 size_t out_length)
218{
219 if ((size != 128) && (size != 256)) {
220 return CX_INVALID_PARAMETER;
221 }
222 memset(hash, 0, sizeof(cx_sha3_t));
223 if (size == 128) {
224 hash->header.info = &cx_shake128_info;
225 }
226 else {
227 hash->header.info = &cx_shake256_info;
228 }
229 hash->output_size = out_length;
230 hash->block_size = (1600 - 2 * size) >> 3;
231 return CX_OK;
232}
233
234void cx_sha3_block(cx_sha3_t *hash)
235{
236 uint64bits_t *block;
237 uint64bits_t *acc;
238 int r, i, n;
239
240 block = (uint64bits_t *) hash->block;
241 acc = (uint64bits_t *) hash->acc;
242
243 if (hash->block_size > 144) {
244 n = 21;
245 }
246 else if (hash->block_size > 136) {
247 n = 18;
248 }
249 else if (hash->block_size > 104) {
250 n = 17;
251 }
252 else if (hash->block_size > 72) {
253 n = 13;
254 }
255 else {
256 n = 9;
257 }
258 for (i = 0; i < n; i++) {
259 acc[i] ^= block[i];
260 }
261
262 for (r = 0; r < 24; r++) {
263 cx_sha3_theta(acc);
264 cx_sha3_rho_pi(acc);
265 cx_sha3_chi(acc);
266 cx_sha3_iota(acc, r);
267 }
268}
269
270cx_err_t cx_sha3_update(cx_sha3_t *ctx, const uint8_t *data, size_t len)
271{
272 size_t r;
273 size_t block_size;
274 uint8_t *block;
275 size_t blen;
276
277 if (ctx == NULL) {
278 return CX_INVALID_PARAMETER;
279 }
280 if (data == NULL) {
281 return len == 0 ? CX_OK : CX_INVALID_PARAMETER;
282 }
283
284 block_size = ctx->block_size;
285 if (block_size > 200) {
286 return CX_INVALID_PARAMETER;
287 }
288
289 block = ctx->block;
290 blen = ctx->blen;
291 ctx->blen = 0;
292
293 if (blen >= block_size) {
294 return CX_INVALID_PARAMETER;
295 }
296
297 // --- append input data and process all blocks ---
298 if ((blen + len) >= block_size) {
299 r = block_size - blen;
300 do {
301 if (ctx->header.counter == CX_HASH_MAX_BLOCK_COUNT) {
302 return INVALID_PARAMETER;
303 }
304 memcpy(block + blen, data, r);
305 cx_sha3_block(ctx);
306
307 blen = 0;
308 ctx->header.counter++;
309 data += r;
310 len -= r;
311 r = block_size;
312 } while (len >= block_size);
313 }
314
315 // --- remind rest data---
316 memcpy(block + blen, data, len);
317 blen += len;
318 ctx->blen = blen;
319 return CX_OK;
320}
321
322cx_err_t cx_sha3_final(cx_sha3_t *hash, uint8_t *digest)
323{
324 size_t block_size;
325 uint8_t *block;
326 size_t blen;
327 size_t len;
328
329 block = hash->block;
330 block_size = hash->block_size;
331 blen = hash->blen;
332
333 // one more block?
334 if (hash->header.info->md_type == CX_KECCAK || hash->header.info->md_type == CX_SHA3) {
335 // last block!
336 memset(block + blen, 0, (200 - blen));
337
338 if (hash->header.info->md_type == CX_KECCAK) {
339 block[blen] |= 01;
340 }
341 else {
342 block[blen] |= 06;
343 }
344 block[block_size - 1] |= 0x80;
345 cx_sha3_block(hash);
346
347 // provide result
348 len = (hash)->output_size;
349 memcpy(digest, hash->acc, len);
350 }
351 else {
352 // CX_SHA3_XOF
353 memset(block + blen, 0, (200 - blen));
354 block[blen] |= 0x1F;
355 block[block_size - 1] |= 0x80;
356 cx_sha3_block(hash);
357 // provide result
358 len = hash->output_size;
359 blen = len;
360
361 memset(block, 0, 200);
362
363 while (blen > block_size) {
364 memcpy(digest, hash->acc, block_size);
365 blen -= block_size;
366 digest += block_size;
367 cx_sha3_block(hash);
368 }
369 memcpy(digest, hash->acc, blen);
370 }
371 return CX_OK;
372}
373
374size_t cx_sha3_get_output_size(const cx_sha3_t *ctx)
375{
376 return ctx->output_size;
377}
378
379#endif // HAVE_SHA3
#define _64BITS(h, l)
Definition cx_utils.h:53
64-bit types, native or by-hands, depending on target and/or compiler support.
Definition lcx_common.h:49
unsigned char uint8_t
Definition usbd_conf.h:53