Embedded SDK
Embedded SDK
cx_ripemd160.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_RIPEMD160
20 
21 #include "cx_ripemd160.h"
22 #include "cx_utils.h"
23 #include "cx_selftests.h"
24 #include "errors.h"
25 #include "exceptions.h"
26 #include "cx_ram.h"
27 
28 #include <string.h>
29 
30 #define RIPEMD_BLOCK_SIZE 64
31 
32 const cx_hash_info_t cx_ripemd160_info
33  = {CX_RIPEMD160,
34  CX_RIPEMD160_SIZE,
35  RIPEMD_BLOCK_SIZE,
36  sizeof(cx_ripemd160_t),
37  (cx_err_t(*)(cx_hash_t * ctx)) cx_ripemd160_init_no_throw,
38  (cx_err_t(*)(cx_hash_t * ctx, const uint8_t *data, size_t len)) cx_ripemd160_update,
39  (cx_err_t(*)(cx_hash_t * ctx, uint8_t *digest)) cx_ripemd160_final,
40  NULL,
41  NULL};
42 
43 /* ----------------------------------------------------------------------- */
44 /* */
45 /* ----------------------------------------------------------------------- */
46 // Message Selection L: left, R: right
47 static const uint8_t zL[] = {
48  /*zL[16..31]*/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
49  /*zL[16..31]*/ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
50  /*zL[32..47]*/ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
51  /*zL[48..63]*/ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
52  /*zL[64..79]*/ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
53 };
54 
55 static const uint8_t zR[] = {
56  /*zR[ 0..15]*/ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
57  /*zR[16..31]*/ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
58  /*zR[32..47]*/ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
59  /*zR[48..63]*/ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
60  /*zR[64..79]*/ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11,
61 };
62 
63 // Rotate left
64 static const uint8_t sL[] = {
65  /*sL[ 0..15],*/ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
66  /*sL[16..31]*/ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
67  /*sL[32..47]*/ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
68  /*sL[48..63]*/ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
69  /*sL[64..79]*/ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
70 };
71 
72 static const uint8_t sR[] = {
73  /*sR[ 0..15]*/ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
74  /*sR[16..31]*/ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
75  /*sR[32..47]*/ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
76  /*sR[48..63]*/ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
77  /*sR[64..79]*/ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11,
78 };
79 
80 static const uint32_t hzero[]
81  = {0x67452301UL, 0xEFCDAB89UL, 0x98BADCFEUL, 0x10325476UL, 0xC3D2E1F0UL};
82 
83 // additive constante
84 #define kL_0_15 0x00000000UL
85 #define kL_16_31 0x5A827999UL
86 #define kL_32_47 0x6ED9EBA1UL
87 #define kL_48_63 0x8F1BBCDCUL
88 #define kL_64_78 0xA953FD4EUL
89 
90 #define kR_0_15 0x50A28BE6UL
91 #define kR_16_31 0x5C4DD124UL
92 #define kR_32_47 0x6D703EF3UL
93 #define kR_48_63 0x7A6D76E9UL
94 #define kR_64_78 0x00000000UL
95 
96 #define x BCD[0]
97 #define y BCD[1]
98 #define z BCD[2]
99 static unsigned long int f1(uint32_t *BCD)
100 {
101  return ((x) ^ (y) ^ (z));
102 }
103 static unsigned long int f2(uint32_t *BCD)
104 {
105  return (((x) & (y)) | ((~x) & (z)));
106 }
107 static unsigned long int f3(uint32_t *BCD)
108 {
109  return (((x) | (~(y))) ^ (z));
110 }
111 static unsigned long int f4(uint32_t *BCD)
112 {
113  return (((x) & (z)) | ((y) & (~(z))));
114 }
115 static unsigned long int f5(uint32_t *BCD)
116 {
117  return ((x) ^ ((y) | (~(z))));
118 }
119 #undef x
120 #undef y
121 #undef z
122 
123 #define rotL(x, n) cx_rotl(x, n)
124 
125 cx_err_t cx_ripemd160_init_no_throw(cx_ripemd160_t *hash)
126 {
127  memset(hash, 0, sizeof(cx_ripemd160_t));
128  hash->header.info = &cx_ripemd160_info;
129  memmove(hash->acc, hzero, sizeof(hzero));
130  return CX_OK;
131 }
132 
133 static void cx_ripemd160_block(cx_ripemd160_t *hash)
134 {
135  uint8_t j;
136  uint32_t Tl;
137  uint32_t Tr;
138 
139  uint32_t ACCl[5];
140  uint32_t ACCr[5];
141  uint32_t *accumulator;
142  uint32_t *X;
143 
144 #define Al ACCl[0]
145 #define Bl ACCl[1]
146 #define Cl ACCl[2]
147 #define Dl ACCl[3]
148 #define El ACCl[4]
149 
150 #define Ar ACCr[0]
151 #define Br ACCr[1]
152 #define Cr ACCr[2]
153 #define Dr ACCr[3]
154 #define Er ACCr[4]
155 
156  // init
157  X = (uint32_t *) &hash->block[0];
158  accumulator = (uint32_t *) &hash->acc[0];
159  memmove(ACCl, accumulator, sizeof(ACCl));
160  memmove(ACCr, accumulator, sizeof(ACCr));
161 
162 #ifdef ARCH_BIG_ENDIAN
163  cx_swap_buffer32(X, 16);
164 #endif
165 
166  for (j = 0; j < 80; j++) {
167  Tl = Al + X[zL[j]];
168  Tr = Ar + X[zR[j]];
169  switch (j >> 4) {
170  case 0:
171  Tl += f1(&Bl) + kL_0_15;
172  Tr += f5(&Br) + kR_0_15;
173  break;
174  case 1:
175  Tl += f2(&Bl) + kL_16_31;
176  Tr += f4(&Br) + kR_16_31;
177  break;
178  case 2:
179  Tl += f3(&Bl) + kL_32_47;
180  Tr += f3(&Br) + kR_32_47;
181  break;
182  case 3:
183  Tl += f4(&Bl) + kL_48_63;
184  Tr += f2(&Br) + kR_48_63;
185  break;
186  case 4:
187  Tl += f5(&Bl) + kL_64_78;
188  Tr += f1(&Br) + kR_64_78;
189  break;
190  default:
191  break;
192  }
193 
194  Tl = rotL(Tl, sL[j]);
195  Tl += El;
196  Al = El;
197  El = Dl;
198  Dl = rotL(Cl, 10);
199  Cl = Bl;
200  Bl = Tl;
201 
202  Tr = rotL(Tr, sR[j]);
203  Tr += Er;
204  Ar = Er;
205  Er = Dr;
206  Dr = rotL(Cr, 10);
207  Cr = Br;
208  Br = Tr;
209  }
210 
211  //(update chaining values)
212  Tl = accumulator[1] + Cl + Dr;
213  accumulator[1] = accumulator[2] + Dl + Er;
214  accumulator[2] = accumulator[3] + El + Ar;
215  accumulator[3] = accumulator[4] + Al + Br;
216  accumulator[4] = accumulator[0] + Bl + Cr;
217  accumulator[0] = Tl;
218 }
219 
220 cx_err_t cx_ripemd160_update(cx_ripemd160_t *ctx, const uint8_t *data, size_t len)
221 {
222  if (ctx == NULL) {
223  return CX_INVALID_PARAMETER;
224  }
225  if (data == NULL && len != 0) {
226  return CX_INVALID_PARAMETER;
227  }
228 
229  unsigned int r;
230  uint8_t block_size;
231  uint8_t *block;
232  unsigned int blen;
233 
234  block_size = 64;
235  block = ctx->block;
236  blen = ctx->blen;
237  ctx->blen = 0;
238 
239  if (blen >= block_size) {
240  return CX_INVALID_PARAMETER;
241  }
242 
243  // --- append input data and process all blocks ---
244  if ((blen + len) >= block_size) {
245  r = block_size - blen;
246  do {
247  if (ctx->header.counter == CX_HASH_MAX_BLOCK_COUNT) {
248  return CX_INVALID_PARAMETER;
249  }
250  memcpy(block + blen, data, r);
251  cx_ripemd160_block(ctx);
252  blen = 0;
253  ctx->header.counter++;
254  data += r;
255  len -= r;
256  r = block_size;
257  } while (len >= block_size);
258  }
259 
260  // --- remind rest data---
261  memcpy(block + blen, data, len);
262  blen += len;
263  ctx->blen = blen;
264  return CX_OK;
265 }
266 
267 cx_err_t cx_ripemd160_final(cx_ripemd160_t *ctx, uint8_t *digest)
268 {
269  uint8_t *block;
270  unsigned int blen;
271  unsigned long int bitlen;
272 
273  block = ctx->block;
274  blen = ctx->blen;
275 
276  // one more block?
277  block[blen] = 0x80;
278  blen++;
279  bitlen
280  = (((unsigned long int) ctx->header.counter) * 64UL + (unsigned long int) blen - 1UL) * 8UL;
281 
282  // one more block?
283  if (64 - blen < 8) {
284  memset(block + blen, 0, (64 - blen));
285  cx_ripemd160_block(ctx);
286  blen = 0;
287  }
288  // last block!
289  memset(block + blen, 0, (64 - blen));
290 #ifdef ARCH_BIG_ENDIAN
291  (*(unsigned long int *) (&block[64 - 8])) = cx_swap_uint32(bitlen);
292 #else
293  (*(uint64_t *) (&block[64 - 8])) = bitlen;
294 #endif
295  cx_ripemd160_block(ctx);
296  // provide result
297 #ifdef ARCH_BIG_ENDIAN
298  cx_swap_buffer32((unsigned long int *) acc, 5);
299 #endif
300  memcpy(digest, ctx->acc, CX_RIPEMD160_SIZE);
301  return CX_OK;
302 }
303 
304 size_t cx_hash_ripemd160(const uint8_t *in, size_t in_len, uint8_t *out, size_t out_len)
305 {
306  if (out_len < CX_RIPEMD160_SIZE) {
307  return 0;
308  }
309  if (cx_ripemd160_init_no_throw(&G_cx.ripemd160) != CX_OK
310  || cx_ripemd160_update(&G_cx.ripemd160, in, in_len) != CX_OK
311  || cx_ripemd160_final(&G_cx.ripemd160, out) != CX_OK) {
312  explicit_bzero(&G_cx.ripemd160, sizeof(cx_ripemd160_t));
313  return 0;
314  }
315  explicit_bzero(&G_cx.ripemd160, sizeof(cx_ripemd160_t));
316  return CX_RIPEMD160_SIZE;
317 }
318 
319 #endif // HAVE_RIPEMD160
union cx_u G_cx
Definition: cx_ram.c:21
uint32_t cx_swap_uint32(uint32_t v)
Definition: cx_utils.c:41
void cx_swap_buffer32(uint32_t *v, size_t len)
Definition: cx_utils.c:47
unsigned char uint8_t
Definition: usbd_conf.h:53