1662 lines
73 KiB
C
1662 lines
73 KiB
C
/******************************************************************************
|
|
* Filename: pka.c
|
|
* Revised: 2020-02-14 11:30:20 +0100 (Fri, 14 Feb 2020)
|
|
* Revision: 56760
|
|
*
|
|
* Description: Driver for the PKA module
|
|
*
|
|
* Copyright (c) 2015 - 2017, Texas Instruments Incorporated
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1) Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2) Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3) Neither the name of the ORGANIZATION nor the names of its contributors may
|
|
* be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "pka.h"
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Handle support for DriverLib in ROM:
|
|
// This section will undo prototype renaming made in the header file
|
|
//
|
|
//*****************************************************************************
|
|
#if !defined(DOXYGEN)
|
|
#undef PKAClearPkaRam
|
|
#define PKAClearPkaRam NOROM_PKAClearPkaRam
|
|
#undef PKAGetOpsStatus
|
|
#define PKAGetOpsStatus NOROM_PKAGetOpsStatus
|
|
#undef PKAArrayAllZeros
|
|
#define PKAArrayAllZeros NOROM_PKAArrayAllZeros
|
|
#undef PKAZeroOutArray
|
|
#define PKAZeroOutArray NOROM_PKAZeroOutArray
|
|
#undef PKABigNumModStart
|
|
#define PKABigNumModStart NOROM_PKABigNumModStart
|
|
#undef PKABigNumModGetResult
|
|
#define PKABigNumModGetResult NOROM_PKABigNumModGetResult
|
|
#undef PKABigNumDivideStart
|
|
#define PKABigNumDivideStart NOROM_PKABigNumDivideStart
|
|
#undef PKABigNumDivideGetQuotient
|
|
#define PKABigNumDivideGetQuotient NOROM_PKABigNumDivideGetQuotient
|
|
#undef PKABigNumDivideGetRemainder
|
|
#define PKABigNumDivideGetRemainder NOROM_PKABigNumDivideGetRemainder
|
|
#undef PKABigNumCmpStart
|
|
#define PKABigNumCmpStart NOROM_PKABigNumCmpStart
|
|
#undef PKABigNumCmpGetResult
|
|
#define PKABigNumCmpGetResult NOROM_PKABigNumCmpGetResult
|
|
#undef PKABigNumInvModStart
|
|
#define PKABigNumInvModStart NOROM_PKABigNumInvModStart
|
|
#undef PKABigNumInvModGetResult
|
|
#define PKABigNumInvModGetResult NOROM_PKABigNumInvModGetResult
|
|
#undef PKABigNumMultiplyStart
|
|
#define PKABigNumMultiplyStart NOROM_PKABigNumMultiplyStart
|
|
#undef PKABigNumMultGetResult
|
|
#define PKABigNumMultGetResult NOROM_PKABigNumMultGetResult
|
|
#undef PKABigNumAddStart
|
|
#define PKABigNumAddStart NOROM_PKABigNumAddStart
|
|
#undef PKABigNumAddGetResult
|
|
#define PKABigNumAddGetResult NOROM_PKABigNumAddGetResult
|
|
#undef PKABigNumSubStart
|
|
#define PKABigNumSubStart NOROM_PKABigNumSubStart
|
|
#undef PKABigNumSubGetResult
|
|
#define PKABigNumSubGetResult NOROM_PKABigNumSubGetResult
|
|
#undef PKAEccMultiplyStart
|
|
#define PKAEccMultiplyStart NOROM_PKAEccMultiplyStart
|
|
#undef PKAEccMontgomeryMultiplyStart
|
|
#define PKAEccMontgomeryMultiplyStart NOROM_PKAEccMontgomeryMultiplyStart
|
|
#undef PKAEccMultiplyGetResult
|
|
#define PKAEccMultiplyGetResult NOROM_PKAEccMultiplyGetResult
|
|
#undef PKAEccAddStart
|
|
#define PKAEccAddStart NOROM_PKAEccAddStart
|
|
#undef PKAEccAddGetResult
|
|
#define PKAEccAddGetResult NOROM_PKAEccAddGetResult
|
|
#undef PKAEccVerifyPublicKeyWeierstrassStart
|
|
#define PKAEccVerifyPublicKeyWeierstrassStart NOROM_PKAEccVerifyPublicKeyWeierstrassStart
|
|
#endif
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Handle support for DriverLib in ROM:
|
|
// This section will undo prototype renaming made in the header file
|
|
//
|
|
//*****************************************************************************
|
|
#if !defined(DOXYGEN)
|
|
#undef PKAClearPkaRam
|
|
#define PKAClearPkaRam NOROM_PKAClearPkaRam
|
|
#undef PKAGetOpsStatus
|
|
#define PKAGetOpsStatus NOROM_PKAGetOpsStatus
|
|
#undef PKAArrayAllZeros
|
|
#define PKAArrayAllZeros NOROM_PKAArrayAllZeros
|
|
#undef PKAZeroOutArray
|
|
#define PKAZeroOutArray NOROM_PKAZeroOutArray
|
|
#undef PKABigNumModStart
|
|
#define PKABigNumModStart NOROM_PKABigNumModStart
|
|
#undef PKABigNumModGetResult
|
|
#define PKABigNumModGetResult NOROM_PKABigNumModGetResult
|
|
#undef PKABigNumDivideStart
|
|
#define PKABigNumDivideStart NOROM_PKABigNumDivideStart
|
|
#undef PKABigNumDivideGetQuotient
|
|
#define PKABigNumDivideGetQuotient NOROM_PKABigNumDivideGetQuotient
|
|
#undef PKABigNumDivideGetRemainder
|
|
#define PKABigNumDivideGetRemainder NOROM_PKABigNumDivideGetRemainder
|
|
#undef PKABigNumCmpStart
|
|
#define PKABigNumCmpStart NOROM_PKABigNumCmpStart
|
|
#undef PKABigNumCmpGetResult
|
|
#define PKABigNumCmpGetResult NOROM_PKABigNumCmpGetResult
|
|
#undef PKABigNumInvModStart
|
|
#define PKABigNumInvModStart NOROM_PKABigNumInvModStart
|
|
#undef PKABigNumInvModGetResult
|
|
#define PKABigNumInvModGetResult NOROM_PKABigNumInvModGetResult
|
|
#undef PKABigNumMultiplyStart
|
|
#define PKABigNumMultiplyStart NOROM_PKABigNumMultiplyStart
|
|
#undef PKABigNumMultGetResult
|
|
#define PKABigNumMultGetResult NOROM_PKABigNumMultGetResult
|
|
#undef PKABigNumAddStart
|
|
#define PKABigNumAddStart NOROM_PKABigNumAddStart
|
|
#undef PKABigNumAddGetResult
|
|
#define PKABigNumAddGetResult NOROM_PKABigNumAddGetResult
|
|
#undef PKABigNumSubStart
|
|
#define PKABigNumSubStart NOROM_PKABigNumSubStart
|
|
#undef PKABigNumSubGetResult
|
|
#define PKABigNumSubGetResult NOROM_PKABigNumSubGetResult
|
|
#undef PKAEccMultiplyStart
|
|
#define PKAEccMultiplyStart NOROM_PKAEccMultiplyStart
|
|
#undef PKAEccMontgomeryMultiplyStart
|
|
#define PKAEccMontgomeryMultiplyStart NOROM_PKAEccMontgomeryMultiplyStart
|
|
#undef PKAEccMultiplyGetResult
|
|
#define PKAEccMultiplyGetResult NOROM_PKAEccMultiplyGetResult
|
|
#undef PKAEccAddStart
|
|
#define PKAEccAddStart NOROM_PKAEccAddStart
|
|
#undef PKAEccAddGetResult
|
|
#define PKAEccAddGetResult NOROM_PKAEccAddGetResult
|
|
#undef PKAEccVerifyPublicKeyWeierstrassStart
|
|
#define PKAEccVerifyPublicKeyWeierstrassStart NOROM_PKAEccVerifyPublicKeyWeierstrassStart
|
|
#endif
|
|
|
|
|
|
|
|
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
|
|
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
|
#define INRANGE(x,y,z) ((x) > (y) && (x) < (z))
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Define for the maximum curve size supported by the PKA module in 32 bit
|
|
// word.
|
|
// \note PKA hardware module can support up to 384 bit curve size due to the
|
|
// 2K of PKA RAM.
|
|
//
|
|
//*****************************************************************************
|
|
#define PKA_MAX_CURVE_SIZE_32_BIT_WORD 12
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Define for the maximum length of the big number supported by the PKA module
|
|
// in 32 bit word.
|
|
//
|
|
//*****************************************************************************
|
|
#define PKA_MAX_LEN_IN_32_BIT_WORD PKA_MAX_CURVE_SIZE_32_BIT_WORD
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Used in PKAWritePkaParam() and PKAWritePkaParamExtraOffset() to specify that
|
|
// the base address of the parameter should not be written to a NPTR register.
|
|
//
|
|
//*****************************************************************************
|
|
#define PKA_NO_POINTER_REG 0xFF
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// NIST P224 constants in little endian format. byte[0] is the least
|
|
// significant byte and byte[NISTP224_PARAM_SIZE_BYTES - 1] is the most
|
|
// significant.
|
|
//
|
|
//*****************************************************************************
|
|
const PKA_EccPoint224 NISTP224_generator = {
|
|
.x = {.byte = {0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34,
|
|
0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A,
|
|
0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B,
|
|
0xBD, 0x0C, 0x0E, 0xB7, }},
|
|
.y = {.byte = {0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44,
|
|
0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD,
|
|
0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5,
|
|
0x88, 0x63, 0x37, 0xBD, }},
|
|
};
|
|
|
|
const PKA_EccParam224 NISTP224_prime = {.byte = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF}};
|
|
|
|
const PKA_EccParam224 NISTP224_a = {.byte = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF}};
|
|
|
|
const PKA_EccParam224 NISTP224_b = {.byte = {0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27,
|
|
0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50,
|
|
0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C,
|
|
0x85, 0x0A, 0x05, 0xB4}};
|
|
|
|
const PKA_EccParam224 NISTP224_order = {.byte = {0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13,
|
|
0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF}};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// NIST P256 constants in little endian format. byte[0] is the least
|
|
// significant byte and byte[NISTP256_PARAM_SIZE_BYTES - 1] is the most
|
|
// significant.
|
|
//
|
|
//*****************************************************************************
|
|
const PKA_EccPoint256 NISTP256_generator = {
|
|
.x = {.byte = {0x96, 0xc2, 0x98, 0xd8, 0x45, 0x39, 0xa1, 0xf4,
|
|
0xa0, 0x33, 0xeb, 0x2d, 0x81, 0x7d, 0x03, 0x77,
|
|
0xf2, 0x40, 0xa4, 0x63, 0xe5, 0xe6, 0xbc, 0xf8,
|
|
0x47, 0x42, 0x2c, 0xe1, 0xf2, 0xd1, 0x17, 0x6b}},
|
|
.y = {.byte = {0xf5, 0x51, 0xbf, 0x37, 0x68, 0x40, 0xb6, 0xcb,
|
|
0xce, 0x5e, 0x31, 0x6b, 0x57, 0x33, 0xce, 0x2b,
|
|
0x16, 0x9e, 0x0f, 0x7c, 0x4a, 0xeb, 0xe7, 0x8e,
|
|
0x9b, 0x7f, 0x1a, 0xfe, 0xe2, 0x42, 0xe3, 0x4f}},
|
|
};
|
|
|
|
const PKA_EccParam256 NISTP256_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
|
|
|
|
const PKA_EccParam256 NISTP256_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
|
|
|
|
const PKA_EccParam256 NISTP256_b = {.byte = {0x4b, 0x60, 0xd2, 0x27, 0x3e, 0x3c, 0xce, 0x3b,
|
|
0xf6, 0xb0, 0x53, 0xcc, 0xb0, 0x06, 0x1d, 0x65,
|
|
0xbc, 0x86, 0x98, 0x76, 0x55, 0xbd, 0xeb, 0xb3,
|
|
0xe7, 0x93, 0x3a, 0xaa, 0xd8, 0x35, 0xc6, 0x5a}};
|
|
|
|
const PKA_EccParam256 NISTP256_order = {.byte = {0x51, 0x25, 0x63, 0xfc, 0xc2, 0xca, 0xb9, 0xf3,
|
|
0x84, 0x9e, 0x17, 0xa7, 0xad, 0xfa, 0xe6, 0xbc,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// NIST P384 constants in little endian format. byte[0] is the least
|
|
// significant byte and byte[NISTP384_PARAM_SIZE_BYTES - 1] is the most
|
|
// significant.
|
|
//
|
|
//*****************************************************************************
|
|
const PKA_EccPoint384 NISTP384_generator = {
|
|
.x = {.byte = {0xb7, 0x0a, 0x76, 0x72, 0x38, 0x5e, 0x54, 0x3a,
|
|
0x6c, 0x29, 0x55, 0xbf, 0x5d, 0xf2, 0x02, 0x55,
|
|
0x38, 0x2a, 0x54, 0x82, 0xe0, 0x41, 0xf7, 0x59,
|
|
0x98, 0x9b, 0xa7, 0x8b, 0x62, 0x3b, 0x1d, 0x6e,
|
|
0x74, 0xad, 0x20, 0xf3, 0x1e, 0xc7, 0xb1, 0x8e,
|
|
0x37, 0x05, 0x8b, 0xbe, 0x22, 0xca, 0x87, 0xaa}},
|
|
.y = {.byte = {0x5f, 0x0e, 0xea, 0x90, 0x7c, 0x1d, 0x43, 0x7a,
|
|
0x9d, 0x81, 0x7e, 0x1d, 0xce, 0xb1, 0x60, 0x0a,
|
|
0xc0, 0xb8, 0xf0, 0xb5, 0x13, 0x31, 0xda, 0xe9,
|
|
0x7c, 0x14, 0x9a, 0x28, 0xbd, 0x1d, 0xf4, 0xf8,
|
|
0x29, 0xdc, 0x92, 0x92, 0xbf, 0x98, 0x9e, 0x5d,
|
|
0x6f, 0x2c, 0x26, 0x96, 0x4a, 0xde, 0x17, 0x36,}},
|
|
};
|
|
|
|
const PKA_EccParam384 NISTP384_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
|
0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
|
|
|
const PKA_EccParam384 NISTP384_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
|
0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
|
|
|
const PKA_EccParam384 NISTP384_b = {.byte = {0xef, 0x2a, 0xec, 0xd3, 0xed, 0xc8, 0x85, 0x2a,
|
|
0x9d, 0xd1, 0x2e, 0x8a, 0x8d, 0x39, 0x56, 0xc6,
|
|
0x5a, 0x87, 0x13, 0x50, 0x8f, 0x08, 0x14, 0x03,
|
|
0x12, 0x41, 0x81, 0xfe, 0x6e, 0x9c, 0x1d, 0x18,
|
|
0x19, 0x2d, 0xf8, 0xe3, 0x6b, 0x05, 0x8e, 0x98,
|
|
0xe4, 0xe7, 0x3e, 0xe2, 0xa7, 0x2f, 0x31, 0xb3}};
|
|
|
|
const PKA_EccParam384 NISTP384_order = {.byte = {0x73, 0x29, 0xc5, 0xcc, 0x6a, 0x19, 0xec, 0xec,
|
|
0x7a, 0xa7, 0xb0, 0x48, 0xb2, 0x0d, 0x1a, 0x58,
|
|
0xdf, 0x2d, 0x37, 0xf4, 0x81, 0x4d, 0x63, 0xc7,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// NIST P521 constants in little endian format. byte[0] is the least
|
|
// significant byte and byte[NISTP521_PARAM_SIZE_BYTES - 1] is the most
|
|
// significant.
|
|
//
|
|
//*****************************************************************************
|
|
const PKA_EccPoint521 NISTP521_generator = {
|
|
.x = {.byte = {0x66, 0xbd, 0xe5, 0xc2, 0x31, 0x7e, 0x7e, 0xf9,
|
|
0x9b, 0x42, 0x6a, 0x85, 0xc1, 0xb3, 0x48, 0x33,
|
|
0xde, 0xa8, 0xff, 0xa2, 0x27, 0xc1, 0x1d, 0xfe,
|
|
0x28, 0x59, 0xe7, 0xef, 0x77, 0x5e, 0x4b, 0xa1,
|
|
0xba, 0x3d, 0x4d, 0x6b, 0x60, 0xaf, 0x28, 0xf8,
|
|
0x21, 0xb5, 0x3f, 0x05, 0x39, 0x81, 0x64, 0x9c,
|
|
0x42, 0xb4, 0x95, 0x23, 0x66, 0xcb, 0x3e, 0x9e,
|
|
0xcd, 0xe9, 0x04, 0x04, 0xb7, 0x06, 0x8e, 0x85,
|
|
0xc6, 0x00}},
|
|
.y = {.byte = {0x50, 0x66, 0xd1, 0x9f, 0x76, 0x94, 0xbe, 0x88,
|
|
0x40, 0xc2, 0x72, 0xa2, 0x86, 0x70, 0x3c, 0x35,
|
|
0x61, 0x07, 0xad, 0x3f, 0x01, 0xb9, 0x50, 0xc5,
|
|
0x40, 0x26, 0xf4, 0x5e, 0x99, 0x72, 0xee, 0x97,
|
|
0x2c, 0x66, 0x3e, 0x27, 0x17, 0xbd, 0xaf, 0x17,
|
|
0x68, 0x44, 0x9b, 0x57, 0x49, 0x44, 0xf5, 0x98,
|
|
0xd9, 0x1b, 0x7d, 0x2c, 0xb4, 0x5f, 0x8a, 0x5c,
|
|
0x04, 0xc0, 0x3b, 0x9a, 0x78, 0x6a, 0x29, 0x39,
|
|
0x18, 0x01}},
|
|
};
|
|
|
|
const PKA_EccParam521 NISTP521_prime = {.byte = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0x01}};
|
|
|
|
const PKA_EccParam521 NISTP521_a = {.byte = {0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0x01}};
|
|
|
|
const PKA_EccParam521 NISTP521_b = {.byte = {0x00, 0x3f, 0x50, 0x6b, 0xd4, 0x1f, 0x45, 0xef,
|
|
0xf1, 0x34, 0x2c, 0x3d, 0x88, 0xdf, 0x73, 0x35,
|
|
0x07, 0xbf, 0xb1, 0x3b, 0xbd, 0xc0, 0x52, 0x16,
|
|
0x7b, 0x93, 0x7e, 0xec, 0x51, 0x39, 0x19, 0x56,
|
|
0xe1, 0x09, 0xf1, 0x8e, 0x91, 0x89, 0xb4, 0xb8,
|
|
0xf3, 0x15, 0xb3, 0x99, 0x5b, 0x72, 0xda, 0xa2,
|
|
0xee, 0x40, 0x85, 0xb6, 0xa0, 0x21, 0x9a, 0x92,
|
|
0x1f, 0x9a, 0x1c, 0x8e, 0x61, 0xb9, 0x3e, 0x95,
|
|
0x51, 0x00}};
|
|
|
|
const PKA_EccParam521 NISTP521_order = {.byte = {0x09, 0x64, 0x38, 0x91, 0x1e, 0xb7, 0x6f, 0xbb,
|
|
0xae, 0x47, 0x9c, 0x89, 0xb8, 0xc9, 0xb5, 0x3b,
|
|
0xd0, 0xa5, 0x09, 0xf7, 0x48, 0x01, 0xcc, 0x7f,
|
|
0x6b, 0x96, 0x2f, 0xbf, 0x83, 0x87, 0x86, 0x51,
|
|
0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0x01}};
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Brainpool P256r1 constants in little endian format. byte[0] is the least
|
|
// significant byte and byte[BrainpoolP256R1_PARAM_SIZE_BYTES - 1] is the most
|
|
// significant.
|
|
//
|
|
//*****************************************************************************
|
|
const PKA_EccPoint256 BrainpoolP256R1_generator = {
|
|
.x = {.byte = {0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A,
|
|
0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9,
|
|
0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C,
|
|
0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B}},
|
|
.y = {.byte = {0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C,
|
|
0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2,
|
|
0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97,
|
|
0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54}},
|
|
};
|
|
|
|
const PKA_EccParam256 BrainpoolP256R1_prime = {.byte = {0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20,
|
|
0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E,
|
|
0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E,
|
|
0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9}};
|
|
|
|
const PKA_EccParam256 BrainpoolP256R1_a = {.byte = {0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9,
|
|
0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB,
|
|
0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE,
|
|
0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D}};
|
|
|
|
const PKA_EccParam256 BrainpoolP256R1_b = {.byte = {0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B,
|
|
0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95,
|
|
0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3,
|
|
0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26,}};
|
|
|
|
const PKA_EccParam256 BrainpoolP256R1_order = {.byte = {0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90,
|
|
0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C,
|
|
0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E,
|
|
0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9}};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Brainpool P384r1 constants in little endian format. byte[0] is the least
|
|
// significant byte and byte[BrainpoolP384R1_PARAM_SIZE_BYTES - 1] is the most
|
|
// significant.
|
|
//
|
|
//*****************************************************************************
|
|
const PKA_EccPoint384 BrainpoolP384R1_generator = {
|
|
.x = {.byte = {0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF,
|
|
0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8,
|
|
0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB,
|
|
0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88,
|
|
0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2,
|
|
0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D}},
|
|
.y = {.byte = {0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42,
|
|
0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E,
|
|
0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1,
|
|
0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62,
|
|
0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C,
|
|
0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A}},
|
|
};
|
|
|
|
const PKA_EccParam384 BrainpoolP384R1_prime = {.byte = {0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87,
|
|
0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC,
|
|
0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12,
|
|
0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15,
|
|
0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F,
|
|
0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C}};
|
|
|
|
const PKA_EccParam384 BrainpoolP384R1_a = {.byte = {0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04,
|
|
0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A,
|
|
0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13,
|
|
0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2,
|
|
0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C,
|
|
0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B}};
|
|
|
|
const PKA_EccParam384 BrainpoolP384R1_b = {.byte = {0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A,
|
|
0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C,
|
|
0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E,
|
|
0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F,
|
|
0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B,
|
|
0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04}};
|
|
|
|
const PKA_EccParam384 BrainpoolP384R1_order = {.byte = {0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B,
|
|
0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF,
|
|
0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F,
|
|
0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15,
|
|
0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F,
|
|
0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C}};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Brainpool P512r1 constants in little endian format. byte[0] is the least
|
|
// significant byte and byte[BrainpoolP512R1_PARAM_SIZE_BYTES - 1] is the most
|
|
// significant.
|
|
//
|
|
//*****************************************************************************
|
|
const PKA_EccPoint512 BrainpoolP512R1_generator = {
|
|
.x = {.byte = {0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B,
|
|
0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C,
|
|
0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50,
|
|
0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF,
|
|
0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4,
|
|
0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85,
|
|
0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A,
|
|
0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81}},
|
|
.y = {.byte = {0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78,
|
|
0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1,
|
|
0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B,
|
|
0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2,
|
|
0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0,
|
|
0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2,
|
|
0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0,
|
|
0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D}},
|
|
};
|
|
|
|
const PKA_EccParam512 BrainpoolP512R1_prime = {.byte = {0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28,
|
|
0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28,
|
|
0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE,
|
|
0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D,
|
|
0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6,
|
|
0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB,
|
|
0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F,
|
|
0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA}};
|
|
|
|
const PKA_EccParam512 BrainpoolP512R1_a = {.byte = {0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7,
|
|
0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F,
|
|
0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A,
|
|
0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D,
|
|
0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8,
|
|
0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94,
|
|
0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2,
|
|
0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78}};
|
|
|
|
const PKA_EccParam512 BrainpoolP512R1_b = {.byte = {0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28,
|
|
0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98,
|
|
0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77,
|
|
0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B,
|
|
0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B,
|
|
0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8,
|
|
0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA,
|
|
0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D}};
|
|
|
|
const PKA_EccParam512 BrainpoolP512R1_order = {.byte = {0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5,
|
|
0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D,
|
|
0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41,
|
|
0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55,
|
|
0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6,
|
|
0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB,
|
|
0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F,
|
|
0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA}};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Curve25519 constants in little endian format. byte[0] is the least
|
|
// significant byte and byte[Curve25519_PARAM_SIZE_BYTES - 1] is the most
|
|
// significant.
|
|
//
|
|
//*****************************************************************************
|
|
const PKA_EccPoint256 Curve25519_generator = {
|
|
.x = {.byte = {0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}},
|
|
.y = {.byte = {0xd9, 0xd3, 0xce, 0x7e, 0xa2, 0xc5, 0xe9, 0x29,
|
|
0xb2, 0x61, 0x7c, 0x6d, 0x7e, 0x4d, 0x3d, 0x92,
|
|
0x4c, 0xd1, 0x48, 0x77, 0x2c, 0xdd, 0x1e, 0xe0,
|
|
0xb4, 0x86, 0xa0, 0xb8, 0xa1, 0x19, 0xae, 0x20}},
|
|
};
|
|
|
|
const PKA_EccParam256 Curve25519_prime = {.byte = {0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}};
|
|
|
|
const PKA_EccParam256 Curve25519_a = {.byte = {0x06, 0x6d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
|
|
|
|
const PKA_EccParam256 Curve25519_b = {.byte = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
|
|
|
|
const PKA_EccParam256 Curve25519_order = {.byte = {0xb9, 0xdc, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
|
|
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}};
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Zeroize PKA RAM. Not threadsafe.
|
|
//
|
|
//*****************************************************************************
|
|
void PKAClearPkaRam(void){
|
|
// Get initial state
|
|
uint32_t secdmaclkgr = HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR);
|
|
|
|
// OR in zeroize bit
|
|
secdmaclkgr |= PRCM_SECDMACLKGR_PKA_ZERIOZE_RESET_N;
|
|
|
|
// Start zeroization
|
|
HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) = secdmaclkgr;
|
|
|
|
// Wait 256 cycles for PKA RAM to be cleared
|
|
CPUdelay(256 / 4);
|
|
|
|
// Turn off zeroization
|
|
HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) = secdmaclkgr & (~PRCM_SECDMACLKGR_PKA_ZERIOZE_RESET_N);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Write a PKA parameter to the PKA module, set required registers, and add an offset.
|
|
//
|
|
//*****************************************************************************
|
|
static uint32_t PKAWritePkaParam(const uint8_t *param, uint32_t paramLength, uint32_t paramOffset, uint32_t ptrRegOffset)
|
|
{
|
|
uint32_t i;
|
|
uint32_t *paramWordAlias = (uint32_t *)param;
|
|
// Take the floor of paramLength in 32-bit words
|
|
uint32_t paramLengthInWords = paramLength / sizeof(uint32_t);
|
|
|
|
// Only copy data if it is specified. We may wish to simply allocate another buffer and get
|
|
// the required offset.
|
|
if (param) {
|
|
// Load the number in PKA RAM
|
|
for (i = 0; i < paramLengthInWords; i++) {
|
|
HWREG(PKA_RAM_BASE + paramOffset + sizeof(uint32_t) * i) = paramWordAlias[i];
|
|
}
|
|
|
|
// If the length is not a word-multiple, fill up a temporary word and copy that in
|
|
// to avoid a bus error. The extra zeros at the end should not matter, as the large
|
|
// number is little-endian and thus has no effect.
|
|
// We could have correctly calculated ceiling(paramLength / sizeof(uint32_t)) above.
|
|
// However, we would not have been able to zero-out the extra few most significant
|
|
// bytes of the most significant word. That would have resulted in doing maths operations
|
|
// on whatever follows param in RAM.
|
|
if (paramLength % sizeof(uint32_t)) {
|
|
uint32_t temp = 0;
|
|
uint8_t j;
|
|
|
|
// Load the entire word line of the param remainder
|
|
temp = paramWordAlias[i];
|
|
|
|
// Zero-out all bytes beyond the end of the param
|
|
for (j = paramLength % sizeof(uint32_t); j < sizeof(uint32_t); j++) {
|
|
((uint8_t *)&temp)[j] = 0;
|
|
}
|
|
|
|
HWREG(PKA_RAM_BASE + paramOffset + sizeof(uint32_t) * i) = temp;
|
|
|
|
// Increment paramLengthInWords since we take the ceiling of length / sizeof(uint32_t)
|
|
paramLengthInWords++;
|
|
}
|
|
}
|
|
|
|
// Update the A, B, C, or D pointer with the offset address of the PKA RAM location
|
|
// where the number will be stored.
|
|
switch (ptrRegOffset) {
|
|
case PKA_O_APTR:
|
|
HWREG(PKA_BASE + PKA_O_APTR) = paramOffset >> 2;
|
|
HWREG(PKA_BASE + PKA_O_ALENGTH) = paramLengthInWords;
|
|
break;
|
|
case PKA_O_BPTR:
|
|
HWREG(PKA_BASE + PKA_O_BPTR) = paramOffset >> 2;
|
|
HWREG(PKA_BASE + PKA_O_BLENGTH) = paramLengthInWords;
|
|
break;
|
|
case PKA_O_CPTR:
|
|
HWREG(PKA_BASE + PKA_O_CPTR) = paramOffset >> 2;
|
|
break;
|
|
case PKA_O_DPTR:
|
|
HWREG(PKA_BASE + PKA_O_DPTR) = paramOffset >> 2;
|
|
break;
|
|
}
|
|
|
|
// Ensure 8-byte alignment of next parameter.
|
|
// Returns the offset for the next parameter.
|
|
return paramOffset + sizeof(uint32_t) * (paramLengthInWords + (paramLengthInWords % 2));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Write a PKA parameter to the PKA module but return a larger offset.
|
|
//
|
|
//*****************************************************************************
|
|
static uint32_t PKAWritePkaParamExtraOffset(const uint8_t *param, uint32_t paramLength, uint32_t paramOffset, uint32_t ptrRegOffset)
|
|
{
|
|
// Ensure 16-byte alignment.
|
|
return (sizeof(uint32_t) * 2) + PKAWritePkaParam(param, paramLength, paramOffset, ptrRegOffset);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Writes the result of a large number arithmetic operation to a provided buffer.
|
|
//
|
|
//*****************************************************************************
|
|
static uint32_t PKAGetBigNumResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
|
|
{
|
|
uint32_t mswOffset;
|
|
uint32_t lswOffset;
|
|
uint32_t lengthInWords;
|
|
uint32_t i;
|
|
uint32_t *resultWordAlias = (uint32_t *)resultBuf;
|
|
|
|
// Check the arguments.
|
|
ASSERT(resultBuf);
|
|
ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
|
|
(resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
|
|
|
|
// Verify that the operation is complete.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
// Get the MSW register value.
|
|
mswOffset = HWREG(PKA_BASE + PKA_O_MSW);
|
|
|
|
// If the result vector is zero, write back one zero byte so the caller does not need
|
|
// to handle a special error for the perhaps valid result of zero.
|
|
// They will only get the error status if they do not provide a buffer
|
|
if (mswOffset & PKA_MSW_RESULT_IS_ZERO_M) {
|
|
if (*resultLength){
|
|
if(resultBuf){
|
|
resultBuf[0] = 0;
|
|
}
|
|
|
|
*resultLength = 1;
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
return PKA_STATUS_BUF_UNDERFLOW;
|
|
}
|
|
}
|
|
|
|
// Get the length of the result
|
|
mswOffset = ((mswOffset & PKA_MSW_MSW_ADDRESS_M) + 1);
|
|
lswOffset = ((resultPKAMemAddr - PKA_RAM_BASE) >> 2);
|
|
|
|
if (mswOffset >= lswOffset) {
|
|
lengthInWords = mswOffset - lswOffset;
|
|
}
|
|
else {
|
|
return PKA_STATUS_RESULT_ADDRESS_INCORRECT;
|
|
}
|
|
|
|
// Check if the provided buffer length is adequate to store the result data.
|
|
if (*resultLength < lengthInWords * sizeof(uint32_t)) {
|
|
return PKA_STATUS_BUF_UNDERFLOW;
|
|
}
|
|
|
|
// Copy the resultant length.
|
|
*resultLength = lengthInWords * sizeof(uint32_t);
|
|
|
|
|
|
if (resultBuf) {
|
|
// Copy the result into the resultBuf.
|
|
for (i = 0; i < lengthInWords; i++) {
|
|
resultWordAlias[i]= HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
|
|
}
|
|
}
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Retrieve the result of a modulo operation or the remainder of a division.
|
|
//
|
|
//*****************************************************************************
|
|
static uint32_t PKAGetBigNumResultRemainder(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
|
|
{
|
|
uint32_t regMSWVal;
|
|
uint32_t lengthInWords;
|
|
uint32_t i;
|
|
uint32_t *resultWordAlias = (uint32_t *)resultBuf;
|
|
|
|
// Check the arguments.
|
|
ASSERT(resultBuf);
|
|
ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
|
|
(resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
|
|
|
|
// Verify that the operation is complete.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
// Get the MSW register value.
|
|
regMSWVal = HWREG(PKA_BASE + PKA_O_DIVMSW);
|
|
|
|
// If the result vector is zero, write back one zero byte so the caller does not need
|
|
// to handle a special error for the perhaps valid result of zero.
|
|
// They will only get the error status if they do not provide a buffer
|
|
if (regMSWVal & PKA_DIVMSW_RESULT_IS_ZERO_M) {
|
|
if (*resultLength){
|
|
if(resultBuf){
|
|
resultBuf[0] = 0;
|
|
}
|
|
|
|
*resultLength = 1;
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
return PKA_STATUS_BUF_UNDERFLOW;
|
|
}
|
|
}
|
|
|
|
// Get the length of the result
|
|
lengthInWords = ((regMSWVal & PKA_DIVMSW_MSW_ADDRESS_M) + 1) - ((resultPKAMemAddr - PKA_RAM_BASE) >> 2);
|
|
|
|
// Check if the provided buffer length is adequate to store the result data.
|
|
if (*resultLength < lengthInWords * sizeof(uint32_t)) {
|
|
return PKA_STATUS_BUF_UNDERFLOW;
|
|
}
|
|
|
|
// Copy the resultant length.
|
|
*resultLength = lengthInWords * sizeof(uint32_t);
|
|
|
|
if (resultBuf) {
|
|
// Copy the result into the resultBuf.
|
|
for (i = 0; i < lengthInWords; i++) {
|
|
resultWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
|
|
}
|
|
}
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Writes the resultant curve point of an ECC operation to the provided buffer.
|
|
//
|
|
//*****************************************************************************
|
|
static uint32_t PKAGetECCResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
|
|
{
|
|
uint32_t i = 0;
|
|
uint32_t *xWordAlias = (uint32_t *)curvePointX;
|
|
uint32_t *yWordAlias = (uint32_t *)curvePointY;
|
|
uint32_t lengthInWordsCeiling = 0;
|
|
|
|
// Check for the arguments.
|
|
ASSERT(curvePointX);
|
|
ASSERT(curvePointY);
|
|
ASSERT((resultPKAMemAddr > PKA_RAM_BASE) &&
|
|
(resultPKAMemAddr < (PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE)));
|
|
|
|
// Verify that the operation is completed.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
if (HWREG(PKA_BASE + PKA_O_SHIFT)) {
|
|
return PKA_STATUS_FAILURE;
|
|
}
|
|
|
|
// Check to make sure that the result vector is not the point at infinity.
|
|
if (HWREG(PKA_BASE + PKA_O_MSW) & PKA_MSW_RESULT_IS_ZERO) {
|
|
return PKA_STATUS_POINT_AT_INFINITY;
|
|
}
|
|
|
|
if (curvePointX != NULL) {
|
|
// Copy the x co-ordinate value of the result from vector D into
|
|
// the curvePoint.
|
|
for (i = 0; i < (length / sizeof(uint32_t)); i++) {
|
|
xWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
|
|
}
|
|
|
|
// If the length is not a word-multiple, fill up a temporary word and copy that in
|
|
// to avoid a bus error.
|
|
if (length % sizeof(uint32_t)) {
|
|
uint32_t temp = 0;
|
|
uint8_t j;
|
|
|
|
// Load the entire word line of the coordinate remainder
|
|
temp = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
|
|
|
|
// Write all remaining bytes to the coordinate
|
|
for (j = 0; j < length % sizeof(uint32_t); j++) {
|
|
curvePointX[i * sizeof(uint32_t) + j] = ((uint8_t *)&temp)[j];
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
lengthInWordsCeiling = (length % sizeof(uint32_t)) ? length / sizeof(uint32_t) + 1 : length / sizeof(uint32_t);
|
|
|
|
resultPKAMemAddr += sizeof(uint32_t) * (2 + lengthInWordsCeiling + (lengthInWordsCeiling % 2));
|
|
|
|
if (curvePointY != NULL) {
|
|
// Copy the y co-ordinate value of the result from vector D into
|
|
// the curvePoint.
|
|
for (i = 0; i < (length / sizeof(uint32_t)); i++) {
|
|
yWordAlias[i] = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
|
|
}
|
|
|
|
// If the length is not a word-multiple, fill up a temporary word and copy that in
|
|
// to avoid a bus error.
|
|
if (length % sizeof(uint32_t)) {
|
|
uint32_t temp = 0;
|
|
uint8_t j;
|
|
|
|
// Load the entire word line of the coordinate remainder
|
|
temp = HWREG(resultPKAMemAddr + sizeof(uint32_t) * i);
|
|
|
|
// Write all remaining bytes to the coordinate
|
|
for (j = 0; j < length % sizeof(uint32_t); j++) {
|
|
curvePointY[i * sizeof(uint32_t) + j] = ((uint8_t *)&temp)[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Provides the PKA operation status.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKAGetOpsStatus(void)
|
|
{
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN_M) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
else {
|
|
return PKA_STATUS_OPERATION_RDY;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Check if an array consists only of zeros.
|
|
//
|
|
//*****************************************************************************
|
|
bool PKAArrayAllZeros(const uint8_t *array, uint32_t arrayLength)
|
|
{
|
|
uint32_t i;
|
|
uint8_t arrayBits = 0;
|
|
|
|
// We could speed things up by comparing word-wise rather than byte-wise.
|
|
// However, this extra overhead is inconsequential compared to running an
|
|
// actual PKA operation. Especially ECC operations.
|
|
for (i = 0; i < arrayLength; i++) {
|
|
arrayBits |= array[i];
|
|
}
|
|
|
|
if (arrayBits) {
|
|
return false;
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Fill an array with zeros
|
|
//
|
|
//*****************************************************************************
|
|
void PKAZeroOutArray(const uint8_t *array, uint32_t arrayLength)
|
|
{
|
|
uint32_t i;
|
|
// Take the floor of paramLength in 32-bit words
|
|
uint32_t arrayLengthInWords = arrayLength / sizeof(uint32_t);
|
|
|
|
// Zero-out the array word-wise until i >= arrayLength
|
|
for (i = 0; i < arrayLengthInWords * sizeof(uint32_t); i += 4) {
|
|
HWREG(array + i) = 0;
|
|
}
|
|
|
|
// If i != arrayLength, there are some remaining bytes to zero-out
|
|
if (arrayLength % sizeof(uint32_t)) {
|
|
// Subtract 4 from i, since i has already overshot the array
|
|
for (i -= 4; i < arrayLength; i++) {
|
|
HWREGB(array + i * sizeof(uint32_t));
|
|
}
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start the big number modulus operation.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumModStart(const uint8_t *bigNum, uint32_t bigNumLength, const uint8_t *modulus, uint32_t modulusLength, uint32_t *resultPKAMemAddr)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check the arguments.
|
|
ASSERT(bigNum);
|
|
ASSERT(modulus);
|
|
ASSERT(resultPKAMemAddr);
|
|
|
|
// Make sure no operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParam(bigNum, bigNumLength, offset, PKA_O_APTR);
|
|
|
|
offset = PKAWritePkaParamExtraOffset(modulus, modulusLength, offset, PKA_O_BPTR);
|
|
|
|
// Copy the result vector address location.
|
|
*resultPKAMemAddr = PKA_RAM_BASE + offset;
|
|
|
|
// Load C pointer with the result location in PKA RAM
|
|
HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
|
|
|
|
// Start the PKCP modulo operation by setting the PKA Function register.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MODULO);
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the result of the big number modulus operation.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumModGetResult(uint8_t *resultBuf, uint32_t length, uint32_t resultPKAMemAddr)
|
|
{
|
|
// Zero-out array in case modulo result is shorter than length
|
|
PKAZeroOutArray(resultBuf, length);
|
|
|
|
return PKAGetBigNumResultRemainder(resultBuf, &length, resultPKAMemAddr);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start the big number divide operation.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumDivideStart(const uint8_t *dividend, uint32_t dividendLength, const uint8_t *divisor, uint32_t divisorLength, uint32_t *resultQuotientMemAddr, uint32_t *resultRemainderMemAddr)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check the arguments.
|
|
ASSERT(dividend);
|
|
ASSERT(divisor);
|
|
ASSERT(resultQuotientMemAddr);
|
|
ASSERT(resultRemainderMemAddr);
|
|
|
|
// Make sure no operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParam(dividend, dividendLength, offset, PKA_O_APTR);
|
|
|
|
offset = PKAWritePkaParamExtraOffset(divisor, divisorLength, offset, PKA_O_BPTR);
|
|
|
|
// Copy the remainder result vector address location.
|
|
if (resultRemainderMemAddr) {
|
|
*resultRemainderMemAddr = PKA_RAM_BASE + offset;
|
|
}
|
|
|
|
// The remainder cannot ever be larger than the divisor. It should fit inside
|
|
// a buffer of that size.
|
|
offset = PKAWritePkaParamExtraOffset(0, divisorLength, offset, PKA_O_CPTR);
|
|
|
|
// Copy the remainder result vector address location.
|
|
if (resultQuotientMemAddr) {
|
|
*resultQuotientMemAddr = PKA_RAM_BASE + offset;
|
|
}
|
|
|
|
// Load D pointer with the quotient location in PKA RAM
|
|
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
|
|
|
|
// Start the PKCP modulo operation by setting the PKA Function register.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_DIVIDE);
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the quotient of the big number divide operation.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumDivideGetQuotient(uint8_t *resultBuf, uint32_t *length, uint32_t resultQuotientMemAddr)
|
|
{
|
|
return PKAGetBigNumResult(resultBuf, length, resultQuotientMemAddr);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the remainder of the big number divide operation.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumDivideGetRemainder(uint8_t *resultBuf, uint32_t *length, uint32_t resultQuotientMemAddr)
|
|
{
|
|
return PKAGetBigNumResultRemainder(resultBuf, length, resultQuotientMemAddr);
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start the comparison of two big numbers.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumCmpStart(const uint8_t *bigNum1, const uint8_t *bigNum2, uint32_t length)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check the arguments.
|
|
ASSERT(bigNum1);
|
|
ASSERT(bigNum2);
|
|
|
|
// Make sure no operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParam(bigNum1, length, offset, PKA_O_APTR);
|
|
|
|
offset = PKAWritePkaParam(bigNum2, length, offset, PKA_O_BPTR);
|
|
|
|
// Set the PKA Function register for the Compare operation
|
|
// and start the operation.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_COMPARE);
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the result of the comparison operation of two big numbers.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumCmpGetResult(void)
|
|
{
|
|
uint32_t status;
|
|
|
|
// verify that the operation is complete.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
// Check the COMPARE register.
|
|
switch(HWREG(PKA_BASE + PKA_O_COMPARE)) {
|
|
case PKA_COMPARE_A_EQUALS_B:
|
|
status = PKA_STATUS_EQUAL;
|
|
break;
|
|
|
|
case PKA_COMPARE_A_GREATER_THAN_B:
|
|
status = PKA_STATUS_A_GREATER_THAN_B;
|
|
break;
|
|
|
|
case PKA_COMPARE_A_LESS_THAN_B:
|
|
status = PKA_STATUS_A_LESS_THAN_B;
|
|
break;
|
|
|
|
default:
|
|
status = PKA_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start the big number inverse modulo operation.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumInvModStart(const uint8_t *bigNum, uint32_t bigNumLength, const uint8_t *modulus, uint32_t modulusLength, uint32_t *resultPKAMemAddr)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check the arguments.
|
|
ASSERT(bigNum);
|
|
ASSERT(modulus);
|
|
ASSERT(resultPKAMemAddr);
|
|
|
|
// Make sure no operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParam(bigNum, bigNumLength, offset, PKA_O_APTR);
|
|
|
|
offset = PKAWritePkaParam(modulus, modulusLength, offset, PKA_O_BPTR);
|
|
|
|
// Copy the result vector address location.
|
|
*resultPKAMemAddr = PKA_RAM_BASE + offset;
|
|
|
|
// Load D pointer with the result location in PKA RAM.
|
|
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
|
|
|
|
// set the PKA function to InvMod operation and the start the operation.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION) = 0x0000F000;
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the result of the big number inverse modulo operation.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumInvModGetResult(uint8_t *resultBuf, uint32_t length, uint32_t resultPKAMemAddr)
|
|
{
|
|
// Zero-out array in case modulo result is shorter than length
|
|
PKAZeroOutArray(resultBuf, length);
|
|
|
|
return PKAGetBigNumResult(resultBuf, &length, resultPKAMemAddr);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start the big number multiplication.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumMultiplyStart(const uint8_t *multiplicand, uint32_t multiplicandLength, const uint8_t *multiplier, uint32_t multiplierLength, uint32_t *resultPKAMemAddr)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check for the arguments.
|
|
ASSERT(multiplicand);
|
|
ASSERT(multiplier);
|
|
ASSERT(resultPKAMemAddr);
|
|
|
|
// Make sure no operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParam(multiplicand, multiplicandLength, offset, PKA_O_APTR);
|
|
|
|
offset = PKAWritePkaParam(multiplier, multiplierLength, offset, PKA_O_BPTR);
|
|
|
|
|
|
// Copy the result vector address location.
|
|
*resultPKAMemAddr = PKA_RAM_BASE + offset;
|
|
|
|
// Load C pointer with the result location in PKA RAM.
|
|
HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
|
|
|
|
// Set the PKA function to the multiplication and start it.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MULTIPLY);
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the results of the big number multiplication.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumMultGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
|
|
{
|
|
return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start the addition of two big number.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumAddStart(const uint8_t *bigNum1, uint32_t bigNum1Length, const uint8_t *bigNum2, uint32_t bigNum2Length, uint32_t *resultPKAMemAddr)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check for arguments.
|
|
ASSERT(bigNum1);
|
|
ASSERT(bigNum2);
|
|
ASSERT(resultPKAMemAddr);
|
|
|
|
// Make sure no operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParam(bigNum1, bigNum1Length, offset, PKA_O_APTR);
|
|
|
|
offset = PKAWritePkaParam(bigNum2, bigNum2Length, offset, PKA_O_BPTR);
|
|
|
|
// Copy the result vector address location.
|
|
*resultPKAMemAddr = PKA_RAM_BASE + offset;
|
|
|
|
// Load C pointer with the result location in PKA RAM.
|
|
HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
|
|
|
|
// Set the function for the add operation and start the operation.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_ADD);
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the result of the addition operation on two big number.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumSubGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
|
|
{
|
|
return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start the addition of two big number.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumSubStart(const uint8_t *minuend, uint32_t minuendLength, const uint8_t *subtrahend, uint32_t subtrahendLength, uint32_t *resultPKAMemAddr)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check for arguments.
|
|
ASSERT(minuend);
|
|
ASSERT(subtrahend);
|
|
ASSERT(resultPKAMemAddr);
|
|
|
|
|
|
// Make sure no operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParam(minuend, minuendLength, offset, PKA_O_APTR);
|
|
|
|
offset = PKAWritePkaParam(subtrahend, subtrahendLength, offset, PKA_O_BPTR);
|
|
|
|
// Copy the result vector address location.
|
|
*resultPKAMemAddr = PKA_RAM_BASE + offset;
|
|
|
|
// Load C pointer with the result location in PKA RAM.
|
|
HWREG(PKA_BASE + PKA_O_CPTR) = offset >> 2;
|
|
|
|
// Set the function for the add operation and start the operation.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_SUBTRACT);
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the result of the addition operation on two big number.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKABigNumAddGetResult(uint8_t *resultBuf, uint32_t *resultLength, uint32_t resultPKAMemAddr)
|
|
{
|
|
return PKAGetBigNumResult(resultBuf, resultLength, resultPKAMemAddr);
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start ECC Multiplication.
|
|
//
|
|
//*****************************************************************************
|
|
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)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check for the arguments.
|
|
ASSERT(scalar);
|
|
ASSERT(curvePointX);
|
|
ASSERT(curvePointY);
|
|
ASSERT(prime);
|
|
ASSERT(a);
|
|
ASSERT(b);
|
|
ASSERT(length <= PKA_MAX_CURVE_SIZE_32_BIT_WORD * sizeof(uint32_t));
|
|
ASSERT(resultPKAMemAddr);
|
|
|
|
// Make sure no PKA operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParam(scalar, length, offset, PKA_O_APTR);
|
|
|
|
offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
|
|
offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
|
|
offset = PKAWritePkaParamExtraOffset(b, length, offset, PKA_NO_POINTER_REG);
|
|
|
|
offset = PKAWritePkaParamExtraOffset(curvePointX, length, offset, PKA_O_CPTR);
|
|
offset = PKAWritePkaParamExtraOffset(curvePointY, length, offset, PKA_NO_POINTER_REG);
|
|
|
|
// Update the result location.
|
|
// The resultPKAMemAddr may be 0 if we only want to check that we generated the point at infinity
|
|
if (resultPKAMemAddr) {
|
|
*resultPKAMemAddr = PKA_RAM_BASE + offset;
|
|
}
|
|
|
|
// Load D pointer with the result location in PKA RAM.
|
|
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
|
|
|
|
// Set the PKA function to ECC-MULT and start the operation.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION) = PKA_FUNCTION_RUN_M | (0x05 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start ECC Montgomery Multiplication.
|
|
//
|
|
//*****************************************************************************
|
|
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)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check for the arguments.
|
|
ASSERT(scalar);
|
|
ASSERT(curvePointX);
|
|
ASSERT(prime);
|
|
ASSERT(a);
|
|
ASSERT(length <= PKA_MAX_CURVE_SIZE_32_BIT_WORD * sizeof(uint32_t));
|
|
ASSERT(resultPKAMemAddr);
|
|
|
|
// Make sure no PKA operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParam(scalar, length, offset, PKA_O_APTR);
|
|
|
|
offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
|
|
offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
|
|
|
|
offset = PKAWritePkaParamExtraOffset(curvePointX, length, offset, PKA_O_CPTR);
|
|
|
|
// Update the result location.
|
|
// The resultPKAMemAddr may be 0 if we only want to check that we generated the point at infinity
|
|
if (resultPKAMemAddr) {
|
|
*resultPKAMemAddr = PKA_RAM_BASE + offset;
|
|
}
|
|
|
|
// Load D pointer with the result location in PKA RAM.
|
|
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
|
|
|
|
// Set the PKA function to Montgomery ECC-MULT and start the operation.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION) = PKA_FUNCTION_RUN_M | (0x02 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the result of ECC Multiplication
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKAEccMultiplyGetResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
|
|
{
|
|
return PKAGetECCResult(curvePointX, curvePointY, resultPKAMemAddr, length);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Start the ECC Addition.
|
|
//
|
|
//*****************************************************************************
|
|
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)
|
|
{
|
|
uint32_t offset = 0;
|
|
|
|
// Check for the arguments.
|
|
ASSERT(curvePoint1X);
|
|
ASSERT(curvePoint1Y);
|
|
ASSERT(curvePoint2X);
|
|
ASSERT(curvePoint2Y);
|
|
ASSERT(prime);
|
|
ASSERT(a);
|
|
ASSERT(resultPKAMemAddr);
|
|
|
|
// Make sure no operation is in progress.
|
|
if (HWREG(PKA_BASE + PKA_O_FUNCTION) & PKA_FUNCTION_RUN) {
|
|
return PKA_STATUS_OPERATION_BUSY;
|
|
}
|
|
|
|
offset = PKAWritePkaParamExtraOffset(curvePoint1X, length, offset, PKA_O_APTR);
|
|
offset = PKAWritePkaParamExtraOffset(curvePoint1Y, length, offset, PKA_NO_POINTER_REG);
|
|
|
|
|
|
offset = PKAWritePkaParamExtraOffset(prime, length, offset, PKA_O_BPTR);
|
|
offset = PKAWritePkaParamExtraOffset(a, length, offset, PKA_NO_POINTER_REG);
|
|
|
|
offset = PKAWritePkaParamExtraOffset(curvePoint2X, length, offset, PKA_O_CPTR);
|
|
offset = PKAWritePkaParamExtraOffset(curvePoint2Y, length, offset, PKA_NO_POINTER_REG);
|
|
|
|
// Copy the result vector location.
|
|
*resultPKAMemAddr = PKA_RAM_BASE + offset;
|
|
|
|
// Load D pointer with the result location in PKA RAM.
|
|
HWREG(PKA_BASE + PKA_O_DPTR) = offset >> 2;
|
|
|
|
// Set the PKA Function to ECC-ADD and start the operation.
|
|
HWREG(PKA_BASE + PKA_O_FUNCTION ) = PKA_FUNCTION_RUN_M | (0x03 << PKA_FUNCTION_SEQUENCER_OPERATIONS_S);
|
|
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Get the result of the ECC Addition
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t PKAEccAddGetResult(uint8_t *curvePointX, uint8_t *curvePointY, uint32_t resultPKAMemAddr, uint32_t length)
|
|
{
|
|
return PKAGetECCResult(curvePointX, curvePointY, resultPKAMemAddr, length);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Verify a public key against the supplied elliptic curve equation
|
|
//
|
|
//*****************************************************************************
|
|
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)
|
|
{
|
|
uint32_t pkaResult;
|
|
uint32_t resultAddress;
|
|
uint32_t resultLength;
|
|
uint8_t *scratchBuffer = (uint8_t *)(PKA_RAM_BASE + PKA_RAM_TOT_BYTE_SIZE / 2);
|
|
uint8_t *scratchBuffer2 = scratchBuffer + 512;
|
|
|
|
|
|
// Verify X in range [0, prime - 1]
|
|
PKABigNumCmpStart(curvePointX,
|
|
prime,
|
|
length);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
pkaResult = PKABigNumCmpGetResult();
|
|
|
|
if (pkaResult != PKA_STATUS_A_LESS_THAN_B) {
|
|
return PKA_STATUS_X_LARGER_THAN_PRIME;
|
|
}
|
|
|
|
// Verify Y in range [0, prime - 1]
|
|
PKABigNumCmpStart(curvePointY,
|
|
prime,
|
|
length);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
pkaResult = PKABigNumCmpGetResult();
|
|
|
|
if (pkaResult != PKA_STATUS_A_LESS_THAN_B) {
|
|
return PKA_STATUS_Y_LARGER_THAN_PRIME;
|
|
}
|
|
|
|
// Verify point on curve
|
|
// Short-Weierstrass equation: Y ^ 2 = X ^3 + a * X + b mod P
|
|
// Reduced: Y ^ 2 = X * (X ^ 2 + a) + b
|
|
|
|
// tmp = X ^ 2
|
|
PKABigNumMultiplyStart(curvePointX, length, curvePointX, length, &resultAddress);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
resultLength = 200;
|
|
pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
|
|
|
|
if (pkaResult != PKA_STATUS_SUCCESS) {
|
|
return PKA_STATUS_FAILURE;
|
|
}
|
|
|
|
// tmp += a
|
|
PKABigNumAddStart(scratchBuffer, resultLength, a, length, &resultAddress);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
resultLength = 200;
|
|
pkaResult = PKABigNumAddGetResult(scratchBuffer, &resultLength, resultAddress);
|
|
|
|
if (pkaResult != PKA_STATUS_SUCCESS) {
|
|
return PKA_STATUS_FAILURE;
|
|
}
|
|
|
|
// tmp *= x
|
|
PKABigNumMultiplyStart(scratchBuffer, resultLength, curvePointX, length, &resultAddress);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
resultLength = 200;
|
|
pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
|
|
|
|
if (pkaResult != PKA_STATUS_SUCCESS) {
|
|
return PKA_STATUS_FAILURE;
|
|
}
|
|
|
|
// tmp += b
|
|
PKABigNumAddStart(scratchBuffer, resultLength, b, length, &resultAddress);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
resultLength = 200;
|
|
pkaResult = PKABigNumAddGetResult(scratchBuffer, &resultLength, resultAddress);
|
|
|
|
if (pkaResult != PKA_STATUS_SUCCESS) {
|
|
return PKA_STATUS_FAILURE;
|
|
}
|
|
|
|
|
|
// tmp2 = tmp % prime to ensure we have no fraction in the division.
|
|
// The number will only shrink from here on out.
|
|
PKABigNumModStart(scratchBuffer, resultLength, prime, length, &resultAddress);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
// If the result is not a multiple of the word-length, the PKA HW will round up
|
|
// because it deals in words only. That means that using 'length' directly
|
|
// would cause and underflow, since length refers to the actual length in bytes of
|
|
// the curve parameters while the PKA HW reports that rounded up to the next
|
|
// word boundary.
|
|
// Use 200 as the resultLength instead since we are copying to the scratch buffer
|
|
// anyway.
|
|
// Practically, this only happens with curves such as NIST-P521 that are not word
|
|
// multiples.
|
|
resultLength = 200;
|
|
pkaResult = PKABigNumModGetResult(scratchBuffer2, resultLength, resultAddress);
|
|
|
|
if (pkaResult != PKA_STATUS_SUCCESS) {
|
|
return PKA_STATUS_FAILURE;
|
|
}
|
|
|
|
// tmp = y^2
|
|
PKABigNumMultiplyStart(curvePointY, length, curvePointY, length, &resultAddress);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
resultLength = 200;
|
|
pkaResult = PKABigNumMultGetResult(scratchBuffer, &resultLength, resultAddress);
|
|
|
|
if (pkaResult != PKA_STATUS_SUCCESS) {
|
|
return PKA_STATUS_FAILURE;
|
|
}
|
|
|
|
// tmp %= prime
|
|
PKABigNumModStart(scratchBuffer, resultLength, prime, length, &resultAddress);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
// If the result is not a multiple of the word-length, the PKA HW will round up
|
|
// because it deals in words only. That means that using 'length' directly
|
|
// would cause and underflow, since length refers to the actual length in bytes of
|
|
// the curve parameters while the PKA HW reports that rounded up to the next
|
|
// word boundary.
|
|
// Use 200 as the resultLength instead since we are copying to the scratch buffer
|
|
// anyway.
|
|
// Practically, this only happens with curves such as NIST-P521 that are not word
|
|
// multiples.
|
|
resultLength = 200;
|
|
pkaResult = PKABigNumModGetResult(scratchBuffer, resultLength, resultAddress);
|
|
|
|
if (pkaResult != PKA_STATUS_SUCCESS) {
|
|
return PKA_STATUS_FAILURE;
|
|
}
|
|
|
|
// tmp ?= tmp2
|
|
PKABigNumCmpStart(scratchBuffer,
|
|
scratchBuffer2,
|
|
length);
|
|
|
|
while(PKAGetOpsStatus() == PKA_STATUS_OPERATION_BUSY);
|
|
|
|
pkaResult = PKABigNumCmpGetResult();
|
|
|
|
if (pkaResult != PKA_STATUS_EQUAL) {
|
|
return PKA_STATUS_POINT_NOT_ON_CURVE;
|
|
}
|
|
else {
|
|
return PKA_STATUS_SUCCESS;
|
|
}
|
|
}
|