Embedded SDK
Embedded SDK
cx_poly1305.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 #if defined(HAVE_POLY1305)
20 
21 #include "cx_poly1305.h"
22 #include "cx_ram.h"
23 #include "cx_utils.h"
24 #include "os_math.h"
25 #include "os_utils.h"
26 #include "ox_bn.h"
27 #include <stddef.h>
28 #include <string.h>
29 
30 #define POLY1305_BLOCK_SIZE 16
31 #define POLY1305_PADDED_BLOCK_SIZE (POLY1305_BLOCK_SIZE + 1)
32 
33 /* 2^130 - 5 */
34 const uint8_t MODULUS[] = {0x3,
35  0xff,
36  0xff,
37  0xff,
38  0xff,
39  0xff,
40  0xff,
41  0xff,
42  0xff,
43  0xff,
44  0xff,
45  0xff,
46  0xff,
47  0xff,
48  0xff,
49  0xff,
50  0xfb};
51 
52 static void cx_le_bytes(const uint8_t *buf, uint8_t *le_buf, size_t len)
53 {
54  size_t i;
55  for (i = 0; i < len; i++) {
56  le_buf[i] = buf[len - 1 - i];
57  }
58 }
59 
60 static cx_err_t cx_poly1305_process(cx_poly1305_context_t *ctx,
61  size_t nblocks,
62  const uint8_t *input,
63  uint8_t needs_padding)
64 {
65  size_t offset = 0;
66  size_t i;
67  cx_bn_t acc, r, p, d, res;
68  uint8_t buf[POLY1305_PADDED_BLOCK_SIZE];
69  cx_err_t error;
70 
71  CX_CHECK(cx_bn_lock(32, 0));
72  CX_CHECK(cx_bn_alloc_init(&p, 32, MODULUS, sizeof(MODULUS)));
73  CX_CHECK(cx_bn_alloc(&acc, 32));
74  CX_CHECK(cx_bn_alloc(&r, 32));
75  CX_CHECK(cx_bn_alloc(&d, 32));
76  CX_CHECK(cx_bn_alloc(&res, 64));
77 
78  /* Process full blocks */
79  for (i = 0; i < nblocks; i++) {
80  /* The input block is treated as a 128-bit little-endian integer */
81  buf[0] = needs_padding;
82  cx_le_bytes(input + offset, buf + 1, POLY1305_BLOCK_SIZE);
83  CX_CHECK(cx_bn_init(d, buf, POLY1305_PADDED_BLOCK_SIZE));
84 
85  buf[0] = (uint8_t) ctx->acc[4];
86  U4BE_ENCODE(buf, 1, ctx->acc[3]);
87  U4BE_ENCODE(buf + 4 + 1, 0, ctx->acc[2]);
88  U4BE_ENCODE(buf + 8 + 1, 0, ctx->acc[1]);
89  U4BE_ENCODE(buf + 12 + 1, 0, ctx->acc[0]);
90  CX_CHECK(cx_bn_init(acc, buf, sizeof(buf)));
91 
92  /* Compute: acc += (padded) block as a 130-bit integer */
93  CX_CHECK(cx_bn_add(acc, acc, d));
94 
95  U4BE_ENCODE(buf, 0, ctx->r[3]);
96  U4BE_ENCODE(buf + 4, 0, ctx->r[2]);
97  U4BE_ENCODE(buf + 8, 0, ctx->r[1]);
98  U4BE_ENCODE(buf + 12, 0, ctx->r[0]);
99  CX_CHECK(cx_bn_init(r, buf, POLY1305_BLOCK_SIZE));
100 
101  /* Compute: acc *= r */
102  CX_CHECK(cx_bn_mul(res, acc, r));
103 
104  /* Compute: acc %= (2^130 - 5) */
105  CX_CHECK(cx_bn_reduce(acc, res, p));
106 
107  CX_CHECK(cx_bn_export(acc, buf, sizeof(MODULUS)));
108  ctx->acc[0] = U4BE(buf, 12 + 1);
109  ctx->acc[1] = U4BE(buf, 8 + 1);
110  ctx->acc[2] = U4BE(buf, 4 + 1);
111  ctx->acc[3] = U4BE(buf, 1);
112  ctx->acc[4] = buf[0];
113 
114  offset += POLY1305_BLOCK_SIZE;
115  }
116 
117 end:
118  cx_bn_unlock();
119  return error;
120 }
121 
122 static cx_err_t cx_poly1305_compute_mac(cx_poly1305_context_t *ctx, uint8_t *tag)
123 {
124  cx_err_t error;
125  cx_bn_t acc, s;
126  uint8_t buf[POLY1305_PADDED_BLOCK_SIZE];
127 
128  CX_CHECK(cx_bn_lock(32, 0));
129  CX_CHECK(cx_bn_alloc(&acc, 32));
130  CX_CHECK(cx_bn_alloc(&s, 32));
131 
132  buf[0] = (uint8_t) ctx->acc[4];
133  U4BE_ENCODE(buf, 1, ctx->acc[3]);
134  U4BE_ENCODE(buf + 4 + 1, 0, ctx->acc[2]);
135  U4BE_ENCODE(buf + 8 + 1, 0, ctx->acc[1]);
136  U4BE_ENCODE(buf + 12 + 1, 0, ctx->acc[0]);
137  CX_CHECK(cx_bn_init(acc, buf, sizeof(buf)));
138 
139  U4BE_ENCODE(buf, 0, ctx->s[3]);
140  U4BE_ENCODE(buf + 4, 0, ctx->s[2]);
141  U4BE_ENCODE(buf + 8, 0, ctx->s[1]);
142  U4BE_ENCODE(buf + 12, 0, ctx->s[0]);
143  CX_CHECK(cx_bn_init(s, buf, POLY1305_BLOCK_SIZE));
144 
145  /* Compute acc += s */
146  CX_CHECK(cx_bn_add(acc, acc, s));
147 
148  /* Compute MAC (128 least significant bits of the accumulator) */
149  CX_CHECK(cx_bn_export(acc, buf, sizeof(MODULUS)));
150  cx_le_bytes(buf + 1, tag, POLY1305_BLOCK_SIZE);
151 
152 end:
153  cx_bn_unlock();
154  return error;
155 }
156 
157 void cx_poly1305_init(cx_poly1305_context_t *ctx)
158 {
159  memset(ctx, 0, sizeof(cx_poly1305_context_t));
160 }
161 
162 void cx_poly1305_set_key(cx_poly1305_context_t *ctx, const uint8_t *key)
163 {
164  /* r &= 0x0ffffffc0ffffffc0ffffffc0fffffff */
165  ctx->r[0] = U4LE(key, 0) & 0x0FFFFFFF;
166  ctx->r[1] = U4LE(key, 4) & 0x0FFFFFFC;
167  ctx->r[2] = U4LE(key, 8) & 0x0FFFFFFC;
168  ctx->r[3] = U4LE(key, 12) & 0x0FFFFFFC;
169  ctx->s[0] = U4LE(key, 16);
170  ctx->s[1] = U4LE(key, 20);
171  ctx->s[2] = U4LE(key, 24);
172  ctx->s[3] = U4LE(key, 28);
173  /* Initial accumulator state */
174  ctx->acc[0] = 0;
175  ctx->acc[1] = 0;
176  ctx->acc[2] = 0;
177  ctx->acc[3] = 0;
178  ctx->acc[4] = 0;
179  memset(ctx->block, 0, sizeof(ctx->block));
180  ctx->block_len = 0;
181 }
182 
183 cx_err_t cx_poly1305_update(cx_poly1305_context_t *ctx, const uint8_t *input, size_t in_len)
184 {
185  size_t offset = 0;
186  size_t remaining = in_len;
187  cx_err_t error = CX_OK;
188  size_t n;
189 
190  if ((remaining > 0) && (ctx->block_len > 0)) {
191  n = POLY1305_BLOCK_SIZE - ctx->block_len;
192  if (in_len < n) {
193  /* Not enough data to complete the block.
194  * Store this data with the other leftovers.
195  */
196  memcpy(&ctx->block[ctx->block_len], input, in_len);
197  ctx->block_len += in_len;
198  remaining = 0;
199  }
200  else {
201  /* Enough data to produce a complete block */
202  memcpy(&ctx->block[ctx->block_len], input, n);
203  ctx->block_len = 0;
204  CX_CHECK(cx_poly1305_process(ctx, 1, ctx->block, 1)); /* add padding bit */
205  offset += n;
206  remaining -= n;
207  }
208  }
209 
210  if (remaining >= POLY1305_BLOCK_SIZE) {
211  n = remaining / POLY1305_BLOCK_SIZE;
212  CX_CHECK(cx_poly1305_process(ctx, n, &input[offset], 1));
213  offset += n * POLY1305_BLOCK_SIZE;
214  remaining %= POLY1305_BLOCK_SIZE;
215  }
216 
217  if (remaining > 0) {
218  /* Store partial block */
219  ctx->block_len = remaining;
220  memcpy(ctx->block, &input[offset], remaining);
221  }
222 
223 end:
224  return error;
225 }
226 
227 cx_err_t cx_poly1305_finish(cx_poly1305_context_t *ctx, uint8_t *tag)
228 {
229  cx_err_t error;
230 
231  /* Process any leftover data */
232  if (ctx->block_len > 0) {
233  /* Add padding bit */
234  ctx->block[ctx->block_len] = 1;
235  ctx->block_len++;
236  /* Pad with zeroes */
237  memset(&ctx->block[ctx->block_len], 0, POLY1305_BLOCK_SIZE - ctx->block_len);
238  CX_CHECK(cx_poly1305_process(ctx, 1, ctx->block, 0));
239  }
240  CX_CHECK(cx_poly1305_compute_mac(ctx, tag));
241 
242 end:
243  return error;
244 }
245 
246 cx_err_t cx_poly1305_mac(const uint8_t *key, const uint8_t *input, size_t in_len, uint8_t *tag)
247 {
248  cx_err_t error;
249  cx_poly1305_context_t *ctx = &G_cx.poly1305;
250  cx_poly1305_init(ctx);
251  cx_poly1305_set_key(ctx, key);
252  CX_CHECK(cx_poly1305_update(ctx, input, in_len));
253  CX_CHECK(cx_poly1305_finish(ctx, tag));
254 
255 end:
256  explicit_bzero(ctx, sizeof(cx_poly1305_context_t));
257  return error;
258 }
259 
260 #endif // HAVE_POLY1305
union cx_u G_cx
Definition: cx_ram.c:21
unsigned char uint8_t
Definition: usbd_conf.h:53