Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
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
28static HashReturn Init(hashState *, int);
29static void Update(hashState *, const BitSequence *, DataLength);
30static void Final(hashState *, BitSequence *);
31
32cx_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
52cx_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
71cx_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
83cx_err_t cx_groestl_final(cx_groestl_t *ctx, uint8_t *digest)
84{
85 Final(&ctx->ctx, digest);
86 return CX_OK;
87}
88
89size_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 */
105static 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 */
124static 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 */
130static 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 */
151static 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 */
164static 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 */
181static 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 */
200static 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 */
213static 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 */
226static void Transform(hashState *ctx, const BitSequence *input, u32 msglen)
227{
228 unsigned int i, j;
229/*
230u8 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 */
266static void OutputTransformation(hashState *ctx)
267{
268 unsigned int i, j;
269/*
270u8 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 */
296static 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
335static 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
368static 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