Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
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/* ----------------------------------------------------------------------- */
38static 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/* ----------------------------------------------------------------------- */
58static 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/* ----------------------------------------------------------------------- */
102static 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/* ----------------------------------------------------------------------- */
120static 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/* ----------------------------------------------------------------------- */
147static 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
168static 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));
202end:
203 return error;
204}
205
206cx_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));
261end:
262 return error;
263}
264
265cx_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 }
310end:
311 return error;
312}
313
314cx_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));
327end:
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