1 /*
2 * Copyright (c) 2023, The TrustedFirmware-M Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "cc3xx_poly1305.h"
9
10 #include <assert.h>
11 #include <string.h>
12
13 static const uint32_t poly_key_r_mask[] = {
14 0x0fffffff,
15 0x0ffffffc,
16 0x0ffffffc,
17 0x0ffffffc
18 };
19
20 static const uint32_t poly_prime[] = {
21 0xfffffffb,
22 0xffffffff,
23 0xffffffff,
24 0xffffffff,
25 0x3
26 };
27
28 static const uint32_t poly_barrett_tag[] = {
29 0x00000000,
30 0x00000000,
31 0x00000080
32 };
33
34 #define POLY1305_PKA_SAVE_REG_AM 3
35
36 static struct cc3xx_poly1305_state_t poly_state;
37
38 const size_t reg_sizes_list[POLY1305_PKA_SAVE_REG_AM] = {
39 sizeof(poly_state.key_r),
40 sizeof(poly_state.key_s),
41 sizeof(poly_state.accumulator)
42 };
43
poly1305_init_from_state(void)44 static void poly1305_init_from_state(void)
45 {
46 cc3xx_lowlevel_pka_write_reg(poly_state.modulus_reg, poly_prime, sizeof(poly_prime));
47 cc3xx_lowlevel_pka_write_reg(poly_state.barrett_tag_reg, poly_barrett_tag,
48 sizeof(poly_barrett_tag));
49
50 cc3xx_lowlevel_pka_set_modulus(poly_state.modulus_reg, false,
51 poly_state.barrett_tag_reg);
52 }
53
54
cc3xx_lowlevel_poly1305_init(uint32_t * poly_key_r,uint32_t * poly_key_s)55 void cc3xx_lowlevel_poly1305_init(uint32_t *poly_key_r, uint32_t *poly_key_s)
56 {
57 cc3xx_lowlevel_pka_init(sizeof(poly_prime));
58
59 poly_state.modulus_reg = cc3xx_lowlevel_pka_allocate_reg();
60 poly_state.barrett_tag_reg = cc3xx_lowlevel_pka_allocate_reg();
61 poly_state.key_r_reg = cc3xx_lowlevel_pka_allocate_reg();
62 poly_state.key_s_reg = cc3xx_lowlevel_pka_allocate_reg();
63 poly_state.accumulator_reg = cc3xx_lowlevel_pka_allocate_reg();
64 poly_state.data_input_reg = cc3xx_lowlevel_pka_allocate_reg();
65 poly_state.mask_reg = cc3xx_lowlevel_pka_allocate_reg();
66
67 cc3xx_lowlevel_pka_write_reg(poly_state.key_r_reg, poly_key_r, POLY1305_KEY_SIZE);
68 cc3xx_lowlevel_pka_write_reg(poly_state.key_s_reg, poly_key_s, POLY1305_KEY_SIZE);
69
70 /* zero the accumulator register */
71 cc3xx_lowlevel_pka_clear(poly_state.accumulator_reg);
72
73 /* Before we use the bit 129 mask reg for the 129th bit or mask, use it for
74 * the key_r mask.
75 */
76 cc3xx_lowlevel_pka_write_reg(poly_state.mask_reg, poly_key_r_mask,
77 sizeof(poly_key_r_mask));
78 cc3xx_lowlevel_pka_and(poly_state.key_r_reg,
79 poly_state.mask_reg, poly_state.key_r_reg);
80
81 poly1305_init_from_state();
82 }
83
poly_process_block(const uint32_t * buf)84 static void poly_process_block(const uint32_t *buf)
85 {
86 cc3xx_lowlevel_pka_write_reg(poly_state.data_input_reg, buf, POLY1305_BLOCK_SIZE);
87
88 /* Set the 129th bit to 1 */
89 cc3xx_lowlevel_pka_set_to_power_of_two(poly_state.mask_reg, POLY1305_BLOCK_SIZE * 8);
90 cc3xx_lowlevel_pka_or(poly_state.data_input_reg,
91 poly_state.mask_reg, poly_state.data_input_reg);
92
93 /* Add the new data to the accumulator */
94 cc3xx_lowlevel_pka_mod_add(poly_state.accumulator_reg,
95 poly_state.data_input_reg, poly_state.accumulator_reg);
96 /* Multiply the accumulator by r */
97 cc3xx_lowlevel_pka_mod_mul(poly_state.accumulator_reg,
98 poly_state.key_r_reg, poly_state.accumulator_reg);
99 }
100
cc3xx_lowlevel_poly1305_update(const uint8_t * buf,size_t length)101 void cc3xx_lowlevel_poly1305_update(const uint8_t *buf, size_t length)
102 {
103 size_t data_to_process_length;
104 uint32_t temp_block[POLY1305_BLOCK_SIZE / sizeof(uint32_t)];
105 size_t buffer_size_free =
106 sizeof(poly_state.block_buf) - poly_state.block_buf_size_in_use;
107
108 /* If there is data remaining in the buf, first fill and dispatch it */
109 if (poly_state.block_buf_size_in_use != 0) {
110 data_to_process_length =
111 length < buffer_size_free ? length : buffer_size_free;
112
113 memcpy(((uint8_t *)poly_state.block_buf) + poly_state.block_buf_size_in_use,
114 buf, data_to_process_length);
115
116 poly_state.block_buf_size_in_use += data_to_process_length;
117 buf += data_to_process_length;
118 length -= data_to_process_length;
119
120 /* If this fills the buffer, dispatch it now (Unlike the DMA buffering,
121 * we don't need to keep a block of data around for finalization).
122 */
123 if (poly_state.block_buf_size_in_use == POLY1305_BLOCK_SIZE) {
124 poly_process_block(poly_state.block_buf);
125 poly_state.block_buf_size_in_use = 0;
126 }
127 }
128
129 if (length == 0) {
130 return;
131 }
132
133 /* Process all remaining full blocks */
134 data_to_process_length = (length / POLY1305_BLOCK_SIZE) * POLY1305_BLOCK_SIZE;
135 while (data_to_process_length > 0) {
136 /* buf is uint8_t*, but PKA requires uint32_t*, so memcpy into the temp
137 * buf to fix this.
138 */
139 memcpy(temp_block, buf, POLY1305_BLOCK_SIZE);
140 poly_process_block(temp_block);
141 data_to_process_length -= POLY1305_BLOCK_SIZE;
142 length -= POLY1305_BLOCK_SIZE;
143 buf += POLY1305_BLOCK_SIZE;
144 }
145
146 /* If any data remains, push it into the block buffer */
147 memcpy(poly_state.block_buf, buf, length);
148 poly_state.block_buf_size_in_use += length;
149 }
150
cc3xx_lowlevel_poly1305_get_state(struct cc3xx_poly1305_state_t * state)151 void cc3xx_lowlevel_poly1305_get_state(struct cc3xx_poly1305_state_t *state)
152 {
153 cc3xx_pka_reg_id_t save_reg_list[POLY1305_PKA_SAVE_REG_AM] = {
154 poly_state.key_r_reg,
155 poly_state.key_s_reg,
156 poly_state.accumulator_reg
157 };
158
159 uint32_t *save_reg_ptr_list[POLY1305_PKA_SAVE_REG_AM] = {
160 state->key_r,
161 state->key_s,
162 state->accumulator
163 };
164
165 memcpy(state, &poly_state, sizeof(*state));
166
167 cc3xx_lowlevel_pka_get_state(&state->pka_state, POLY1305_PKA_SAVE_REG_AM, save_reg_list,
168 save_reg_ptr_list, reg_sizes_list);
169 }
170
cc3xx_lowlevel_poly1305_set_state(const struct cc3xx_poly1305_state_t * state)171 void cc3xx_lowlevel_poly1305_set_state(const struct cc3xx_poly1305_state_t *state)
172 {
173 cc3xx_pka_reg_id_t load_reg_list[POLY1305_PKA_SAVE_REG_AM] = {
174 poly_state.key_r_reg,
175 poly_state.key_s_reg,
176 poly_state.accumulator_reg
177 };
178
179 const uint32_t *load_reg_ptr_list[POLY1305_PKA_SAVE_REG_AM] = {
180 state->key_r,
181 state->key_s,
182 state->accumulator
183 };
184
185 memcpy(&poly_state, state, sizeof(poly_state));
186
187 cc3xx_lowlevel_pka_set_state(&state->pka_state, POLY1305_PKA_SAVE_REG_AM, load_reg_list,
188 load_reg_ptr_list, reg_sizes_list);
189
190 poly1305_init_from_state();
191 }
192
cc3xx_lowlevel_poly1305_finish(uint32_t * tag)193 void cc3xx_lowlevel_poly1305_finish(uint32_t *tag)
194 {
195 /* Flush the final block */
196 if (poly_state.block_buf_size_in_use != 0) {
197 /* Zero any unused block */
198 memset(((uint8_t*)poly_state.block_buf) + poly_state.block_buf_size_in_use,
199 0, POLY1305_BLOCK_SIZE - poly_state.block_buf_size_in_use);
200 poly_process_block(poly_state.block_buf);
201 }
202
203 /* Finally, the tag is a + s */
204 cc3xx_lowlevel_pka_mod_add(poly_state.accumulator_reg,
205 poly_state.key_s_reg, poly_state.accumulator_reg);
206
207 /* Read back the first 16 bytes for the accumulator into the tag */
208 cc3xx_lowlevel_pka_read_reg(poly_state.accumulator_reg, tag, POLY1305_TAG_LEN);
209
210 cc3xx_lowlevel_poly1305_uninit();
211 }
212
cc3xx_lowlevel_poly1305_uninit(void)213 void cc3xx_lowlevel_poly1305_uninit(void)
214 {
215 memset(&poly_state, 0, sizeof(poly_state));
216
217 cc3xx_lowlevel_pka_uninit();
218 }
219