Use the client-server API to isolate the Crypto hardware from non-secure application access.
The functions and other declarations used in this part of the driver are in cy_crypto.h and cy_crypto_server.h. You can also include cy_pdl.h to get access to all functions and declarations in the PDL.
The firmware initializes and starts the Crypto server. The server can run on any core and works with the Crypto hardware. The Crypto server is implemented as a secure block. It performs all cryptographic operations for the client. Access to the server is through the Inter Process Communication (IPC) driver. Direct access is not allowed.
The Crypto client can run on any core too. The firmware initializes and starts the client. The firmware then provides configuration data required for the desired cryptographic technique and a request that the server run the cryptographic operation.
Note that Client-server model is not supported when DCache is enabled.
This document contains the following topics:
Architectural model
The client-server implementation uses:
- one IPC channel for data exchange between client and server applications;
- three interrupts: an IPC notify interrupt, an IPC release interrupt, and an interrupt for error handling.
Firmware initializes and starts the Crypto server. The server can run on any core and works with the Crypto hardware. The Crypto server is implemented as a secure block. It performs all cryptographic operations for the client. Access to the server is through the Inter Process Communication (IPC) driver. Direct access is not allowed.
The Crypto client can also run on any core. Firmware initializes and starts the client. The firmware then provides the configuration data required for the desired cryptographic technique, and requests that the server run the cryptographic operation.
- Note
- Only one Crypto server and only one Crypto client can be run at the same time on any core. So, valid configurations are:
- one server instance runs on CM0+ and one client instance on CM4 (and vice versa).
- one server instance and one client instance run on CM0+ (** This is not recommended, use Direct Crypto API's to perform Crypto operations on a single core).
- one server instance and one client instance run on CM4 (** This is not recommended, use Direct Crypto API's to perform Crypto operations on a single core).
IPC communication between the client and server is completely transparent. Using IPC for communication provides a simple synchronization mechanism to handle concurrent requests from different cores.
Configuration Structure
IPC communication for the Crypto driver is handled transparently. User should select the IPC channel, and configure the required notify, release, and error interrupts.
These initialization routines, Cy_Crypto_Server_Start (server) and Cy_Crypto_Init (client), use separate instances of the same cy_stc_crypto_config_t configuration structure. Some fields should be the same, and some are set specifically by either the server or client. The table lists each field in the config structure, and which initialization routine sets the value.
Field | Which | Description | Notes |
ipcChannel | Server and Client | IPC channel for communication between client and server | IPC Channel, same for both |
acquireNotifierChannel | Server and Client | IPC interrupt structure used for the new request notifications | Notify interrupt number, for Server side only |
releaseNotifierChannel | Server and Client | IPC interrupt structure used for data ready notifications. Used to call userCompleteCallback handler function. | Release interrupt number, for Client side only |
userCompleteCallback | Client | User-defined callback for the Release interrupt handler; can be NULL | See Implementing Crypto Interrupts |
releaseNotifierConfig | Client | IRQ handler settings for data ready notifications. This interrupt occurs when server completely processed all input data and released an IPC communication channel. | configuration for the interrupt |
userGetDataHandler | Server | User-defined function to override default interrupt handler; NULL = use default | ISR for the Notify interrupt |
acquireNotifierConfig | Server | IRQ handler settings for new request notifications. This interrupt occurs when client sent a new request for processing. | configuration for the interrupt |
userErrorHandler | Server | User-defined function to override default interrupt handler; NULL = use default | ISR for a server error |
cryptoErrorIntrConfig | Server | IRQ handler settings for hardware error events | configuration for the interrupt |
Server Initialization
Use a Cy_Crypto_Server_Start function. Provide the configuration parameters (cy_stc_crypto_config_t) and a pointer to the server context (cy_stc_crypto_server_context_t) that will be used to store all temporary data.
#define MY_CHAN_CRYPTO (uint32_t)(9u)
#define MY_INTR_CRYPTO_SRV (uint32_t)(1u)
#define MY_INTR_CRYPTO_CLI (uint32_t)(2u)
#define MY_INTR_CRYPTO_SRV_MUX (IRQn_Type)(2u)
#define MY_INTR_CRYPTO_CLI_MUX (IRQn_Type)(3u)
#define MY_INTR_CRYPTO_ERR_MUX (IRQn_Type)(4u)
{
MY_CHAN_CRYPTO,
MY_INTR_CRYPTO_SRV,
MY_INTR_CRYPTO_CLI,
{
#if (CY_CPU_CORTEX_M0P)
MY_INTR_CRYPTO_CLI_MUX,
cpuss_interrupts_ipc_2_IRQn,
#else
#if defined (CPUSS_SYSTEM_IRQ_PRESENT) && (CPUSS_SYSTEM_IRQ_PRESENT == 1)
#else
cpuss_interrupts_ipc_2_IRQn,
#endif
#endif
2u,
},
NULL,
NULL,
NULL,
{
#if (CY_CPU_CORTEX_M0P)
MY_INTR_CRYPTO_SRV_MUX,
cpuss_interrupts_ipc_1_IRQn,
#else
#if defined (CPUSS_SYSTEM_IRQ_PRESENT) && (CPUSS_SYSTEM_IRQ_PRESENT == 1)
#else
cpuss_interrupts_ipc_1_IRQn,
#endif
#endif
2u,
},
{
#if (CY_CPU_CORTEX_M0P)
MY_INTR_CRYPTO_ERR_MUX,
cpuss_interrupt_crypto_IRQn,
#else
#if defined (CPUSS_SYSTEM_IRQ_PRESENT) && (CPUSS_SYSTEM_IRQ_PRESENT == 1)
#else
cpuss_interrupt_crypto_IRQn,
#endif
#endif
2u,
}
};
Because the two cores operate asynchronously, ensure that server initialization is complete before initializing the client. There are several ways to do this:
All crypto operations are asynchronous. To ensure that any crypto operation is complete and the result is valid, use Cy_Crypto_Sync. Use the CY_CRYPTO_SYNC_NON_BLOCKING parameter to check status. Use CY_CRYPTO_SYNC_BLOCKING to wait for the operation to complete.
Client initialization
Use Cy_Crypto_Init to initialize the Crypto client with the configuration parameters (cy_stc_crypto_config_t) and a pointer to the context (cy_stc_crypto_context_t). Do not fill in the values for the context structure.
Then call Cy_Crypto_Enable to enable the Crypto hardware IP block. After this, the Crypto driver is ready to execute crypto functions. These calls must be made on the client side. Firmware can implement the client on either core.
#define MY_CHAN_CRYPTO (uint32_t)(9u)
#define MY_INTR_CRYPTO_SRV (uint32_t)(1u)
#define MY_INTR_CRYPTO_CLI (uint32_t)(2u)
#define MY_INTR_CRYPTO_SRV_MUX (IRQn_Type)(2u)
#define MY_INTR_CRYPTO_CLI_MUX (IRQn_Type)(3u)
#define MY_INTR_CRYPTO_ERR_MUX (IRQn_Type)(4u)
{
MY_CHAN_CRYPTO,
MY_INTR_CRYPTO_SRV,
MY_INTR_CRYPTO_CLI,
{
#if (CY_CPU_CORTEX_M0P)
MY_INTR_CRYPTO_CLI_MUX,
cpuss_interrupts_ipc_2_IRQn,
#else
#if defined (CPUSS_SYSTEM_IRQ_PRESENT) && (CPUSS_SYSTEM_IRQ_PRESENT == 1)
#else
cpuss_interrupts_ipc_2_IRQn,
#endif
#endif
2u,
},
NULL,
NULL,
NULL,
{
#if (CY_CPU_CORTEX_M0P)
MY_INTR_CRYPTO_SRV_MUX,
cpuss_interrupts_ipc_1_IRQn,
#else
#if defined (CPUSS_SYSTEM_IRQ_PRESENT) && (CPUSS_SYSTEM_IRQ_PRESENT == 1)
#else
cpuss_interrupts_ipc_1_IRQn,
#endif
#endif
2u,
},
{
#if (CY_CPU_CORTEX_M0P)
MY_INTR_CRYPTO_ERR_MUX,
cpuss_interrupt_crypto_IRQn,
#else
#if defined (CPUSS_SYSTEM_IRQ_PRESENT) && (CPUSS_SYSTEM_IRQ_PRESENT == 1)
#else
cpuss_interrupt_crypto_IRQn,
#endif
#endif
2u,
}
};
Common Use Cases
CRC Calculation
To calculate CRC of a data image:
Code example:
#define CRC_BITLEN (16u)
#define CRC_POLYNOMIAL (0x1021u)
#define CRC_LFSR_SEED (0xffffu)
#define CRC_DATA_REVERSE (0u)
#define CRC_DATA_XOR (0u)
#define CRC_REM_REVERSE (0u)
#define CRC_REM_XOR (0x0000u)
CY_ALIGN(4) uint8_t message[9] = "123456789";
CY_ALIGN(4) uint32_t calculatedCrc = 0;
CRC_DATA_REVERSE,
CRC_DATA_XOR,
CRC_REM_REVERSE,
(CRC_REM_XOR << (32 - CRC_BITLEN)),
&cryptoCrcContext);
sizeof(message),
&calculatedCrc,
(uint32_t)(CRC_LFSR_SEED << (32u - CRC_BITLEN)),
&cryptoCrcContext);
if (CRC_DATA_REVERSE == 0u)
{
calculatedCrc = calculatedCrc >> (32 - CRC_BITLEN);
}
Pseudo Random Number Generation
To generate a pseudo random number:
Code example:
#define LFSR32_INITSTATE (0xd8959bc9)
#define LFSR31_INITSTATE (0x2bb911f8)
#define LFSR29_INITSTATE (0x060c31b7)
#define MAX_PRNG_VALUE (255UL)
uint32_t rndNum = 0;
LFSR32_INITSTATE,
LFSR31_INITSTATE,
LFSR29_INITSTATE, &cryptoPrngContext);
True Random Number Generation
To generate a true random number:
Code example:
#define GARO31_INITSTATE (0x04c11db7)
#define FIRO31_INITSTATE (0x04c11db7)
#define MAX_TRNG_BIT_SIZE (32UL)
uint32_t rndNum = 0;
GARO31_INITSTATE,
FIRO31_INITSTATE,
MAX_TRNG_BIT_SIZE,
&rndNum, &cryptoTrngContext);
DES encryption
To encrypt a message using the DES algorithm:
- Place DES key into an array,
- Call Cy_Crypto_Des_Run with required parameters, including the key array
Code example:
#define STRING_LENGTH 8
CY_ALIGN(4) uint8_t msgString[STRING_LENGTH] = "Crypto!";
CY_ALIGN(4) uint8_t encString[STRING_LENGTH];
#define KEY1 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
CY_ALIGN(4) uint8_t desKey[] = { KEY1 };
(uint32_t *)desKey,
(uint32_t *)encString,
(uint32_t *)msgString,
&cryptoDesContext );
TDES encryption
To encrypt a message using the TDES algorithm:
- Place 3 DES keys into a solid array,
- Call Cy_Crypto_Tdes_Run with required parameters, including the array of keys
Code example:
#define STRING_LENGTH 8
CY_ALIGN(4) uint8_t msgString[STRING_LENGTH] = "Crypto!";
CY_ALIGN(4) uint8_t encString[STRING_LENGTH];
#define KEY1 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
#define KEY2 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
#define KEY3 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
CY_ALIGN(4) uint8_t tdesKey[] = { KEY1, KEY2, KEY3 };
(uint32_t *)tdesKey,
(uint32_t *)encString,
(uint32_t *)msgString,
&cryptoDesContext );
AES encryption
The Crypto driver provides a four AES encryption algorithms (ECB, CBC, CFB and CTR) that are used similarly.
To encrypt a message using AES ECB algorithm (as example):
Code example:
0x2Bu, 0x7Eu, 0x15u, 0x16u, 0x28u, 0xAEu, 0xD2u, 0xA6u,
0xABu, 0xF7u, 0x15u, 0x88u, 0x09u, 0xCFu, 0x4Fu, 0x3Cu
};
0x6Bu, 0xC0u, 0xBCu, 0xE1u, 0x2Au, 0x45u, 0x99u, 0x91u,
0xE1u, 0x34u, 0x74u, 0x1Au, 0x7Fu, 0x9Eu, 0x19u, 0x25u
};
(uint32_t *)aesKey,
&cryptoAesContext);
(uint32_t*)aesEcbCipherText,
(uint32_t*)aesEcbPlainText,
&cryptoAesContext);
SHA digest calculation
To calculate a SHA digest of a message:
Code example:
CY_ALIGN(4) uint8_t sha256PlainText_1[3] = "abc";
(uint32_t *)sha256PlainText_1,
sizeof(sha256PlainText_1),
(uint32_t *)sha256Digest,
&cryptoShaContext);
CMAC calculation
To calculate CMAC of a message:
Code example:
{
0x60u, 0x3Du, 0xEBu, 0x10u, 0x15u, 0xCAu, 0x71u, 0xBEu,
0x2Bu, 0x73u, 0xAEu, 0xF0u, 0x85u, 0x7Du, 0x77u, 0x81u,
0x1Fu, 0x35u, 0x2Cu, 0x07u, 0x3Bu, 0x61u, 0x08u, 0xD7u,
0x2Du, 0x98u, 0x10u, 0xA3u, 0x09u, 0x14u, 0xDFu, 0xF4u
};
CY_ALIGN(4) uint8_t cmac256PlainText[16] =
{
0x6Bu, 0xC1u, 0xBEu, 0xE2u, 0x2Eu, 0x40u, 0x9Fu, 0x96u,
0xE9u, 0x3Du, 0x7Eu, 0x11u, 0x73u, 0x93u, 0x17u, 0x2Au
};
(uint32_t *)cmac256PlainText,
sizeof(cmac256PlainText),
(uint32_t *)cmacKey,
(uint32_t *)cmac,
&cryptoAesContext);
HMAC calculation
To calculate HMAC of a message:
- Place HMAC key into array of appropriate size
- Call Cy_Crypto_Hmac_Run with appropriate parameters to make an operation
Code example:
CY_ALIGN(4) uint8_t hmac256Key[32] =
{
0x00u, 0x01u, 0x02u, 0x03u, 0x04u, 0x05u, 0x06u, 0x07u,
0x08u, 0x09u, 0x0Au, 0x0Bu, 0x0Cu, 0x0Du, 0x0Eu, 0x0Fu,
0x10u, 0x11u, 0x12u, 0x13u, 0x14u, 0x15u, 0x16u, 0x17u,
0x18u, 0x19u, 0x1Au, 0x1Bu, 0x1Cu, 0x1Du, 0x1Eu, 0x1Fu
};
CY_ALIGN(4) uint8_t hmac256PlainText[34] =
{
0x53u, 0x61u,
0x6Du, 0x70u, 0x6Cu, 0x65u, 0x20u, 0x6Du, 0x65u, 0x73u,
0x73u, 0x61u, 0x67u, 0x65u, 0x20u, 0x66u, 0x6Fu, 0x72u,
0x20u, 0x6Bu, 0x65u, 0x79u, 0x6Cu, 0x65u, 0x6Eu, 0x3Cu,
0x62u, 0x6Cu, 0x6Fu, 0x63u, 0x6Bu, 0x6Cu, 0x65u, 0x6Eu
};
(uint32_t *)hmac256,
(uint32_t *)hmac256PlainText,
sizeof(hmac256PlainText),
(uint32_t *)hmac256Key,
sizeof(hmac256Key),
&cryptoShaContext);
RSA signature verification
To verify the RSA signature of the data image:
Code example:
#define RSA_MODULO_LENGTH 2048u
#define RSA_MODULO_DATA_SIZE (RSA_MODULO_LENGTH / 8)
typedef struct
{
uint8_t moduloData[RSA_MODULO_DATA_SIZE];
uint8_t expData [32];
uint8_t k1Data [RSA_MODULO_DATA_SIZE+4];
uint8_t k2Data [RSA_MODULO_DATA_SIZE];
uint8_t k3Data [RSA_MODULO_DATA_SIZE];
} cy_stc_public_key_t;
cy_stc_public_key_t cy_publicKey =
{
.publicKeyStruct =
{
.moduloPtr = 0,
.moduloLength = RSA_MODULO_LENGTH,
.pubExpPtr = 0,
.pubExpLength = 24,
.barretCoefPtr = NULL,
.inverseModuloPtr = NULL,
.rBarPtr = NULL
},
.moduloData =
{
0xD9u, 0x94u, 0x94u, 0x38u, 0xA4u, 0xE0u, 0x50u, 0xA1u,
0xADu, 0xC5u, 0xE2u, 0x66u, 0xA9u, 0x7Fu, 0xE7u, 0xD7u,
0xA8u, 0x10u, 0x87u, 0x3Au, 0xBEu, 0xB3u, 0x0Eu, 0x6Au,
0xB2u, 0x8Bu, 0x2Eu, 0x8Du, 0xC2u, 0x45u, 0x41u, 0xA6u,
0xDBu, 0xEBu, 0x90u, 0x20u, 0x56u, 0xECu, 0xFDu, 0x8Cu,
0x23u, 0x09u, 0x13u, 0x5Du, 0x65u, 0xA2u, 0xADu, 0x9Du,
0x3Bu, 0xF2u, 0x5Bu, 0xF6u, 0xABu, 0x2Eu, 0xFEu, 0xF2u,
0x69u, 0x98u, 0x29u, 0x6Du, 0xD1u, 0x2Eu, 0x91u, 0x5Au,
0x65u, 0x83u, 0xF5u, 0x7Fu, 0x8Eu, 0x73u, 0xFFu, 0xA1u,
0x8Cu, 0x70u, 0x07u, 0xDFu, 0x4Du, 0xF4u, 0x79u, 0xB7u,
0x18u, 0xC1u, 0xA3u, 0x2Bu, 0x82u, 0x5Bu, 0x9Eu, 0xE2u,
0xF0u, 0xA0u, 0xB8u, 0xDAu, 0x19u, 0xADu, 0xBBu, 0x2Bu,
0xD5u, 0x07u, 0x5Au, 0x85u, 0x12u, 0x03u, 0xD8u, 0x60u,
0x53u, 0x3Du, 0xC6u, 0x34u, 0xE2u, 0x7Fu, 0x96u, 0x4Cu,
0x26u, 0x1Eu, 0x82u, 0xB1u, 0x85u, 0xC3u, 0x0Du, 0x54u,
0x68u, 0x37u, 0x97u, 0x58u, 0x19u, 0x36u, 0x43u, 0x9Cu,
0xD9u, 0xC3u, 0x42u, 0xEBu, 0xBEu, 0xE2u, 0x8Fu, 0x72u,
0xF1u, 0x5Eu, 0x2Au, 0x15u, 0x56u, 0x52u, 0xD4u, 0x6Du,
0x61u, 0x97u, 0x16u, 0xFEu, 0xC3u, 0xF9u, 0x17u, 0x3Cu,
0x37u, 0xD5u, 0xE1u, 0xA1u, 0x0Au, 0xB7u, 0xD9u, 0x65u,
0xA1u, 0x15u, 0xECu, 0xC7u, 0x39u, 0xECu, 0xEDu, 0x39u,
0x98u, 0x96u, 0x66u, 0x50u, 0x8Cu, 0x25u, 0xC3u, 0x29u,
0xB9u, 0xF8u, 0x25u, 0x55u, 0x92u, 0x7Au, 0xBFu, 0xFBu,
0x45u, 0x2Au, 0x28u, 0x8Au, 0xF9u, 0xE5u, 0xE2u, 0x30u,
0x72u, 0x0Eu, 0x0Au, 0x1Cu, 0x25u, 0x09u, 0x86u, 0x6Fu,
0xF6u, 0x6Fu, 0x15u, 0xEDu, 0x14u, 0xE6u, 0x1Eu, 0x53u,
0x5Au, 0x15u, 0x25u, 0xB9u, 0x5Eu, 0xC9u, 0xBAu, 0x48u,
0xA3u, 0xE3u, 0x93u, 0x62u, 0x3Cu, 0x6Cu, 0x3Cu, 0x83u,
0x17u, 0x29u, 0xFBu, 0xAEu, 0x91u, 0x47u, 0xC9u, 0x41u,
0x2Fu, 0xF9u, 0x82u, 0x29u, 0x7Bu, 0xB4u, 0x5Au, 0x93u,
0x01u, 0x95u, 0xDBu, 0x08u, 0x7Eu, 0x7Bu, 0x99u, 0x1Eu,
0xD4u, 0x25u, 0xD3u, 0x2Au, 0xF4u, 0xC7u, 0x9Fu, 0xB3u,
},
.expData = { 0x01, 0x00, 0x01 },
.k1Data = { 0, },
.k2Data = { 0, },
.k3Data = { 0, },
};
CY_ALIGN(4) uint8_t rsaEncryptedSign[RSA_MODULO_DATA_SIZE] =
{
0x12u, 0xCEu, 0x13u, 0x83u, 0x4Fu, 0xFFu, 0x39u, 0x9Bu,
0x33u, 0xDEu, 0xDCu, 0xDBu, 0x7Cu, 0x62u, 0xA5u, 0x10u,
0x24u, 0x07u, 0xEAu, 0x4Cu, 0x04u, 0x4Au, 0xCEu, 0x7Bu,
0x8Cu, 0xD8u, 0xD4u, 0x64u, 0xD1u, 0x98u, 0xA2u, 0x33u,
0x2Eu, 0xFFu, 0x06u, 0x13u, 0xD6u, 0x5Au, 0x50u, 0x3Cu,
0xA2u, 0x5Eu, 0xE3u, 0x11u, 0x54u, 0x7Cu, 0x6Au, 0x49u,
0x39u, 0xA3u, 0x62u, 0x02u, 0x66u, 0xB0u, 0x19u, 0x82u,
0xFBu, 0x5Du, 0x15u, 0xB2u, 0x0Bu, 0xF7u, 0xECu, 0x6Cu,
0xBEu, 0xEBu, 0x04u, 0x1Fu, 0x0Bu, 0x5Bu, 0x18u, 0x0Eu,
0x96u, 0x03u, 0xC4u, 0x1Eu, 0x56u, 0xB6u, 0x1Fu, 0xF2u,
0x08u, 0x7Au, 0x81u, 0x96u, 0x86u, 0xA4u, 0x93u, 0x5Du,
0x66u, 0x63u, 0x10u, 0xD5u, 0x9Bu, 0xA9u, 0xD7u, 0x52u,
0xCDu, 0xEFu, 0x23u, 0xDCu, 0x58u, 0xC7u, 0x3Du, 0x72u,
0x3Fu, 0x09u, 0x5Eu, 0x3Bu, 0x03u, 0xF9u, 0x91u, 0x10u,
0x63u, 0x2Au, 0x56u, 0xFAu, 0xCEu, 0x8Cu, 0x8Au, 0xBFu,
0xB5u, 0xA1u, 0xA7u, 0x0Fu, 0xBBu, 0xD8u, 0xACu, 0x7Fu,
0x43u, 0x3Cu, 0xBFu, 0x11u, 0xD8u, 0xAEu, 0x55u, 0xE7u,
0x23u, 0xF8u, 0xA4u, 0xE0u, 0x56u, 0xCFu, 0x3Fu, 0x21u,
0xA9u, 0xB6u, 0x01u, 0x34u, 0xDFu, 0xB6u, 0xDCu, 0xAAu,
0x29u, 0xB0u, 0x97u, 0x9Du, 0xD9u, 0xAAu, 0x47u, 0xD4u,
0xD9u, 0x4Au, 0x97u, 0x52u, 0x3Cu, 0xB9u, 0x36u, 0xDAu,
0xF6u, 0xA6u, 0x14u, 0x97u, 0xDEu, 0xE6u, 0x76u, 0xBFu,
0x1Bu, 0x23u, 0xDBu, 0x68u, 0x66u, 0xEAu, 0x0Eu, 0xC6u,
0xD3u, 0x52u, 0x05u, 0x86u, 0x26u, 0x04u, 0x31u, 0xCEu,
0xCFu, 0x8Du, 0x13u, 0x84u, 0x81u, 0xF2u, 0x7Bu, 0xB7u,
0xDCu, 0x93u, 0x23u, 0x93u, 0xD1u, 0x0Cu, 0xF4u, 0xDFu,
0x37u, 0x44u, 0x3Du, 0xD7u, 0xAFu, 0xBFu, 0xAFu, 0x32u,
0xE7u, 0x31u, 0x50u, 0x70u, 0x62u, 0xC3u, 0xABu, 0x31u,
0x51u, 0x28u, 0x2Bu, 0x0Bu, 0x31u, 0xC6u, 0xD3u, 0x0Fu,
0x74u, 0xE6u, 0x31u, 0x21u, 0xF0u, 0xA3u, 0x40u, 0x5Du,
0xEDu, 0xFFu, 0xC9u, 0xEBu, 0x5Au, 0x65u, 0xF3u, 0xCBu,
0x67u, 0x50u, 0x62u, 0x2Du, 0x8Au, 0xEAu, 0xC3u, 0xBDu,
};
{
0xf4u, 0xcbu, 0x29u, 0x53u, 0xadu, 0xc2u, 0xbdu, 0x49u,
0x6bu, 0x43u, 0x28u, 0x2bu, 0x63u, 0xb7u, 0x0du, 0x16u,
0xa9u, 0xd4u, 0x90u, 0x65u, 0x6eu, 0x7bu, 0x6du, 0xb7u,
0x0bu, 0x17u, 0xefu, 0x60u, 0x02u, 0x12u, 0x0fu, 0x90u
};
CY_ALIGN(4) uint8_t rsaOutput[RSA_MODULO_DATA_SIZE];
cy_publicKey.publicKeyStruct.moduloPtr = cy_publicKey.moduloData;
cy_publicKey.publicKeyStruct.pubExpPtr = cy_publicKey.expData;
&cy_publicKey.publicKeyStruct,
(const uint32_t*)rsaEncryptedSign, sizeof(rsaEncryptedSign),
(uint32_t *)rsaOutput,
&cryptoRsaContext);
&verResult,
(const uint32_t*)sha256Digest,
(const uint32_t*)rsaOutput, sizeof(rsaOutput),
&cryptoRsaVerContext);
{
}
else
{
}
RSA Usage Considerations
General RSA encryption and decryption is supported. Cy_Crypto_Rsa_Proc encrypts or decrypts data based on the parameters passed to the function. If you pass in plain text and a public key, the output is encrypted (cipher text). If you pass in cipher text and a private key, the output is decrypted (plain text).
One parameter for this function call is a structure that defines the key: cy_stc_crypto_rsa_pub_key_t. The four modulus and exponent fields are mandatory. They represent the data for either the public or private key as appropriate.
- Note
- The modulus and exponent values in the cy_stc_crypto_rsa_pub_key_t must be in little-endian order.
Use the Cy_Crypto_InvertEndianness function to convert to or from little-endian order.
The remaining fields represent three pre-calculated coefficients that can reduce execution time by up to 5x. The fields are: coefficient for Barrett reduction, binary inverse of the modulus, and the result of (2^moduloLength mod modulo). These fields are optional, and can be set to NULL.
Calculate these coefficients with Cy_Crypto_Rsa_CalcCoefs. Pass them in the address of the key structure with the modulus and exponent values for the key. The function returns the coefficients for the key in the key structure, replacing any previous values.
The RSA functionality also implements functions to decrypt a signature using a public key. This signature must follow the RSASSA-PKCS-v1_5 standard. The signature must contain a SHA digest (hash). MD2, MD4, and MD5 message digests are not supported.
An encrypted signature is stored as big-endian data. It must be inverted for RSA processing. To use the provided signature decryption, firmware must
- Calculate the SHA digest of the data to be verified with Cy_Crypto_Sha_Run.
- Ensure that the RSA signature is in little-endian format. Use Cy_Crypto_InvertEndianness.
- Decrypt the RSA signature with a public key, by calling Cy_Crypto_Rsa_Proc.
- Invert the byte order of the output, to return to big-endian format. Use Cy_Crypto_InvertEndianness.
- Call Cy_Crypto_Rsa_Verify (which requires data in big-endian format).
Implementing Crypto Interrupts
The Crypto driver uses three interrupts:
- A notify interrupt when data is ready for a cryptographic operation
- A release interrupt when a cryptographic operation is complete
- An error interrupt if the server encounters a hardware error
You can modify default behavior for each interrupt.
Notify Interrupt: the Crypto server has a default ISR to handle this interrupt, Cy_Crypto_Server_GetDataHandler. The default ISR clears the interrupt, retrieves the data from the IPC channel, and dispatches control to the desired cryptographic operation.
To use the default handler, set the userGetDataHandler field of the cy_stc_crypto_config_t structure to NULL.
To override, populate this field with your ISR. Then call Crypto Server Start function. Your ISR can perform additional tasks required by your application logic, but must also call Cy_Crypto_Server_GetDataHandler to dispatch the data to the correct cryptographic operation.
- Note
- Cy_Crypto_Server_Process should be performed from this ISR or from any other task in the multi-task environment.
void My_Crypto_Server_GetDataHandler(void)
{
uint32_t interruptMasked;
if ((1uL << (cy_crypto_serverContext->ipcChannel)) == interruptMasked )
{
}
}
#define MY_CHAN_CRYPTO (uint32_t)(9u)
#define MY_INTR_CRYPTO_SRV (uint32_t)(1u)
#define MY_INTR_CRYPTO_CLI (uint32_t)(2u)
#define MY_INTR_CRYPTO_SRV_MUX (IRQn_Type)(2u)
#define MY_INTR_CRYPTO_CLI_MUX (IRQn_Type)(3u)
#define MY_INTR_CRYPTO_ERR_MUX (IRQn_Type)(4u)
{
MY_CHAN_CRYPTO,
MY_INTR_CRYPTO_SRV,
MY_INTR_CRYPTO_CLI,
{
#if (CY_CPU_CORTEX_M0P)
MY_INTR_CRYPTO_CLI_MUX,
cpuss_interrupts_ipc_2_IRQn,
#else
#if defined (CPUSS_SYSTEM_IRQ_PRESENT) && (CPUSS_SYSTEM_IRQ_PRESENT == 1)
#else
cpuss_interrupts_ipc_2_IRQn,
#endif
#endif
2u,
},
NULL,
My_Crypto_Server_GetDataHandler,
NULL,
{
#if (CY_CPU_CORTEX_M0P)
MY_INTR_CRYPTO_SRV_MUX,
cpuss_interrupts_ipc_1_IRQn,
#else
#if defined (CPUSS_SYSTEM_IRQ_PRESENT) && (CPUSS_SYSTEM_IRQ_PRESENT == 1)
#else
cpuss_interrupts_ipc_1_IRQn,
#endif
#endif
2u,
},
{
#if (CY_CPU_CORTEX_M0P)
MY_INTR_CRYPTO_ERR_MUX,
cpuss_interrupt_crypto_IRQn,
#else
#if defined (CPUSS_SYSTEM_IRQ_PRESENT) && (CPUSS_SYSTEM_IRQ_PRESENT == 1)
#else
cpuss_interrupt_crypto_IRQn,
#endif
#endif
2u,
}
};
cryptoStatus = Cy_Crypto_Server_Start_Base(&myCryptoConfig, &myCryptoServerContext);
Release Interrupt: The Crypto driver includes a handler for this interrupt. The interrupt handler clears the interrupt and calls a user-provided callback routine. You cannot override this interrupt handler. By default the interrupt is disabled.
To use default behavior (interrupt disabled), set the userCompleteCallback field of the cy_stc_crypto_config_t structure to NULL. To enable the interrupt, populate this field with your callback function. Then call Cy_Crypto_Init. If the callback function is not NULL, the Init function enables the interrupt, and default behavior calls your routine.
When performing cryptographic operations, firmware must ensure the operation is complete before acting on the results. If the release interrupt is disabled, typically calls to Cy_Crypto_Sync should be blocking. If the interrupt is enabled, your callback function is called when the operation is complete. This lets you avoid blocking calls to Cy_Crypto_Sync.
Error Interrupt: The Crypto server has a default ISR to handle this interrupt. It clears the interrupt and sets an internal flag that an error has occurred.
To use the default handler, set the userErrorHandler field of the cy_stc_crypto_config_t structure to NULL. To override, populate this field with your ISR. Then call Crypto Server Start function.
Your ISR must call Cy_Crypto_Server_ErrorHandler, and can perform any additional tasks required by your application logic.