1 /***************************************************************************//**
2 * \file cy_crypto_core_ecc_ecdsa.c
3 * \version 2.40
4 *
5 * \brief
6 * This file provides constant and parameters for the API for the ECC ECDSA
7 * in the Crypto driver.
8 *
9 ********************************************************************************
10 * Copyright 2016-2020 Cypress Semiconductor Corporation
11 * SPDX-License-Identifier: Apache-2.0
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *******************************************************************************/
25
26 #include "cy_device.h"
27
28 #if defined (CY_IP_MXCRYPTO)
29
30 #include "cy_crypto_core_ecc.h"
31
32 #if defined(__cplusplus)
33 extern "C" {
34 #endif
35
36 #include "cy_crypto_core_ecc_nist_p.h"
37 #include "cy_crypto_core_mem.h"
38 #include "cy_crypto_core_vu.h"
39
40 /*******************************************************************************
41 * Function Name: Cy_Crypto_Core_ECC_SignHash
42 ****************************************************************************//**
43 *
44 * Sign a message digest.
45 *
46 * \param base
47 * The pointer to a Crypto instance.
48 *
49 * \param hash
50 * The message digest to sign. Provided as is in data buffer.
51 *
52 * \param hashlen
53 * The length of the digest in bytes.
54 *
55 * \param sig
56 * [out] The destination for the signature, 'r' followed by 's'.
57 *
58 * \param key
59 * Key used for signature generation. See \ref cy_stc_crypto_ecc_key.
60 *
61 * \param messageKey
62 * Message key.
63 *
64 * \return status code. See \ref cy_en_crypto_status_t.
65 *
66 *******************************************************************************/
Cy_Crypto_Core_ECC_SignHash(CRYPTO_Type * base,const uint8_t * hash,uint32_t hashlen,uint8_t * sig,const cy_stc_crypto_ecc_key * key,const uint8_t * messageKey)67 cy_en_crypto_status_t Cy_Crypto_Core_ECC_SignHash(CRYPTO_Type *base, const uint8_t *hash, uint32_t hashlen, uint8_t *sig,
68 const cy_stc_crypto_ecc_key *key, const uint8_t *messageKey)
69 {
70 cy_en_crypto_status_t tmpResult = CY_CRYPTO_BAD_PARAMS;
71
72 cy_stc_crypto_ecc_key ephKey;
73 uint8_t myKGX[CY_CRYPTO_ECC_MAX_BYTE_SIZE];
74 uint8_t myKGY[CY_CRYPTO_ECC_MAX_BYTE_SIZE];
75
76 const cy_stc_crypto_ecc_dp_type *eccDp;
77 uint32_t mallocMask = 0U;
78
79 /* NULL parameters checking */
80 if ((hash != NULL) && (sig != NULL) && (key != NULL) && (messageKey != NULL))
81 {
82 tmpResult = CY_CRYPTO_NOT_SUPPORTED;
83
84 eccDp = Cy_Crypto_Core_ECC_GetCurveParams(key->curveID);
85
86 if (eccDp != NULL)
87 {
88 uint32_t bitsize = eccDp->size;
89 uint32_t bytesize = CY_CRYPTO_BYTE_SIZE_OF_BITS(eccDp->size);
90 uint32_t datasize = hashlen;
91
92 /* make ephemeral key pair */
93 ephKey.pubkey.x = myKGX;
94 ephKey.pubkey.y = myKGY;
95
96 tmpResult = Cy_Crypto_Core_ECC_MakePublicKey(base, key->curveID, messageKey, &ephKey);
97
98 if (CY_CRYPTO_SUCCESS == tmpResult)
99 {
100 tmpResult = CY_CRYPTO_BAD_PARAMS;
101
102 uint32_t dividend = 0U; /* for whatever reason Crypto_EC_DivMod only works if dividend is in register 0 */
103 uint32_t p_temp = 8U;
104 uint32_t p_r = 9U;
105 uint32_t p_s = 10U;
106 uint32_t p_d = 11U;
107
108 /* load values needed for reduction modulo order of the base point */
109 CY_CRYPTO_VU_ALLOC_MEM (base, VR_P, bitsize);
110 Cy_Crypto_Core_Vu_SetMemValue (base, VR_P, (uint8_t *)eccDp->order, bitsize);
111
112 CY_CRYPTO_VU_ALLOC_MEM (base, VR_BARRETT, bitsize + 1U);
113 Cy_Crypto_Core_Vu_SetMemValue (base, VR_BARRETT, (uint8_t *)eccDp->barrett_o, bitsize);
114
115 CY_CRYPTO_VU_ALLOC_MEM (base, p_r, bitsize);
116 CY_CRYPTO_VU_ALLOC_MEM (base, p_s, bitsize);
117 Cy_Crypto_Core_Vu_SetMemValue (base, p_r, (uint8_t *)ephKey.pubkey.x, bitsize);
118
119 mallocMask = CY_CRYPTO_VU_REG_BIT(VR_P) | CY_CRYPTO_VU_REG_BIT(VR_BARRETT) |
120 CY_CRYPTO_VU_REG_BIT(p_r) | CY_CRYPTO_VU_REG_BIT(p_s);
121
122 if (!Cy_Crypto_Core_Vu_IsRegZero(base, p_r))
123 {
124 tmpResult = CY_CRYPTO_SUCCESS;
125
126 CY_CRYPTO_VU_ALLOC_MEM (base, p_temp, bitsize);
127 CY_CRYPTO_VU_ALLOC_MEM (base, p_d, datasize * 8u);
128
129 /* check that x1 is smaller than the order of the base point */
130 if (!Cy_Crypto_Core_Vu_IsRegLess(base, p_r, VR_P))
131 {
132 /* x1 >= order, needs reduction */
133 CY_CRYPTO_VU_MOV(base, p_temp, p_r);
134 Cy_Crypto_Core_Vu_WaitForComplete(base);
135
136 /* z = x % mod */
137 Cy_Crypto_Core_EC_Bar_MulRed(base, p_r, p_temp, bitsize);
138
139 /* r = x1 mod n */
140 Cy_Crypto_Core_Vu_GetMemValue (base, sig, p_r, bitsize);
141
142 if (Cy_Crypto_Core_Vu_IsRegZero(base, p_r))
143 {
144 /* R is zero!!! */
145 tmpResult = CY_CRYPTO_HW_ERROR;
146 }
147 }
148 else
149 {
150 /* carry is clear, i. e. x1 < order, r = x1 */
151 Cy_Crypto_Core_Vu_GetMemValue(base, sig, p_r, bitsize);
152 }
153
154 if (CY_CRYPTO_SUCCESS == tmpResult)
155 {
156 /* find s = (e + d*r)/k */
157 /* load signing private key */
158 Cy_Crypto_Core_Vu_SetMemValue (base, p_temp, (uint8_t *)key->k, bitsize);
159
160 /* use Barrett reduction algorithm for operations modulo n (order of the base point) */
161 Cy_Crypto_Core_EC_NistP_SetRedAlg(CY_CRYPTO_NIST_P_BARRETT_RED_ALG);
162
163 /* d*r mod n */
164 Cy_Crypto_Core_EC_MulMod(base, p_s, p_temp, p_r, bitsize); /* z = a * b % mod */
165
166 /* load message hash, truncate it if needed. */
167 Cy_Crypto_Core_Vu_SetMemValue (base, p_d, (uint8_t *)hash, datasize * 8u);
168 Cy_Crypto_Core_VU_RegInvertEndianness(base, p_d);
169
170 if ((datasize * 8u) > bitsize)
171 {
172 CY_CRYPTO_VU_SET_REG(base, dividend, (datasize * 8u) - bitsize, 1u);
173 CY_CRYPTO_VU_LSR(base, p_d, p_d, dividend);
174 }
175
176 /* check that the prepared hash value is smaller than the order of base point */
177 if (!Cy_Crypto_Core_Vu_IsRegLess(base, p_d, VR_P))
178 {
179 CY_CRYPTO_VU_MOV(base, p_temp, p_d);
180 Cy_Crypto_Core_Vu_WaitForComplete(base);
181
182 /* z = x % mod */
183 Cy_Crypto_Core_EC_Bar_MulRed(base, p_d, p_temp, bitsize);
184 }
185
186 /* Use p_r as temporary register */
187 Cy_Crypto_Core_Vu_SetMemValue (base, p_r, messageKey, bitsize);
188
189 /* e + d*r mod n */
190 Cy_Crypto_Core_EC_AddMod (base, p_s, p_d, p_s); /* z = a + b % mod */
191
192 /* (e + d*r)/k mod n */
193 CY_CRYPTO_VU_ALLOC_MEM (base, dividend, bitsize);
194
195 CY_CRYPTO_VU_MOV(base, dividend, p_s);
196 Cy_Crypto_Core_Vu_WaitForComplete(base);
197
198 /* z = a / b % mod */
199 Cy_Crypto_Core_EC_DivMod(base, p_s, dividend, p_r, bitsize);
200
201 CY_CRYPTO_VU_FREE_MEM(base, CY_CRYPTO_VU_REG_BIT(dividend));
202
203 if (!Cy_Crypto_Core_Vu_IsRegZero(base, p_s))
204 {
205 /* S is not zero!!! */
206 Cy_Crypto_Core_Vu_GetMemValue (base, &sig[bytesize], p_s, bitsize);
207 }
208 else
209 {
210 tmpResult = CY_CRYPTO_HW_ERROR;
211 }
212 }
213
214 CY_CRYPTO_VU_FREE_MEM(base, CY_CRYPTO_VU_REG_BIT(p_d) | CY_CRYPTO_VU_REG_BIT(p_temp));
215 }
216
217 CY_CRYPTO_VU_FREE_MEM(base, mallocMask);
218 }
219 }
220 }
221
222 return (tmpResult);
223 }
224
225
226 /*******************************************************************************
227 * Function Name: Cy_Crypto_Core_ECC_VerifyHash
228 ****************************************************************************//**
229 *
230 * Verify an ECC signature.
231 *
232 * \param base
233 * The pointer to a Crypto instance.
234 *
235 * \param sig
236 * The signature to verify, 'R' followed by 'S'.
237 *
238 * \param hash
239 * The hash (message digest) that was signed.
240 *
241 * \param hashlen
242 * The length of the hash (octets).
243 *
244 * \param stat
245 * Result of signature, 1==valid, 0==invalid.
246 *
247 * \param key
248 * The corresponding public ECC key. See \ref cy_stc_crypto_ecc_key.
249 *
250 * \return status code. See \ref cy_en_crypto_status_t.
251 *
252 *******************************************************************************/
Cy_Crypto_Core_ECC_VerifyHash(CRYPTO_Type * base,const uint8_t * sig,const uint8_t * hash,uint32_t hashlen,uint8_t * stat,const cy_stc_crypto_ecc_key * key)253 cy_en_crypto_status_t Cy_Crypto_Core_ECC_VerifyHash(CRYPTO_Type *base,
254 const uint8_t *sig, const uint8_t *hash, uint32_t hashlen,
255 uint8_t *stat, const cy_stc_crypto_ecc_key *key)
256 {
257 cy_en_crypto_status_t tmpResult = CY_CRYPTO_BAD_PARAMS;
258
259 const cy_stc_crypto_ecc_dp_type *eccDp;
260
261 uint32_t mallocMask = 0U;
262
263 /* NULL parameters checking */
264 if ((sig != NULL) && (hash != NULL) && (stat != NULL) && (key != NULL))
265 {
266 tmpResult = CY_CRYPTO_NOT_SUPPORTED;
267
268 eccDp = Cy_Crypto_Core_ECC_GetCurveParams(key->curveID);
269
270 if (eccDp != NULL)
271 {
272 tmpResult = CY_CRYPTO_SUCCESS;
273
274 uint32_t bitsize = eccDp->size;
275 uint32_t bytesize = CY_CRYPTO_BYTE_SIZE_OF_BITS(eccDp->size);
276 uint32_t datasize = hashlen;
277
278 uint32_t dividend = 0u; /* for whatever reason Crypto_EC_DivMod only works if dividend is in register 0 */
279 uint32_t p_r = 4U;
280 uint32_t p_s = 5U;
281 uint32_t p_u1 = 6U;
282 uint32_t p_u2 = 7U;
283 uint32_t p_o = 8U;
284 uint32_t p_gx = 9U;
285 uint32_t p_gy = 10U;
286 uint32_t p_qx = 11U;
287 uint32_t p_qy = 12U;
288
289 /* use Barrett reduction algorithm for operations modulo n (order of the base point) */
290 Cy_Crypto_Core_EC_NistP_SetRedAlg(CY_CRYPTO_NIST_P_BARRETT_RED_ALG);
291 Cy_Crypto_Core_EC_NistP_SetMode(bitsize);
292
293 /*******************************************************************************/
294 /* load values needed for reduction modulo order of the base point */
295 CY_CRYPTO_VU_ALLOC_MEM (base, VR_P, bitsize);
296 Cy_Crypto_Core_Vu_SetMemValue (base, VR_P, (uint8_t *)eccDp->order, bitsize);
297
298 CY_CRYPTO_VU_ALLOC_MEM (base, VR_BARRETT, bitsize + 1U);
299 Cy_Crypto_Core_Vu_SetMemValue (base, VR_BARRETT, (uint8_t *)eccDp->barrett_o, bitsize + 1U);
300
301 /*******************************************************************************/
302 /* check that R and S are within the valid range, i.e. 0 < R < n and 0 < S < n */
303 CY_CRYPTO_VU_ALLOC_MEM (base, p_r, bitsize);
304 CY_CRYPTO_VU_ALLOC_MEM (base, p_s, bitsize);
305 Cy_Crypto_Core_Vu_SetMemValue (base, p_r, (uint8_t *)sig, bitsize);
306 Cy_Crypto_Core_Vu_SetMemValue (base, p_s, (uint8_t *)&sig[bytesize], bitsize);
307
308 mallocMask = CY_CRYPTO_VU_REG_BIT(VR_P) | CY_CRYPTO_VU_REG_BIT(VR_BARRETT) |
309 CY_CRYPTO_VU_REG_BIT(p_r) | CY_CRYPTO_VU_REG_BIT(p_s);
310
311 /* Check R and S range */
312 if (Cy_Crypto_Core_Vu_IsRegZero(base, p_r))
313 {
314 /* R is zero!!! */
315 tmpResult = CY_CRYPTO_BAD_PARAMS;
316 }
317 if (!Cy_Crypto_Core_Vu_IsRegLess(base, p_r, VR_P))
318 {
319 /* R is not less than n!!! */
320 tmpResult = CY_CRYPTO_BAD_PARAMS;
321 }
322 if (Cy_Crypto_Core_Vu_IsRegZero(base, p_s))
323 {
324 /* S is zero!!! */
325 tmpResult = CY_CRYPTO_BAD_PARAMS;
326 }
327 if (!Cy_Crypto_Core_Vu_IsRegLess(base, p_s, VR_P))
328 {
329 /* S is not less than n!!! */
330 tmpResult = CY_CRYPTO_BAD_PARAMS;
331 }
332
333 if (CY_CRYPTO_SUCCESS == tmpResult)
334 {
335 CY_CRYPTO_VU_ALLOC_MEM (base, p_u1, bitsize);
336 CY_CRYPTO_VU_ALLOC_MEM (base, p_u2, bitsize);
337
338 CY_CRYPTO_VU_ALLOC_MEM (base, p_gx, bitsize);
339 CY_CRYPTO_VU_ALLOC_MEM (base, p_gy, bitsize);
340 CY_CRYPTO_VU_ALLOC_MEM (base, p_qx, bitsize);
341 CY_CRYPTO_VU_ALLOC_MEM (base, p_qy, bitsize);
342
343 mallocMask |= CY_CRYPTO_VU_REG_BIT(dividend) |
344 CY_CRYPTO_VU_REG_BIT(p_u1) | CY_CRYPTO_VU_REG_BIT(p_u2) |
345 CY_CRYPTO_VU_REG_BIT(p_gx) | CY_CRYPTO_VU_REG_BIT(p_gy) |
346 CY_CRYPTO_VU_REG_BIT(p_qx) | CY_CRYPTO_VU_REG_BIT(p_qy);
347
348 /* load message hash, truncate it if needed */
349 CY_CRYPTO_VU_SET_TO_ZERO(base, p_u1);
350
351 /* load message hash, truncate it if needed. */
352 CY_CRYPTO_VU_ALLOC_MEM (base, p_o, datasize * 8u);
353
354 CY_CRYPTO_VU_SET_TO_ZERO(base, p_o);
355 Cy_Crypto_Core_Vu_SetMemValue (base, p_o, (uint8_t *)hash, datasize * 8u);
356 Cy_Crypto_Core_VU_RegInvertEndianness(base, p_o);
357
358 if ((datasize * 8u) > bitsize)
359 {
360 CY_CRYPTO_VU_SET_REG(base, dividend, (datasize * 8u) - bitsize, 1u);
361 CY_CRYPTO_VU_LSR(base, p_o, p_o, dividend);
362 }
363
364 /* Use p_o as temporary register */
365 CY_CRYPTO_VU_MOV(base, p_u1, p_o);
366
367 CY_CRYPTO_VU_FREE_MEM(base, CY_CRYPTO_VU_REG_BIT(p_o));
368 CY_CRYPTO_VU_ALLOC_MEM (base, p_o, bitsize);
369 CY_CRYPTO_VU_ALLOC_MEM (base, dividend, bitsize);
370
371 /* check that the prepared hash value is smaller than the order of base point */
372 if (!Cy_Crypto_Core_Vu_IsRegLess(base, p_u1, VR_P))
373 {
374 /* Use p_o as temporary register */
375 CY_CRYPTO_VU_MOV(base, p_o, p_u1);
376 Cy_Crypto_Core_Vu_WaitForComplete(base);
377
378 /* z = x % mod */
379 Cy_Crypto_Core_EC_Bar_MulRed(base, p_u1, p_o, bitsize);
380 }
381
382 /* w = s^-1 mod n */
383 CY_CRYPTO_VU_SET_TO_ONE(base, dividend);
384 Cy_Crypto_Core_EC_DivMod(base, p_s, dividend, p_s, bitsize);
385
386 /* u1 = e*w mod n */
387 Cy_Crypto_Core_EC_MulMod(base, p_u1, p_u1, p_s, bitsize);
388
389 /* u2 = r*w mod n */
390 Cy_Crypto_Core_EC_MulMod(base, p_u2, p_r, p_s, bitsize);
391
392 /* Initialize point multiplication */
393 Cy_Crypto_Core_EC_NistP_SetRedAlg(eccDp->algo);
394
395 /* load prime, order and Barrett coefficient */
396 Cy_Crypto_Core_Vu_SetMemValue (base, VR_P, (uint8_t *)eccDp->prime, bitsize);
397 Cy_Crypto_Core_Vu_SetMemValue (base, VR_BARRETT, (uint8_t *)eccDp->barrett_p, bitsize + 1U);
398
399 /* load base Point G */
400 Cy_Crypto_Core_Vu_SetMemValue (base, p_gx, (uint8_t *)eccDp->Gx, bitsize);
401 Cy_Crypto_Core_Vu_SetMemValue (base, p_gy, (uint8_t *)eccDp->Gy, bitsize);
402
403 /* load public key Qa */
404 Cy_Crypto_Core_Vu_SetMemValue (base, p_qx, (uint8_t *)key->pubkey.x, bitsize);
405 Cy_Crypto_Core_Vu_SetMemValue (base, p_qy, (uint8_t *)key->pubkey.y, bitsize);
406
407 /* u1 * G */
408 Cy_Crypto_Core_EC_NistP_PointMul(base, p_gx, p_gy, p_u1, p_o, bitsize);
409
410 /* u2 * Qa */
411 Cy_Crypto_Core_EC_NistP_PointMul(base, p_qx, p_qy, p_u2, p_o, bitsize);
412
413 /* P = u1 * G + u2 * Qa. Only Px is needed */
414 Cy_Crypto_Core_EC_SubMod(base, dividend, p_qy, p_gy); /* (y2-y1) */
415 Cy_Crypto_Core_EC_SubMod(base, p_s, p_qx, p_gx); /* (x2-x1) */
416 Cy_Crypto_Core_EC_DivMod(base, p_s, dividend, p_s, bitsize); /* s = (y2-y1)/(x2-x1) */
417
418 Cy_Crypto_Core_EC_SquareMod (base, p_s, p_s, bitsize); /* s^2 */
419 Cy_Crypto_Core_EC_SubMod (base, p_s, p_s, p_gx); /* s^2 - x1 */
420 Cy_Crypto_Core_EC_SubMod (base, p_s, p_s, p_qx); /* s^2 - x1 - x2 which is Px mod n */
421
422 CY_CRYPTO_VU_FREE_MEM(base, CY_CRYPTO_VU_REG_BIT(p_o));
423
424 if (Cy_Crypto_Core_Vu_IsRegEqual(base, p_s, p_r))
425 {
426 *stat = 1u;
427 }
428 else
429 {
430 *stat = 0u;
431 }
432 }
433
434 CY_CRYPTO_VU_FREE_MEM(base, mallocMask);
435 }
436 }
437
438 return (tmpResult);
439 }
440
441 #if defined(__cplusplus)
442 }
443 #endif
444
445 #endif /* CY_IP_MXCRYPTO */
446
447
448 /* [] END OF FILE */
449