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