From d631270af4bf13decbbf8f50fc2fdfbba7263aa9 Mon Sep 17 00:00:00 2001 From: AntiCat Date: Sun, 18 Oct 2015 20:14:17 +0200 Subject: [PATCH] cc2538: Add PKA drivers, ECC algorithms and examples --- cpu/cc2538/Makefile.cc2538 | 2 + cpu/cc2538/dev/bignum-driver.c | 1064 ++++++++++++++++++++++++++++ cpu/cc2538/dev/bignum-driver.h | 462 ++++++++++++ cpu/cc2538/dev/ecc-algorithm.c | 200 ++++++ cpu/cc2538/dev/ecc-algorithm.h | 178 +++++ cpu/cc2538/dev/ecc-curve.c | 91 +++ cpu/cc2538/dev/ecc-curve.h | 65 ++ cpu/cc2538/dev/ecc-driver.c | 559 +++++++++++++++ cpu/cc2538/dev/ecc-driver.h | 227 ++++++ cpu/cc2538/dev/pka.c | 128 ++++ cpu/cc2538/dev/pka.h | 871 +++++++++++++++++++++++ cpu/cc2538/lpm.c | 2 +- cpu/cc2538/startup-gcc.c | 3 +- examples/cc2538dk/pka/Makefile | 6 + examples/cc2538dk/pka/ecc-ecdh.c | 188 +++++ examples/cc2538dk/pka/ecc-sign.c | 139 ++++ examples/cc2538dk/pka/ecc-verify.c | 122 ++++ platform/cc2538dk/README.md | 1 + platform/remote/README.md | 1 + 19 files changed, 4307 insertions(+), 2 deletions(-) create mode 100644 cpu/cc2538/dev/bignum-driver.c create mode 100644 cpu/cc2538/dev/bignum-driver.h create mode 100644 cpu/cc2538/dev/ecc-algorithm.c create mode 100644 cpu/cc2538/dev/ecc-algorithm.h create mode 100644 cpu/cc2538/dev/ecc-curve.c create mode 100644 cpu/cc2538/dev/ecc-curve.h create mode 100644 cpu/cc2538/dev/ecc-driver.c create mode 100644 cpu/cc2538/dev/ecc-driver.h create mode 100644 cpu/cc2538/dev/pka.c create mode 100644 cpu/cc2538/dev/pka.h create mode 100644 examples/cc2538dk/pka/Makefile create mode 100644 examples/cc2538dk/pka/ecc-ecdh.c create mode 100644 examples/cc2538dk/pka/ecc-sign.c create mode 100644 examples/cc2538dk/pka/ecc-verify.c diff --git a/cpu/cc2538/Makefile.cc2538 b/cpu/cc2538/Makefile.cc2538 index 29795111c..2ace72f76 100644 --- a/cpu/cc2538/Makefile.cc2538 +++ b/cpu/cc2538/Makefile.cc2538 @@ -51,6 +51,8 @@ CONTIKI_CPU_SOURCEFILES += clock.c rtimer-arch.c uart.c watchdog.c CONTIKI_CPU_SOURCEFILES += nvic.c cpu.c sys-ctrl.c gpio.c ioc.c spi.c adc.c CONTIKI_CPU_SOURCEFILES += crypto.c aes.c ccm.c sha256.c CONTIKI_CPU_SOURCEFILES += cc2538-rf.c udma.c lpm.c +CONTIKI_CPU_SOURCEFILES += pka.c bignum-driver.c ecc-driver.c ecc-algorithm.c +CONTIKI_CPU_SOURCEFILES += ecc-curve.c CONTIKI_CPU_SOURCEFILES += dbg.c ieee-addr.c CONTIKI_CPU_SOURCEFILES += slip-arch.c slip.c CONTIKI_CPU_SOURCEFILES += i2c.c cc2538-temp-sensor.c vdd3-sensor.c diff --git a/cpu/cc2538/dev/bignum-driver.c b/cpu/cc2538/dev/bignum-driver.c new file mode 100644 index 000000000..60ced2960 --- /dev/null +++ b/cpu/cc2538/dev/bignum-driver.c @@ -0,0 +1,1064 @@ +/* + * Original file: + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Port to Contiki: + * Authors: Andreas Dröscher + * Hu Luo + * Hossein Shafagh + * + * 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 copyright holder 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. + */ +/** + * \addtogroup cc2538-bignum + * @{ + * + * \file + * Implementation of the cc2538 BigNum driver + * + * bignum_subtract_start bignum_subtract_get_result (subtraction) + * bignum_add_start bignum_add_get_result (addition) + * bignum_mod_start bignum_mod_get_result (modulo) + * bignum_exp_mod_start bignum_exp_mod_get_result (modular exponentiation operation) + * bignum_inv_mod_start bignum_inv_mod_get_result (inverse modulo operation) + * bignum_mul_start bignum_mul_get_result (multiplication) + * bignum_divide_start bignum_divide_get_result (division) + * bignum_cmp_start bignum_cmp_get_result (comparison) + */ +#include "bignum-driver.h" + +#include "stdio.h" + +#include "reg.h" +#include "nvic.h" + +#define ASSERT(IF) if(!(IF)) { return PKA_STATUS_INVALID_PARAM; } + +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_mod_start(const uint32_t *number, + const uint8_t number_size, + const uint32_t *modulus, + const uint8_t modulus_size, + uint32_t *result_vector, + struct process *process) +{ + + uint8_t extraBuf; + uint32_t offset; + int i; + + /* Check the arguments. */ + ASSERT(NULL != number); + ASSERT(NULL != modulus); + ASSERT(NULL != result_vector); + + /* make sure no operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* calculate the extra buffer requirement. */ + extraBuf = 2 + modulus_size % 2; + + offset = 0; + + /* Update the A ptr with the offset address of the PKA RAM location + * where the number will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the number in PKA RAM */ + for(i = 0; i < number_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = number[i]; + } + + /* determine the offset for the next data input. */ + offset += 4 * (i + number_size % 2); + + /* Update the B ptr with the offset address of the PKA RAM location + * where the divisor will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Load the divisor in PKA RAM. */ + for(i = 0; i < modulus_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = modulus[i]; + } + + /* determine the offset for the next data. */ + offset += 4 * (i + extraBuf); + + /* Copy the result vector address location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load C ptr with the result location in PKA RAM */ + REG(PKA_CPTR) = offset >> 2; + + /* Load A length registers with Big number length in 32 bit words. */ + REG(PKA_ALENGTH) = number_size; + + /* Load B length registers Divisor length in 32-bit words. */ + REG(PKA_BLENGTH) = modulus_size; + + /* Start the PKCP modulo operation by setting the PKA Function register. */ + REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MODULO); + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_mod_get_result(uint32_t *buffer, + const uint8_t buffer_size, + const uint32_t result_vector) +{ + + uint32_t regMSWVal; + uint32_t len; + int i; + + /* Check the arguments. */ + ASSERT(NULL != buffer); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + /* verify that the operation is complete. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + /* Get the MSW register value. */ + regMSWVal = REG(PKA_DIVMSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_DIVMSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result. */ + len = ((regMSWVal & PKA_DIVMSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + + /* If the size of the buffer provided is less than the result length than + * return error. */ + if(buffer_size < len) { + return PKA_STATUS_BUF_UNDERFLOW; + } + /* copy the result from vector C into the pResult. */ + for(i = 0; i < len; i++) { + buffer[i] = REG(result_vector + 4 * i); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_cmp_start(const uint32_t *number1, + const uint32_t *number2, + const uint8_t size, + struct process *process) +{ + + uint32_t offset; + int i; + + /* Check the arguments. */ + ASSERT(NULL != number1); + ASSERT(NULL != number2); + + offset = 0; + + /* Make sure no operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Update the A ptr with the offset address of the PKA RAM location + * where the first big number will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the first big number in PKA RAM. */ + for(i = 0; i < size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = number1[i]; + } + + /* Determine the offset in PKA RAM for the next pointer. */ + offset += 4 * (i + size % 2); + + /* Update the B ptr with the offset address of the PKA RAM location + * where the second big number will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Load the second big number in PKA RAM. */ + for(i = 0; i < size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = number2[i]; + } + + /* Load length registers in 32 bit word size. */ + REG(PKA_ALENGTH) = size; + + /* Set the PKA Function register for the compare operation + * and start the operation. */ + REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_COMPARE); + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_cmp_get_result(void) +{ + uint8_t status; + + /* verify that the operation is complete. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + status = PKA_STATUS_OPERATION_INPRG; + return status; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + /* Check the compare register. */ + switch(REG(PKA_COMPARE)) { + case PKA_COMPARE_A_EQUALS_B: + status = PKA_STATUS_SUCCESS; + break; + + case PKA_COMPARE_A_GREATER_THAN_B: + status = PKA_STATUS_A_GR_B; + break; + + case PKA_COMPARE_A_LESS_THAN_B: + status = PKA_STATUS_A_LT_B; + break; + + default: + status = PKA_STATUS_FAILURE; + break; + } + + return status; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_inv_mod_start(const uint32_t *number, + const uint8_t number_size, + const uint32_t *modulus, + const uint8_t modulus_size, + uint32_t *result_vector, + struct process *process) +{ + + uint32_t offset; + int i; + + /* Check the arguments. */ + ASSERT(NULL != number); + ASSERT(NULL != modulus); + ASSERT(NULL != result_vector); + + offset = 0; + + /* Make sure no operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Update the A ptr with the offset address of the PKA RAM location + * where the number will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the \e number number in PKA RAM. */ + for(i = 0; i < number_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = number[i]; + } + + /* Determine the offset for next data. */ + offset += 4 * (i + number_size % 2); + + /* Update the B ptr with the offset address of the PKA RAM location + * where the modulus will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Load the \e modulus divisor in PKA RAM. */ + for(i = 0; i < modulus_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = modulus[i]; + } + + /* Determine the offset for result data. */ + offset += 4 * (i + modulus_size % 2); + + /* Copy the result vector address location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load D ptr with the result location in PKA RAM. */ + REG(PKA_DPTR) = offset >> 2; + + /* Load the respective length registers. */ + REG(PKA_ALENGTH) = number_size; + REG(PKA_BLENGTH) = modulus_size; + + /* set the PKA function to InvMod operation and the start the operation. */ + REG(PKA_FUNCTION) = 0x0000F000; + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_inv_mod_get_result(uint32_t *buffer, + const uint8_t buffer_size, + const uint32_t result_vector) +{ + + uint32_t regMSWVal; + uint32_t len; + int i; + + /* Check the arguments. */ + ASSERT(NULL != buffer); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + /* Verify that the operation is complete. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + /* Get the MSW register value. */ + regMSWVal = REG(PKA_MSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result */ + len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + + /* Check if the provided buffer length is adequate to store the result + * data. */ + if(buffer_size < len) { + return PKA_STATUS_BUF_UNDERFLOW; + } + + /* Copy the result from vector C into the \e buffer. */ + for(i = 0; i < len; i++) { + buffer[i] = REG(result_vector + 4 * i); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_mul_start(const uint32_t *multiplicand, + const uint8_t multiplicand_size, + const uint32_t *multiplier, + const uint8_t multiplier_size, + uint32_t *result_vector, + struct process *process) +{ + + uint32_t offset; + int i; + + /* Check for the arguments. */ + ASSERT(NULL != multiplicand); + ASSERT(NULL != multiplier); + ASSERT(NULL != result_vector); + + offset = 0; + + /* Make sure no operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Update the A ptr with the offset address of the PKA RAM location + * where the multiplicand will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the multiplicand in PKA RAM. */ + for(i = 0; i < multiplicand_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = *multiplicand; + multiplicand++; + } + + /* Determine the offset for the next data. */ + offset += 4 * (i + (multiplicand_size % 2)); + + /* Update the B ptr with the offset address of the PKA RAM location + * where the multiplier will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Load the multiplier in PKA RAM. */ + for(i = 0; i < multiplier_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = *multiplier; + multiplier++; + } + + /* Determine the offset for the next data. */ + offset += 4 * (i + (multiplier_size % 2)); + + /* Copy the result vector address location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load C ptr with the result location in PKA RAM. */ + REG(PKA_CPTR) = offset >> 2; + + /* Load the respective length registers. */ + REG(PKA_ALENGTH) = multiplicand_size; + REG(PKA_BLENGTH) = multiplier_size; + + /* Set the PKA function to the multiplication and start it. */ + REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_MULTIPLY); + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_mul_get_result(uint32_t *buffer, + uint32_t *buffer_size, + const uint32_t result_vector) +{ + + uint32_t regMSWVal; + uint32_t len; + int i; + + /* Check for arguments. */ + ASSERT(NULL != buffer); + ASSERT(NULL != buffer_size); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + /* Verify that the operation is complete. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + /* Get the MSW register value. */ + regMSWVal = REG(PKA_MSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result. */ + len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + + /* Make sure that the length of the supplied result buffer is adequate + * to store the resultant. */ + if(*buffer_size < len) { + return PKA_STATUS_BUF_UNDERFLOW; + } + + /* Copy the resultant length. */ + *buffer_size = len; + + /* Copy the result from vector C into the pResult. */ + for(i = 0; i < *buffer_size; i++) { + buffer[i] = REG(result_vector + 4 * i); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_add_start(const uint32_t *number1, + const uint8_t number1_size, + const uint32_t *number2, + const uint8_t number2_size, + uint32_t *result_vector, + struct process *process) +{ + + uint32_t offset; + int i; + + /* Check for arguments. */ + ASSERT(NULL != number1); + ASSERT(NULL != number2); + ASSERT(NULL != result_vector); + + offset = 0; + + /* Make sure no operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Update the A ptr with the offset address of the PKA RAM location + * where the big number 1 will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the big number 1 in PKA RAM. */ + for(i = 0; i < number1_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = number1[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + (number1_size % 2)); + + /* Update the B ptr with the offset address of the PKA RAM location + * where the big number 2 will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Load the big number 2 in PKA RAM. */ + for(i = 0; i < number2_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = number2[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + (number2_size % 2)); + + /* Copy the result vector address location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load C ptr with the result location in PKA RAM. */ + REG(PKA_CPTR) = offset >> 2; + + /* Load respective length registers. */ + REG(PKA_ALENGTH) = number1_size; + REG(PKA_BLENGTH) = number2_size; + + /* Set the function for the add operation and start the operation. */ + REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_ADD); + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_add_get_result(uint32_t *buffer, + uint32_t *buffer_size, + const uint32_t result_vector) +{ + + uint32_t regMSWVal; + uint32_t len; + int i; + + /* Check for the arguments. */ + ASSERT(NULL != buffer); + ASSERT(NULL != buffer_size); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + /* Verify that the operation is complete. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + /* Get the MSW register value. */ + regMSWVal = REG(PKA_MSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result. */ + len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + + /* Make sure that the supplied result buffer is adequate to store the + * resultant data. */ + if(*buffer_size < len) { + return PKA_STATUS_BUF_UNDERFLOW; + } + + /* Copy the length. */ + *buffer_size = len; + + /* Copy the result from vector C into the provided buffer. */ + for(i = 0; i < *buffer_size; i++) { + buffer[i] = REG(result_vector + 4 * i); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +/* below functions are added by hu luo */ +uint8_t +bignum_subtract_start(const uint32_t *number1, + const uint8_t number1_size, + const uint32_t *number2, + const uint8_t number2_size, + uint32_t *result_vector, + struct process *process) +{ + + uint32_t offset; + int i; + + /* Check for arguments. */ + ASSERT(NULL != number1); + ASSERT(NULL != number2); + ASSERT(NULL != result_vector); + + offset = 0; + + /* Make sure no operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Update the A ptr with the offset address of the PKA RAM location + * where the big number 1 will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the big number 1 in PKA RAM. */ + for(i = 0; i < number1_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = number1[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + (number1_size % 2)); + + /* Update the B ptr with the offset address of the PKA RAM location + * where the big number 2 will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Load the big number 2 in PKA RAM. */ + for(i = 0; i < number2_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = number2[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + (number2_size % 2)); + + /* Copy the result vector address location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load C ptr with the result location in PKA RAM. */ + REG(PKA_CPTR) = offset >> 2; + + /* Load respective length registers. */ + REG(PKA_ALENGTH) = number1_size; + REG(PKA_BLENGTH) = number2_size; + + /* Set the function for the add operation and start the operation. */ + REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_SUBTRACT); + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_subtract_get_result(uint32_t *buffer, + uint32_t *buffer_size, + const uint32_t result_vector) +{ + + uint32_t regMSWVal; + uint32_t len; + int i; + + /* Check for the arguments. */ + ASSERT(NULL != buffer); + ASSERT(NULL != buffer_size); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + /* Verify that the operation is complete. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + /* Get the MSW register value. */ + regMSWVal = REG(PKA_MSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result. */ + len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + + /* Make sure that the supplied result buffer is adequate to store the + * resultant data. */ + if(*buffer_size < len) { + return PKA_STATUS_BUF_UNDERFLOW; + } + + /* Copy the length. */ + *buffer_size = len; + + /* Copy the result from vector C into the provided buffer. */ + for(i = 0; i < *buffer_size; i++) { + buffer[i] = REG(result_vector + 4 * i); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_exp_mod_start(const uint32_t *number, + const uint8_t number_size, + const uint32_t *modulus, + const uint8_t modulus_size, + const uint32_t *base, + const uint8_t base_size, + uint32_t *result_vector, + struct process *process) +{ + uint32_t offset; + int i; + + /* Check for the arguments. */ + ASSERT(NULL != number); + ASSERT(NULL != modulus); + ASSERT(NULL != base); + ASSERT(NULL != result_vector); + ASSERT(modulus != base); + + offset = 0; + + /* Make sure no PKA operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Update the A ptr with the offset address of the PKA RAM location + * where the exponent will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the Exponent in PKA RAM. */ + for(i = 0; i < number_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = number[i]; + } + + /* Determine the offset for the next data(BPTR). */ + offset += 4 * (i + number_size % 2); + /* Update the B ptr with the offset address of the PKA RAM location + * where the divisor will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Load the Modulus in PKA RAM. */ + for(i = 0; i < modulus_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = modulus[i]; + } + + /* Determine the offset for the next data(CPTR). */ + offset += 4 * (i + modulus_size % 2 + 2); + /* Update the C ptr with the offset address of the PKA RAM location + * where the Base will be stored. */ + REG(PKA_CPTR) = offset >> 2; + + /* Write Base to the Vector C in PKA RAM */ + + for(i = 0; i < base_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = base[i]; + } + + /* Determine the offset for the next data. + * INFO D and B can share the same memory area! + * offset += 4 * (i + extraBuf + 2); */ + + /* Copy the result vector address location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load D ptr with the result location in PKA RAM */ + REG(PKA_DPTR) = offset >> 2; + + /* Load A length registers with Big number length in 32 bit words. */ + REG(PKA_ALENGTH) = number_size; + + /* Load B length registers Divisor length in 32-bit words. */ + REG(PKA_BLENGTH) = modulus_size; + /* REG(PKA_SHIFT) = 0x00000001; + * Required for (EXPMod-variable): 0x0000A000 + * Start the PKCP modulo exponentiation operation(EXPMod-ACT2) + * by setting the PKA Function register. */ + REG(PKA_FUNCTION) = 0x0000C000; + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_exp_mod_get_result(uint32_t *buffer, + const uint8_t buffer_size, + const uint32_t result_vector) +{ + + uint32_t regMSWVal; + uint32_t len; + int i; + + /* Check the arguments. */ + ASSERT(NULL != buffer); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + /* verify that the operation is complete. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + /* Get the MSW register value. */ + regMSWVal = REG(PKA_MSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result */ + len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + /* If the size of the buffer provided is less than the result length than + * return error. */ + if(buffer_size < len) { + return PKA_STATUS_BUF_UNDERFLOW; + } + + /* copy the result from vector C into the pResult. */ + for(i = 0; i < len; i++) { + buffer[i] = REG(result_vector + 4 * i); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_divide_start(const uint32_t *dividend, + const uint8_t dividend_size, + const uint32_t *divisor, + const uint8_t divisor_size, + uint32_t *result_vector, + struct process *process) +{ + + uint32_t offset; + uint32_t spacing; + int i; + + /* We use largest len for spacing */ + if(dividend_size > divisor_size) { + spacing = dividend_size; + } else { + spacing = divisor_size; + } + spacing += 2 + spacing % 2; + + /* Check for the arguments. */ + ASSERT(NULL != dividend); + ASSERT(NULL != divisor); + ASSERT(NULL != result_vector); + + /* Make sure no operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Update the A ptr with the offset address of the PKA RAM location + * where the multiplicand will be stored. */ + offset = 0; + REG(PKA_APTR) = offset >> 2; + + /* Load the multiplicand in PKA RAM. */ + for(i = 0; i < dividend_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = *dividend; + dividend++; + } + + /* Determine the offset for the next data. */ + offset += 4 * spacing; + + /* Update the B ptr with the offset address of the PKA RAM location + * where the multiplier will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Load the multiplier in PKA RAM. */ + for(i = 0; i < divisor_size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = *divisor; + divisor++; + } + + /* Determine the offset for the reminder. */ + offset += 4 * spacing; + + /* Load C ptr with the result location in PKA RAM. */ + REG(PKA_CPTR) = offset >> 2; + + /* Determine the offset for the quotient. */ + offset += 4 * spacing; + + /* Copy the quotient vector address location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load D ptr with the result location in PKA RAM. */ + REG(PKA_DPTR) = offset >> 2; + + /* Load the respective length registers. */ + REG(PKA_ALENGTH) = dividend_size; + REG(PKA_BLENGTH) = divisor_size; + + /* Set the PKA function to the multiplication and start it. */ + REG(PKA_FUNCTION) = (PKA_FUNCTION_RUN | PKA_FUNCTION_DIVIDE); + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +bignum_divide_get_result(uint32_t *buffer, + uint32_t *buffer_size, + const uint32_t result_vector) +{ + + uint32_t regMSWVal; + uint32_t len; + int i; + + /* Check for arguments. */ + ASSERT(NULL != buffer); + ASSERT(NULL != buffer_size); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + /* Verify that the operation is complete. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + /* Get the MSW register value. */ + regMSWVal = REG(PKA_MSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result. */ + len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + + /* Make sure that the length of the supplied result buffer is adequate + * to store the resultant. */ + if(*buffer_size < len) { + return PKA_STATUS_BUF_UNDERFLOW; + } + + /* Copy the resultant length. */ + *buffer_size = len; + + /* Copy the result from vector C into the pResult. */ + for(i = 0; i < *buffer_size; i++) { + buffer[i] = REG(result_vector + 4 * i); + } + + return PKA_STATUS_SUCCESS; +} +/** @} */ + diff --git a/cpu/cc2538/dev/bignum-driver.h b/cpu/cc2538/dev/bignum-driver.h new file mode 100644 index 000000000..7cc646a84 --- /dev/null +++ b/cpu/cc2538/dev/bignum-driver.h @@ -0,0 +1,462 @@ +/* + * Original file: + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Port to Contiki: + * Authors: Andreas Dröscher + * Hu Luo + * Hossein Shafagh + * + * 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 copyright holder 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. + */ +/** + * \addtogroup cc2538-pka + * @{ + * + * \defgroup cc2538-bignum cc2538 BigNum math function driver + * + * Driver for the cc2538 BigNum math functions of the PKC engine + * @{ + * + * \file + * Header file for the cc2538 BigNum driver + * + * bignum_subtract_start bignum_subtract_get_result (subtraction) + * bignum_add_start bignum_add_get_result (addition) + * bignum_mod_start bignum_mod_get_result (modulo) + * bignum_exp_mod_start bignum_exp_mod_get_result (modular exponentiation operation) + * bignum_inv_mod_start bignum_inv_mod_get_result (inverse modulo operation) + * bignum_mul_start bignum_mul_get_result (multiplication) + * bignum_divide_start bignum_divide_get_result (division) + * bignum_cmp_start bignum_cmp_get_result (comparison) + */ +#ifndef BIGNUM_DRIVER_H_ +#define BIGNUM_DRIVER_H_ + +#include "contiki.h" +#include "pka.h" + +#include + +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \brief Starts the big number modulus operation. + * + * \param number Pointer to the big number on which modulo operation + * needs to be carried out. + * \param number_size Size of the big number \sa number in 32-bit word. + * \param modulus Pointer to the divisor. + * \param modulus_size Size of the divisor \sa modulus. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the modulo operation on the big num \sa number + * using the divisor \sa modulus. The PKA RAM location where the result + * will be available is stored in \sa result_vector. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t bignum_mod_start(const uint32_t *number, + const uint8_t number_size, + const uint32_t *modulus, + const uint8_t modulus_size, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the result of the big number modulus operation. + * + * \param buffer Pointer to buffer where the result needs to + * be stored. + * \param buffer_size Size of the provided buffer in 32 bit size word. + * \param result_vector Address of the result location which + * was provided by the start function \sa PKABigNumModStart(). + * + * This function gets the result of the big number modulus operation which was + * previously started using the function \sa PKABigNumModStart(). + * + * \retval PKA_STATUS_SUCCESS if successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_BUF_UNDERFLOW if the \e size is less than the length + * of the result. + */ +uint8_t bignum_mod_get_result(uint32_t *buffer, + const uint8_t buffer_size, + const uint32_t result_vector); + +/** \brief Starts the comparison of two big numbers. + * + * \param number1 Pointer to the first big number. + * \param number2 Pointer to the second big number. + * \param size Size of the big number in 32 bit size word. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the comparison of two big numbers pointed by + * \e number1 and \e number2. + * Note this function expects the size of the two big numbers equal. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t bignum_cmp_start(const uint32_t *number1, + const uint32_t *number2, + uint8_t size, + struct process *process); + +/** \brief Gets the result of the comparison operation of two big numbers. + * + * This function provides the results of the comparison of two big numbers + * which was started using the \sa PKABigNumCmpStart(). + * + * \retval PKA_STATUS_OPERATION_INPRG if the operation is in progress. + * \retval PKA_STATUS_SUCCESS if the two big numbers are equal. + * \retval PKA_STATUS_A_GR_B if the first number is greater than the second. + * \retval PKA_STATUS_A_LT_B if the first number is less than the second. + */ +uint8_t bignum_cmp_get_result(void); + +/** \brief Starts the big number inverse modulo operation. + * + * \param number Pointer to the buffer containing the big number + * (dividend). + * \param number_size Size of the \e number in 32 bit word. + * \param modulus Pointer to the buffer containing the modulus. + * \param modulus_size Size of the modulus in 32 bit word. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the the inverse modulo operation on \e number + * using the divisor \e modulus. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t bignum_inv_mod_start(const uint32_t *number, + const uint8_t number_size, + const uint32_t *modulus, + const uint8_t modulus_size, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the result of the big number inverse modulo operation. + * + * \param buffer Pointer to buffer where the result needs to be + * stored. + * \param buffer_size Size of the provided buffer in 32 bit size + * word. + * \param result_vector Address of the result location which + * was provided by the start function \sa PKABigNumInvModStart(). + * + * This function gets the result of the big number inverse modulo operation + * previously started using the function \sa PKABigNumInvModStart(). + * + * \retval PKA_STATUS_SUCCESS if the operation is successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy performing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_BUF_UNDERFLOW if the length of the provided buffer is less + * then the result. + */ +uint8_t bignum_inv_mod_get_result(uint32_t *buffer, + const uint8_t buffer_size, + const uint32_t result_vector); + +/** \brief Starts the big number multiplication. + * + * \param multiplicand Pointer to the buffer containing the big + * number multiplicand. + * \param multiplicand_size Size of the multiplicand in 32-bit word. + * \param multiplier Pointer to the buffer containing the big + * number multiplier. + * \param multiplier_size Size of the multiplier in 32-bit word. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the multiplication of the two big numbers. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t bignum_mul_start(const uint32_t *multiplicand, + const uint8_t multiplicand_size, + const uint32_t *multiplier, + const uint8_t multiplier_size, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the results of the big number multiplication. + * + * \param buffer Pointer to buffer where the result needs to be stored. + * \param buffer_size Address of the variable containing the length of the + * buffer. After the operation, the actual length of the resultant is + * stored at this address. + * \param result_vector Address of the result location which + * was provided by the start function \sa PKABigNumMultiplyStart(). + * + * This function gets the result of the multiplication of two big numbers + * operation previously started using the function \sa + * PKABigNumMultiplyStart(). + * + * \retval PKA_STATUS_SUCCESS if the operation is successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy performing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_FAILURE if the operation is not successful. + * \retval PKA_STATUS_BUF_UNDERFLOW if the length of the provided buffer is less + * then the length of the result. + */ +uint8_t bignum_mul_get_result(uint32_t *buffer, + uint32_t *buffer_size, + const uint32_t result_vector); + +/** \brief Starts the addition of two big number. + * + * \param number1 Pointer to the buffer containing the first big mumber. + * \param number1_size Size of the first big number in 32-bit word. + * \param number2 Pointer to the buffer containing the second big number. + * \param number2_size Size of the second big number in 32-bit word. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the addition of the two big numbers. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t bignum_add_start(const uint32_t *number1, + const uint8_t number1_size, + const uint32_t *number2, + const uint8_t number2_size, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the result of the addition operation on two big number. + * + * \param buffer Pointer to buffer where the result + * needs to be stored. + * \param buffer_size Address of the variable containing the length of + * the buffer. After the operation the actual length of the + * resultant is stored at this address. + * \param result_vector Address of the result location which + * was provided by the start function \sa PKABigNumAddStart(). + * + * This function gets the result of the addition operation on two big numbers, + * previously started using the function \sa PKABigNumAddStart(). + * + * \retval PKA_STATUS_SUCCESS if the operation is successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy performing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_FAILURE if the operation is not successful. + * \retval PKA_STATUS_BUF_UNDERFLOW if the length of the provided buffer is less + * then the length of the result. + */ +uint8_t bignum_add_get_result(uint32_t *buffer, + uint32_t *buffer_size, + const uint32_t result_vector); + +/** \brief Starts the substract of two big number. + * + * \param number1 Pointer to the buffer containing the first big mumber. + * \param number1_size Size of the first big number in 32-bit word. + * \param number2 Pointer to the buffer containing the second big number. + * \param number2_size Size of the second big number in 32-bit word. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the substraction of the two big numbers. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t bignum_subtract_start(const uint32_t *number1, + const uint8_t number1_size, + const uint32_t *number2, + const uint8_t number2_size, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the result of big number subtract. + * + * \param buffer Pointer to store the result of subtraction. + * \param buffer_size Address of the variable containing the length of the + * buffer. After the operation, the actual length of the resultant is + * stored at this address. + * \param result_vector Address of the result location which + * was provided by the start function PKABigNumSubtractStart(). + * + * This function gets the result of PKABigNumSubtractStart(). + * + * \retval PKA_STATUS_SUCCESS if the operation is successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy performing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_FAILURE if the operation is not successful. + */ +uint8_t bignum_subtract_get_result(uint32_t *buffer, + uint32_t *buffer_size, + const uint32_t result_vector); + +/** \brief Starts the big number moduluar Exponentiation operation. + * + * \param number Pointer to the Exponent on which moduluar Exponentiation operation + * needs to be carried out. + * \param number_size Size of the the Exponent number number in 32-bit word. + * \param modulus Pointer to the divisor. + * \param modulus_size Size of the divisor modulus. + * \param base Pointer to the Base. + * \param base_size Size of the divisor base. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the moduluar Exponentiation operation on the base num base + * using the Exponent number and the Modulus num modulus. The PKA RAM location where the result + * will be available is stored in \sa result_vector. + * IMPORTANT = Modulus and Based should have buffers of the same length! + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t bignum_exp_mod_start(const uint32_t *number, + const uint8_t number_size, + const uint32_t *modulus, + const uint8_t modulus_size, + const uint32_t *base, + const uint8_t base_size, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the result of the big number modulus operation result. + * + * \param buffer Pointer to buffer where the result needs to + * be stored. + * \param buffer_size Size of the provided buffer in 32 bit size word. + * \param result_vector Address of the result location which + * was provided by the start function \sa PKABigNumExpModStart(). + * + * This function gets the result of the big number modulus operation which was + * previously started using the function \sa PKABigNumExpModStart(). + * + * \retval PKA_STATUS_SUCCESS if successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_BUF_UNDERFLOW if the \e size is less than the length + * of the result. + * + * \note + * - 0 < number_size <= Max_Len + * - 1 < modulus_size <=Max_Len + * - modulus must be odd and modulus > 232 + * - base < modulus + */ +uint8_t bignum_exp_mod_get_result(uint32_t *buffer, + const uint8_t buffer_size, + const uint32_t result_vector); + +/** \brief Starts the big number Divide. + * + * \param dividend Pointer to the buffer containing the big + * number dividend. + * \param dividend_size Size of the dividend in 32-bit word. + * \param divisor Pointer to the buffer containing the big + * number divisor. + * \param divisor_size Size of the divisor in 32-bit word. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the divide of the two big numbers. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t bignum_divide_start(const uint32_t *dividend, + const uint8_t dividend_size, + const uint32_t *divisor, + const uint8_t divisor_size, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the results of the big number Divide. + * + * \param buffer Pointer to buffer where the result needs to be stored. + * \param buffer_size Address of the variable containing the length of the + * buffer. After the operation, the actual length of the resultant is + * stored at this address. + * \param result_vector Address of the result location which + * was provided by the start function \sa PKABigNumMultiplyStart(). + * + * This function gets the result of the Divide of two big numbers + * operation previously started using the function \sa + * PKABigNumDivideStart(). + * + * \retval PKA_STATUS_SUCCESS if the operation is successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy performing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_FAILURE if the operation is not successful. + * \retval PKA_STATUS_BUF_UNDERFLOW if the length of the provided buffer is less + * then the length of the result. + */ +uint8_t bignum_divide_get_result(uint32_t *buffer, + uint32_t *buffer_size, + const uint32_t result_vector); + +/** @} */ + +#endif /* BIGNUM_DRIVER_H_ */ + +/** + * @} + * @} + */ diff --git a/cpu/cc2538/dev/ecc-algorithm.c b/cpu/cc2538/dev/ecc-algorithm.c new file mode 100644 index 000000000..103e35bcb --- /dev/null +++ b/cpu/cc2538/dev/ecc-algorithm.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich. + * All rights reserved. + * + * Author: Andreas Dröscher + * + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + */ +/** + * \addtogroup c2538-ecc-algo + * @{ + * + * \file + * Implementation of the cc2538 ECC Algorithms + */ +#include +#include + +#include +#include + +#include "ecc-algorithm.h" +#include "ecc-driver.h" +#include "pka.h" + +#define CHECK_RESULT(...) \ + state->result = __VA_ARGS__; \ + if(state->result) { \ + printf("Line: %u Error: %u\n", __LINE__, (unsigned int)state->result); \ + PT_EXIT(&state->pt); \ + } + +PT_THREAD(ecc_compare(ecc_compare_state_t *state)) { + PT_BEGIN(&state->pt); + + CHECK_RESULT(bignum_cmp_start(state->a, state->b, state->size, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + state->result = bignum_cmp_get_result(); + + PT_END(&state->pt); +} + +PT_THREAD(ecc_multiply(ecc_multiply_state_t *state)) { + PT_BEGIN(&state->pt); + + CHECK_RESULT(ecc_mul_start(state->secret, &state->point_in, state->curve_info, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(ecc_mul_get_result(&state->point_out, state->rv)); + + PT_END(&state->pt); +} + +PT_THREAD(ecc_dsa_sign(ecc_dsa_sign_state_t *state)) { + /* Executed Every Time */ + uint8_t size = state->curve_info->size; + const uint32_t *ord = state->curve_info->n; + + ec_point_t point; + memcpy(point.x, state->curve_info->x, sizeof(point.x)); + memcpy(point.y, state->curve_info->y, sizeof(point.y)); + + PT_BEGIN(&state->pt); + + /* Invert k_e mod n */ + CHECK_RESULT(bignum_inv_mod_start(state->k_e, size, ord, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(bignum_inv_mod_get_result(state->k_e_inv, size, state->rv)); + + /* Calculate Point R = K_e * GeneratorPoint */ + CHECK_RESULT(ecc_mul_start(state->k_e, &point, state->curve_info, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(ecc_mul_get_result(&state->point_r, state->rv)); + + /* Calculate signature using big math functions + * d*r (r is the x coordinate of PointR) */ + CHECK_RESULT(bignum_mul_start(state->secret, size, state->point_r.x, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + state->len = 24; + CHECK_RESULT(bignum_mul_get_result(state->signature_s, &state->len, state->rv)); + + /* d*r mod n */ + CHECK_RESULT(bignum_mod_start(state->signature_s, state->len, ord, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(bignum_mod_get_result(state->signature_s, size, state->rv)); + + /* hash + d*r */ + CHECK_RESULT(bignum_add_start(state->hash, size, state->signature_s, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + state->len = 24; + CHECK_RESULT(bignum_add_get_result(state->signature_s, &state->len, state->rv)); + + /* hash + d*r mod n */ + CHECK_RESULT(bignum_mod_start(state->signature_s, state->len, ord, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(bignum_mod_get_result(state->signature_s, size, state->rv)); + + /* k_e_inv * (hash + d*r) */ + CHECK_RESULT(bignum_mul_start(state->k_e_inv, size, state->signature_s, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + state->len = 24; + CHECK_RESULT(bignum_mul_get_result(state->signature_s, &state->len, state->rv)); + + /* k_e_inv * (hash + d*r) mod n */ + CHECK_RESULT(bignum_mod_start(state->signature_s, state->len, ord, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(bignum_mod_get_result(state->signature_s, size, state->rv)); + + PT_END(&state->pt); +} + +PT_THREAD(ecc_dsa_verify(ecc_dsa_verify_state_t *state)) { + /* Executed Every Time */ + uint8_t size = state->curve_info->size; + const uint32_t *ord = state->curve_info->n; + + ec_point_t point; + memcpy(point.x, state->curve_info->x, sizeof(point.x)); + memcpy(point.y, state->curve_info->y, sizeof(point.y)); + + PT_BEGIN(&state->pt); + + /* Invert s mod n */ + CHECK_RESULT(bignum_inv_mod_start(state->signature_s, size, ord, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(bignum_inv_mod_get_result(state->s_inv, size, state->rv)); + + /* Calculate u1 = s_inv * hash */ + CHECK_RESULT(bignum_mul_start(state->s_inv, size, state->hash, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + state->len = 24; + CHECK_RESULT(bignum_mul_get_result(state->u1, &state->len, state->rv)); + + /* Calculate u1 = s_inv * hash mod n */ + CHECK_RESULT(bignum_mod_start(state->u1, state->len, ord, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(bignum_mod_get_result(state->u1, size, state->rv)); + + /* Calculate u2 = s_inv * r */ + CHECK_RESULT(bignum_mul_start(state->s_inv, size, state->signature_r, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + state->len = 24; + CHECK_RESULT(bignum_mul_get_result(state->u2, &state->len, state->rv)); + + /* Calculate u2 = s_inv * r mod n */ + CHECK_RESULT(bignum_mod_start(state->u2, state->len, ord, size, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(bignum_mod_get_result(state->u2, size, state->rv)); + + /* Calculate p1 = u1 * A */ + CHECK_RESULT(ecc_mul_start(state->u1, &point, state->curve_info, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(ecc_mul_get_result(&state->p1, state->rv)); + + /* Calculate p2 = u1 * B */ + CHECK_RESULT(ecc_mul_start(state->u2, &state->public, state->curve_info, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(ecc_mul_get_result(&state->p2, state->rv)); + + /* Calculate P = p1 + p2 */ + CHECK_RESULT(ecc_add_start(&state->p1, &state->p2, state->curve_info, &state->rv, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + CHECK_RESULT(ecc_add_get_result(&state->p1, state->rv)); + + /* Verify Result */ + CHECK_RESULT(bignum_cmp_start(state->signature_r, state->p1.x, size, state->process)); + PT_WAIT_UNTIL(&state->pt, pka_check_status()); + state->result = bignum_cmp_get_result(); + if((state->result == PKA_STATUS_A_GR_B) || (state->result == PKA_STATUS_A_LT_B)) { + state->result = PKA_STATUS_SIGNATURE_INVALID; + } + + PT_END(&state->pt); +} + +/** + * @} + * @} + */ diff --git a/cpu/cc2538/dev/ecc-algorithm.h b/cpu/cc2538/dev/ecc-algorithm.h new file mode 100644 index 000000000..31f07ec2e --- /dev/null +++ b/cpu/cc2538/dev/ecc-algorithm.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich. + * All rights reserved. + * + * Author: Andreas Dröscher + * + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + */ +/** + * \addtogroup cc2538-ecc + * @{ + * + * \defgroup cc2538-ecc-algo cc2538 ECC Algorithms + * + * This is a implementation of ECDH, ECDSA sign and ECDSA verify. It + * uses ecc-driver to communicate with the PKA. It uses continuations + * to free the main CPU / thread while the PKA is calculating. + * + * \note + * Only one request can be processed at a time. + * Maximal supported key length is 384bit (12 words). + * @{ + * + * \file + * Header file for the cc2538 ECC Algorithms + */ +#ifndef ECC_ALGORITHM_H_ +#define ECC_ALGORITHM_H_ + +#include "bignum-driver.h" +#include "ecc-driver.h" + +typedef struct { + /* Containers for the State */ + struct pt pt; + struct process *process; + + /* Input Variables */ + uint32_t a[12]; /**< Left Number */ + uint32_t b[12]; /**< Right Number */ + uint8_t size; /**< Length of a and b */ + + /* Output Variables */ + uint8_t result; /**< Result Code */ +} ecc_compare_state_t; + +/** + * \brief Do a compare of two big numbers + * + * This function can be used for ECDH as well as + * Calculating a Public Key for ECDSA + */ +PT_THREAD(ecc_compare(ecc_compare_state_t *state)); + +typedef struct { + /* Containers for the State */ + struct pt pt; + struct process *process; + + /* Input Variables */ + ecc_curve_info_t *curve_info; /**< Curve defining the CyclicGroup */ + ec_point_t point_in; /**< Generator Point */ + uint32_t secret[12]; /**< Secret */ + + /* Variables Holding intermediate data (initialized/used internally) */ + uint32_t rv; /**< Address of Next Result in PKA SRAM */ + + /* Output Variables */ + uint8_t result; /**< Result Code */ + ec_point_t point_out; /**< Generated Point */ +} ecc_multiply_state_t; + +/** + * \brief Do a Multiplication on a EC + * + * This function can be used for ECDH as well as + * Calculating a Public Key for ECDSA + */ +PT_THREAD(ecc_multiply(ecc_multiply_state_t *state)); + +typedef struct { + /* Containers for the State */ + struct pt pt; + struct process *process; + + /* Input Variables */ + ecc_curve_info_t *curve_info; /**< Curve defining the CyclicGroup */ + uint32_t secret[12]; /**< Secret Key */ + uint32_t k_e[12]; /**< Ephemeral Key */ + uint32_t hash[12]; /**< Hash to be signed */ + + /* Variables Holding intermediate data (initialized/used internally) */ + uint32_t rv; /**< Address of Next Result in PKA SRAM */ + uint32_t k_e_inv[12]; /**< Inverted ephemeral Key */ + uint32_t len; /**< Length of intermediate Result */ + + /* Output Variables */ + uint8_t result; /**< Result Code */ + ec_point_t point_r; /**< Signature R (x coordinate) */ + uint32_t signature_s[24]; /**< Signature S */ +} ecc_dsa_sign_state_t; + +/** + * \brief Sign a Hash + * + * This function has to be called several times until the + * pt state is EXIT + * If the result code is 0 (SUCCESS) the signature can be + * read from point_r and signature_s + */ +PT_THREAD(ecc_dsa_sign(ecc_dsa_sign_state_t *state)); + +typedef struct { + /* Containers for the State */ + struct pt pt; + struct process *process; + + /* Input Variables */ + ecc_curve_info_t *curve_info; /**< Curve defining the CyclicGroup */ + uint32_t signature_r[12]; /**< Signature R */ + uint32_t signature_s[12]; /**< Signature S */ + uint32_t hash[12]; /**< Hash to be signed */ + ec_point_t public; /**< Signature R (x coordinate) */ + + /* Variables Holding intermediate data (initialized/used internally) */ + uint32_t rv; /**< Address of Next Result in PKA SRAM */ + uint32_t s_inv[12]; /**< Inverted ephemeral Key */ + uint32_t u1[24]; /**< Intermediate result */ + uint32_t u2[24]; /**< Intermediate result */ + ec_point_t p1; /**< Intermediate result */ + ec_point_t p2; /**< Intermediate result */ + uint32_t len; /**< Length of intermediate Result */ + + /* Output Variables */ + uint8_t result; /**< Result Code */ +} ecc_dsa_verify_state_t; + +/** + * \brief Verify Signature + * + * This function has to be called several times until the + * pt state is EXIT + * If the result code is 0 (SUCCESS) the verification + * was success full. + * \note some error codes signal internal errors + * and others signal falls signatures. + */ +PT_THREAD(ecc_dsa_verify(ecc_dsa_verify_state_t *state)); + +#endif /* ECC_ALGORITHM_H_ */ + +/** + * @} + * @} + */ + diff --git a/cpu/cc2538/dev/ecc-curve.c b/cpu/cc2538/dev/ecc-curve.c new file mode 100644 index 000000000..bc3e9e8c6 --- /dev/null +++ b/cpu/cc2538/dev/ecc-curve.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich. + * All rights reserved. + * + * Author: Andreas Dröscher + * + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + */ +/** + * \addtogroup c2538-ecc-curves + * @{ + */ +#include +#include + +/* [NIST P-256, X9.62 prime256v1] */ +static const uint32_t nist_p_256_p[8] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF }; +static const uint32_t nist_p_256_n[8] = { 0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF }; +static const uint32_t nist_p_256_a[8] = { 0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF }; +static const uint32_t nist_p_256_b[8] = { 0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, + 0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8 }; +static const uint32_t nist_p_256_x[8] = { 0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81, + 0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2 }; +static const uint32_t nist_p_256_y[8] = { 0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357, + 0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2 }; + +ecc_curve_info_t nist_p_256 = { + .name = "NIST P-256", + .size = 8, + .prime = nist_p_256_p, + .n = nist_p_256_n, + .a = nist_p_256_a, + .b = nist_p_256_b, + .x = nist_p_256_x, + .y = nist_p_256_y +}; + +/* [NIST P-192, X9.62 prime192v1] */ +static const uint32_t nist_p_192_p[6] = { 0xffffffff, 0xffffffff, 0xfffffffe, 0xffffffff, + 0xffffffff, 0xffffffff }; +static const uint32_t nist_p_192_a[6] = { 0xfffffffc, 0xffffffff, 0xfffffffe, 0xffffffff, + 0xffffffff, 0xffffffff }; +static const uint32_t nist_p_192_b[6] = { 0xc146b9b1, 0xfeb8deec, 0x72243049, 0x0fa7e9ab, + 0xe59c80e7, 0x64210519 }; +static const uint32_t nist_p_192_x[6] = { 0x82ff1012, 0xf4ff0afd, 0x43a18800, 0x7cbf20eb, + 0xb03090f6, 0x188da80e }; +static const uint32_t nist_p_192_y[6] = { 0x1e794811, 0x73f977a1, 0x6b24cdd5, 0x631011ed, + 0xffc8da78, 0x07192b95 }; +static const uint32_t nist_p_192_n[6] = { 0xb4d22831, 0x146bc9b1, 0x99def836, 0xffffffff, + 0xffffffff, 0xffffffff }; + +ecc_curve_info_t nist_p_192 = { + .name = "NIST P-192", + .size = 6, + .prime = nist_p_192_p, + .n = nist_p_192_n, + .a = nist_p_192_a, + .b = nist_p_192_b, + .x = nist_p_192_x, + .y = nist_p_192_y +}; + +/** + * @} + * @} + */ diff --git a/cpu/cc2538/dev/ecc-curve.h b/cpu/cc2538/dev/ecc-curve.h new file mode 100644 index 000000000..66c050a08 --- /dev/null +++ b/cpu/cc2538/dev/ecc-curve.h @@ -0,0 +1,65 @@ +/* + * Original file: + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Port to Contiki: + * Copyright (c) 2014 Andreas Dröscher + * + * 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 copyright holder 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. + */ +/** + * \addtogroup cc2538-ecc + * @{ + * + * \defgroup cc2538-ecc-curves cc2538 NIST curves + * + * NIST curves for various key sizes + * @{ + * + * \file + * NIST curves for various key sizes + */ +#ifndef ECC_CURVE_H_ +#define ECC_CURVE_H_ + +/* + * NIST P-256, X9.62 prime256v1 + */ +ecc_curve_info_t nist_p_256; + +/* + * NIST P-192, X9.62 prime192v1 + */ +ecc_curve_info_t nist_p_192; + +#endif /* CURVE_INFO_H_ */ + +/** + * @} + * @} + */ diff --git a/cpu/cc2538/dev/ecc-driver.c b/cpu/cc2538/dev/ecc-driver.c new file mode 100644 index 000000000..89a345e14 --- /dev/null +++ b/cpu/cc2538/dev/ecc-driver.c @@ -0,0 +1,559 @@ +/* + * Original file: + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Port to Contiki: + * Copyright (c) 2014 Andreas Dröscher + * + * 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 copyright holder 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. + */ +/** + * \addtogroup cc2538-ecc + * @{ + * + * \file + * Implementation of the cc2538 ECC driver + */ +#include "ecc-driver.h" +#include "reg.h" +#include "dev/nvic.h" + +#define ASSERT(IF) if(!(IF)) { return PKA_STATUS_INVALID_PARAM; } + +/*---------------------------------------------------------------------------*/ +uint8_t +ecc_mul_start(uint32_t *scalar, ec_point_t *ec_point, + ecc_curve_info_t *curve, uint32_t *result_vector, + struct process *process) +{ + + uint8_t extraBuf; + uint32_t offset; + int i; + + /* Check for the arguments. */ + ASSERT(NULL != scalar); + ASSERT(NULL != ec_point); + ASSERT(NULL != ec_point->x); + ASSERT(NULL != ec_point->y); + ASSERT(NULL != curve); + ASSERT(curve->size <= PKA_MAX_CURVE_SIZE); + ASSERT(NULL != result_vector); + + offset = 0; + + /* Make sure no PKA operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Calculate the extra buffer requirement. */ + extraBuf = 2 + curve->size % 2; + + /* Update the A ptr with the offset address of the PKA RAM location + * where the scalar will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the scalar in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = *scalar++; + } + + /* Determine the offset for the next data. */ + offset += 4 * (i + (curve->size % 2)); + + /* Update the B ptr with the offset address of the PKA RAM location + * where the curve parameters will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Write curve parameter 'p' as 1st part of vector B immediately + * following vector A at PKA RAM */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->prime[i]; + } + + /* Determine the offset for the next data. */ + offset += 4 * (i + extraBuf); + + /* Copy curve parameter 'a' in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->a[i]; + } + + /* Determine the offset for the next data. */ + offset += 4 * (i + extraBuf); + + /* Copy curve parameter 'b' in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->b[i]; + } + + /* Determine the offset for the next data. */ + offset += 4 * (i + extraBuf); + + /* Update the C ptr with the offset address of the PKA RAM location + * where the x, y will be stored. */ + REG(PKA_CPTR) = offset >> 2; + + /* Write elliptic curve point.x co-ordinate value. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = ec_point->x[i]; + } + + /* Determine the offset for the next data. */ + offset += 4 * (i + extraBuf); + + /* Write elliptic curve point.y co-ordinate value. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = ec_point->y[i]; + } + + /* Determine the offset for the next data. */ + offset += 4 * (i + extraBuf); + + /* Update the result location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load D ptr with the result location in PKA RAM. */ + REG(PKA_DPTR) = offset >> 2; + + /* Load length registers. */ + REG(PKA_ALENGTH) = curve->size; + REG(PKA_BLENGTH) = curve->size; + + /* set the PKA function to ECC-MULT and start the operation. */ + REG(PKA_FUNCTION) = 0x0000D000; + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +ecc_mul_get_result(ec_point_t *ec_point, + uint32_t result_vector) +{ + int i; + uint32_t addr; + uint32_t regMSWVal; + uint32_t len; + + /* Check for the arguments. */ + ASSERT(NULL != ec_point); + ASSERT(NULL != ec_point->x); + ASSERT(NULL != ec_point->y); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + /* Verify that the operation is completed. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + if(REG(PKA_SHIFT) == 0x00000000) { + /* Get the MSW register value. */ + regMSWVal = REG(PKA_MSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result */ + len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + + addr = result_vector; + + /* copy the x co-ordinate value of the result from vector D into + * the \e ec_point. */ + for(i = 0; i < len; i++) { + ec_point->x[i] = REG(addr + 4 * i); + } + + addr += 4 * (i + 2 + len % 2); + + /* copy the y co-ordinate value of the result from vector D into + * the \e ec_point. */ + for(i = 0; i < len; i++) { + ec_point->y[i] = REG(addr + 4 * i); + } + + return PKA_STATUS_SUCCESS; + } else { + return PKA_STATUS_FAILURE; + } +} +/*---------------------------------------------------------------------------*/ +uint8_t +ecc_mul_gen_pt_start(uint32_t *scalar, ecc_curve_info_t *curve, + uint32_t *result_vector, struct process *process) +{ + uint8_t extraBuf; + uint32_t offset; + int i; + + /* check for the arguments. */ + ASSERT(NULL != scalar); + ASSERT(NULL != curve); + ASSERT(curve->size <= PKA_MAX_CURVE_SIZE); + ASSERT(NULL != result_vector); + + offset = 0; + + /* Make sure no operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Calculate the extra buffer requirement. */ + extraBuf = 2 + curve->size % 2; + + /* Update the A ptr with the offset address of the PKA RAM location + * where the scalar will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the scalar in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = *scalar++; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + (curve->size % 2)); + + /* Update the B ptr with the offset address of the PKA RAM location + * where the curve parameters will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Write curve parameter 'p' as 1st part of vector B. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->prime[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Write curve parameter 'a' in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->a[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* write curve parameter 'b' in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->b[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Update the C ptr with the offset address of the PKA RAM location + * where the x, y will be stored. */ + REG(PKA_CPTR) = offset >> 2; + + /* Write x co-ordinate value of the Generator point in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->x[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Write y co-ordinate value of the Generator point in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->y[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Update the result location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load D ptr with the result location in PKA RAM. */ + REG(PKA_DPTR) = offset >> 2; + + /* Load length registers. */ + REG(PKA_ALENGTH) = curve->size; + REG(PKA_BLENGTH) = curve->size; + + /* Set the PKA function to ECC-MULT and start the operation. */ + REG(PKA_FUNCTION) = 0x0000D000; + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +ecc_mul_gen_pt_get_result(ec_point_t *ec_point, + uint32_t result_vector) +{ + + int i; + uint32_t regMSWVal; + uint32_t addr; + uint32_t len; + + /* Check for the arguments. */ + ASSERT(NULL != ec_point); + ASSERT(NULL != ec_point->x); + ASSERT(NULL != ec_point->y); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + /* Verify that the operation is completed. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + if(REG(PKA_SHIFT) == 0x00000000) { + /* Get the MSW register value. */ + regMSWVal = REG(PKA_MSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result. */ + len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + + addr = result_vector; + + /* Copy the x co-ordinate value of the result from vector D into the + * EC point. */ + for(i = 0; i < len; i++) { + ec_point->x[i] = REG(addr + 4 * i); + } + + addr += 4 * (i + 2 + len % 2); + + /* Copy the y co-ordinate value of the result from vector D into the + * EC point. */ + for(i = 0; i < len; i++) { + ec_point->y[i] = REG(addr + 4 * i); + } + + return PKA_STATUS_SUCCESS; + } else { + return PKA_STATUS_FAILURE; + } +} +/*---------------------------------------------------------------------------*/ +uint8_t +ecc_add_start(ec_point_t *ec_point1, ec_point_t *ec_point2, + ecc_curve_info_t *curve, uint32_t *result_vector, + struct process *process) +{ + + uint8_t extraBuf; + uint32_t offset; + int i; + + /* Check for the arguments. */ + ASSERT(NULL != ec_point1); + ASSERT(NULL != ec_point1->x); + ASSERT(NULL != ec_point1->y); + ASSERT(NULL != ec_point2); + ASSERT(NULL != ec_point2->x); + ASSERT(NULL != ec_point2->y); + ASSERT(NULL != curve); + ASSERT(NULL != result_vector); + + offset = 0; + + /* Make sure no operation is in progress. */ + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Calculate the extra buffer requirement. */ + extraBuf = 2 + curve->size % 2; + + /* Update the A ptr with the offset address of the PKA RAM location + * where the first ecPt will be stored. */ + REG(PKA_APTR) = offset >> 2; + + /* Load the x co-ordinate value of the first EC point in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = ec_point1->x[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Load the y co-ordinate value of the first EC point in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = ec_point1->y[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Update the B ptr with the offset address of the PKA RAM location + * where the curve parameters will be stored. */ + REG(PKA_BPTR) = offset >> 2; + + /* Write curve parameter 'p' as 1st part of vector B */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->prime[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Write curve parameter 'a'. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = (uint32_t)curve->a[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Update the C ptr with the offset address of the PKA RAM location + * where the ecPt2 will be stored. */ + REG(PKA_CPTR) = offset >> 2; + + /* Load the x co-ordinate value of the second EC point in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = ec_point2->x[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Load the y co-ordinate value of the second EC point in PKA RAM. */ + for(i = 0; i < curve->size; i++) { + REG(PKA_RAM_BASE + offset + 4 * i) = ec_point2->y[i]; + } + + /* Determine the offset in PKA RAM for the next data. */ + offset += 4 * (i + extraBuf); + + /* Copy the result vector location. */ + *result_vector = PKA_RAM_BASE + offset; + + /* Load D ptr with the result location in PKA RAM. */ + REG(PKA_DPTR) = offset >> 2; + + /* Load length registers. */ + REG(PKA_BLENGTH) = curve->size; + + /* Set the PKA Function to ECC-ADD and start the operation. */ + REG(PKA_FUNCTION) = 0x0000B000; + + /* Enable Interrupt */ + if(process != NULL) { + pka_register_process_notification(process); + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_enable(NVIC_INT_PKA); + } + + return PKA_STATUS_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +ecc_add_get_result(ec_point_t *ec_point, uint32_t result_vector) +{ + uint32_t regMSWVal; + uint32_t addr; + int i; + uint32_t len; + + /* Check for the arguments. */ + ASSERT(NULL != ec_point); + ASSERT(NULL != ec_point->x); + ASSERT(NULL != ec_point->y); + ASSERT(result_vector > PKA_RAM_BASE); + ASSERT(result_vector < (PKA_RAM_BASE + PKA_RAM_SIZE)); + + if((REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) != 0) { + return PKA_STATUS_OPERATION_INPRG; + } + + /* Disable Interrupt */ + nvic_interrupt_disable(NVIC_INT_PKA); + pka_register_process_notification(NULL); + + if(REG(PKA_SHIFT) == 0x00000000) { + /* Get the MSW register value. */ + regMSWVal = REG(PKA_MSW); + + /* Check to make sure that the result vector is not all zeroes. */ + if(regMSWVal & PKA_MSW_RESULT_IS_ZERO) { + return PKA_STATUS_RESULT_0; + } + + /* Get the length of the result. */ + len = ((regMSWVal & PKA_MSW_MSW_ADDRESS_M) + 1) + - ((result_vector - PKA_RAM_BASE) >> 2); + + addr = result_vector; + + /* Copy the x co-ordinate value of result from vector D into the + * the output EC Point. */ + for(i = 0; i < len; i++) { + ec_point->x[i] = REG(addr + 4 * i); + } + + addr += 4 * (i + 2 + len % 2); + + /* Copy the y co-ordinate value of result from vector D into the + * the output EC Point. */ + for(i = 0; i < len; i++) { + ec_point->y[i] = REG(addr + 4 * i); + } + + return PKA_STATUS_SUCCESS; + } else { + return PKA_STATUS_FAILURE; + } +} +/** @} */ diff --git a/cpu/cc2538/dev/ecc-driver.h b/cpu/cc2538/dev/ecc-driver.h new file mode 100644 index 000000000..8afcc8332 --- /dev/null +++ b/cpu/cc2538/dev/ecc-driver.h @@ -0,0 +1,227 @@ +/* + * Original file: + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Port to Contiki: + * Copyright (c) 2014 Andreas Dröscher + * + * 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 copyright holder 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. + */ +/** + * \addtogroup cc2538-pka + * @{ + * + * \defgroup cc2538-ecc cc2538 ECC driver + * + * Driver for the cc2538 ECC mode of the PKC engine + * @{ + * + * \file + * Header file for the cc2538 ECC driver + */ +#ifndef ECC_DRIVER_H_ +#define ECC_DRIVER_H_ + +#include "contiki.h" +#include "pka.h" + +#include +/*---------------------------------------------------------------------------*/ +/** \name ECC structures + * @{ + */ +typedef struct { + const char *name; /**< Name of the curve. */ + const uint8_t size; /**< Size of the curve in 32-bit word. */ + const uint32_t *prime; /**< The prime that defines the field of the curve. */ + const uint32_t *n; /**< Order of the curve. */ + const uint32_t *a; /**< Co-efficient a of the equation. */ + const uint32_t *b; /**< co-efficient b of the equation. */ + const uint32_t *x; /**< x co-ordinate value of the generator point. */ + const uint32_t *y; /**< y co-ordinate value of the generator point. */ +} ecc_curve_info_t; + +typedef struct { + uint32_t x[12]; /**< Pointer to value of the x co-ordinate. */ + uint32_t y[12]; /**< Pointer to value of the y co-ordinate. */ +} ec_point_t; + +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name ECC functions + * \note Not all sequencer functions are implemented in this driver + * look at the CC2538 manual for a complete list. + * @{ + */ + +/** \brief Starts ECC Multiplication. + * + * \param scalar Pointer to the buffer containing the scalar + * value to be multiplied. + * \param ec_point Pointer to the structure containing the + * elliptic curve point to be multiplied. The point should be + * on the given curve. + * \param curve Pointer to the structure containing the curve + * info. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the Elliptical curve cryptography (ECC) point + * multiplication operation on the EC point and the scalar value. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t ecc_mul_start(uint32_t *scalar, + ec_point_t *ec_point, + ecc_curve_info_t *curve, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the result of ECC Multiplication + * + * \param ec_point Pointer to the structure where the resultant EC + * point will be stored. The callee is responsible to allocate the + * space for the ec point structure and the x and y co-ordinate as well. + * \param result_vector Address of the result location which + * was provided by the start function \sa PKAECCMultiplyStart(). + * + * This function gets the result of ecc point multiplication operation on the + * ec point and the scalar value, previously started using the function + * \sa PKAECCMultiplyStart(). + * + * \retval PKA_STATUS_SUCCESS if the operation is successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy performing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_FAILURE if the operation is not successful. + */ +uint8_t ecc_mul_get_result(ec_point_t *ec_point, + uint32_t result_vector); + +/** \brief Starts the ECC Multiplication with Generator point. + * + * \param scalar Pointer to the buffer containing the + * scalar value. + * \param curve Pointer to the structure containing the curve + * info. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the ecc point multiplication operation of the + * scalar value with the well known generator point of the given curve. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t ecc_mul_gen_pt_start(uint32_t *scalar, + ecc_curve_info_t *curve, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the result of ECC Multiplication with Generator point. + * + * \param ec_point Pointer to the structure where the resultant EC + * point will be stored. The callee is responsible to allocate the + * space for the ec point structure and the x and y co-ordinate as well. + * \param result_vector Address of the result location which + * was provided by the start function \sa PKAECCMultGenPtStart(). + * + * This function gets the result of ecc point multiplication operation on the + * scalar point and the known generator point on the curve, previously started + * using the function \sa PKAECCMultGenPtStart(). + * + * \retval PKA_STATUS_SUCCESS if the operation is successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy performing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_FAILURE if the operation is not successful. + */ +uint8_t ecc_mul_gen_pt_get_result(ec_point_t *ec_point, + uint32_t result_vector); + +/** \brief Starts the ECC Addition. + * + * \param ec_point1 Pointer to the structure containing the first + * ecc point. + * \param ec_point2 Pointer to the structure containing the + * second ecc point. + * \param curve Pointer to the structure containing the curve + * info. + * \param result_vector Pointer to the result vector location + * which will be set by this function. + * \param process Process to be polled upon completion of the + * operation, or \c NULL + * + * This function starts the ecc point addition operation on the + * two given ec points and generates the resultant ecc point. + * + * \retval PKA_STATUS_SUCCESS if successful in starting the operation. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy doing + * some other operation. + */ +uint8_t ecc_add_start(ec_point_t *ec_point1, ec_point_t *ec_point2, + ecc_curve_info_t *curve, + uint32_t *result_vector, + struct process *process); + +/** \brief Gets the result of the ECC Addition + * + * \param ptOutEcPt Pointer to the structure where the resultant + * point will be stored. The callee is responsible to allocate memory, + * for the ec point structure including the memory for x and y + * co-ordinate values. + * \param ui32ResultLoc Address of the result location which + * was provided by the function \sa PKAECCAddStart(). + * + * This function gets the result of ecc point addition operation on the + * on the two given ec points, previously started using the function \sa + * PKAECCAddStart(). + * + * \retval PKA_STATUS_SUCCESS if the operation is successful. + * \retval PKA_STATUS_OPERATION_INPRG if the PKA hw module is busy performing + * the operation. + * \retval PKA_STATUS_RESULT_0 if the result is all zeroes. + * \retval PKA_STATUS_FAILURE if the operation is not successful. + */ +uint8_t ecc_add_get_result(ec_point_t *ptOutEcPt, uint32_t ui32ResultLoc); + +/** @} */ + +#endif /* ECC_DRIVER_H_ */ + +/** + * @} + * @} + */ diff --git a/cpu/cc2538/dev/pka.c b/cpu/cc2538/dev/pka.c new file mode 100644 index 000000000..b325a454e --- /dev/null +++ b/cpu/cc2538/dev/pka.c @@ -0,0 +1,128 @@ +/* + * Original file: + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Port to Contiki: + * Copyright (c) 2014 Andreas Dröscher + * + * 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 copyright holder 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. + */ +/** + * \addtogroup cc2538-pka + * @{ + * + * \file + * Implementation of the cc2538 PKA engine driver + */ +#include "contiki.h" +#include "sys/energest.h" +#include "dev/pka.h" +#include "dev/sys-ctrl.h" +#include "dev/nvic.h" +#include "lpm.h" +#include "reg.h" + +#include +#include + +static volatile struct process *notification_process = NULL; +/*---------------------------------------------------------------------------*/ +/** \brief The PKA engine ISR + * + * This is the interrupt service routine for the PKA engine. + * + * This ISR is called at worst from PM0, so lpm_exit() does not need + * to be called. + */ +void +pka_isr(void) +{ + ENERGEST_ON(ENERGEST_TYPE_IRQ); + + nvic_interrupt_unpend(NVIC_INT_PKA); + nvic_interrupt_disable(NVIC_INT_PKA); + + if(notification_process != NULL) { + process_poll((struct process *)notification_process); + notification_process = NULL; + } + + ENERGEST_OFF(ENERGEST_TYPE_IRQ); +} +/*---------------------------------------------------------------------------*/ +static bool +permit_pm1(void) +{ + return (REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) == 0; +} +/*---------------------------------------------------------------------------*/ +void +pka_init(void) +{ + volatile int i; + + lpm_register_peripheral(permit_pm1); + + pka_enable(); + + /* Reset the PKA engine */ + REG(SYS_CTRL_SRSEC) |= SYS_CTRL_SRSEC_PKA; + for(i = 0; i < 16; i++) { + REG(SYS_CTRL_SRSEC) &= ~SYS_CTRL_SRSEC_PKA; + } +} +/*---------------------------------------------------------------------------*/ +void +pka_enable(void) +{ + /* Enable the clock for the PKA engine */ + REG(SYS_CTRL_RCGCSEC) |= SYS_CTRL_RCGCSEC_PKA; + REG(SYS_CTRL_SCGCSEC) |= SYS_CTRL_SCGCSEC_PKA; + REG(SYS_CTRL_DCGCSEC) |= SYS_CTRL_DCGCSEC_PKA; +} +/*---------------------------------------------------------------------------*/ +void +pka_disable(void) +{ + /* Gate the clock for the PKA engine */ + REG(SYS_CTRL_RCGCSEC) &= ~SYS_CTRL_RCGCSEC_PKA; + REG(SYS_CTRL_SCGCSEC) &= ~SYS_CTRL_SCGCSEC_PKA; + REG(SYS_CTRL_DCGCSEC) &= ~SYS_CTRL_DCGCSEC_PKA; +} +/*---------------------------------------------------------------------------*/ +uint8_t +pka_check_status(void) +{ + return (REG(PKA_FUNCTION) & PKA_FUNCTION_RUN) == 0; +} +void +pka_register_process_notification(struct process *p) +{ + notification_process = p; +} +/** @} */ diff --git a/cpu/cc2538/dev/pka.h b/cpu/cc2538/dev/pka.h new file mode 100644 index 000000000..7a63a3d02 --- /dev/null +++ b/cpu/cc2538/dev/pka.h @@ -0,0 +1,871 @@ +/* + * Original file: + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Port to Contiki: + * Copyright (c) 2014 Andreas Dröscher + * + * 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 copyright holder 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. + */ +/** + * \addtogroup cc2538 + * @{ + * + * \defgroup cc2538-pka cc2538 PKA engine + * + * Driver for the cc2538 PKA engine + * @{ + * + * \file + * Header file for the cc2538 PKA engine driver + */ +#ifndef PKA_H_ +#define PKA_H_ + +#include "contiki.h" +#include + +/*---------------------------------------------------------------------------*/ +/** \name PKA memory + * @{ + */ +#define PKA_RAM_BASE 0x44006000 /**< PKA Memory Address */ +#define PKA_RAM_SIZE 0x800 /**< PKA Memory Size */ +#define PKA_MAX_CURVE_SIZE 12 /**< Define for the maximum curve + size supported by the PKA module + in 32 bit word. */ +#define PKA_MAX_LEN 12 /**< Define for the maximum length of + the big number supported by the + PKA module in 32 bit word. */ +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA register offsets + * @{ + */ +#define PKA_APTR 0x44004000 /**< PKA vector A address During + execution of basic PKCP + operations, this register is + double buffered and can be + written with a new value for the + next operation; when not + written, the value remains + intact. During the execution of + sequencer-controlled complex + operations, this register may + not be written and its value is + undefined at the conclusion of + the operation. The driver + software cannot rely on the + written value to remain intact. */ +#define PKA_BPTR 0x44004004 /**< PKA vector B address During + execution of basic PKCP + operations, this register is + double buffered and can be + written with a new value for the + next operation; when not + written, the value remains + intact. During the execution of + sequencer-controlled complex + operations, this register may + not be written and its value is + undefined at the conclusion of + the operation. The driver + software cannot rely on the + written value to remain intact. */ +#define PKA_CPTR 0x44004008 /**< PKA vector C address During + execution of basic PKCP + operations, this register is + double buffered and can be + written with a new value for the + next operation; when not + written, the value remains + intact. During the execution of + sequencer-controlled complex + operations, this register may + not be written and its value is + undefined at the conclusion of + the operation. The driver + software cannot rely on the + written value to remain intact. */ +#define PKA_DPTR 0x4400400C /**< PKA vector D address During + execution of basic PKCP + operations, this register is + double buffered and can be + written with a new value for the + next operation; when not + written, the value remains + intact. During the execution of + sequencer-controlled complex + operations, this register may + not be written and its value is + undefined at the conclusion of + the operation. The driver + software cannot rely on the + written value to remain intact. */ +#define PKA_ALENGTH 0x44004010 /**< PKA vector A length During + execution of basic PKCP + operations, this register is + double buffered and can be + written with a new value for the + next operation; when not + written, the value remains + intact. During the execution of + sequencer-controlled complex + operations, this register may + not be written and its value is + undefined at the conclusion of + the operation. The driver + software cannot rely on the + written value to remain intact. */ +#define PKA_BLENGTH 0x44004014 /**< PKA vector B length During + execution of basic PKCP + operations, this register is + double buffered and can be + written with a new value for the + next operation; when not + written, the value remains + intact. During the execution of + sequencer-controlled complex + operations, this register may + not be written and its value is + undefined at the conclusion of + the operation. The driver + software cannot rely on the + written value to remain intact. */ +#define PKA_SHIFT 0x44004018 /**< PKA bit shift value For basic + PKCP operations, modifying the + contents of this register is + made impossible while the + operation is being performed. + For the ExpMod-variable and + ExpMod-CRT operations, this + register is used to indicate the + number of odd powers to use + (directly as a value in the + range 1-16). For the ModInv and + ECC operations, this register is + used to hold a completion code. */ +#define PKA_FUNCTION 0x4400401C /**< PKA function This register + contains the control bits to + start basic PKCP as well as + complex sequencer operations. + The run bit can be used to poll + for the completion of the + operation. Modifying bits [11:0] + is made impossible during the + execution of a basic PKCP + operation. During the execution + of sequencer-controlled complex + operations, this register is + modified; the run and stall + result bits are set to zero at + the conclusion, but other bits + are undefined. Attention: + Continuously reading this + register to poll the run bit is + not allowed when executing + complex sequencer operations + (the sequencer cannot access the + PKCP when this is done). Leave + at least one sysclk cycle + between poll operations. */ +#define PKA_COMPARE 0x44004020 /**< PKA compare result This + register provides the result of + a basic PKCP compare operation. + It is updated when the run bit + in the PKA_FUNCTION register is + reset at the end of that + operation. Status after a + complex sequencer operation is + unknown */ +#define PKA_MSW 0x44004024 /**< PKA most-significant-word of + result vector This register + indicates the (word) address in + the PKA RAM where the most + significant nonzero 32-bit word + of the result is stored. Should + be ignored for modulo + operations. For basic PKCP + operations, this register is + updated when the run bit in the + PKA_FUNCTION register is reset + at the end of the operation. For + the complex-sequencer controlled + operations, updating of the + final value matching the actual + result is done near the end of + the operation; note that the + result is only meaningful if no + errors were detected and that + for ECC operations, the PKA_MSW + register will provide + information for the x-coordinate + of the result point only. */ +#define PKA_DIVMSW 0x44004028 /**< PKA most-significant-word of + divide remainder This register + indicates the (32-bit word) + address in the PKA RAM where the + most significant nonzero 32-bit + word of the remainder result for + the basic divide and modulo + operations is stored. Bits [4:0] + are loaded with the bit number + of the most-significant nonzero + bit in the most-significant + nonzero word when MS one control + bit is set. For divide, modulo, + and MS one reporting, this + register is updated when the RUN + bit in the PKA_FUNCTION register + is reset at the end of the + operation. For the complex + sequencer controlled operations, + updating of bits [4:0] of this + register with the + most-significant bit location of + the actual result is done near + the end of the operation. The + result is meaningful only if no + errors were detected and that + for ECC operations; the + PKA_DIVMSW register provides + information for the x-coordinate + of the result point only. */ +#define PKA_SEQ_CTRL 0x440040C8 /**< PKA sequencer control and + status register The sequencer is + interfaced with the outside + world through a single control + and status register. With the + exception of bit [31], the + actual use of bits in the + separate sub-fields of this + register is determined by the + sequencer firmware. This + register need only be accessed + when the sequencer program is + stored in RAM. The reset value + of the RESTE bit depends upon + the option chosen for sequencer + program storage. */ +#define PKA_OPTIONS 0x440040F4 /**< PKA hardware options register + This register provides the host + with a means to determine the + hardware configuration + implemented in this PKA engine, + focused on options that have an + effect on software interacting + with the module. Note: (32 x + (1st LNME nr. of PEs + 1st LNME + FIFO RAM depth - 10)) equals the + maximum modulus vector length + (in bits) that can be handled by + the modular exponentiation and + ECC operations executed on a PKA + engine that includes an LNME. */ +#define PKA_SW_REV 0x440040F8 /**< PKA firmware revision and + capabilities register This + register allows the host access + to the internal firmware + revision number of the PKA + Engine for software driver + matching and diagnostic + purposes. This register also + contains a field that encodes + the capabilities of the embedded + firmware. The PKA_SW_REV + register is written by the + firmware within a few clock + cycles after starting up that + firmware. The hardware reset + value is zero, indicating that + the information has not been + written yet. */ +#define PKA_REVISION 0x440040FC /**< PKA hardware revision register + This register allows the host + access to the hardware revision + number of the PKA engine for + software driver matching and + diagnostic purposes. It is + always located at the highest + address in the access space of + the module and contains an + encoding of the EIP number (with + its complement as signature) for + recognition of the hardware + module. */ +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_APTR register registers bit fields + * @{ + */ +#define PKA_APTR_APTR_M 0x000007FF /**< This register specifies the + location of vector A within the + PKA RAM. Vectors are identified + through the location of their + least-significant 32-bit word. + Note that bit [0] must be zero + to ensure that the vector starts + at an 8-byte boundary. */ +#define PKA_APTR_APTR_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_BPTR register registers bit fields + * @{ + */ +#define PKA_BPTR_BPTR_M 0x000007FF /**< This register specifies the + location of vector B within the + PKA RAM. Vectors are identified + through the location of their + least-significant 32-bit word. + Note that bit [0] must be zero + to ensure that the vector starts + at an 8-byte boundary. */ +#define PKA_BPTR_BPTR_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_CPTR register registers bit fields + * @{ + */ +#define PKA_CPTR_CPTR_M 0x000007FF /**< This register specifies the + location of vector C within the + PKA RAM. Vectors are identified + through the location of their + least-significant 32-bit word. + Note that bit [0] must be zero + to ensure that the vector starts + at an 8-byte boundary. */ +#define PKA_CPTR_CPTR_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_DPTR register registers bit fields + * @{ + */ +#define PKA_DPTR_DPTR_M 0x000007FF /**< This register specifies the + location of vector D within the + PKA RAM. Vectors are identified + through the location of their + least-significant 32-bit word. + Note that bit [0] must be zero + to ensure that the vector starts + at an 8-byte boundary. */ +#define PKA_DPTR_DPTR_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_ALENGTH register registers bit fields + * @{ + */ +#define PKA_ALENGTH_ALENGTH_M 0x000001FF /**< This register specifies the + length (in 32-bit words) of + Vector A. */ +#define PKA_ALENGTH_ALENGTH_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_BLENGTH register registers bit fields + * @{ + */ +#define PKA_BLENGTH_BLENGTH_M 0x000001FF /**< This register specifies the + length (in 32-bit words) of + Vector B. */ +#define PKA_BLENGTH_BLENGTH_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_SHIFT register registers bit fields + * @{ + */ +#define PKA_SHIFT_NUM_BITS_TO_SHIFT_M \ + 0x0000001F /**< This register specifies the + number of bits to shift the + input vector (in the range 0-31) + during a Rshift or Lshift + operation. */ + +#define PKA_SHIFT_NUM_BITS_TO_SHIFT_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_FUNCTION register registers bit fields + * @{ + */ +#define PKA_FUNCTION_STALL_RESULT \ + 0x01000000 /**< When written with a 1b, + updating of the PKA_COMPARE, + PKA_MSW and PKA_DIVMSW + registers, as well as resetting + the run bit is stalled beyond + the point that a running + operation is actually finished. + Use this to allow software + enough time to read results from + a previous operation when the + newly started operation is known + to take only a short amount of + time. If a result is waiting, + the result registers is updated + and the run bit is reset in the + clock cycle following writing + the stall result bit back to 0b. + The Stall result function may + only be used for basic PKCP + operations. */ + +#define PKA_FUNCTION_STALL_RESULT_M \ + 0x01000000 +#define PKA_FUNCTION_STALL_RESULT_S 24 +#define PKA_FUNCTION_RUN 0x00008000 /**< The host sets this bit to + instruct the PKA module to begin + processing the basic PKCP or + complex sequencer operation. + This bit is reset low + automatically when the operation + is complete. The complement of + this bit is output as + interrupts[1]. After a reset, + the run bit is always set to 1b. + Depending on the option, program + ROM or program RAM, the + following applies: Program ROM - + The first sequencer instruction + sets the bit to 0b. This is done + immediately after the hardware + reset is released. Program RAM - + The sequencer must set the bit + to 0b. As a valid firmware may + not have been loaded, the + sequencer is held in software + reset after the hardware reset + is released (the reset bit in + PKA_SEQ_CRTL is set to 1b). + After the FW image is loaded and + the Reset bit is cleared, the + sequencer starts to execute the + FW. The first instruction clears + the run bit. In both cases a few + clock cycles are needed before + the first instruction is + executed and the run bit state + has been propagated. */ +#define PKA_FUNCTION_RUN_M 0x00008000 +#define PKA_FUNCTION_RUN_S 15 +#define PKA_FUNCTION_SEQUENCER_OPERATIONS_M \ + 0x00007000 /**< These bits select the complex + sequencer operation to perform: + 000b: None 001b: ExpMod-CRT + 010b: ExpMod-ACT4 (compatible + with EIP2315) 011b: ECC-ADD (if + available in firmware, otherwise + reserved) 100b: ExpMod-ACT2 + (compatible with EIP2316) 101b: + ECC-MUL (if available in + firmware, otherwise reserved) + 110b: ExpMod-variable 111b: + ModInv (if available in + firmware, otherwise reserved) + The encoding of these operations + is determined by sequencer + firmware. */ + +#define PKA_FUNCTION_SEQUENCER_OPERATIONS_S 12 +#define PKA_FUNCTION_COPY 0x00000800 /**< Perform copy operation */ +#define PKA_FUNCTION_COPY_M 0x00000800 +#define PKA_FUNCTION_COPY_S 11 +#define PKA_FUNCTION_COMPARE 0x00000400 /**< Perform compare operation */ +#define PKA_FUNCTION_COMPARE_M 0x00000400 +#define PKA_FUNCTION_COMPARE_S 10 +#define PKA_FUNCTION_MODULO 0x00000200 /**< Perform modulo operation */ +#define PKA_FUNCTION_MODULO_M 0x00000200 +#define PKA_FUNCTION_MODULO_S 9 +#define PKA_FUNCTION_DIVIDE 0x00000100 /**< Perform divide operation */ +#define PKA_FUNCTION_DIVIDE_M 0x00000100 +#define PKA_FUNCTION_DIVIDE_S 8 +#define PKA_FUNCTION_LSHIFT 0x00000080 /**< Perform left shift operation */ +#define PKA_FUNCTION_LSHIFT_M 0x00000080 +#define PKA_FUNCTION_LSHIFT_S 7 +#define PKA_FUNCTION_RSHIFT 0x00000040 /**< Perform right shift operation */ +#define PKA_FUNCTION_RSHIFT_M 0x00000040 +#define PKA_FUNCTION_RSHIFT_S 6 +#define PKA_FUNCTION_SUBTRACT 0x00000020 /**< Perform subtract operation */ +#define PKA_FUNCTION_SUBTRACT_M 0x00000020 +#define PKA_FUNCTION_SUBTRACT_S 5 +#define PKA_FUNCTION_ADD 0x00000010 /**< Perform add operation */ +#define PKA_FUNCTION_ADD_M 0x00000010 +#define PKA_FUNCTION_ADD_S 4 +#define PKA_FUNCTION_MS_ONE 0x00000008 /**< Loads the location of the Most + Significant one bit within the + result word indicated in the + PKA_MSW register into bits [4:0] + of the PKA_DIVMSW register - can + only be used with basic PKCP + operations, except for Divide, + Modulo and Compare. */ +#define PKA_FUNCTION_MS_ONE_M 0x00000008 +#define PKA_FUNCTION_MS_ONE_S 3 +#define PKA_FUNCTION_ADDSUB 0x00000002 /**< Perform combined add/subtract + operation */ +#define PKA_FUNCTION_ADDSUB_M 0x00000002 +#define PKA_FUNCTION_ADDSUB_S 1 +#define PKA_FUNCTION_MULTIPLY 0x00000001 /**< Perform multiply operation */ +#define PKA_FUNCTION_MULTIPLY_M 0x00000001 +#define PKA_FUNCTION_MULTIPLY_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_COMPARE register registers bit fields + * @{ + */ +#define PKA_COMPARE_A_GREATER_THAN_B \ + 0x00000004 /**< Vector_A is greater than + Vector_B */ + +#define PKA_COMPARE_A_GREATER_THAN_B_M \ + 0x00000004 +#define PKA_COMPARE_A_GREATER_THAN_B_S 2 +#define PKA_COMPARE_A_LESS_THAN_B \ + 0x00000002 /**< Vector_A is less than Vector_B */ + +#define PKA_COMPARE_A_LESS_THAN_B_M \ + 0x00000002 +#define PKA_COMPARE_A_LESS_THAN_B_S 1 +#define PKA_COMPARE_A_EQUALS_B 0x00000001 /**< Vector_A is equal to Vector_B */ +#define PKA_COMPARE_A_EQUALS_B_M \ + 0x00000001 +#define PKA_COMPARE_A_EQUALS_B_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_MSW register registers bit fields + * @{ + */ +#define PKA_MSW_RESULT_IS_ZERO 0x00008000 /**< The result vector is all + zeroes, ignore the address + returned in bits [10:0] */ +#define PKA_MSW_RESULT_IS_ZERO_M \ + 0x00008000 +#define PKA_MSW_RESULT_IS_ZERO_S 15 +#define PKA_MSW_MSW_ADDRESS_M 0x000007FF /**< Address of the most-significant + nonzero 32-bit word of the + result vector in PKA RAM */ +#define PKA_MSW_MSW_ADDRESS_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_DIVMSW register registers bit fields + * @{ + */ +#define PKA_DIVMSW_RESULT_IS_ZERO \ + 0x00008000 /**< The result vector is all + zeroes, ignore the address + returned in bits [10:0] */ + +#define PKA_DIVMSW_RESULT_IS_ZERO_M \ + 0x00008000 +#define PKA_DIVMSW_RESULT_IS_ZERO_S 15 +#define PKA_DIVMSW_MSW_ADDRESS_M \ + 0x000007FF /**< Address of the most significant + nonzero 32-bit word of the + remainder result vector in PKA + RAM */ + +#define PKA_DIVMSW_MSW_ADDRESS_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_SEQ_CTRL register registers bit fields + * @{ + */ +#define PKA_SEQ_CTRL_RESET 0x80000000 /**< Option program ROM: Reset value + = 0. Read/Write, reset value 0b + (ZERO). Writing 1b resets the + sequencer, write to 0b to + restart operations again. As the + reset value is 0b, the sequencer + will automatically start + operations executing from + program ROM. This bit should + always be written with zero and + ignored when reading this + register. Option Program RAM: + Reset value =1. Read/Write, + reset value 1b (ONE). When 1b, + the sequencer is held in a reset + state and the PKA_PROGRAM area + is accessible for loading the + sequencer program (while the + PKA_DATA_RAM is inaccessible), + write to 0b to (re)start + sequencer operations and disable + PKA_PROGRAM area accessibility + (also enables the PKA_DATA_RAM + accesses). Resetting the + sequencer (in order to load + other firmware) should only be + done when the PKA Engine is not + performing any operations (i.e. + the run bit in the PKA_FUNCTION + register should be zero). */ +#define PKA_SEQ_CTRL_RESET_M 0x80000000 +#define PKA_SEQ_CTRL_RESET_S 31 +#define PKA_SEQ_CTRL_SEQUENCER_STATUS_M \ + 0x0000FF00 /**< These read-only bits can be + used by the sequencer to + communicate status to the + outside world. Bit [8] is also + used as sequencer interrupt, + with the complement of this bit + ORed into the run bit in + PKA_FUNCTION. This field should + always be written with zeroes + and ignored when reading this + register. */ + +#define PKA_SEQ_CTRL_SEQUENCER_STATUS_S 8 +#define PKA_SEQ_CTRL_SW_CONTROL_STATUS_M \ + 0x000000FF /**< These bits can be used by + software to trigger sequencer + operations. External logic can + set these bits by writing 1b, + cannot reset them by writing 0b. + The sequencer can reset these + bits by writing 0b, cannot set + them by writing 1b. Setting the + run bit in PKA_FUNCTION together + with a nonzero sequencer + operations field automatically + sets bit [0] here. This field + should always be written with + zeroes and ignored when reading + this register. */ + +#define PKA_SEQ_CTRL_SW_CONTROL_STATUS_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_OPTIONS register registers bit fields + * @{ + */ +#define PKA_OPTIONS_FIRST_LNME_FIFO_DEPTH_M \ + 0xFF000000 /**< Number of words in the first + LNME's FIFO RAM Should be + ignored if LNME configuration is + 0. The contents of this field + indicate the actual depth as + selected by the LNME FIFO RAM + size strap input, fifo_size_sel. + Note: Reset value is undefined */ + +#define PKA_OPTIONS_FIRST_LNME_FIFO_DEPTH_S 24 +#define PKA_OPTIONS_FIRST_LNME_NR_OF_PES_M \ + 0x003F0000 /**< Number of processing elements + in the pipeline of the first + LNME Should be ignored if LNME + configuration is 0. Note: Reset + value is undefined. */ + +#define PKA_OPTIONS_FIRST_LNME_NR_OF_PES_S 16 +#define PKA_OPTIONS_MMM3A 0x00001000 /**< Reserved for a future + functional extension to the LNME + Always 0b */ +#define PKA_OPTIONS_MMM3A_M 0x00001000 +#define PKA_OPTIONS_MMM3A_S 12 +#define PKA_OPTIONS_INT_MASKING 0x00000800 /**< Value 0b indicates that the + main interrupt output (bit [1] + of the interrupts output bus) is + the direct complement of the run + bit in the PKA_CONTROL register, + value 1b indicates that + interrupt masking logic is + present for this output. Note: + Reset value is undefined */ +#define PKA_OPTIONS_INT_MASKING_M \ + 0x00000800 +#define PKA_OPTIONS_INT_MASKING_S 11 +#define PKA_OPTIONS_PROTECTION_OPTION_M \ + 0x00000700 /**< Value 0 indicates no additional + protection against side channel + attacks, value 1 indicates the + SCAP option, value 3 indicates + the PROT option; other values + are reserved. Note: Reset value + is undefined */ + +#define PKA_OPTIONS_PROTECTION_OPTION_S 8 +#define PKA_OPTIONS_PROGRAM_RAM 0x00000080 /**< Value 1b indicates sequencer + program storage in RAM, value 0b + in ROM. Note: Reset value is + undefined */ +#define PKA_OPTIONS_PROGRAM_RAM_M \ + 0x00000080 +#define PKA_OPTIONS_PROGRAM_RAM_S 7 +#define PKA_OPTIONS_SEQUENCER_CONFIGURATION_M \ + 0x00000060 /**< Value 1 indicates a standard + sequencer; other values are + reserved. */ + +#define PKA_OPTIONS_SEQUENCER_CONFIGURATION_S 5 +#define PKA_OPTIONS_LNME_CONFIGURATION_M \ + 0x0000001C /**< Value 0 indicates NO LNME, + value 1 indicates one standard + LNME (with alpha = 32, beta = + 8); other values reserved. Note: + Reset value is undefined */ + +#define PKA_OPTIONS_LNME_CONFIGURATION_S 2 +#define PKA_OPTIONS_PKCP_CONFIGURATION_M \ + 0x00000003 /**< Value 1 indicates a PKCP with a + 16x16 multiplier, value 2 + indicates a PKCP with a 32x32 + multiplier, other values + reserved. Note: Reset value is + undefined. */ + +#define PKA_OPTIONS_PKCP_CONFIGURATION_S 0 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_SW_REV register registers bit fields + * @{ + */ +#define PKA_SW_REV_FW_CAPABILITIES_M \ + 0xF0000000 /**< 4-bit binary encoding for the + functionality implemented in the + firmware. Value 0 indicates + basic ModExp with/without CRT. + Value 1 adds Modular Inversion, + value 2 adds Modular Inversion + and ECC operations. Values 3-15 + are reserved. */ + +#define PKA_SW_REV_FW_CAPABILITIES_S 28 +#define PKA_SW_REV_MAJOR_FW_REVISION_M \ + 0x0F000000 /**< 4-bit binary encoding of the + major firmware revision number */ + +#define PKA_SW_REV_MAJOR_FW_REVISION_S 24 +#define PKA_SW_REV_MINOR_FW_REVISION_M \ + 0x00F00000 /**< 4-bit binary encoding of the + minor firmware revision number */ + +#define PKA_SW_REV_MINOR_FW_REVISION_S 20 +#define PKA_SW_REV_FW_PATCH_LEVEL_M \ + 0x000F0000 /**< 4-bit binary encoding of the + firmware patch level, initial + release will carry value zero + Patches are used to remove bugs + without changing the + functionality or interface of a + module. */ + +#define PKA_SW_REV_FW_PATCH_LEVEL_S 16 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA_REVISION register registers bit fields + * @{ + */ +#define PKA_REVISION_MAJOR_HW_REVISION_M \ + 0x0F000000 /**< 4-bit binary encoding of the + major hardware revision number */ + +#define PKA_REVISION_MAJOR_HW_REVISION_S 24 +#define PKA_REVISION_MINOR_HW_REVISION_M \ + 0x00F00000 /**< 4-bit binary encoding of the + minor hardware revision number */ + +#define PKA_REVISION_MINOR_HW_REVISION_S 20 +#define PKA_REVISION_HW_PATCH_LEVEL_M \ + 0x000F0000 /**< 4-bit binary encoding of the + hardware patch level, initial + release will carry value zero + Patches are used to remove bugs + without changing the + functionality or interface of a + module. */ + +#define PKA_REVISION_HW_PATCH_LEVEL_S 16 +#define PKA_REVISION_COMPLEMENT_OF_BASIC_EIP_NUMBER_M \ + 0x0000FF00 /**< Bit-by-bit logic complement of + bits [7:0], EIP-28 gives 0xE3 */ + +#define PKA_REVISION_COMPLEMENT_OF_BASIC_EIP_NUMBER_S 8 +#define PKA_REVISION_BASIC_EIP_NUMBER_M \ + 0x000000FF /**< 8-bit binary encoding of the + EIP number, EIP-28 gives 0x1C */ + +#define PKA_REVISION_BASIC_EIP_NUMBER_S 0 + +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA driver return codes + * @{ + */ +#define PKA_STATUS_SUCCESS 0 /**< Success */ +#define PKA_STATUS_FAILURE 1 /**< Failure */ +#define PKA_STATUS_INVALID_PARAM 2 /**< Invalid parameter */ +#define PKA_STATUS_BUF_UNDERFLOW 3 /**< Buffer underflow */ +#define PKA_STATUS_RESULT_0 4 /**< Result is all zeros */ +#define PKA_STATUS_A_GR_B 5 /**< Big number compare return status if + the first big num is greater than + the second. */ +#define PKA_STATUS_A_LT_B 6 /**< Big number compare return status if + the first big num is less than the + second. */ +#define PKA_STATUS_OPERATION_INPRG 7 /**< PKA operation is in progress. */ +#define PKA_STATUS_OPERATION_NOT_INPRG 8 /**< No PKA operation is in progress. */ +#define PKA_STATUS_SIGNATURE_INVALID 9 /**< Signature is invalid. */ + +/** @} */ +/*---------------------------------------------------------------------------*/ +/** \name PKA functions + * @{ + */ + +/** \brief Enables and resets the PKA engine + */ +void pka_init(void); + +/** \brief Enables the PKA engine + */ +void pka_enable(void); + +/** \brief Disables the PKA engine + * \note Call this function to save power when the engine is unused. + */ +void pka_disable(void); + +/** \brief Checks the status of the PKA engine operation + * \retval false Result not yet available, and no error occurred + * \retval true Result available, or error occurred + */ +uint8_t pka_check_status(void); + +/** \brief Registers a process to be notified of the completion of a PKA + * operation + * \param p Process to be polled upon IRQ + * \note This function is only supposed to be called by the PKA drivers. + */ +void pka_register_process_notification(struct process *p); + +/** @} */ + +#endif /* PKA_H_ */ + +/** + * @} + * @} + */ diff --git a/cpu/cc2538/lpm.c b/cpu/cc2538/lpm.c index 45c7756e6..3aacf5149 100644 --- a/cpu/cc2538/lpm.c +++ b/cpu/cc2538/lpm.c @@ -101,7 +101,7 @@ static uint8_t max_pm; #ifdef LPM_CONF_PERIPH_PERMIT_PM1_FUNCS_MAX #define LPM_PERIPH_PERMIT_PM1_FUNCS_MAX LPM_CONF_PERIPH_PERMIT_PM1_FUNCS_MAX #else -#define LPM_PERIPH_PERMIT_PM1_FUNCS_MAX 3 +#define LPM_PERIPH_PERMIT_PM1_FUNCS_MAX 4 #endif static lpm_periph_permit_pm1_func_t diff --git a/cpu/cc2538/startup-gcc.c b/cpu/cc2538/startup-gcc.c index 2aa82894e..0c0da7104 100644 --- a/cpu/cc2538/startup-gcc.c +++ b/cpu/cc2538/startup-gcc.c @@ -68,6 +68,7 @@ void usb_isr(void) WEAK_ALIAS(default_handler); void uart0_isr(void) WEAK_ALIAS(default_handler); void uart1_isr(void) WEAK_ALIAS(default_handler); void crypto_isr(void); +void pka_isr(void); /* Boot Loader Backdoor selection */ #if FLASH_CCA_CONF_BOOTLDR_BACKDOOR @@ -271,7 +272,7 @@ void(*const vectors[])(void) = cc2538_rf_rx_tx_isr, /* 157 RFCORE RX/TX */ cc2538_rf_err_isr, /* 158 RFCORE Error */ crypto_isr, /* 159 AES */ - default_handler, /* 160 PKA */ + pka_isr, /* 160 PKA */ rtimer_isr, /* 161 SM Timer */ default_handler, /* 162 MACTimer */ }; diff --git a/examples/cc2538dk/pka/Makefile b/examples/cc2538dk/pka/Makefile new file mode 100644 index 000000000..5d1279f4c --- /dev/null +++ b/examples/cc2538dk/pka/Makefile @@ -0,0 +1,6 @@ +CONTIKI_PROJECT = ecc-ecdh ecc-sign ecc-verify + +all: $(CONTIKI_PROJECT) + +CONTIKI = ../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/cc2538dk/pka/ecc-ecdh.c b/examples/cc2538dk/pka/ecc-ecdh.c new file mode 100644 index 000000000..ec809fc29 --- /dev/null +++ b/examples/cc2538dk/pka/ecc-ecdh.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich. + * All rights reserved. + * + * Author: Andreas Dröscher + * + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + */ +/** + * \addtogroup cc2538-examples + * @{ + * + * \defgroup cc2538-ecdh-test cc2538dk ECDH Test Project + * + * ECDH example for CC2538 on SmartRF06EB. + * + * This example shows how ECDH should be used. The example also verifies + * the ECDH functionality. + * + * @{ + * + * \file + * Example demonstrating ECDH on the cc2538dk platform + */ +#include "contiki.h" +#include "ecc-algorithm.h" +#include "ecc-curve.h" +#include "random.h" +#include "rtimer.h" +#include "pt.h" + +#include +#include + +static void +ecc_set_random(uint32_t *secret) +{ + int i; + for(i = 0; i < 8; ++i) { + secret[i] = (uint32_t)random_rand() | (uint32_t)random_rand() << 16; + } +} + +PROCESS(ecdh_test, "ecdh test"); +AUTOSTART_PROCESSES(&ecdh_test); + +PROCESS_THREAD(ecdh_test, ev, data) { + PROCESS_BEGIN(); + + /* + * Variable for Time Measurement + */ + static rtimer_clock_t time; + + /* + * Activate Engine + */ + puts("-----------------------------------------\n" + "Initializing pka..."); + pka_init(); + + /* + * Generate secrets make sure they are valid (smaller as order) + */ + static ecc_compare_state_t state = { + .process = &ecdh_test, + .size = 8, + }; + memcpy(state.b, nist_p_256.n, sizeof(uint32_t) * 8); + static uint32_t secret_a[8]; + do { + ecc_set_random(secret_a); + memcpy(state.a, secret_a, sizeof(uint32_t) * 8); + PT_SPAWN(&(ecdh_test.pt), &(state.pt), ecc_compare(&state)); + } while(state.result != PKA_STATUS_A_LT_B); + + static uint32_t secret_b[8]; + ecc_set_random(secret_b); + do { + ecc_set_random(secret_b); + memcpy(state.a, secret_b, sizeof(uint32_t) * 8); + PT_SPAWN(&(ecdh_test.pt), &(state.pt), ecc_compare(&state)); + } while(state.result != PKA_STATUS_A_LT_B); + + /* + * Prepare Points + */ + static ecc_multiply_state_t side_a = { + .process = &ecdh_test, + .curve_info = &nist_p_256, + }; + memcpy(side_a.point_in.x, nist_p_256.x, sizeof(uint32_t) * 8); + memcpy(side_a.point_in.y, nist_p_256.y, sizeof(uint32_t) * 8); + memcpy(side_a.secret, secret_a, sizeof(secret_a)); + + static ecc_multiply_state_t side_b = { + .process = &ecdh_test, + .curve_info = &nist_p_256, + }; + memcpy(side_b.point_in.x, nist_p_256.x, sizeof(uint32_t) * 8); + memcpy(side_b.point_in.y, nist_p_256.y, sizeof(uint32_t) * 8); + memcpy(side_b.secret, secret_b, sizeof(secret_b)); + + /* + * Round 1 + */ + time = RTIMER_NOW(); + PT_SPAWN(&(ecdh_test.pt), &(side_a.pt), ecc_multiply(&side_a)); + time = RTIMER_NOW() - time; + printf("Round 1, Side a: %i, %lu ms\n", (unsigned)side_a.result, + (uint32_t)((uint64_t)time * 1000 / RTIMER_SECOND)); + + time = RTIMER_NOW(); + PT_SPAWN(&(ecdh_test.pt), &(side_b.pt), ecc_multiply(&side_b)); + time = RTIMER_NOW() - time; + printf("Round 1, Side b: %i, %lu ms\n", (unsigned)side_b.result, + (uint32_t)((uint64_t)time * 1000 / RTIMER_SECOND)); + + /* + * Key Exchange + */ + memcpy(side_a.point_in.x, side_b.point_out.x, sizeof(uint32_t) * 8); + memcpy(side_a.point_in.y, side_b.point_out.y, sizeof(uint32_t) * 8); + memcpy(side_b.point_in.x, side_a.point_out.x, sizeof(uint32_t) * 8); + memcpy(side_b.point_in.y, side_a.point_out.y, sizeof(uint32_t) * 8); + + /* + * Round 2 + */ + time = RTIMER_NOW(); + PT_SPAWN(&(ecdh_test.pt), &(side_a.pt), ecc_multiply(&side_a)); + time = RTIMER_NOW() - time; + printf("Round 2, Side a: %i, %lu ms\n", (unsigned)side_a.result, + (uint32_t)((uint64_t)time * 1000 / RTIMER_SECOND)); + time = RTIMER_NOW(); + PT_SPAWN(&(ecdh_test.pt), &(side_b.pt), ecc_multiply(&side_b)); + time = RTIMER_NOW() - time; + printf("Round 2, Side b: %i, %lu ms\n", (unsigned)side_b.result, + (uint32_t)((uint64_t)time * 1000 / RTIMER_SECOND)); + + /* + * Check Result + */ + memcpy(state.a, side_a.point_out.x, sizeof(uint32_t) * 8); + memcpy(state.b, side_b.point_out.x, sizeof(uint32_t) * 8); + + PT_SPAWN(&(ecdh_test.pt), &(state.pt), ecc_compare(&state)); + if(state.result) { + puts("shared secrets do not match"); + } else { + puts("shared secrets MATCH"); + } + + puts("-----------------------------------------\n" + "Disabling pka..."); + pka_disable(); + + puts("Done!"); + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/examples/cc2538dk/pka/ecc-sign.c b/examples/cc2538dk/pka/ecc-sign.c new file mode 100644 index 000000000..5114073eb --- /dev/null +++ b/examples/cc2538dk/pka/ecc-sign.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich. + * All rights reserved. + * + * Author: Andreas Dröscher + * + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + */ +/** + * \addtogroup cc2538-examples + * @{ + * + * \defgroup cc2538-ecdsa-sign-test cc2538dk ECDSA-Sign Test Project + * + * ECDSA-Sign example for CC2538 on SmartRF06EB. + * + * This example shows how ECDSA-Sign should be used. The example also verifies + * the ECDSA-Sign functionality. + * + * @{ + * + * \file + * Example demonstrating ECDSA-Sign on the cc2538dk platform + */ +#include "contiki.h" +#include "ecc-algorithm.h" +#include "ecc-curve.h" +#include "rtimer.h" +#include "pt.h" + +#include +#include + +PROCESS(ecdsa_sign_test, "ecdsa sign test"); +AUTOSTART_PROCESSES(&ecdsa_sign_test); + +PROCESS_THREAD(ecdsa_sign_test, ev, data) { + PROCESS_BEGIN(); + + /* + * Variable for Time Measurement + */ + static rtimer_clock_t time; + + /* + * Activate Engine + */ + puts("-----------------------------------------\n" + "Initializing pka..."); + pka_init(); + + /* + * Setup Variables + */ + static ecc_compare_state_t comp_state = { + .process = &ecdsa_sign_test, + .size = 8, + }; + static ecc_dsa_sign_state_t state = { + .process = &ecdsa_sign_test, + .curve_info = &nist_p_256, + .secret = { 0x94A949FA, 0x401455A1, 0xAD7294CA, 0x896A33BB, + 0x7A80E714, 0x4321435B, 0x51247A14, 0x41C1CB6B }, + .k_e = { 0x1D1E1F20, 0x191A1B1C, 0x15161718, 0x11121314, + 0x0D0E0F10, 0x090A0B0C, 0x05060708, 0x01020304 }, + .hash = { 0x65637572, 0x20612073, 0x68206F66, 0x20686173, + 0x69732061, 0x68697320, 0x6F2C2054, 0x48616C6C }, + }; + + /* + * Sign + */ + time = RTIMER_NOW(); + PT_SPAWN(&(ecdsa_sign_test.pt), &(state.pt), ecc_dsa_sign(&state)); + time = RTIMER_NOW() - time; + printf("ecc_dsa_sign(), %lu ms\n", + (uint32_t)((uint64_t)time * 1000 / RTIMER_SECOND)); + + /* + * Check Result + */ + static uint32_t ecdsaTestresultR1[] = { 0xC3B4035F, 0x515AD0A6, 0xBF375DCA, 0x0CC1E997, + 0x7F54FDCD, 0x04D3FECA, 0xB9E396B9, 0x515C3D6E }; + static uint32_t ecdsaTestresultS1[] = { 0x5366B1AB, 0x0F1DBF46, 0xB0C8D3C4, 0xDB755B6F, + 0xB9BF9243, 0xE644A8BE, 0x55159A59, 0x6F9E52A6 }; + + memcpy(comp_state.a, state.point_r.x, sizeof(uint32_t) * 8); + memcpy(comp_state.b, ecdsaTestresultR1, sizeof(uint32_t) * 8); + PT_SPAWN(&(ecdsa_sign_test.pt), &(comp_state.pt), ecc_compare(&comp_state)); + if(comp_state.result) { + puts("r1 of signature does not match"); + } else { + puts("r1 of signature OK"); + } + + memcpy(comp_state.a, state.signature_s, sizeof(uint32_t) * 8); + memcpy(comp_state.b, ecdsaTestresultS1, sizeof(uint32_t) * 8); + PT_SPAWN(&(ecdsa_sign_test.pt), &(comp_state.pt), ecc_compare(&comp_state)); + if(comp_state.result) { + puts("s1 of signature does not match"); + } else { + puts("s1 of signature OK"); + } + + puts("-----------------------------------------\n" + "Disabling pka..."); + pka_disable(); + + puts("Done!"); + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/examples/cc2538dk/pka/ecc-verify.c b/examples/cc2538dk/pka/ecc-verify.c new file mode 100644 index 000000000..a970d2a02 --- /dev/null +++ b/examples/cc2538dk/pka/ecc-verify.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich. + * All rights reserved. + * + * Author: Andreas Dröscher + * + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + */ +/** + * \addtogroup cc2538-examples + * @{ + * + * \defgroup cc2538-ecdsa-verify-test cc2538dk ECDSA-Verify Test Project + * + * ECDSA-Verify example for CC2538 on SmartRF06EB. + * + * This example shows how ECDSA-Verify should be used. The example also verifies + * the ECDSA-Verify functionality. + * + * @{ + * + * \file + * Example demonstrating ECDSA-Verify on the cc2538dk platform + */ +#include "contiki.h" +#include "ecc-algorithm.h" +#include "ecc-curve.h" +#include "rtimer.h" +#include "pt.h" + +#include +#include + +PROCESS(ecdsa_verify_test, "ecdsa verify test"); +AUTOSTART_PROCESSES(&ecdsa_verify_test); + +PROCESS_THREAD(ecdsa_verify_test, ev, data) { + PROCESS_BEGIN(); + + /* + * Variable for Time Measurement + */ + static rtimer_clock_t time; + + /* + * Activate Engine + */ + puts("-----------------------------------------\n" + "Initializing pka..."); + pka_init(); + + /* + * Setup Variables + */ + static ecc_dsa_verify_state_t state = { + .process = &ecdsa_verify_test, + .curve_info = &nist_p_256, + .signature_r = { 0xC3B4035F, 0x515AD0A6, 0xBF375DCA, 0x0CC1E997, + 0x7F54FDCD, 0x04D3FECA, 0xB9E396B9, 0x515C3D6E }, + .signature_s = { 0x5366B1AB, 0x0F1DBF46, 0xB0C8D3C4, 0xDB755B6F, + 0xB9BF9243, 0xE644A8BE, 0x55159A59, 0x6F9E52A6 }, + .hash = { 0x65637572, 0x20612073, 0x68206F66, 0x20686173, + 0x69732061, 0x68697320, 0x6F2C2054, 0x48616C6C }, + }; + static uint32_t public_x[8] = { 0x5fa58f52, 0xe47cfbf2, 0x300c28c5, 0x6375ba10, + 0x62684e91, 0xda0a9a8f, 0xf9f2ed29, 0x36dfe2c6 }; + static uint32_t public_y[8] = { 0xc772f829, 0x4fabc36f, 0x09daed0b, 0xe93f9872, + 0x35a7cfab, 0x5a3c7869, 0xde1ab878, 0x71a0d4fc }; + + memcpy(state.public.x, public_x, sizeof(public_x)); + memcpy(state.public.y, public_y, sizeof(public_y)); + + /* + * Verify + */ + time = RTIMER_NOW(); + PT_SPAWN(&(ecdsa_verify_test.pt), &(state.pt), ecc_dsa_verify(&state)); + time = RTIMER_NOW() - time; + printf("ecc_dsa_verify(), %lu ms\n", + (uint32_t)((uint64_t)time * 1000 / RTIMER_SECOND)); + + if(state.result) { + puts("signature verification failed"); + } else { + puts("signature verification OK"); + } + + puts("-----------------------------------------\n" + "Disabling pka..."); + pka_disable(); + + puts("Done!"); + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */ diff --git a/platform/cc2538dk/README.md b/platform/cc2538dk/README.md index dde73842e..295777c8e 100644 --- a/platform/cc2538dk/README.md +++ b/platform/cc2538dk/README.md @@ -30,6 +30,7 @@ In terms of hardware support, the following drivers have been implemented: * General-Purpose Timers. NB: GPT0 is in use by the platform code, the remaining GPTs are available for application development. * ADC * Cryptoprocessor (AES-CCM-256, SHA-256) + * Public Key Accelerator (ECDH, ECDSA) * SmartRF06 EB and BB peripherals * LEDs * Buttons diff --git a/platform/remote/README.md b/platform/remote/README.md index 7172ebd02..387591caa 100644 --- a/platform/remote/README.md +++ b/platform/remote/README.md @@ -45,6 +45,7 @@ In terms of hardware support, the following drivers have been implemented: * General-Purpose Timers. NB: GPT0 is in use by the platform code, the remaining GPTs are available for application development. * ADC * Cryptoprocessor (AES-CCM-256, SHA-256) + * Public Key Accelerator (ECDH, ECDSA) * LEDs * Buttons * Internal/external 2.4GHz antenna switch controllable by SW.