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