Embedded SDK
Embedded SDK
cx_Groestl-ref.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_GROESTL
20 
21 #include "cx_utils.h"
22 #include "cx_ram.h"
23 
24 #include <string.h>
25 
26 #include "cx_Groestl-ref.h"
27 
28 static HashReturn Init(hashState *, int);
29 static void Update(hashState *, const BitSequence *, DataLength);
30 static void Final(hashState *, BitSequence *);
31 
32 cx_err_t cx_groestl_init_no_throw(cx_groestl_t *hash, size_t size)
33 {
34  memset(hash, 0, sizeof(cx_groestl_t));
35  switch (size) {
36  case 224:
37  case 256:
38  case 384:
39  case 512:
40  hash->output_size = size >> 3;
41  break;
42  default:
43  return CX_INVALID_PARAMETER;
44  }
45 
46  if (Init(&hash->ctx, size) != SUCCESS) {
47  return CX_INVALID_PARAMETER;
48  }
49  return CX_OK;
50 }
51 
52 cx_err_t cx_groestl(cx_groestl_t *hash,
53  uint32_t mode,
54  const uint8_t *in,
55  size_t len,
56  uint8_t *out,
57  size_t out_len)
58 {
59  size_t sz = 0;
60  Update(&((cx_groestl_t *) hash)->ctx, in, len);
61  if (mode & CX_LAST) {
62  sz = ((cx_groestl_t *) hash)->output_size;
63  if (out && (out_len < sz)) {
64  return CX_INVALID_PARAMETER;
65  }
66  Final(&((cx_groestl_t *) hash)->ctx, out);
67  }
68  return CX_OK;
69 }
70 
71 cx_err_t cx_groestl_update(cx_groestl_t *ctx, const uint8_t *data, size_t len)
72 {
73  if (ctx == NULL) {
74  return CX_INVALID_PARAMETER;
75  }
76  if (data == NULL) {
77  return len == 0 ? CX_OK : CX_INVALID_PARAMETER;
78  }
79  Update(&ctx->ctx, data, len);
80  return CX_OK;
81 }
82 
83 cx_err_t cx_groestl_final(cx_groestl_t *ctx, uint8_t *digest)
84 {
85  Final(&ctx->ctx, digest);
86  return CX_OK;
87 }
88 
89 size_t cx_groestl_get_output_size(const cx_groestl_t *ctx)
90 {
91  return ctx->output_size;
92 }
93 
94 /* Groestl-ref.c January 2011
95  * Reference ANSI C code
96  * Authors: Soeren S. Thomsen
97  * Krystian Matusiewicz
98  *
99  * This code is placed in the public domain
100  */
101 
102 #include "cx_Groestl-ref.h"
103 
104 /* S-box */
105 static const u8 S[256] = {
106  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
107  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
108  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
109  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
110  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
111  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
112  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
113  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
114  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
115  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
116  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
117  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
118  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
119  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
120  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
121  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
122 
123 /* Shift values for short/long variants */
124 static const u8 Shift[2][2][ROWS] = {
125  {{0, 1, 2, 3, 4, 5, 6, 7}, {1, 3, 5, 7, 0, 2, 4, 6} },
126  {{0, 1, 2, 3, 4, 5, 6, 11}, {1, 3, 5, 11, 0, 2, 4, 6}}
127 };
128 
129 /* AddRoundConstant xors a round-dependent constant to the state */
130 static void AddRoundConstant(u8 x[ROWS][COLS1024], int columns, u8 round, Variant v)
131 {
132  int i, j;
133  if ((v & 1) == 0) {
134  for (i = 0; i < columns; i++) {
135  x[0][i] ^= (i << 4) ^ round;
136  }
137  }
138  else {
139  for (i = 0; i < columns; i++) {
140  for (j = 0; j < ROWS - 1; j++) {
141  x[j][i] ^= 0xff;
142  }
143  }
144  for (i = 0; i < columns; i++) {
145  x[ROWS - 1][i] ^= (i << 4) ^ 0xff ^ round;
146  }
147  }
148 }
149 
150 /* SubBytes replaces each byte by a value from the S-box */
151 static void SubBytes(u8 x[ROWS][COLS1024], int columns)
152 {
153  int i, j;
154 
155  for (i = 0; i < ROWS; i++) {
156  for (j = 0; j < columns; j++) {
157  x[i][j] = S[x[i][j]];
158  }
159  }
160 }
161 
162 /* ShiftBytes cyclically shifts each row to the left by a number of
163  positions */
164 static void ShiftBytes(u8 x[ROWS][COLS1024], int columns, Variant v)
165 {
166  const u8 *R = Shift[v / 2][v & 1];
167  int i, j;
168  u8 temp[COLS1024];
169 
170  for (i = 0; i < ROWS; i++) {
171  for (j = 0; j < columns; j++) {
172  temp[j] = x[i][(j + R[i]) % columns];
173  }
174  for (j = 0; j < columns; j++) {
175  x[i][j] = temp[j];
176  }
177  }
178 }
179 
180 /* MixBytes reversibly mixes the bytes within a column */
181 static void MixBytes(u8 x[ROWS][COLS1024], int columns)
182 {
183  int i, j;
184  u8 temp[ROWS];
185 
186  for (i = 0; i < columns; i++) {
187  for (j = 0; j < ROWS; j++) {
188  temp[j] = mul2(x[(j + 0) % ROWS][i]) ^ mul2(x[(j + 1) % ROWS][i])
189  ^ mul3(x[(j + 2) % ROWS][i]) ^ mul4(x[(j + 3) % ROWS][i])
190  ^ mul5(x[(j + 4) % ROWS][i]) ^ mul3(x[(j + 5) % ROWS][i])
191  ^ mul5(x[(j + 6) % ROWS][i]) ^ mul7(x[(j + 7) % ROWS][i]);
192  }
193  for (j = 0; j < ROWS; j++) {
194  x[j][i] = temp[j];
195  }
196  }
197 }
198 
199 /* apply P-permutation to x */
200 static void P(hashState *ctx, u8 x[ROWS][COLS1024])
201 {
202  u8 i;
203  Variant v = ctx->columns == 8 ? P512 : P1024;
204  for (i = 0; i < ctx->rounds; i++) {
205  AddRoundConstant(x, ctx->columns, i, v);
206  SubBytes(x, ctx->columns);
207  ShiftBytes(x, ctx->columns, v);
208  MixBytes(x, ctx->columns);
209  }
210 }
211 
212 /* apply Q-permutation to x */
213 static void Q(hashState *ctx, u8 x[ROWS][COLS1024])
214 {
215  u8 i;
216  Variant v = ctx->columns == 8 ? Q512 : Q1024;
217  for (i = 0; i < ctx->rounds; i++) {
218  AddRoundConstant(x, ctx->columns, i, v);
219  SubBytes(x, ctx->columns);
220  ShiftBytes(x, ctx->columns, v);
221  MixBytes(x, ctx->columns);
222  }
223 }
224 
225 /* digest (up to) msglen bytes */
226 static void Transform(hashState *ctx, const BitSequence *input, u32 msglen)
227 {
228  unsigned int i, j;
229 /*
230 u8 temp1[ROWS][COLS1024], temp2[ROWS][COLS1024];
231 */
232 #define temp1 G_cx.groestl.temp1
233 #define temp2 G_cx.groestl.temp2
234 
235  /* digest one message block at the time */
236  for (; msglen >= ctx->statesize; msglen -= ctx->statesize, input += ctx->statesize) {
237  /* store message block (m) in temp2, and xor of chaining (h) and
238  message block in temp1 */
239  for (i = 0; i < ROWS; i++) {
240  for (j = 0; j < ctx->columns; j++) {
241  temp1[i][j] = ctx->chaining[i][j] ^ input[j * ROWS + i];
242  temp2[i][j] = input[j * ROWS + i];
243  }
244  }
245 
246  P(ctx, temp1); /* P(h+m) */
247  Q(ctx, temp2); /* Q(m) */
248 
249  /* xor P(h+m) and Q(m) onto chaining, yielding P(h+m)+Q(m)+h */
250  for (i = 0; i < ROWS; i++) {
251  cx_memxor(ctx->chaining[i], temp1[i], ctx->columns);
252  cx_memxor(ctx->chaining[i], temp2[i], ctx->columns);
253  // for (j = 0; j < ctx->columns; j++) {
254  // ctx->chaining[i][j] ^= temp1[i][j] ^ temp2[i][j];
255  // }
256  }
257 
258  /* increment block counter */
259  ctx->block_counter++;
260  }
261 #undef temp1
262 #undef temp2
263 }
264 
265 /* do output transformation, P(h)+h */
266 static void OutputTransformation(hashState *ctx)
267 {
268  unsigned int i, j;
269 /*
270 u8 temp[ROWS][COLS1024];
271 */
272 // OK because no used at the same time than tmp in Transform
273 #define temp G_cx.groestl.temp1
274 
275  /* store chaining ("h") in temp */
276  for (i = 0; i < ROWS; i++) {
277  for (j = 0; j < ctx->columns; j++) {
278  temp[i][j] = ctx->chaining[i][j];
279  }
280  }
281 
282  /* compute P(temp) = P(h) */
283  P(ctx, temp);
284 
285  /* feed chaining forward, yielding P(h)+h */
286  for (i = 0; i < ROWS; i++) {
287  cx_memxor(ctx->chaining[i], temp[i], ctx->columns);
288  // for (j = 0; j < ctx->columns; j++) {
289  // ctx->chaining[i][j] ^= temp[i][j];
290  // }
291  }
292 #undef temp
293 }
294 
295 /* initialise context */
296 static HashReturn Init(hashState *ctx, int hashbitlen)
297 {
298  unsigned int i, j;
299 
300  if (hashbitlen <= 0 || (hashbitlen % 8) || hashbitlen > 512) {
301  return BAD_HASHLEN;
302  }
303 
304  if (hashbitlen <= 256) {
305  ctx->rounds = ROUNDS512;
306  ctx->columns = COLS512;
307  ctx->statesize = SIZE512;
308  }
309  else {
310  ctx->rounds = ROUNDS1024;
311  ctx->columns = COLS1024;
312  ctx->statesize = SIZE1024;
313  }
314 
315  /* zeroise chaining variable */
316  for (i = 0; i < ROWS; i++) {
317  for (j = 0; j < ctx->columns; j++) {
318  ctx->chaining[i][j] = 0;
319  }
320  }
321 
322  /* store hashbitlen and set initial value */
323  ctx->hashlen = hashbitlen / 8u;
324  for (i = ROWS - sizeof(int); i < ROWS; i++) {
325  ctx->chaining[i][ctx->columns - 1] = (u8) (hashbitlen >> (8 * (7 - i)));
326  }
327 
328  /* initialise other variables */
329  ctx->buf_ptr = 0;
330  ctx->block_counter = 0;
331 
332  return SUCCESS;
333 }
334 
335 static void Update(hashState *ctx, const BitSequence *input, DataLength msglen)
336 {
337  unsigned int index = 0;
338 
339  /* if the buffer contains data that still needs to be digested */
340  if (ctx->buf_ptr) {
341  /* copy data into buffer until buffer is full, or there is no more
342  data */
343  for (index = 0; ctx->buf_ptr < ctx->statesize && index < msglen; index++, ctx->buf_ptr++) {
344  ctx->buffer[ctx->buf_ptr] = input[index];
345  }
346 
347  if (ctx->buf_ptr < ctx->statesize) {
348  /* this chunk of message does not fill the buffer */
349  return;
350  }
351 
352  /* the buffer is full, digest */
353  ctx->buf_ptr = 0;
354  Transform(ctx, ctx->buffer, ctx->statesize);
355  }
356 
357  /* digest remainder of data modulo the block size */
358  Transform(ctx, input + index, msglen - index);
359  index += ((msglen - index) / ctx->statesize) * ctx->statesize;
360 
361  /* copy remaining data to buffer */
362  for (; index < msglen; index++, ctx->buf_ptr++) {
363  ctx->buffer[ctx->buf_ptr] = input[index];
364  }
365  return;
366 }
367 
368 static void Final(hashState *ctx, BitSequence *output)
369 {
370  unsigned int zeroise;
371  unsigned int i, j;
372 
373  /* 100... padding */
374  ctx->buffer[ctx->buf_ptr++] = 0x80;
375 
376  if (ctx->buf_ptr > ctx->statesize - LENGTHFIELDLEN) {
377  /* padding requires two blocks */
378  while (ctx->buf_ptr < ctx->statesize) {
379  ctx->buffer[ctx->buf_ptr++] = 0;
380  }
381  Transform(ctx, ctx->buffer, ctx->statesize);
382  ctx->buf_ptr = 0;
383  }
384  while (ctx->buf_ptr < ctx->statesize - LENGTHFIELDLEN) {
385  ctx->buffer[ctx->buf_ptr++] = 0;
386  }
387 
388  /* length padding */
389  ctx->block_counter++;
390  ctx->buf_ptr = ctx->statesize;
391  while (ctx->buf_ptr > ctx->statesize - LENGTHFIELDLEN) {
392  ctx->buffer[--ctx->buf_ptr] = (u8) ctx->block_counter;
393  ctx->block_counter >>= 8;
394  }
395 
396  /* digest (last) padding block */
397  Transform(ctx, ctx->buffer, ctx->statesize);
398  /* output transformation */
399  OutputTransformation(ctx);
400 
401  /* store hash output */
402  if (output) {
403  zeroise = 1;
404  }
405  else {
406  zeroise = 0;
407  output = ctx->buffer;
408  }
409  j = 0;
410  for (i = ctx->statesize - ctx->hashlen; i < ctx->statesize; i++, j++) {
411  output[j] = ctx->chaining[i % ROWS][i / ROWS];
412  }
413  if (zeroise == 0) {
414  zeroise = j;
415  }
416 
417  /* zeroise */
418  for (i = 0; i < ROWS; i++) {
419  for (j = 0; j < ctx->columns; j++) {
420  ctx->chaining[i][j] = 0;
421  }
422  }
423 
424  for (i = zeroise; i < ctx->statesize; i++) {
425  ctx->buffer[i] = 0;
426  }
427 }
428 
429 #endif // HAVE_GROESTL
void cx_memxor(uint8_t *buf1, const uint8_t *buf2, size_t len)
Definition: cx_utils.c:173
#define CX_LAST
Definition: lcx_common.h:115
unsigned char uint8_t
Definition: usbd_conf.h:53