Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
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
32const 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
47static 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
55static 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
64static 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
72static 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
80static 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]
99static unsigned long int f1(uint32_t *BCD)
100{
101 return ((x) ^ (y) ^ (z));
102}
103static unsigned long int f2(uint32_t *BCD)
104{
105 return (((x) & (y)) | ((~x) & (z)));
106}
107static unsigned long int f3(uint32_t *BCD)
108{
109 return (((x) | (~(y))) ^ (z));
110}
111static unsigned long int f4(uint32_t *BCD)
112{
113 return (((x) & (z)) | ((y) & (~(z))));
114}
115static 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
125cx_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
133static 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
220cx_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
267cx_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
304size_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