Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
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 */
34const 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
52static 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
60static 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
117end:
118 cx_bn_unlock();
119 return error;
120}
121
122static 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
152end:
153 cx_bn_unlock();
154 return error;
155}
156
157void cx_poly1305_init(cx_poly1305_context_t *ctx)
158{
159 memset(ctx, 0, sizeof(cx_poly1305_context_t));
160}
161
162void 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
183cx_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
223end:
224 return error;
225}
226
227cx_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
242end:
243 return error;
244}
245
246cx_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
255end:
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