1 /******************************************************************************
2 * Filename: pka.c
3 * Revised: 2020-02-14 11:30:20 +0100 (Fri, 14 Feb 2020)
4 * Revision: 56760
5 *
6 * Description: Driver for the PKA module
7 *
8 * Copyright (c) 2015 - 2017, Texas Instruments Incorporated
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * 1) Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 *
17 * 2) Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 *
21 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
22 * be used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ******************************************************************************/
38
39 #include "pka.h"
40
41 //*****************************************************************************
42 //
43 // Handle support for DriverLib in ROM:
44 // This section will undo prototype renaming made in the header file
45 //
46 //*****************************************************************************
47 #if !defined(DOXYGEN)
48 #undef PKAClearPkaRam
49 #define PKAClearPkaRam NOROM_PKAClearPkaRam
50 #undef PKAGetOpsStatus
51 #define PKAGetOpsStatus NOROM_PKAGetOpsStatus
52 #undef PKAArrayAllZeros
53 #define PKAArrayAllZeros NOROM_PKAArrayAllZeros
54 #undef PKAZeroOutArray
55 #define PKAZeroOutArray NOROM_PKAZeroOutArray
56 #undef PKABigNumModStart
57 #define PKABigNumModStart NOROM_PKABigNumModStart
58 #undef PKABigNumModGetResult
59 #define PKABigNumModGetResult NOROM_PKABigNumModGetResult
60 #undef PKABigNumDivideStart
61 #define PKABigNumDivideStart NOROM_PKABigNumDivideStart
62 #undef PKABigNumDivideGetQuotient
63 #define PKABigNumDivideGetQuotient NOROM_PKABigNumDivideGetQuotient
64 #undef PKABigNumDivideGetRemainder
65 #define PKABigNumDivideGetRemainder NOROM_PKABigNumDivideGetRemainder
66 #undef PKABigNumCmpStart
67 #define PKABigNumCmpStart NOROM_PKABigNumCmpStart
68 #undef PKABigNumCmpGetResult
69 #define PKABigNumCmpGetResult NOROM_PKABigNumCmpGetResult
70 #undef PKABigNumInvModStart
71 #define PKABigNumInvModStart NOROM_PKABigNumInvModStart
72 #undef PKABigNumInvModGetResult
73 #define PKABigNumInvModGetResult NOROM_PKABigNumInvModGetResult
74 #undef PKABigNumMultiplyStart
75 #define PKABigNumMultiplyStart NOROM_PKABigNumMultiplyStart
76 #undef PKABigNumMultGetResult
77 #define PKABigNumMultGetResult NOROM_PKABigNumMultGetResult
78 #undef PKABigNumAddStart
79 #define PKABigNumAddStart NOROM_PKABigNumAddStart
80 #undef PKABigNumAddGetResult
81 #define PKABigNumAddGetResult NOROM_PKABigNumAddGetResult
82 #undef PKABigNumSubStart
83 #define PKABigNumSubStart NOROM_PKABigNumSubStart
84 #undef PKABigNumSubGetResult
85 #define PKABigNumSubGetResult NOROM_PKABigNumSubGetResult
86 #undef PKAEccMultiplyStart
87 #define PKAEccMultiplyStart NOROM_PKAEccMultiplyStart
88 #undef PKAEccMontgomeryMultiplyStart
89 #define PKAEccMontgomeryMultiplyStart NOROM_PKAEccMontgomeryMultiplyStart
90 #undef PKAEccMultiplyGetResult
91 #define PKAEccMultiplyGetResult NOROM_PKAEccMultiplyGetResult
92 #undef PKAEccAddStart
93 #define PKAEccAddStart NOROM_PKAEccAddStart
94 #undef PKAEccAddGetResult
95 #define PKAEccAddGetResult NOROM_PKAEccAddGetResult
96 #undef PKAEccVerifyPublicKeyWeierstrassStart
97 #define PKAEccVerifyPublicKeyWeierstrassStart NOROM_PKAEccVerifyPublicKeyWeierstrassStart
98 #endif
99
100 //*****************************************************************************
101 //
102 // Handle support for DriverLib in ROM:
103 // This section will undo prototype renaming made in the header file
104 //
105 //*****************************************************************************
106 #if !defined(DOXYGEN)
107 #undef PKAClearPkaRam
108 #define PKAClearPkaRam NOROM_PKAClearPkaRam
109 #undef PKAGetOpsStatus
110 #define PKAGetOpsStatus NOROM_PKAGetOpsStatus
111 #undef PKAArrayAllZeros
112 #define PKAArrayAllZeros NOROM_PKAArrayAllZeros
113 #undef PKAZeroOutArray
114 #define PKAZeroOutArray NOROM_PKAZeroOutArray
115 #undef PKABigNumModStart
116 #define PKABigNumModStart NOROM_PKABigNumModStart
117 #undef PKABigNumModGetResult
118 #define PKABigNumModGetResult NOROM_PKABigNumModGetResult
119 #undef PKABigNumDivideStart
120 #define PKABigNumDivideStart NOROM_PKABigNumDivideStart
121 #undef PKABigNumDivideGetQuotient
122 #define PKABigNumDivideGetQuotient NOROM_PKABigNumDivideGetQuotient
123 #undef PKABigNumDivideGetRemainder
124 #define PKABigNumDivideGetRemainder NOROM_PKABigNumDivideGetRemainder
125 #undef PKABigNumCmpStart
126 #define PKABigNumCmpStart NOROM_PKABigNumCmpStart
127 #undef PKABigNumCmpGetResult
128 #define PKABigNumCmpGetResult NOROM_PKABigNumCmpGetResult
129 #undef PKABigNumInvModStart
130 #define PKABigNumInvModStart NOROM_PKABigNumInvModStart
131 #undef PKABigNumInvModGetResult
132 #define PKABigNumInvModGetResult NOROM_PKABigNumInvModGetResult
133 #undef PKABigNumMultiplyStart
134 #define PKABigNumMultiplyStart NOROM_PKABigNumMultiplyStart
135 #undef PKABigNumMultGetResult
136 #define PKABigNumMultGetResult NOROM_PKABigNumMultGetResult
137 #undef PKABigNumAddStart
138 #define PKABigNumAddStart NOROM_PKABigNumAddStart
139 #undef PKABigNumAddGetResult
140 #define PKABigNumAddGetResult NOROM_PKABigNumAddGetResult
141 #undef PKABigNumSubStart
142 #define PKABigNumSubStart NOROM_PKABigNumSubStart
143 #undef PKABigNumSubGetResult
144 #define PKABigNumSubGetResult NOROM_PKABigNumSubGetResult
145 #undef PKAEccMultiplyStart
146 #define PKAEccMultiplyStart NOROM_PKAEccMultiplyStart
147 #undef PKAEccMontgomeryMultiplyStart
148 #define PKAEccMontgomeryMultiplyStart NOROM_PKAEccMontgomeryMultiplyStart
149 #undef PKAEccMultiplyGetResult
150 #define PKAEccMultiplyGetResult NOROM_PKAEccMultiplyGetResult
151 #undef PKAEccAddStart
152 #define PKAEccAddStart NOROM_PKAEccAddStart
153 #undef PKAEccAddGetResult
154 #define PKAEccAddGetResult NOROM_PKAEccAddGetResult
155 #undef PKAEccVerifyPublicKeyWeierstrassStart
156 #define PKAEccVerifyPublicKeyWeierstrassStart NOROM_PKAEccVerifyPublicKeyWeierstrassStart
157 #endif
158
159
160
161 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
162 #define MIN(x,y) (((x) < (y)) ? (x) : (y))
163 #define INRANGE(x,y,z) ((x) > (y) && (x) < (z))
164
165
166 //*****************************************************************************
167 //
168 // Define for the maximum curve size supported by the PKA module in 32 bit
169 // word.
170 // \note PKA hardware module can support up to 384 bit curve size due to the
171 // 2K of PKA RAM.
172 //
173 //*****************************************************************************
174 #define PKA_MAX_CURVE_SIZE_32_BIT_WORD 12
175
176 //*****************************************************************************
177 //
178 // Define for the maximum length of the big number supported by the PKA module
179 // in 32 bit word.
180 //
181 //*****************************************************************************
182 #define PKA_MAX_LEN_IN_32_BIT_WORD PKA_MAX_CURVE_SIZE_32_BIT_WORD
183
184 //*****************************************************************************
185 //
186 // Used in PKAWritePkaParam() and PKAWritePkaParamExtraOffset() to specify that
187 // the base address of the parameter should not be written to a NPTR register.
188 //
189 //*****************************************************************************
190 #define PKA_NO_POINTER_REG 0xFF
191
192 //*****************************************************************************
193 //
194 // NIST P224 constants in little endian format. byte[0] is the least
195 // significant byte and byte[NISTP224_PARAM_SIZE_BYTES - 1] is the most
196 // significant.
197 //
198 //*****************************************************************************
199 const PKA_EccPoint224 NISTP224_generator = {
200 .x = {.byte = {0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34,
201 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A,
202 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B,
203 0xBD, 0x0C, 0x0E, 0xB7, }},
204 .y = {.byte = {0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44,
205 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD,
206 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5,
207 0x88, 0x63, 0x37, 0xBD, }},
208 };
209
210 const PKA_EccParam224 NISTP224_prime = {.byte = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
212 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
213 0xFF, 0xFF, 0xFF, 0xFF}};
214
215 const PKA_EccParam224 NISTP224_a = {.byte = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
216 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
217 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
218 0xFF, 0xFF, 0xFF, 0xFF}};
219
220 const PKA_EccParam224 NISTP224_b = {.byte = {0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27,
221 0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50,
222 0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C,
223 0x85, 0x0A, 0x05, 0xB4}};
224
225 const PKA_EccParam224 NISTP224_order = {.byte = {0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13,
226 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF,
227 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
228 0xFF, 0xFF, 0xFF, 0xFF}};
229
230 //*****************************************************************************
231 //
232 // NIST P256 constants in little endian format. byte[0] is the least
233 // significant byte and byte[NISTP256_PARAM_SIZE_BYTES - 1] is the most
234 // significant.
235 //
236 //*****************************************************************************
237 const PKA_EccPoint256 NISTP256_generator = {
238 .x = {.byte = {0x96, 0xc2, 0x98, 0xd8, 0x45, 0x39, 0xa1, 0xf4,
239 0xa0, 0x33, 0xeb, 0x2d, 0x81, 0x7d, 0x03, 0x77,
240 0xf2, 0x40, 0xa4, 0x63, 0xe5, 0xe6, 0xbc, 0xf8,
241 0x47, 0x42, 0x2c, 0xe1, 0xf2, 0xd1, 0x17, 0x6b}},
242 .y = {.byte = {0xf5, 0x51, 0xbf, 0x37, 0x68, 0x40, 0xb6, 0xcb,
243 0xce, 0x5e, 0x31, 0x6b, 0x57, 0x33, 0xce, 0x2b,
244 0x16, 0x9e, 0x0f, 0x7c, 0x4a, 0xeb, 0xe7, 0x8e,
245 0x9b, 0x7f, 0x1a, 0xfe, 0xe2, 0x42, 0xe3, 0x4f}},
246 };
247
248 const PKA_EccParam256 NISTP256_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
249 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
252
253 const PKA_EccParam256 NISTP256_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
254 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
257
258 const PKA_EccParam256 NISTP256_b = {.byte = {0x4b, 0x60, 0xd2, 0x27, 0x3e, 0x3c, 0xce, 0x3b,
259 0xf6, 0xb0, 0x53, 0xcc, 0xb0, 0x06, 0x1d, 0x65,
260 0xbc, 0x86, 0x98, 0x76, 0x55, 0xbd, 0xeb, 0xb3,
261 0xe7, 0x93, 0x3a, 0xaa, 0xd8, 0x35, 0xc6, 0x5a}};
262
263 const PKA_EccParam256 NISTP256_order = {.byte = {0x51, 0x25, 0x63, 0xfc, 0xc2, 0xca, 0xb9, 0xf3,
264 0x84, 0x9e, 0x17, 0xa7, 0xad, 0xfa, 0xe6, 0xbc,
265 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
266 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
267
268 //*****************************************************************************
269 //
270 // NIST P384 constants in little endian format. byte[0] is the least
271 // significant byte and byte[NISTP384_PARAM_SIZE_BYTES - 1] is the most
272 // significant.
273 //
274 //*****************************************************************************
275 const PKA_EccPoint384 NISTP384_generator = {
276 .x = {.byte = {0xb7, 0x0a, 0x76, 0x72, 0x38, 0x5e, 0x54, 0x3a,
277 0x6c, 0x29, 0x55, 0xbf, 0x5d, 0xf2, 0x02, 0x55,
278 0x38, 0x2a, 0x54, 0x82, 0xe0, 0x41, 0xf7, 0x59,
279 0x98, 0x9b, 0xa7, 0x8b, 0x62, 0x3b, 0x1d, 0x6e,
280 0x74, 0xad, 0x20, 0xf3, 0x1e, 0xc7, 0xb1, 0x8e,
281 0x37, 0x05, 0x8b, 0xbe, 0x22, 0xca, 0x87, 0xaa}},
282 .y = {.byte = {0x5f, 0x0e, 0xea, 0x90, 0x7c, 0x1d, 0x43, 0x7a,
283 0x9d, 0x81, 0x7e, 0x1d, 0xce, 0xb1, 0x60, 0x0a,
284 0xc0, 0xb8, 0xf0, 0xb5, 0x13, 0x31, 0xda, 0xe9,
285 0x7c, 0x14, 0x9a, 0x28, 0xbd, 0x1d, 0xf4, 0xf8,
286 0x29, 0xdc, 0x92, 0x92, 0xbf, 0x98, 0x9e, 0x5d,
287 0x6f, 0x2c, 0x26, 0x96, 0x4a, 0xde, 0x17, 0x36,}},
288 };
289
290 const PKA_EccParam384 NISTP384_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
292 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
293 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
294 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
295 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
296
297 const PKA_EccParam384 NISTP384_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
299 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
300 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
301 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
302 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
303
304 const PKA_EccParam384 NISTP384_b = {.byte = {0xef, 0x2a, 0xec, 0xd3, 0xed, 0xc8, 0x85, 0x2a,
305 0x9d, 0xd1, 0x2e, 0x8a, 0x8d, 0x39, 0x56, 0xc6,
306 0x5a, 0x87, 0x13, 0x50, 0x8f, 0x08, 0x14, 0x03,
307 0x12, 0x41, 0x81, 0xfe, 0x6e, 0x9c, 0x1d, 0x18,
308 0x19, 0x2d, 0xf8, 0xe3, 0x6b, 0x05, 0x8e, 0x98,
309 0xe4, 0xe7, 0x3e, 0xe2, 0xa7, 0x2f, 0x31, 0xb3}};
310
311 const PKA_EccParam384 NISTP384_order = {.byte = {0x73, 0x29, 0xc5, 0xcc, 0x6a, 0x19, 0xec, 0xec,
312 0x7a, 0xa7, 0xb0, 0x48, 0xb2, 0x0d, 0x1a, 0x58,
313 0xdf, 0x2d, 0x37, 0xf4, 0x81, 0x4d, 0x63, 0xc7,
314 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
315 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
316 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
317
318
319 //*****************************************************************************
320 //
321 // NIST P521 constants in little endian format. byte[0] is the least
322 // significant byte and byte[NISTP521_PARAM_SIZE_BYTES - 1] is the most
323 // significant.
324 //
325 //*****************************************************************************
326 const PKA_EccPoint521 NISTP521_generator = {
327 .x = {.byte = {0x66, 0xbd, 0xe5, 0xc2, 0x31, 0x7e, 0x7e, 0xf9,
328 0x9b, 0x42, 0x6a, 0x85, 0xc1, 0xb3, 0x48, 0x33,
329 0xde, 0xa8, 0xff, 0xa2, 0x27, 0xc1, 0x1d, 0xfe,
330 0x28, 0x59, 0xe7, 0xef, 0x77, 0x5e, 0x4b, 0xa1,
331 0xba, 0x3d, 0x4d, 0x6b, 0x60, 0xaf, 0x28, 0xf8,
332 0x21, 0xb5, 0x3f, 0x05, 0x39, 0x81, 0x64, 0x9c,
333 0x42, 0xb4, 0x95, 0x23, 0x66, 0xcb, 0x3e, 0x9e,
334 0xcd, 0xe9, 0x04, 0x04, 0xb7, 0x06, 0x8e, 0x85,
335 0xc6, 0x00}},
336 .y = {.byte = {0x50, 0x66, 0xd1, 0x9f, 0x76, 0x94, 0xbe, 0x88,
337 0x40, 0xc2, 0x72, 0xa2, 0x86, 0x70, 0x3c, 0x35,
338 0x61, 0x07, 0xad, 0x3f, 0x01, 0xb9, 0x50, 0xc5,
339 0x40, 0x26, 0xf4, 0x5e, 0x99, 0x72, 0xee, 0x97,
340 0x2c, 0x66, 0x3e, 0x27, 0x17, 0xbd, 0xaf, 0x17,
341 0x68, 0x44, 0x9b, 0x57, 0x49, 0x44, 0xf5, 0x98,
342 0xd9, 0x1b, 0x7d, 0x2c, 0xb4, 0x5f, 0x8a, 0x5c,
343 0x04, 0xc0, 0x3b, 0x9a, 0x78, 0x6a, 0x29, 0x39,
344 0x18, 0x01}},
345 };
346
347 const PKA_EccParam521 NISTP521_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
348 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
349 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
350 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
351 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
352 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
353 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
354 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
355 0xff, 0x01}};
356
357 const PKA_EccParam521 NISTP521_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
358 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
359 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
360 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
361 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
362 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
363 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
364 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
365 0xff, 0x01}};
366
367 const PKA_EccParam521 NISTP521_b = {.byte = {0x00, 0x3f, 0x50, 0x6b, 0xd4, 0x1f, 0x45, 0xef,
368 0xf1, 0x34, 0x2c, 0x3d, 0x88, 0xdf, 0x73, 0x35,
369 0x07, 0xbf, 0xb1, 0x3b, 0xbd, 0xc0, 0x52, 0x16,
370 0x7b, 0x93, 0x7e, 0xec, 0x51, 0x39, 0x19, 0x56,
371 0xe1, 0x09, 0xf1, 0x8e, 0x91, 0x89, 0xb4, 0xb8,
372 0xf3, 0x15, 0xb3, 0x99, 0x5b, 0x72, 0xda, 0xa2,
373 0xee, 0x40, 0x85, 0xb6, 0xa0, 0x21, 0x9a, 0x92,
374 0x1f, 0x9a, 0x1c, 0x8e, 0x61, 0xb9, 0x3e, 0x95,
375 0x51, 0x00}};
376
377 const PKA_EccParam521 NISTP521_order = {.byte = {0x09, 0x64, 0x38, 0x91, 0x1e, 0xb7, 0x6f, 0xbb,
378 0xae, 0x47, 0x9c, 0x89, 0xb8, 0xc9, 0xb5, 0x3b,
379 0xd0, 0xa5, 0x09, 0xf7, 0x48, 0x01, 0xcc, 0x7f,
380 0x6b, 0x96, 0x2f, 0xbf, 0x83, 0x87, 0x86, 0x51,
381 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
382 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
383 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
384 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
385 0xff, 0x01}};
386
387
388 //*****************************************************************************
389 //
390 // Brainpool P256r1 constants in little endian format. byte[0] is the least
391 // significant byte and byte[BrainpoolP256R1_PARAM_SIZE_BYTES - 1] is the most
392 // significant.
393 //
394 //*****************************************************************************
395 const PKA_EccPoint256 BrainpoolP256R1_generator = {
396 .x = {.byte = {0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A,
397 0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9,
398 0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C,
399 0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B}},
400 .y = {.byte = {0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C,
401 0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2,
402 0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97,
403 0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54}},
404 };
405
406 const PKA_EccParam256 BrainpoolP256R1_prime = {.byte = {0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20,
407 0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E,
408 0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E,
409 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9}};
410
411 const PKA_EccParam256 BrainpoolP256R1_a = {.byte = {0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9,
412 0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB,
413 0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE,
414 0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D}};
415
416 const PKA_EccParam256 BrainpoolP256R1_b = {.byte = {0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B,
417 0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95,
418 0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3,
419 0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26,}};
420
421 const PKA_EccParam256 BrainpoolP256R1_order = {.byte = {0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90,
422 0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C,
423 0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E,
424 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9}};
425
426 //*****************************************************************************
427 //
428 // Brainpool P384r1 constants in little endian format. byte[0] is the least
429 // significant byte and byte[BrainpoolP384R1_PARAM_SIZE_BYTES - 1] is the most
430 // significant.
431 //
432 //*****************************************************************************
433 const PKA_EccPoint384 BrainpoolP384R1_generator = {
434 .x = {.byte = {0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF,
435 0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8,
436 0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB,
437 0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88,
438 0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2,
439 0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D}},
440 .y = {.byte = {0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42,
441 0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E,
442 0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1,
443 0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62,
444 0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C,
445 0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A}},
446 };
447
448 const PKA_EccParam384 BrainpoolP384R1_prime = {.byte = {0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87,
449 0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC,
450 0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12,
451 0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15,
452 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F,
453 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C}};
454
455 const PKA_EccParam384 BrainpoolP384R1_a = {.byte = {0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04,
456 0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A,
457 0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13,
458 0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2,
459 0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C,
460 0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B}};
461
462 const PKA_EccParam384 BrainpoolP384R1_b = {.byte = {0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A,
463 0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C,
464 0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E,
465 0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F,
466 0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B,
467 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04}};
468
469 const PKA_EccParam384 BrainpoolP384R1_order = {.byte = {0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B,
470 0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF,
471 0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F,
472 0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15,
473 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F,
474 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C}};
475
476 //*****************************************************************************
477 //
478 // Brainpool P512r1 constants in little endian format. byte[0] is the least
479 // significant byte and byte[BrainpoolP512R1_PARAM_SIZE_BYTES - 1] is the most
480 // significant.
481 //
482 //*****************************************************************************
483 const PKA_EccPoint512 BrainpoolP512R1_generator = {
484 .x = {.byte = {0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B,
485 0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C,
486 0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50,
487 0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF,
488 0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4,
489 0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85,
490 0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A,
491 0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81}},
492 .y = {.byte = {0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78,
493 0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1,
494 0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B,
495 0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2,
496 0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0,
497 0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2,
498 0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0,
499 0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D}},
500 };
501
502 const PKA_EccParam512 BrainpoolP512R1_prime = {.byte = {0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28,
503 0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28,
504 0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE,
505 0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D,
506 0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6,
507 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB,
508 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F,
509 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA}};
510
511 const PKA_EccParam512 BrainpoolP512R1_a = {.byte = {0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7,
512 0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F,
513 0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A,
514 0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D,
515 0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8,
516 0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94,
517 0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2,
518 0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78}};
519
520 const PKA_EccParam512 BrainpoolP512R1_b = {.byte = {0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28,
521 0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98,
522 0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77,
523 0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B,
524 0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B,
525 0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8,
526 0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA,
527 0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D}};
528
529 const PKA_EccParam512 BrainpoolP512R1_order = {.byte = {0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5,
530 0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D,
531 0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41,
532 0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55,
533 0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6,
534 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB,
535 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F,
536 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA}};
537
538 //*****************************************************************************
539 //
540 // Curve25519 constants in little endian format. byte[0] is the least
541 // significant byte and byte[Curve25519_PARAM_SIZE_BYTES - 1] is the most
542 // significant.
543 //
544 //*****************************************************************************
545 const PKA_EccPoint256 Curve25519_generator = {
546 .x = {.byte = {0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}},
550 .y = {.byte = {0xd9, 0xd3, 0xce, 0x7e, 0xa2, 0xc5, 0xe9, 0x29,
551 0xb2, 0x61, 0x7c, 0x6d, 0x7e, 0x4d, 0x3d, 0x92,
552 0x4c, 0xd1, 0x48, 0x77, 0x2c, 0xdd, 0x1e, 0xe0,
553 0xb4, 0x86, 0xa0, 0xb8, 0xa1, 0x19, 0xae, 0x20}},
554 };
555
556 const PKA_EccParam256 Curve25519_prime = {.byte = {0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
557 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
558 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
559 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}};
560
561 const PKA_EccParam256 Curve25519_a = {.byte = {0x06, 0x6d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
565
566 const PKA_EccParam256 Curve25519_b = {.byte = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
570
571 const PKA_EccParam256 Curve25519_order = {.byte = {0xb9, 0xdc, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
572 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
575
576
577 //*****************************************************************************
578 //
579 // Zeroize PKA RAM. Not threadsafe.
580 //
581 //*****************************************************************************
PKAClearPkaRam(void)582 void PKAClearPkaRam(void){
583 // Get initial state
584 uint32_t secdmaclkgr = HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR);
585
586 // OR in zeroize bit
587 secdmaclkgr |= PRCM_SECDMACLKGR_PKA_ZERIOZE_RESET_N;
588
589 // Start zeroization
590 HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) = secdmaclkgr;
591
592 // Wait 256 cycles for PKA RAM to be cleared
593 CPUdelay(256 / 4);
594
595 // Turn off zeroization
596 HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) = secdmaclkgr & (~PRCM_SECDMACLKGR_PKA_ZERIOZE_RESET_N);
597 }
598
599 //*****************************************************************************
600 //
601 // Write a PKA parameter to the PKA module, set required registers, and add an offset.
602 //
603 //*****************************************************************************
PKAWritePkaParam(const uint8_t * param,uint32_t paramLength,uint32_t paramOffset,uint32_t ptrRegOffset)604 static uint32_t PKAWritePkaParam(const uint8_t *param, uint32_t paramLength, uint32_t paramOffset, uint32_t ptrRegOffset)
605 {
606 uint32_t i;
607 uint32_t *paramWordAlias = (uint32_t *)param;
608 // Take the floor of paramLength in 32-bit words
609 uint32_t paramLengthInWords = paramLength / sizeof(uint32_t);
610
611 // Only copy data if it is specified. We may wish to simply allocate another buffer and get
612 // the required offset.
613 if (param) {
614 // Load the number in PKA RAM
615 for (i = 0; i < paramLengthInWords; i++) {
616 HWREG(PKA_RAM_BASE + paramOffset + sizeof(uint32_t) * i) = paramWordAlias[i];
617 }
618
619 // If the length is not a word-multiple, fill up a temporary word and copy that in
620 // to avoid a bus error. The extra zeros at the end should not matter, as the large
621 // number is little-endian and thus has no effect.
622 // We could have correctly calculated ceiling(paramLength / sizeof(uint32_t)) above.
623 // However, we would not have been able to zero-out the extra few most significant
624 // bytes of the most significant word. That would have resulted in doing maths operations
625 // on whatever follows param in RAM.
626 if (paramLength % sizeof(uint32_t)) {
627 uint32_t temp = 0;
628 uint8_t j;
629
630 // Load the entire word line of the param remainder
631 temp = paramWordAlias[i];
632
633 // Zero-out all bytes beyond the end of the param
634 for (j = paramLength % sizeof(uint32_t); j < sizeof(uint32_t); j++) {
635 ((uint8_t *)&temp)[j] = 0;
636 }
637
638 HWREG(PKA_RAM_BASE + paramOffset + sizeof(uint32_t) * i) = temp;
639
640 // Increment paramLengthInWords since we take the ceiling of length / sizeof(uint32_t)
641 paramLengthInWords++;
642 }
643 }
644
645 // Update the A, B, C, or D pointer with the offset address of the PKA RAM location
646 // where the number will be stored.
647 switch (ptrRegOffset) {
648 case PKA_O_APTR:
649 HWREG(PKA_BASE + PKA_O_APTR) = paramOffset >> 2;
650 HWREG(PKA_BASE + PKA_O_ALENGTH) = paramLengthInWords;
651 break;
652 case PKA_O_BPTR:
653 HWREG(PKA_BASE + PKA_O_BPTR) = paramOffset >> 2;
654 HWREG(PKA_BASE + PKA_O_BLENGTH) = paramLengthInWords;
655 break;
656 case PKA_O_CPTR:
657 HWREG(PKA_BASE + PKA_O_CPTR) = paramOffset >> 2;
658 break;
659 case PKA_O_DPTR:
660 HWREG(PKA_BASE + PKA_O_DPTR) = paramOffset >> 2;
661 break;
662 }
663
664 // Ensure 8-byte alignment of next parameter.
665 // Returns the offset for the next parameter.
666 return paramOffset + sizeof(uint32_t) * (paramLengthInWords + (paramLengthInWords % 2));
667 }
668
669 //*****************************************************************************
670 //
671 // Write a PKA parameter to the PKA module but return a larger offset.
672 //
673 //*****************************************************************************
PKAWritePkaParamExtraOffset(const uint8_t * param,uint32_t paramLength,uint32_t paramOffset,uint32_t ptrRegOffset)674 static uint32_t PKAWritePkaParamExtraOffset(const uint8_t *param, uint32_t paramLength, uint32_t paramOffset, uint32_t ptrRegOffset)
675 {
676 // Ensure 16-byte alignment.
677 return (sizeof(uint32_t) * 2) + PKAWritePkaParam(param, paramLength, paramOffset, ptrRegOffset);
678 }
679
680 //*****************************************************************************
681 //
682 // Writes the result of a large number arithmetic operation to a provided buffer.
683 //
684 //*****************************************************************************
PKAGetBigNumResult(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)685 static uint32_t PKAGetBigNumResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
686 {
687 uint32_t mswOffset;
688 uint32_t lswOffset;
689 uint32_t lengthInWords;
690 uint32_t i;
691 uint32_t *resultWordAlias = (uint32_t *)resultBuf;
692
693 // Check the arguments.
694 ASSERT(resultBuf);
695 ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
696 (resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
697
698 // Verify that the operation is complete.
699 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
700 return PKA_STATUS_OPERATION_BUSY;
701 }
702
703 // Get the MSW register value.
704 mswOffset = HWREG(PKA_BASE + PKA_O_MSW);
705
706 // If the result vector is zero, write back one zero byte so the caller does not need
707 // to handle a special error for the perhaps valid result of zero.
708 // They will only get the error status if they do not provide a buffer
709 if (mswOffset & PKA_MSW_RESULT_IS_ZERO_M) {
710 if (*resultLength){
711 if(resultBuf){
712 resultBuf[0] = 0;
713 }
714
715 *resultLength = 1;
716
717 return PKA_STATUS_SUCCESS;
718 }
719 else {
720 return PKA_STATUS_BUF_UNDERFLOW;
721 }
722 }
723
724 // Get the length of the result
725 mswOffset = ((mswOffset & PKA_MSW_MSW_ADDRESS_M) + 1);
726 lswOffset = ((resultPKAMemAddr - PKA_RAM_BASE) >> 2);
727
728 if (mswOffset >= lswOffset) {
729 lengthInWords = mswOffset - lswOffset;
730 }
731 else {
732 return PKA_STATUS_RESULT_ADDRESS_INCORRECT;
733 }
734
735 // Check if the provided buffer length is adequate to store the result data.
736 if (*resultLength < lengthInWords * sizeof(uint32_t)) {
737 return PKA_STATUS_BUF_UNDERFLOW;
738 }
739
740 // Copy the resultant length.
741 *resultLength = lengthInWords * sizeof(uint32_t);
742
743
744 if (resultBuf) {
745 // Copy the result into the resultBuf.
746 for (i = 0; i < lengthInWords; i++) {
747 resultWordAlias[i]= HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
748 }
749 }
750
751 return PKA_STATUS_SUCCESS;
752 }
753
754 //*****************************************************************************
755 //
756 // Retrieve the result of a modulo operation or the remainder of a division.
757 //
758 //*****************************************************************************
PKAGetBigNumResultRemainder(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)759 static uint32_t PKAGetBigNumResultRemainder(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
760 {
761 uint32_t regMSWVal;
762 uint32_t lengthInWords;
763 uint32_t i;
764 uint32_t *resultWordAlias = (uint32_t *)resultBuf;
765
766 // Check the arguments.
767 ASSERT(resultBuf);
768 ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
769 (resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
770
771 // Verify that the operation is complete.
772 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
773 return PKA_STATUS_OPERATION_BUSY;
774 }
775
776 // Get the MSW register value.
777 regMSWVal = HWREG(PKA_BASE + PKA_O_DIVMSW);
778
779 // If the result vector is zero, write back one zero byte so the caller does not need
780 // to handle a special error for the perhaps valid result of zero.
781 // They will only get the error status if they do not provide a buffer
782 if (regMSWVal & PKA_DIVMSW_RESULT_IS_ZERO_M) {
783 if (*resultLength){
784 if(resultBuf){
785 resultBuf[0] = 0;
786 }
787
788 *resultLength = 1;
789
790 return PKA_STATUS_SUCCESS;
791 }
792 else {
793 return PKA_STATUS_BUF_UNDERFLOW;
794 }
795 }
796
797 // Get the length of the result
798 lengthInWords = ((regMSWVal & PKA_DIVMSW_MSW_ADDRESS_M) + 1) - ((resultPKAMemAddr - PKA_RAM_BASE) >> 2);
799
800 // Check if the provided buffer length is adequate to store the result data.
801 if (*resultLength < lengthInWords * sizeof(uint32_t)) {
802 return PKA_STATUS_BUF_UNDERFLOW;
803 }
804
805 // Copy the resultant length.
806 *resultLength = lengthInWords * sizeof(uint32_t);
807
808 if (resultBuf) {
809 // Copy the result into the resultBuf.
810 for (i = 0; i < lengthInWords; i++) {
811 resultWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
812 }
813 }
814
815 return PKA_STATUS_SUCCESS;
816 }
817
818 //*****************************************************************************
819 //
820 // Writes the resultant curve point of an ECC operation to the provided buffer.
821 //
822 //*****************************************************************************
PKAGetECCResult(uint8_t * curvePointX,uint8_t * curvePointY,uint32_t resultPKAMemAddr,uint32_t length)823 static uint32_t PKAGetECCResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
824 {
825 uint32_t i = 0;
826 uint32_t *xWordAlias = (uint32_t *)curvePointX;
827 uint32_t *yWordAlias = (uint32_t *)curvePointY;
828 uint32_t lengthInWordsCeiling = 0;
829
830 // Check for the arguments.
831 ASSERT(curvePointX);
832 ASSERT(curvePointY);
833 ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
834 (resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
835
836 // Verify that the operation is completed.
837 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
838 return PKA_STATUS_OPERATION_BUSY;
839 }
840
841 if (HWREG(PKA_BASE + PKA_O_SHIFT)) {
842 return PKA_STATUS_FAILURE;
843 }
844
845 // Check to make sure that the result vector is not the point at infinity.
846 if (HWREG(PKA_BASE + PKA_O_MSW) & PKA_MSW_RESULT_IS_ZERO) {
847 return PKA_STATUS_POINT_AT_INFINITY;
848 }
849
850 if (curvePointX != NULL) {
851 // Copy the x co-ordinate value of the result from vector D into
852 // the curvePoint.
853 for (i = 0; i < (length / sizeof(uint32_t)); i++) {
854 xWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
855 }
856
857 // If the length is not a word-multiple, fill up a temporary word and copy that in
858 // to avoid a bus error.
859 if (length % sizeof(uint32_t)) {
860 uint32_t temp = 0;
861 uint8_t j;
862
863 // Load the entire word line of the coordinate remainder
864 temp = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
865
866 // Write all remaining bytes to the coordinate
867 for (j = 0; j < length % sizeof(uint32_t); j++) {
868 curvePointX[i * sizeof(uint32_t) + j] = ((uint8_t *)&temp)[j];
869 }
870
871 }
872 }
873
874 lengthInWordsCeiling = (length % sizeof(uint32_t)) ? length / sizeof(uint32_t) + 1 : length / sizeof(uint32_t);
875
876 resultPKAMemAddr += sizeof(uint32_t) * (2 + lengthInWordsCeiling + (lengthInWordsCeiling % 2));
877
878 if (curvePointY != NULL) {
879 // Copy the y co-ordinate value of the result from vector D into
880 // the curvePoint.
881 for (i = 0; i < (length / sizeof(uint32_t)); i++) {
882 yWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
883 }
884
885 // If the length is not a word-multiple, fill up a temporary word and copy that in
886 // to avoid a bus error.
887 if (length % sizeof(uint32_t)) {
888 uint32_t temp = 0;
889 uint8_t j;
890
891 // Load the entire word line of the coordinate remainder
892 temp = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
893
894 // Write all remaining bytes to the coordinate
895 for (j = 0; j < length % sizeof(uint32_t); j++) {
896 curvePointY[i * sizeof(uint32_t) + j] = ((uint8_t *)&temp)[j];
897 }
898 }
899 }
900
901
902 return PKA_STATUS_SUCCESS;
903 }
904
905
906 //*****************************************************************************
907 //
908 // Provides the PKA operation status.
909 //
910 //*****************************************************************************
PKAGetOpsStatus(void)911 uint32_t PKAGetOpsStatus(void)
912 {
913 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN_M) {
914 return PKA_STATUS_OPERATION_BUSY;
915 }
916 else {
917 return PKA_STATUS_OPERATION_RDY;
918 }
919 }
920
921 //*****************************************************************************
922 //
923 // Check if an array consists only of zeros.
924 //
925 //*****************************************************************************
PKAArrayAllZeros(const uint8_t * array,uint32_t arrayLength)926 bool PKAArrayAllZeros(const uint8_t *array, uint32_t arrayLength)
927 {
928 uint32_t i;
929 uint8_t arrayBits = 0;
930
931 // We could speed things up by comparing word-wise rather than byte-wise.
932 // However, this extra overhead is inconsequential compared to running an
933 // actual PKA operation. Especially ECC operations.
934 for (i = 0; i < arrayLength; i++) {
935 arrayBits |= array[i];
936 }
937
938 if (arrayBits) {
939 return false;
940 }
941 else {
942 return true;
943 }
944
945 }
946
947 //*****************************************************************************
948 //
949 // Fill an array with zeros
950 //
951 //*****************************************************************************
PKAZeroOutArray(const uint8_t * array,uint32_t arrayLength)952 void PKAZeroOutArray(const uint8_t *array, uint32_t arrayLength)
953 {
954 uint32_t i;
955 // Take the floor of paramLength in 32-bit words
956 uint32_t arrayLengthInWords = arrayLength / sizeof(uint32_t);
957
958 // Zero-out the array word-wise until i >= arrayLength
959 for (i = 0; i < arrayLengthInWords * sizeof(uint32_t); i += 4) {
960 HWREG(array + i) = 0;
961 }
962
963 // If i != arrayLength, there are some remaining bytes to zero-out
964 if (arrayLength % sizeof(uint32_t)) {
965 // Subtract 4 from i, since i has already overshot the array
966 for (i -= 4; i < arrayLength; i++) {
967 HWREGB(array + i * sizeof(uint32_t));
968 }
969 }
970 }
971
972 //*****************************************************************************
973 //
974 // Start the big number modulus operation.
975 //
976 //*****************************************************************************
PKABigNumModStart(const uint8_t * bigNum,uint32_t bigNumLength,const uint8_t * modulus,uint32_t modulusLength,uint32_t * resultPKAMemAddr)977 uint32_t PKABigNumModStart(const uint8_t *bigNum, uint32_t bigNumLength, const uint8_t *modulus, uint32_t modulusLength, uint32_t *resultPKAMemAddr)
978 {
979 uint32_t offset = 0;
980
981 // Check the arguments.
982 ASSERT(bigNum);
983 ASSERT(modulus);
984 ASSERT(resultPKAMemAddr);
985
986 // Make sure no operation is in progress.
987 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
988 return PKA_STATUS_OPERATION_BUSY;
989 }
990
991 offset = PKAWritePkaParam(bigNum, bigNumLength, offset, PKA_O_APTR);
992
993 offset = PKAWritePkaParamExtraOffset(modulus, modulusLength, offset, PKA_O_BPTR);
994
995 // Copy the result vector address location.
996 *resultPKAMemAddr = PKA_RAM_BASE + offset;
997
998 // Load C pointer with the result location in PKA RAM
999 HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
1000
1001 // Start the PKCP modulo operation by setting the PKA Function register.
1002 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MODULO);
1003
1004 return PKA_STATUS_SUCCESS;
1005 }
1006
1007 //*****************************************************************************
1008 //
1009 // Get the result of the big number modulus operation.
1010 //
1011 //*****************************************************************************
PKABigNumModGetResult(uint8_t * resultBuf,uint32_t length,uint32_t resultPKAMemAddr)1012 uint32_t PKABigNumModGetResult(uint8_t *resultBuf, uint32_t length, uint32_t resultPKAMemAddr)
1013 {
1014 // Zero-out array in case modulo result is shorter than length
1015 PKAZeroOutArray(resultBuf, length);
1016
1017 return PKAGetBigNumResultRemainder(resultBuf, &length, resultPKAMemAddr);
1018 }
1019
1020 //*****************************************************************************
1021 //
1022 // Start the big number divide operation.
1023 //
1024 //*****************************************************************************
PKABigNumDivideStart(const uint8_t * dividend,uint32_t dividendLength,const uint8_t * divisor,uint32_t divisorLength,uint32_t * resultQuotientMemAddr,uint32_t * resultRemainderMemAddr)1025 uint32_t PKABigNumDivideStart(const uint8_t *dividend, uint32_t dividendLength, const uint8_t *divisor, uint32_t divisorLength, uint32_t *resultQuotientMemAddr, uint32_t *resultRemainderMemAddr)
1026 {
1027 uint32_t offset = 0;
1028
1029 // Check the arguments.
1030 ASSERT(dividend);
1031 ASSERT(divisor);
1032 ASSERT(resultQuotientMemAddr);
1033 ASSERT(resultRemainderMemAddr);
1034
1035 // Make sure no operation is in progress.
1036 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1037 return PKA_STATUS_OPERATION_BUSY;
1038 }
1039
1040 offset = PKAWritePkaParam(dividend, dividendLength, offset, PKA_O_APTR);
1041
1042 offset = PKAWritePkaParamExtraOffset(divisor, divisorLength, offset, PKA_O_BPTR);
1043
1044 // Copy the remainder result vector address location.
1045 if (resultRemainderMemAddr) {
1046 *resultRemainderMemAddr = PKA_RAM_BASE + offset;
1047 }
1048
1049 // The remainder cannot ever be larger than the divisor. It should fit inside
1050 // a buffer of that size.
1051 offset = PKAWritePkaParamExtraOffset(0, divisorLength, offset, PKA_O_CPTR);
1052
1053 // Copy the remainder result vector address location.
1054 if (resultQuotientMemAddr) {
1055 *resultQuotientMemAddr = PKA_RAM_BASE + offset;
1056 }
1057
1058 // Load D pointer with the quotient location in PKA RAM
1059 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1060
1061 // Start the PKCP modulo operation by setting the PKA Function register.
1062 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_DIVIDE);
1063
1064 return PKA_STATUS_SUCCESS;
1065 }
1066
1067 //*****************************************************************************
1068 //
1069 // Get the quotient of the big number divide operation.
1070 //
1071 //*****************************************************************************
PKABigNumDivideGetQuotient(uint8_t * resultBuf,uint32_t * length,uint32_t resultQuotientMemAddr)1072 uint32_t PKABigNumDivideGetQuotient(uint8_t *resultBuf, uint32_t *length, uint32_t resultQuotientMemAddr)
1073 {
1074 return PKAGetBigNumResult(resultBuf, length, resultQuotientMemAddr);
1075 }
1076
1077 //*****************************************************************************
1078 //
1079 // Get the remainder of the big number divide operation.
1080 //
1081 //*****************************************************************************
PKABigNumDivideGetRemainder(uint8_t * resultBuf,uint32_t * length,uint32_t resultQuotientMemAddr)1082 uint32_t PKABigNumDivideGetRemainder(uint8_t *resultBuf, uint32_t *length, uint32_t resultQuotientMemAddr)
1083 {
1084 return PKAGetBigNumResultRemainder(resultBuf, length, resultQuotientMemAddr);
1085 }
1086
1087
1088 //*****************************************************************************
1089 //
1090 // Start the comparison of two big numbers.
1091 //
1092 //*****************************************************************************
PKABigNumCmpStart(const uint8_t * bigNum1,const uint8_t * bigNum2,uint32_t length)1093 uint32_t PKABigNumCmpStart(const uint8_t *bigNum1, const uint8_t *bigNum2, uint32_t length)
1094 {
1095 uint32_t offset = 0;
1096
1097 // Check the arguments.
1098 ASSERT(bigNum1);
1099 ASSERT(bigNum2);
1100
1101 // Make sure no operation is in progress.
1102 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1103 return PKA_STATUS_OPERATION_BUSY;
1104 }
1105
1106 offset = PKAWritePkaParam(bigNum1, length, offset, PKA_O_APTR);
1107
1108 offset = PKAWritePkaParam(bigNum2, length, offset, PKA_O_BPTR);
1109
1110 // Set the PKA Function register for the Compare operation
1111 // and start the operation.
1112 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_COMPARE);
1113
1114 return PKA_STATUS_SUCCESS;
1115 }
1116
1117 //*****************************************************************************
1118 //
1119 // Get the result of the comparison operation of two big numbers.
1120 //
1121 //*****************************************************************************
PKABigNumCmpGetResult(void)1122 uint32_t PKABigNumCmpGetResult(void)
1123 {
1124 uint32_t status;
1125
1126 // verify that the operation is complete.
1127 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1128 return PKA_STATUS_OPERATION_BUSY;
1129 }
1130
1131 // Check the COMPARE register.
1132 switch(HWREG(PKA_BASE + PKA_O_COMPARE)) {
1133 case PKA_COMPARE_A_EQUALS_B:
1134 status = PKA_STATUS_EQUAL;
1135 break;
1136
1137 case PKA_COMPARE_A_GREATER_THAN_B:
1138 status = PKA_STATUS_A_GREATER_THAN_B;
1139 break;
1140
1141 case PKA_COMPARE_A_LESS_THAN_B:
1142 status = PKA_STATUS_A_LESS_THAN_B;
1143 break;
1144
1145 default:
1146 status = PKA_STATUS_FAILURE;
1147 break;
1148 }
1149
1150 return status;
1151 }
1152
1153 //*****************************************************************************
1154 //
1155 // Start the big number inverse modulo operation.
1156 //
1157 //*****************************************************************************
PKABigNumInvModStart(const uint8_t * bigNum,uint32_t bigNumLength,const uint8_t * modulus,uint32_t modulusLength,uint32_t * resultPKAMemAddr)1158 uint32_t PKABigNumInvModStart(const uint8_t *bigNum, uint32_t bigNumLength, const uint8_t *modulus, uint32_t modulusLength, uint32_t *resultPKAMemAddr)
1159 {
1160 uint32_t offset = 0;
1161
1162 // Check the arguments.
1163 ASSERT(bigNum);
1164 ASSERT(modulus);
1165 ASSERT(resultPKAMemAddr);
1166
1167 // Make sure no operation is in progress.
1168 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1169 return PKA_STATUS_OPERATION_BUSY;
1170 }
1171
1172 offset = PKAWritePkaParam(bigNum, bigNumLength, offset, PKA_O_APTR);
1173
1174 offset = PKAWritePkaParam(modulus, modulusLength, offset, PKA_O_BPTR);
1175
1176 // Copy the result vector address location.
1177 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1178
1179 // Load D pointer with the result location in PKA RAM.
1180 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1181
1182 // set the PKA function to InvMod operation and the start the operation.
1183 HWREG(PKA_BASE + PKA_O_FUNCTION) = 0x0000F000;
1184
1185 return PKA_STATUS_SUCCESS;
1186 }
1187
1188 //*****************************************************************************
1189 //
1190 // Get the result of the big number inverse modulo operation.
1191 //
1192 //*****************************************************************************
PKABigNumInvModGetResult(uint8_t * resultBuf,uint32_t length,uint32_t resultPKAMemAddr)1193 uint32_t PKABigNumInvModGetResult(uint8_t *resultBuf, uint32_t length, uint32_t resultPKAMemAddr)
1194 {
1195 // Zero-out array in case modulo result is shorter than length
1196 PKAZeroOutArray(resultBuf, length);
1197
1198 return PKAGetBigNumResult(resultBuf, &length, resultPKAMemAddr);
1199 }
1200
1201 //*****************************************************************************
1202 //
1203 // Start the big number multiplication.
1204 //
1205 //*****************************************************************************
PKABigNumMultiplyStart(const uint8_t * multiplicand,uint32_t multiplicandLength,const uint8_t * multiplier,uint32_t multiplierLength,uint32_t * resultPKAMemAddr)1206 uint32_t PKABigNumMultiplyStart(const uint8_t *multiplicand, uint32_t multiplicandLength, const uint8_t *multiplier, uint32_t multiplierLength, uint32_t *resultPKAMemAddr)
1207 {
1208 uint32_t offset = 0;
1209
1210 // Check for the arguments.
1211 ASSERT(multiplicand);
1212 ASSERT(multiplier);
1213 ASSERT(resultPKAMemAddr);
1214
1215 // Make sure no operation is in progress.
1216 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1217 return PKA_STATUS_OPERATION_BUSY;
1218 }
1219
1220 offset = PKAWritePkaParam(multiplicand, multiplicandLength, offset, PKA_O_APTR);
1221
1222 offset = PKAWritePkaParam(multiplier, multiplierLength, offset, PKA_O_BPTR);
1223
1224
1225 // Copy the result vector address location.
1226 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1227
1228 // Load C pointer with the result location in PKA RAM.
1229 HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
1230
1231 // Set the PKA function to the multiplication and start it.
1232 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MULTIPLY);
1233
1234 return PKA_STATUS_SUCCESS;
1235 }
1236
1237 //*****************************************************************************
1238 //
1239 // Get the results of the big number multiplication.
1240 //
1241 //*****************************************************************************
PKABigNumMultGetResult(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)1242 uint32_t PKABigNumMultGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
1243 {
1244 return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
1245 }
1246
1247 //*****************************************************************************
1248 //
1249 // Start the addition of two big number.
1250 //
1251 //*****************************************************************************
PKABigNumAddStart(const uint8_t * bigNum1,uint32_t bigNum1Length,const uint8_t * bigNum2,uint32_t bigNum2Length,uint32_t * resultPKAMemAddr)1252 uint32_t PKABigNumAddStart(const uint8_t *bigNum1, uint32_t bigNum1Length, const uint8_t *bigNum2, uint32_t bigNum2Length, uint32_t *resultPKAMemAddr)
1253 {
1254 uint32_t offset = 0;
1255
1256 // Check for arguments.
1257 ASSERT(bigNum1);
1258 ASSERT(bigNum2);
1259 ASSERT(resultPKAMemAddr);
1260
1261 // Make sure no operation is in progress.
1262 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1263 return PKA_STATUS_OPERATION_BUSY;
1264 }
1265
1266 offset = PKAWritePkaParam(bigNum1, bigNum1Length, offset, PKA_O_APTR);
1267
1268 offset = PKAWritePkaParam(bigNum2, bigNum2Length, offset, PKA_O_BPTR);
1269
1270 // Copy the result vector address location.
1271 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1272
1273 // Load C pointer with the result location in PKA RAM.
1274 HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
1275
1276 // Set the function for the add operation and start the operation.
1277 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_ADD);
1278
1279 return PKA_STATUS_SUCCESS;
1280 }
1281
1282 //*****************************************************************************
1283 //
1284 // Get the result of the addition operation on two big number.
1285 //
1286 //*****************************************************************************
PKABigNumSubGetResult(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)1287 uint32_t PKABigNumSubGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
1288 {
1289 return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
1290 }
1291
1292 //*****************************************************************************
1293 //
1294 // Start the addition of two big number.
1295 //
1296 //*****************************************************************************
PKABigNumSubStart(const uint8_t * minuend,uint32_t minuendLength,const uint8_t * subtrahend,uint32_t subtrahendLength,uint32_t * resultPKAMemAddr)1297 uint32_t PKABigNumSubStart(const uint8_t *minuend, uint32_t minuendLength, const uint8_t *subtrahend, uint32_t subtrahendLength, uint32_t *resultPKAMemAddr)
1298 {
1299 uint32_t offset = 0;
1300
1301 // Check for arguments.
1302 ASSERT(minuend);
1303 ASSERT(subtrahend);
1304 ASSERT(resultPKAMemAddr);
1305
1306
1307 // Make sure no operation is in progress.
1308 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1309 return PKA_STATUS_OPERATION_BUSY;
1310 }
1311
1312 offset = PKAWritePkaParam(minuend, minuendLength, offset, PKA_O_APTR);
1313
1314 offset = PKAWritePkaParam(subtrahend, subtrahendLength, offset, PKA_O_BPTR);
1315
1316 // Copy the result vector address location.
1317 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1318
1319 // Load C pointer with the result location in PKA RAM.
1320 HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
1321
1322 // Set the function for the add operation and start the operation.
1323 HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_SUBTRACT);
1324
1325 return PKA_STATUS_SUCCESS;
1326 }
1327
1328 //*****************************************************************************
1329 //
1330 // Get the result of the addition operation on two big number.
1331 //
1332 //*****************************************************************************
PKABigNumAddGetResult(uint8_t * resultBuf,uint32_t * resultLength,uint32_t resultPKAMemAddr)1333 uint32_t PKABigNumAddGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
1334 {
1335 return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
1336 }
1337
1338
1339 //*****************************************************************************
1340 //
1341 // Start ECC Multiplication.
1342 //
1343 //*****************************************************************************
PKAEccMultiplyStart(const uint8_t * scalar,const uint8_t * curvePointX,const uint8_t * curvePointY,const uint8_t * prime,const uint8_t * a,const uint8_t * b,uint32_t length,uint32_t * resultPKAMemAddr)1344 uint32_t PKAEccMultiplyStart(const uint8_t *scalar, const uint8_t *curvePointX, const uint8_t *curvePointY, const uint8_t *prime, const uint8_t *a, const uint8_t *b, uint32_t length, uint32_t *resultPKAMemAddr)
1345 {
1346 uint32_t offset = 0;
1347
1348 // Check for the arguments.
1349 ASSERT(scalar);
1350 ASSERT(curvePointX);
1351 ASSERT(curvePointY);
1352 ASSERT(prime);
1353 ASSERT(a);
1354 ASSERT(b);
1355 ASSERT(length <= PKA_MAX_CURVE_SIZE_32_BIT_WORD * sizeof(uint32_t));
1356 ASSERT(resultPKAMemAddr);
1357
1358 // Make sure no PKA operation is in progress.
1359 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1360 return PKA_STATUS_OPERATION_BUSY;
1361 }
1362
1363 offset = PKAWritePkaParam(scalar, length, offset, PKA_O_APTR);
1364
1365 offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
1366 offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
1367 offset = PKAWritePkaParamExtraOffset(b, length, offset, PKA_NO_POINTER_REG);
1368
1369 offset = PKAWritePkaParamExtraOffset(curvePointX, length, offset, PKA_O_CPTR);
1370 offset = PKAWritePkaParamExtraOffset(curvePointY, length, offset, PKA_NO_POINTER_REG);
1371
1372 // Update the result location.
1373 // The resultPKAMemAddr may be 0 if we only want to check that we generated the point at infinity
1374 if (resultPKAMemAddr) {
1375 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1376 }
1377
1378 // Load D pointer with the result location in PKA RAM.
1379 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1380
1381 // Set the PKA function to ECC-MULT and start the operation.
1382 HWREG(PKA_BASE + PKA_O_FUNCTION) = PKA_FUNCTION_RUN_M | (0x05 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
1383
1384 return PKA_STATUS_SUCCESS;
1385 }
1386
1387
1388 //*****************************************************************************
1389 //
1390 // Start ECC Montgomery Multiplication.
1391 //
1392 //*****************************************************************************
PKAEccMontgomeryMultiplyStart(const uint8_t * scalar,const uint8_t * curvePointX,const uint8_t * prime,const uint8_t * a,uint32_t length,uint32_t * resultPKAMemAddr)1393 uint32_t PKAEccMontgomeryMultiplyStart(const uint8_t *scalar, const uint8_t *curvePointX, const uint8_t *prime, const uint8_t *a, uint32_t length, uint32_t *resultPKAMemAddr)
1394 {
1395 uint32_t offset = 0;
1396
1397 // Check for the arguments.
1398 ASSERT(scalar);
1399 ASSERT(curvePointX);
1400 ASSERT(prime);
1401 ASSERT(a);
1402 ASSERT(length <= PKA_MAX_CURVE_SIZE_32_BIT_WORD * sizeof(uint32_t));
1403 ASSERT(resultPKAMemAddr);
1404
1405 // Make sure no PKA operation is in progress.
1406 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1407 return PKA_STATUS_OPERATION_BUSY;
1408 }
1409
1410 offset = PKAWritePkaParam(scalar, length, offset, PKA_O_APTR);
1411
1412 offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
1413 offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
1414
1415 offset = PKAWritePkaParamExtraOffset(curvePointX, length, offset, PKA_O_CPTR);
1416
1417 // Update the result location.
1418 // The resultPKAMemAddr may be 0 if we only want to check that we generated the point at infinity
1419 if (resultPKAMemAddr) {
1420 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1421 }
1422
1423 // Load D pointer with the result location in PKA RAM.
1424 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1425
1426 // Set the PKA function to Montgomery ECC-MULT and start the operation.
1427 HWREG(PKA_BASE + PKA_O_FUNCTION) = PKA_FUNCTION_RUN_M | (0x02 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
1428
1429 return PKA_STATUS_SUCCESS;
1430 }
1431
1432
1433 //*****************************************************************************
1434 //
1435 // Get the result of ECC Multiplication
1436 //
1437 //*****************************************************************************
PKAEccMultiplyGetResult(uint8_t * curvePointX,uint8_t * curvePointY,uint32_t resultPKAMemAddr,uint32_t length)1438 uint32_t PKAEccMultiplyGetResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
1439 {
1440 return PKAGetECCResult(curvePointX, curvePointY, resultPKAMemAddr, length);
1441 }
1442
1443 //*****************************************************************************
1444 //
1445 // Start the ECC Addition.
1446 //
1447 //*****************************************************************************
PKAEccAddStart(const uint8_t * curvePoint1X,const uint8_t * curvePoint1Y,const uint8_t * curvePoint2X,const uint8_t * curvePoint2Y,const uint8_t * prime,const uint8_t * a,uint32_t length,uint32_t * resultPKAMemAddr)1448 uint32_t PKAEccAddStart(const uint8_t *curvePoint1X, const uint8_t *curvePoint1Y, const uint8_t *curvePoint2X, const uint8_t *curvePoint2Y, const uint8_t *prime, const uint8_t *a, uint32_t length, uint32_t *resultPKAMemAddr)
1449 {
1450 uint32_t offset = 0;
1451
1452 // Check for the arguments.
1453 ASSERT(curvePoint1X);
1454 ASSERT(curvePoint1Y);
1455 ASSERT(curvePoint2X);
1456 ASSERT(curvePoint2Y);
1457 ASSERT(prime);
1458 ASSERT(a);
1459 ASSERT(resultPKAMemAddr);
1460
1461 // Make sure no operation is in progress.
1462 if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
1463 return PKA_STATUS_OPERATION_BUSY;
1464 }
1465
1466 offset = PKAWritePkaParamExtraOffset(curvePoint1X, length, offset, PKA_O_APTR);
1467 offset = PKAWritePkaParamExtraOffset(curvePoint1Y, length, offset, PKA_NO_POINTER_REG);
1468
1469
1470 offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
1471 offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
1472
1473 offset = PKAWritePkaParamExtraOffset(curvePoint2X, length, offset, PKA_O_CPTR);
1474 offset = PKAWritePkaParamExtraOffset(curvePoint2Y, length, offset, PKA_NO_POINTER_REG);
1475
1476 // Copy the result vector location.
1477 *resultPKAMemAddr = PKA_RAM_BASE + offset;
1478
1479 // Load D pointer with the result location in PKA RAM.
1480 HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
1481
1482 // Set the PKA Function to ECC-ADD and start the operation.
1483 HWREG(PKA_BASE + PKA_O_FUNCTION ) = PKA_FUNCTION_RUN_M | (0x03 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
1484
1485 return PKA_STATUS_SUCCESS;
1486 }
1487
1488 //*****************************************************************************
1489 //
1490 // Get the result of the ECC Addition
1491 //
1492 //*****************************************************************************
PKAEccAddGetResult(uint8_t * curvePointX,uint8_t * curvePointY,uint32_t resultPKAMemAddr,uint32_t length)1493 uint32_t PKAEccAddGetResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
1494 {
1495 return PKAGetECCResult(curvePointX, curvePointY, resultPKAMemAddr, length);
1496 }
1497
1498 //*****************************************************************************
1499 //
1500 // Verify a public key against the supplied elliptic curve equation
1501 //
1502 //*****************************************************************************
PKAEccVerifyPublicKeyWeierstrassStart(const uint8_t * curvePointX,const uint8_t * curvePointY,const uint8_t * prime,const uint8_t * a,const uint8_t * b,const uint8_t * order,uint32_t length)1503 uint32_t PKAEccVerifyPublicKeyWeierstrassStart(const uint8_t *curvePointX, const uint8_t *curvePointY, const uint8_t *prime, const uint8_t *a, const uint8_t *b, const uint8_t *order, uint32_t length)
1504 {
1505 uint32_t pkaResult;
1506 uint32_t resultAddress;
1507 uint32_t resultLength;
1508 uint8_t *scratchBuffer = (uint8_t *)(PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE / 2);
1509 uint8_t *scratchBuffer2 = scratchBuffer + 512;
1510
1511
1512 // Verify X in range [0, prime - 1]
1513 PKABigNumCmpStart(curvePointX,
1514 prime,
1515 length);
1516
1517 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1518
1519 pkaResult = PKABigNumCmpGetResult();
1520
1521 if (pkaResult != PKA_STATUS_A_LESS_THAN_B) {
1522 return PKA_STATUS_X_LARGER_THAN_PRIME;
1523 }
1524
1525 // Verify Y in range [0, prime - 1]
1526 PKABigNumCmpStart(curvePointY,
1527 prime,
1528 length);
1529
1530 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1531
1532 pkaResult = PKABigNumCmpGetResult();
1533
1534 if (pkaResult != PKA_STATUS_A_LESS_THAN_B) {
1535 return PKA_STATUS_Y_LARGER_THAN_PRIME;
1536 }
1537
1538 // Verify point on curve
1539 // Short-Weierstrass equation: Y ^ 2 = X ^3 + a * X + b mod P
1540 // Reduced: Y ^ 2 = X * (X ^ 2 + a) + b
1541
1542 // tmp = X ^ 2
1543 PKABigNumMultiplyStart(curvePointX, length, curvePointX, length, &resultAddress);
1544
1545 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1546
1547 resultLength = 200;
1548 pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
1549
1550 if (pkaResult != PKA_STATUS_SUCCESS) {
1551 return PKA_STATUS_FAILURE;
1552 }
1553
1554 // tmp += a
1555 PKABigNumAddStart(scratchBuffer, resultLength, a, length, &resultAddress);
1556
1557 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1558
1559 resultLength = 200;
1560 pkaResult = PKABigNumAddGetResult(scratchBuffer, &resultLength, resultAddress);
1561
1562 if (pkaResult != PKA_STATUS_SUCCESS) {
1563 return PKA_STATUS_FAILURE;
1564 }
1565
1566 // tmp *= x
1567 PKABigNumMultiplyStart(scratchBuffer, resultLength, curvePointX, length, &resultAddress);
1568
1569 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1570
1571 resultLength = 200;
1572 pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
1573
1574 if (pkaResult != PKA_STATUS_SUCCESS) {
1575 return PKA_STATUS_FAILURE;
1576 }
1577
1578 // tmp += b
1579 PKABigNumAddStart(scratchBuffer, resultLength, b, length, &resultAddress);
1580
1581 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1582
1583 resultLength = 200;
1584 pkaResult = PKABigNumAddGetResult(scratchBuffer, &resultLength, resultAddress);
1585
1586 if (pkaResult != PKA_STATUS_SUCCESS) {
1587 return PKA_STATUS_FAILURE;
1588 }
1589
1590
1591 // tmp2 = tmp % prime to ensure we have no fraction in the division.
1592 // The number will only shrink from here on out.
1593 PKABigNumModStart(scratchBuffer, resultLength, prime, length, &resultAddress);
1594
1595 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1596
1597 // If the result is not a multiple of the word-length, the PKA HW will round up
1598 // because it deals in words only. That means that using 'length' directly
1599 // would cause and underflow, since length refers to the actual length in bytes of
1600 // the curve parameters while the PKA HW reports that rounded up to the next
1601 // word boundary.
1602 // Use 200 as the resultLength instead since we are copying to the scratch buffer
1603 // anyway.
1604 // Practically, this only happens with curves such as NIST-P521 that are not word
1605 // multiples.
1606 resultLength = 200;
1607 pkaResult = PKABigNumModGetResult(scratchBuffer2, resultLength, resultAddress);
1608
1609 if (pkaResult != PKA_STATUS_SUCCESS) {
1610 return PKA_STATUS_FAILURE;
1611 }
1612
1613 // tmp = y^2
1614 PKABigNumMultiplyStart(curvePointY, length, curvePointY, length, &resultAddress);
1615
1616 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1617
1618 resultLength = 200;
1619 pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
1620
1621 if (pkaResult != PKA_STATUS_SUCCESS) {
1622 return PKA_STATUS_FAILURE;
1623 }
1624
1625 // tmp %= prime
1626 PKABigNumModStart(scratchBuffer, resultLength, prime, length, &resultAddress);
1627
1628 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1629
1630 // If the result is not a multiple of the word-length, the PKA HW will round up
1631 // because it deals in words only. That means that using 'length' directly
1632 // would cause and underflow, since length refers to the actual length in bytes of
1633 // the curve parameters while the PKA HW reports that rounded up to the next
1634 // word boundary.
1635 // Use 200 as the resultLength instead since we are copying to the scratch buffer
1636 // anyway.
1637 // Practically, this only happens with curves such as NIST-P521 that are not word
1638 // multiples.
1639 resultLength = 200;
1640 pkaResult = PKABigNumModGetResult(scratchBuffer, resultLength, resultAddress);
1641
1642 if (pkaResult != PKA_STATUS_SUCCESS) {
1643 return PKA_STATUS_FAILURE;
1644 }
1645
1646 // tmp ?= tmp2
1647 PKABigNumCmpStart(scratchBuffer,
1648 scratchBuffer2,
1649 length);
1650
1651 while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
1652
1653 pkaResult = PKABigNumCmpGetResult();
1654
1655 if (pkaResult != PKA_STATUS_EQUAL) {
1656 return PKA_STATUS_POINT_NOT_ON_CURVE;
1657 }
1658 else {
1659 return PKA_STATUS_SUCCESS;
1660 }
1661 }
1662