Embedded SDK
Embedded SDK
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 
36 const 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 
47 const 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 
58 const 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 
69 const 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 
84 static 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 
101 static 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 
104 static 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 
107 static 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 
122 static 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 
137 static 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 
151 static void cx_sha3_iota(uint64bits_t state[], int round)
152 {
153  S64(0, 0) ^= C_cx_iota_RC[round];
154 }
155 
156 static 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 
170 cx_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 
182 cx_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 
191 cx_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 
203 cx_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 
215 cx_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 
234 void 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 
270 cx_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 
322 cx_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 
374 size_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