Embedded SDK
Embedded SDK
cx_rng_rfc6979.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_RNG_RFC6979
20 
21 #include <string.h>
22 #include "cx_rng_rfc6979.h"
23 #include "cx_hmac.h"
24 #include "cx_hash.h"
25 #include "cx_ram.h"
26 #include "exceptions.h"
27 #include "errors.h"
28 
29 /* ----------------------------------------------------------------------- */
30 /* Compute r = a-b */
31 /* */
32 /* Params: */
33 /* r : result */
34 /* a : first operand */
35 /* b : first operand */
36 /* len: bytes length of a,b and r */
37 /* ----------------------------------------------------------------------- */
38 static void cx_rfc6979_sub(uint8_t *r, uint8_t *a, uint8_t *b, size_t len)
39 {
40  uint32_t c;
41  c = 0;
42  while (len--) {
43  c = a[len] - b[len] - c;
44  r[len] = c & 0xFF;
45  c = c & 0xFFFFFF00 ? 1 : 0;
46  }
47 }
48 
49 /* ----------------------------------------------------------------------- */
50 /* Convert an arbitrary bits string to BE int of r_len bits */
51 /* -> keep only the first q_len bits of b, */
52 /* -> expand to r_len bits */
53 /* */
54 /* Params: */
55 /* b : b string to convert */
56 /* b_len: bits length os b, shall be multiple of 8, true by design */
57 /* ----------------------------------------------------------------------- */
58 static size_t cx_rfc6979_bits2int(cx_rnd_rfc6979_ctx_t *rfc_ctx,
59  const uint8_t *b,
60  size_t b_len,
61  uint8_t *b_out)
62 {
63  if (b_len > rfc_ctx->q_len) {
64  uint8_t right_shift = (b_len - rfc_ctx->q_len) & 7;
65  // For example copy a SHA384 digest in a 256-bit buffer: 384 > 256
66  // bits2int copy the high 256 bits from b into b_out
67  if (right_shift == 0) {
68  // Easy case: copy bytes directly
69  memmove(b_out, b, rfc_ctx->r_len >> 3);
70  }
71  else {
72  // Shift bits of b from (b_len - rfc_ctx->q_len) bytes to the right, into b_out
73  uint8_t carry = 0;
74  size_t i, rlen = rfc_ctx->r_len >> 3;
75 
76  for (i = 0; i < rlen; i++) {
77  uint8_t x = b[i];
78  b_out[i] = carry | (x >> right_shift);
79  carry = (x << (8 - right_shift)) & 0xff;
80  }
81  }
82  }
83  else {
84  // Pad b with zeros
85  b_len = b_len >> 3;
86  size_t padding_len = (rfc_ctx->r_len >> 3) - b_len;
87  memset(b_out, 0, padding_len);
88  memmove(b_out + padding_len, b, b_len);
89  }
90  return rfc_ctx->r_len;
91 }
92 
93 /* ----------------------------------------------------------------------- */
94 /* Convert an arbitrary bits string to BE int of r_len bits, lesser that q */
95 /* -> z = bits2int(bs) */
96 /* -> z = z-q if z>q */
97 /* */
98 /* Params: */
99 /* b : b string to convert */
100 /* b_len: bits length os b, shall be multiple of 8, true by design */
101 /* ----------------------------------------------------------------------- */
102 static void cx_rfc6979_bits2octets(cx_rnd_rfc6979_ctx_t *rfc_ctx,
103  const uint8_t *b,
104  size_t b_len,
105  uint8_t *b_out)
106 {
107  cx_rfc6979_bits2int(rfc_ctx, b, b_len, b_out);
108  if (memcmp(b_out, rfc_ctx->q, rfc_ctx->r_len >> 3) > 0) {
109  cx_rfc6979_sub(b_out, b_out, rfc_ctx->q, rfc_ctx->r_len >> 3);
110  }
111 }
112 
113 /* ----------------------------------------------------------------------- */
114 /* Convert an integer bits string to BE int of r_len bits */
115 /* */
116 /* Params: */
117 /* i : integer to convert */
118 /* i_len: bits length os i, shall be multiple of 8, true by design */
119 /* ----------------------------------------------------------------------- */
120 static void cx_rfc6979_int2octets(cx_rnd_rfc6979_ctx_t *rfc_ctx,
121  const uint8_t *i,
122  size_t i_len,
123  uint8_t *b_out)
124 {
125  int32_t delta;
126  delta = (i_len >> 3) - (rfc_ctx->r_len >> 3);
127  if (delta < 0) {
128  delta = -delta;
129  memcpy(b_out + delta, i, i_len >> 3);
130  while (delta--) {
131  b_out[delta] = 0;
132  }
133  }
134  else {
135  // assume first bytes are null
136  memcpy(b_out, i + delta, rfc_ctx->r_len >> 3);
137  }
138 }
139 
140 /* ----------------------------------------------------------------------- */
141 /* Compute effective bits length of 'b' */
142 /* */
143 /* Params: */
144 /* b : b */
145 /* b_len: bytes length b */
146 /* ----------------------------------------------------------------------- */
147 static uint32_t cx_rfc6979_bitslength(const uint8_t *a, size_t a_len)
148 {
149  uint8_t b;
150 
151  while (*a == 0) {
152  a++;
153  a_len--;
154  if (a_len == 0) {
155  return 0;
156  }
157  }
158  // note: here len != 0 && *a != 0
159  a_len = a_len * 8;
160  b = *a;
161  while ((b & 0x80) == 0) {
162  a_len--;
163  b = b << 1;
164  }
165  return a_len;
166 }
167 
168 static cx_err_t cx_rfc6979_hmacVK(cx_rnd_rfc6979_ctx_t *rfc_ctx,
169  int8_t opt,
170  const uint8_t *x,
171  size_t x_len,
172  const uint8_t *h1,
173  size_t h1_len,
174  /*const uint8_t *additional_input, size_t additional_input_len,*/
175  uint8_t *out)
176 {
177  size_t len;
178  cx_err_t error;
179 
180  len = rfc_ctx->md_len;
181  CX_CHECK(cx_hmac_init(&rfc_ctx->hmac, rfc_ctx->hash_id, rfc_ctx->k, rfc_ctx->md_len));
182  if (opt >= 0) {
183  rfc_ctx->v[rfc_ctx->md_len] = opt;
184  len++;
185  }
186  CX_CHECK(cx_hmac_update(&rfc_ctx->hmac, rfc_ctx->v, len));
187  if (x) {
188  cx_rfc6979_int2octets(rfc_ctx, x, x_len * 8, rfc_ctx->tmp);
189  CX_CHECK(cx_hmac_update(&rfc_ctx->hmac, rfc_ctx->tmp, rfc_ctx->r_len >> 3));
190  }
191  if (h1) {
192  cx_rfc6979_bits2octets(rfc_ctx, h1, h1_len * 8, rfc_ctx->tmp);
193  CX_CHECK(cx_hmac_update(&rfc_ctx->hmac, rfc_ctx->tmp, rfc_ctx->r_len >> 3));
194  }
195  /*
196  if (additional_input) {
197  CX_CHECK(cx_hmac_update(&rfc_ctx->hmac, additional_input, additional_input_len));
198  }
199  */
200  len = rfc_ctx->md_len;
201  CX_CHECK(cx_hmac_final(&rfc_ctx->hmac, out, &len));
202 end:
203  return error;
204 }
205 
206 cx_err_t cx_rng_rfc6979_init(cx_rnd_rfc6979_ctx_t *rfc_ctx,
207  cx_md_t hash_id,
208  const uint8_t *x,
209  size_t x_len,
210  const uint8_t *h1,
211  size_t h1_len,
212  const uint8_t *q,
213  size_t q_len
214  /*const uint8_t *additional_input, size_t additional_input_len*/)
215 {
216  cx_err_t error;
217  const cx_hash_info_t *hash_info = cx_hash_get_info(hash_id);
218  if (hash_info == NULL || hash_info->output_size == 0) {
219  return CX_INVALID_PARAMETER;
220  }
221 
222  // setup params
223  memcpy(rfc_ctx->q, q, q_len);
224  rfc_ctx->q_len = cx_rfc6979_bitslength(q, q_len);
225  rfc_ctx->r_len = (rfc_ctx->q_len + 7) & ~7;
226  rfc_ctx->hash_id = hash_id;
227  rfc_ctx->md_len = hash_info->output_size;
228 
229  // STEP A: h1 = HASH(m)
230  // input is h1
231 
232  // Step B: V = 0x01...01 @digest_len
233  memset(rfc_ctx->v, 0x01, rfc_ctx->md_len);
234 
235  // Step C: K = 0x00...00 @digest_len
236  memset(rfc_ctx->k, 0x00, rfc_ctx->md_len);
237 
238  // Step D: K = HMAC (K, V || 0x00 || int2octets(x) || bits2octetc(h1) [ || additional_input])
239  CX_CHECK(cx_rfc6979_hmacVK(rfc_ctx,
240  0,
241  x,
242  x_len,
243  h1,
244  h1_len,
245  rfc_ctx->k /*, additional_input, additional_input_len*/));
246 
247  // Step E: V = HMAC (K, V).
248  CX_CHECK(cx_rfc6979_hmacVK(rfc_ctx, -1, NULL, 0, NULL, 0, rfc_ctx->v));
249 
250  // Step F: K = HMAC (K, V || 0x01 || int2octets(x) || bits2octetc(h1) [ || additional_input])
251  CX_CHECK(cx_rfc6979_hmacVK(rfc_ctx,
252  0x01,
253  x,
254  x_len,
255  h1,
256  h1_len,
257  rfc_ctx->k /*, additional_input, additional_input_len*/));
258 
259  // Step G: V = HMAC (K, V).
260  CX_CHECK(cx_rfc6979_hmacVK(rfc_ctx, -1, NULL, 0, NULL, 0, rfc_ctx->v));
261 end:
262  return error;
263 }
264 
265 cx_err_t cx_rng_rfc6979_next(cx_rnd_rfc6979_ctx_t *rfc_ctx, uint8_t *out, size_t out_len)
266 {
267  size_t t_Blen;
268  size_t r_Blen;
269  bool found;
270  cx_err_t error = CX_OK;
271 
272  if ((out_len * 8) < rfc_ctx->r_len) {
273  return CX_INVALID_PARAMETER;
274  }
275 
276  r_Blen = rfc_ctx->r_len >> 3;
277  found = false;
278  while (!found) {
279  // Step H1:
280  t_Blen = 0;
281 
282  // Step H2:
283  // while t_Blen<qlen
284  // V = HMAC (K, V).
285  // T = T || V
286  while (t_Blen < r_Blen) {
287  CX_CHECK(cx_rfc6979_hmacVK(rfc_ctx, -1, NULL, 0, NULL, 0, rfc_ctx->v));
288  if (rfc_ctx->md_len > (r_Blen - t_Blen)) {
289  memcpy(out + t_Blen, rfc_ctx->v, r_Blen - t_Blen);
290  t_Blen = r_Blen;
291  }
292  else {
293  memcpy(out + t_Blen, rfc_ctx->v, rfc_ctx->md_len);
294  t_Blen += rfc_ctx->md_len;
295  }
296  }
297 
298  // STEP H3: k = bits2int(T)
299  cx_rfc6979_bits2int(rfc_ctx, out, t_Blen * 8, out);
300  if (memcmp(out, rfc_ctx->q, rfc_ctx->r_len >> 3) < 0) {
301  found = true;
302  }
303 
304  // STEP H3 bis:
305  // K = HMAC (K, V || 0).
306  CX_CHECK(cx_rfc6979_hmacVK(rfc_ctx, 0, NULL, 0, NULL, 0, rfc_ctx->k));
307  // V = HMAC (K, V).
308  CX_CHECK(cx_rfc6979_hmacVK(rfc_ctx, -1, NULL, 0, NULL, 0, rfc_ctx->v));
309  }
310 end:
311  return error;
312 }
313 
314 cx_err_t cx_rng_rfc6979(cx_md_t hash_id,
315  const uint8_t *x,
316  size_t x_len,
317  const uint8_t *h1,
318  size_t h1_len,
319  const uint8_t *q,
320  size_t q_len,
321  uint8_t *out,
322  size_t out_len)
323 {
324  cx_err_t error;
325  CX_CHECK(cx_rng_rfc6979_init(&G_cx.rfc6979, hash_id, x, x_len, h1, h1_len, q, q_len));
326  CX_CHECK(cx_rng_rfc6979_next(&G_cx.rfc6979, out, out_len));
327 end:
328  return error;
329 }
330 #endif // HAVE_RNG_RFC6979
union cx_u G_cx
Definition: cx_ram.c:21
unsigned char uint8_t
Definition: usbd_conf.h:53
signed char int8_t
Definition: usbd_conf.h:49