/* ================================================================== >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< ------------------------------------------------------------------ Copyright (c) 2019-2020 by Lattice Semiconductor Corporation ALL RIGHTS RESERVED ------------------------------------------------------------------ IMPORTANT: THIS FILE IS USED BY OR GENERATED BY the LATTICE PROPELâ„¢ DEVELOPMENT SUITE, WHICH INCLUDES PROPEL BUILDER AND PROPEL SDK. Lattice grants permission to use this code pursuant to the terms of the Lattice Propel License Agreement. DISCLAIMER: LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. LATTICE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE 'S REQUIREMENTS, OR THAT LICENSEE' S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS HEREIN WILL BE CORRECTED. LICENSEE ASSUMES RESPONSIBILITY FOR SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM. LICENSEE ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE SOFTWARE.IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE 'S SOLE LIABILITY, AND LICENSEE' S SOLE REMEDY, IS SET FORTH ABOVE. LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY RIGHTS, INCLUDING ANY PATENT. IT IS THE USER' S RESPONSIBILITY TO VERIFY THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE USE OF FORMAL SOFTWARE VALIDATION METHODS. ------------------------------------------------------------------ ================================================================== */ #include "esb.h" #include #define CONREG_BASE (0x20000) #define AESREG_BASE (0x22000) #define SHAREG_BASE (0x23000) #define DMEM_BASE (0x1F800) #define PORT_SEL_BASE (0x25000) #define RI_CTRL1_AES 0x09 #define RI_CTRL1_SHA 0x05 #define RI_CTRL1_TRNG 0x02 #define RI_CTRL1_PUBK 0x04 #define RI_CTRL1_ECDH 0x0A #define RI_CTRL1_ECDSA_VRF 0x0D // ECDSA verification #define RI_CTRL4_AES128 0x00 #define RI_CTRL4_AES256 0x01 #define RO_GP0_READY 0xB0 #define RO_GP0_BUSY 0xB1 #define RO_GP0_DONE 0xB2 #define AS_SRC_SEL_SHAAC 0x00 #define AS_SRC_SEL_SHALMMI 0x02 #define AS_SRC_SEL_SHAHSP 0x03 #define AS_SRC_SEL_AESLMMI 0x00 #define AS_SRC_SEL_AESHSP 0x04 #define AES_CON_ENC 0x00 #define AES_CON_DEC 0x01 #define AES_STS_KEY_EXP_DONE 0x01 #define AES_STS_AES_DONE 0x02 #define SHA_CON_INIT 0x01 #define SHA_STS_DONE 0x01 #define SHA_STS_BUSY 0x02 #define esb_ri_ctrl1 (CONREG_BASE+0x0c) #define esb_ri_ctrl3 (CONREG_BASE+0x14) #define esb_ri_ctrl4 (CONREG_BASE+0x18) #define esb_ro_gp0 (CONREG_BASE+0x20) #define esb_as_src_sel (CONREG_BASE+0x3c) #define esb_aes_key (AESREG_BASE+0x00) //8 words #define esb_aes_in (AESREG_BASE+0x20) //4words #define esb_aes_res (AESREG_BASE+0x30) //4words #define esb_aes_con (AESREG_BASE+0x40) #define esb_aes_sts (AESREG_BASE+0x44) #define esb_sha_in (SHAREG_BASE+0x4c) #define esb_sha_res (SHAREG_BASE+0x50) //8 words #define esb_sha_con (SHAREG_BASE+0x70) #define esb_sha_sts (SHAREG_BASE+0x74) #define esb_dmem (DMEM_BASE) #define esb_dmem20 (DMEM_BASE+0x20) //8 words #define esb_dmem40 (DMEM_BASE+0x40) //8 words #define esb_dmem60 (DMEM_BASE+0x60) //8 words #define esb_dmem80 (DMEM_BASE+0x80) //8 words #define esb_dmemA0 (DMEM_BASE+0xA0) //8 words #define esb_dmemC0 (DMEM_BASE+0xC0) //440 words #define esb_dmem400 (DMEM_BASE+0x400) //16 words #define esb_dmem480 (DMEM_BASE+0x480) //16 words #define esb_port_select (PORT_SEL_BASE) //used for the sequence to load key and signature into ESB for verification unsigned char rd_idx[] = { 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08 }; unsigned char esb_wait_state(struct esb_instance *this_esb, enum esb_state state) { if (NULL == this_esb) { return 1; } while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != state) { ; } return 0; } unsigned char esb_init(struct esb_instance *this_esb, unsigned int base_addr) { if (NULL == this_esb) { return 1; } this_esb->base_addr = base_addr; return 0; } unsigned char esb_mux_port_sel(struct esb_instance *this_esb, unsigned int sel_port) { if (NULL == this_esb) { return 1; } *(volatile unsigned int *) (this_esb->base_addr + esb_port_select) = sel_port; return 0; } unsigned char esb_switch_idle(struct esb_instance *this_esb) { if (NULL == this_esb) { return 1; } *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = 0x00; return 0; } unsigned char esb_trng32bits_get(struct esb_instance *this_esb, unsigned int *trn_value) { if (NULL == this_esb) { return 1; } //set secuesb_rity engine to TRNG *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = RI_CTRL1_TRNG; //Wait until done while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_DONE); //Read random number, we are only reading one word worth *(volatile unsigned int *) (this_esb->base_addr + trn_value) = ((volatile unsigned int *) (this_esb->base_addr + esb_dmem80))[0]; //Clear secuesb_rity engine *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = 0; return 0; } /* * Output: p_trn: True Random Number (32-bytes) */ unsigned char esb_trng256bits_get(struct esb_instance *this_esb, unsigned char p_trn[32]) { unsigned int i; unsigned int temp; if (NULL == this_esb) { return 1; } //Wait until ready while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_READY); //set secuesb_rity engine to TRNG *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = RI_CTRL1_TRNG; //Wait until done while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_DONE); //Read random number - 256bits/32bytes for (i = 0; i < 8; i++) { temp = ((volatile unsigned int *) (this_esb->base_addr + esb_dmem80))[i]; p_trn[i * 4] = temp; p_trn[(i * 4) + 1] = temp >> 8; p_trn[(i * 4) + 2] = temp >> 16; p_trn[(i * 4) + 3] = temp >> 24; } //Clear secuesb_rity engine *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = 0; return 0; } /* * Output: p_trn: True Random Number (15-bytes) * plus byte 16 as checksum */ unsigned char get_nonce(struct esb_instance *this_esb, unsigned char p_trn[16]) { unsigned int i; unsigned int temp; unsigned char checksum = 0; if (NULL == this_esb) { return 1; } //Wait until ready while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_READY); //set secuesb_rity engine to TRNG *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = RI_CTRL1_TRNG; //Wait until done while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_DONE); //Read random number - 128bits/16bytes for (i = 0; i < 4; i++) { temp = ((volatile unsigned int *) (this_esb->base_addr + esb_dmem80))[i]; p_trn[i * 4] = temp; p_trn[(i * 4) + 1] = temp >> 8; p_trn[(i * 4) + 2] = temp >> 16; p_trn[(i * 4) + 3] = temp >> 24; } //Clear security engine *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = 0; for (i = 0; i < 15; i++) { checksum = checksum + p_trn[i]; } p_trn[15] = ~checksum; return 0; } /* * Input: p_privateKey - 32 bytes * Output: p_publicKey - 64 bytes (x,y) */ unsigned char esb_pubkey_derive(struct esb_instance *this_esb, EccPoint * p_publicKey, unsigned char p_privateKey[NUM_ECC_DIGITS]) { unsigned int i; unsigned int temp; if (NULL == this_esb) { return 1; } //Wait until ready while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_READY); //load pesb_rivate key for (i = 0; i < 8; i++) { ((volatile unsigned int *) (this_esb->base_addr + esb_dmem))[i] = (p_privateKey[i * 4]) + (p_privateKey[(i * 4) + 1] << 8) + (p_privateKey[(i * 4) + 2] << 16) + (p_privateKey[(i * 4) + 3] << 24); } //set secuesb_rity engine to Pub Key *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = RI_CTRL1_PUBK; //Wait until done while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_DONE); //Read Qx public key for (i = 0; i < 8; i++) { temp = ((volatile unsigned int *) (this_esb->base_addr + esb_dmem400))[i]; p_publicKey->x[i * 4] = temp; p_publicKey->x[(i * 4) + 1] = temp >> 8; p_publicKey->x[(i * 4) + 2] = temp >> 16; p_publicKey->x[(i * 4) + 3] = temp >> 24; } //Read Qy public key for (i = 0; i < 8; i++) { temp = ((volatile unsigned int *) (this_esb->base_addr + esb_dmem480))[i]; p_publicKey->y[(i * 4)] = temp; p_publicKey->y[(i * 4) + 1] = temp >> 8; p_publicKey->y[(i * 4) + 2] = temp >> 16; p_publicKey->y[(i * 4) + 3] = temp >> 24; } //Clear secuesb_rity engine *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = 0; return 0; } /* * Input: p_privateKey - 32 bytes * Input: p_publicKey - 64 bytes (x,y) * Output: p_secret: ECDH shared secret (x coordinate) */ unsigned char esb_ecdh_get(struct esb_instance *this_esb, unsigned char p_secret[NUM_ECC_DIGITS], EccPoint * p_publicKey, unsigned char p_privateKey[NUM_ECC_DIGITS]) { unsigned int i; if (NULL == this_esb) { return 1; } //Wait until ready while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_READY); for (i = 0; i < NUM_ECC_DIGITS / 4; i++) { ((volatile unsigned int *) (this_esb->base_addr + esb_dmem))[i] = (p_privateKey[i * 4]) + (p_privateKey[(i * 4) + 1] << 8) + (p_privateKey[(i * 4) + 2] << 16) + (p_privateKey[(i * 4) + 3] << 24); } for (i = 0; i < NUM_ECC_DIGITS / 4; i++) { ((volatile unsigned int *) (this_esb->base_addr + esb_dmem20))[i] = (p_publicKey->x[i * 4]) + (p_publicKey->x[(i * 4) + 1] << 8) + (p_publicKey->x[(i * 4) + 2] << 16) + (p_publicKey->x[(i * 4) + 3] << 24); ((volatile unsigned int *) (this_esb->base_addr + esb_dmem40))[i] = (p_publicKey->y[i * 4]) + (p_publicKey->y[(i * 4) + 1] << 8) + (p_publicKey->y[(i * 4) + 2] << 16) + (p_publicKey->y[(i * 4) + 3] << 24); //z axis, 0x01 if (i == 0) ((volatile unsigned int *) (this_esb->base_addr + esb_dmem60))[i] = 1; else ((volatile unsigned int *) (this_esb->base_addr + esb_dmem60))[i] = 0; //don't care ((volatile unsigned int *) (this_esb->base_addr + esb_dmem80))[i] = 0; ((volatile unsigned int *) (this_esb->base_addr + esb_dmemC0))[i] = 0; } *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl3) = 4; *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = RI_CTRL1_ECDH; //Wait until done while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_DONE); for (i = 0; i < NUM_ECC_DIGITS / 4; i++) { p_secret[i * 4] = ((volatile unsigned int *) (this_esb->base_addr + esb_dmemA0))[i]; p_secret[(i * 4) + 1] = ((volatile unsigned int *) (this_esb->base_addr + esb_dmemA0))[i] >> 8; p_secret[(i * 4) + 2] = ((volatile unsigned int *) (this_esb->base_addr + esb_dmemA0))[i] >> 16; p_secret[(i * 4) + 3] = ((volatile unsigned int *) (this_esb->base_addr + esb_dmemA0))[i] >> 24; } //Clear secuesb_rity engine *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = 0; return 0; } /* * Input: key - 128 bit key [16 bytes] * Input/Ouptut: buffer - 16 byte array * Input: decrypt - 0 for encryption, non-zero for decryption */ unsigned char esb_aes(struct esb_instance *this_esb, unsigned char *key, unsigned char *bufferIn, unsigned char *bufferOut, unsigned int decrypt) { unsigned int i; unsigned int tmp; if (NULL == this_esb) { return 1; } //Set source for AES to LMMI interface *(volatile unsigned int *) (this_esb->base_addr + esb_as_src_sel) = AS_SRC_SEL_AESLMMI; //Set AES Engine to Encrypt or Decrypt if (decrypt) *(volatile unsigned int *) (this_esb->base_addr + esb_aes_con) = AES_CON_DEC; else *(volatile unsigned int *) (this_esb->base_addr + esb_aes_con) = AES_CON_ENC; //Set key size to 128 *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl4) = RI_CTRL4_AES128; //Write Key to AES engine, 128 bit key to last 4 words (esb_aes_key4-7) ((volatile unsigned int *) (this_esb->base_addr + esb_aes_key))[4] = (key[15] << 24) + (key[14] << 16) + (key[13] << 8) + key[12]; ((volatile unsigned int *) (this_esb->base_addr + esb_aes_key))[5] = (key[11] << 24) + (key[10] << 16) + (key[9] << 8) + key[8]; ((volatile unsigned int *) (this_esb->base_addr + esb_aes_key))[6] = (key[7] << 24) + (key[6] << 16) + (key[5] << 8) + key[4]; ((volatile unsigned int *) (this_esb->base_addr + esb_aes_key))[7] = (key[3] << 24) + (key[2] << 16) + (key[1] << 8) + key[0]; //Wait for Key Expansion while ((*(volatile unsigned int *) (this_esb->base_addr + esb_aes_sts) & AES_STS_KEY_EXP_DONE) != AES_STS_KEY_EXP_DONE); //Set security engine to AES *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = RI_CTRL1_AES; //Load buf into security engine ((volatile unsigned int *) (this_esb->base_addr + esb_aes_in))[0] = (bufferIn[0] << 24) + (bufferIn[1] << 16) + (bufferIn[2] << 8) + bufferIn[3]; ((volatile unsigned int *) (this_esb->base_addr + esb_aes_in))[1] = (bufferIn[4] << 24) + (bufferIn[5] << 16) + (bufferIn[6] << 8) + bufferIn[7]; ((volatile unsigned int *) (this_esb->base_addr + esb_aes_in))[2] = (bufferIn[8] << 24) + (bufferIn[9] << 16) + (bufferIn[10] << 8) + bufferIn[11]; ((volatile unsigned int *) (this_esb->base_addr + esb_aes_in))[3] = (bufferIn[12] << 24) + (bufferIn[13] << 16) + (bufferIn[14] << 8) + bufferIn[15]; //Wait until complete while ((*(volatile unsigned int *) (this_esb->base_addr + esb_aes_sts) & AES_STS_AES_DONE) != AES_STS_AES_DONE); //Read result for (i = 0; i < 4; i++) { tmp = ((volatile unsigned int *) (this_esb->base_addr + esb_aes_res))[i]; bufferOut[(i * 4)] = tmp >> 24; bufferOut[(i * 4) + 1] = tmp >> 16; bufferOut[(i * 4) + 2] = tmp >> 8; bufferOut[(i * 4 + 3)] = tmp; } //Wait until done while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_DONE); //Clear security engine *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = 0; return 0; } //uint8_t esb_sha256(struct esb_instance* this_esb, unsigned char *data_in, unsigned int length, unsigned int *digest_out) //xp: unsigned char esb_sha256(struct esb_instance *this_esb, struct sha256_ctx *ctx) { int tmp = 0; if (NULL == this_esb) { return 1; } //Setup ESB for SHA Hash *(volatile unsigned int *) (this_esb->base_addr + esb_as_src_sel) = AS_SRC_SEL_SHAHSP; //Select HSP //0x02 - Wishbone; // sha256 engine *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = RI_CTRL1_SHA; // 1->0 initialize the sha engine *(volatile unsigned int *) (this_esb->base_addr + esb_sha_con) = 0x01; tmp = 1; *(volatile unsigned int *) (this_esb->base_addr + esb_sha_con) = 0x00; // feed the data if (ctx->spiRead2ESB_fun) { esb_mux_port_sel(this_esb, ESB_PORT_HSP); ctx->spiRead2ESB_fun(ctx->spi_master, ctx->start_address, ctx->image_size, ctx->addr4B); esb_mux_port_sel(this_esb, ESB_PORT_WISHBONE); } else { if (ctx->data_in == NULL) return -1; // add last byte indicator in the input data ctx->data_in[ctx->length - 1] |= 1 << 31; for (int i = 0; i < ctx->length; i++) { *(volatile unsigned int *) (this_esb->base_addr + esb_sha_in) = (unsigned int) ctx->data_in[i]; } } // Waiting for Digest Ready do { tmp = *(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0); } while (tmp != 0xb2); //Read Digest for (int i = 0; i < 8; i++) { ctx->digest_out[i] = *((volatile unsigned int *) (this_esb->base_addr + esb_sha_res) + i); } //Clear security engine *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = 0x00; return 0; } // 1 - pass , 0 - fail unsigned char esb_esdsa_verify(struct esb_instance *this_esb, unsigned int digest[], unsigned int pub_key[], unsigned int signature[], unsigned char *auth_pass) { unsigned int tmp = 0; //Wait until ready while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_READY) { ; } for (int i = 0; i < 40; i++) { if (i < 16) { *((volatile unsigned int *) (this_esb->base_addr + esb_dmem) + i) = pub_key[rd_idx[i]]; } else if (i >= 16 && i < 32) { *((volatile unsigned int *) (this_esb->base_addr + esb_dmem) + i) = signature[rd_idx[i]]; } else { *((volatile unsigned int *) (this_esb->base_addr + esb_dmem) + i) = digest[i - 32]; } } *(volatile unsigned int *) (this_esb->base_addr + esb_ri_ctrl1) = RI_CTRL1_ECDSA_VRF; while (*(volatile unsigned int *) (this_esb->base_addr + esb_ro_gp0) != RO_GP0_DONE) { ; } for (int i = 0; i < 8; i++) { tmp = *((volatile unsigned int *) (this_esb->base_addr + esb_dmem80) + i); // DEBUG_PRINTF("Result(%d): 0x%08x\r\n",i,tmp); if (tmp != signature[7 - i]) { *auth_pass = 0; break; }; *auth_pass = 1; } return 0; }