diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/CMakeLists.txt b/connectivity/drivers/mbedtls/TARGET_NUVOTON/CMakeLists.txt index 2a28282160..dc8246c758 100644 --- a/connectivity/drivers/mbedtls/TARGET_NUVOTON/CMakeLists.txt +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/CMakeLists.txt @@ -1,7 +1,9 @@ # Copyright (c) 2020 ARM Limited. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -if("M480" IN_LIST MBED_TARGET_LABELS) +if("M460" IN_LIST MBED_TARGET_LABELS) + add_subdirectory(TARGET_M460) +elseif("M480" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_M480) elseif("NUC472" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_NUC472) diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/CMakeLists.txt b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/CMakeLists.txt new file mode 100644 index 0000000000..b6a0850b2f --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright (c) 2020 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-mbedtls + INTERFACE + . + ./aes + ./ecp + ./rsa + ./sha +) + +target_sources(mbed-mbedtls + INTERFACE + aes/aes_alt.c + ecp/ecp_internal_alt.c + rsa/rsa_alt.c + sha/sha1_alt.c + sha/sha256_alt.c + sha/sha512_alt.c + sha/sha_alt_hw.c +) diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/aes/aes_alt.c b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/aes/aes_alt.c new file mode 100644 index 0000000000..8f414f586f --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/aes/aes_alt.c @@ -0,0 +1 @@ +/* TODO */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/aes/aes_alt.h b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/aes/aes_alt.h new file mode 100644 index 0000000000..8f414f586f --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/aes/aes_alt.h @@ -0,0 +1 @@ +/* TODO */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/ecp/ecp_internal_alt.c b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/ecp/ecp_internal_alt.c new file mode 100644 index 0000000000..15947b4bc3 --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/ecp/ecp_internal_alt.c @@ -0,0 +1,1114 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/* Some internal functions are used for Nuvoton internal self-test. + * Remove the static modifier for self-test compile. */ +#if defined(NU_CRYPTO_SELF_TEST) && NU_CRYPTO_SELF_TEST +#define NU_STATIC +#else +#define NU_STATIC static +#endif + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" +#include "mbedtls/threading.h" +#include "mbedtls/error.h" + +#include + +#if !defined(MBEDTLS_ECP_ALT) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + +#include "mbedtls/platform.h" +#include "mbedtls/ecp_internal.h" +#include "mbed_toolchain.h" +#include "mbed_assert.h" +#include "mbed_error.h" +#include "mbed_toolchain.h" +#include "nu_bitutil.h" +#include "crypto-misc.h" + +/* Max key size supported */ +#define NU_ECC_MAXKEYBITS 571 +/* Max ECC big-number words */ +#define NU_ECC_BIGNUM_MAXWORD 18 +/* words in limb */ +#define wiL (sizeof (mbedtls_mpi_uint) / sizeof (uint32_t)) +/* Min MPI limbs for ECC big-number */ +#define NU_ECC_BIGNUM_MINLIMB (NU_ECC_BIGNUM_MAXWORD / wiL) + +/* + * Convert between words and number of limbs + * Divide first in order to avoid potential overflows + */ +#define WORDS_TO_LIMBS(i) ( (i) / wiL + ( (i) % wiL != 0 ) ) + + +#define ECCOP_POINT_MUL (0x0UL << CRPT_ECC_CTL_ECCOP_Pos) +#define ECCOP_MODULE (0x1UL << CRPT_ECC_CTL_ECCOP_Pos) +#define ECCOP_POINT_ADD (0x2UL << CRPT_ECC_CTL_ECCOP_Pos) +#define ECCOP_POINT_DOUBLE (0x3UL << CRPT_ECC_CTL_ECCOP_Pos) + +#define MODOP_DIV (0x0UL << CRPT_ECC_CTL_MODOP_Pos) +#define MODOP_MUL (0x1UL << CRPT_ECC_CTL_MODOP_Pos) +#define MODOP_ADD (0x2UL << CRPT_ECC_CTL_MODOP_Pos) +#define MODOP_SUB (0x3UL << CRPT_ECC_CTL_MODOP_Pos) + +/** + * \brief Check if MPI has been normalized + * + * \param N Input MPI which is to check + * \param P Prime modulus + * + * \return 0 if not normalized, + * 1 if normalized + */ +#define INTERNAL_MPI_IS_NORM(N, P) \ + ((mbedtls_mpi_cmp_int(&N, 0) >= 0) && (mbedtls_mpi_cmp_mpi(&N, &P) < 0)) + + +/** + * \brief Normalize MPI if it is not normalized yet + * + * \param R Holds pointer to normalized MPI (N1 or N2) + * \param N1 Input MPI which is to normalize + * \param N2 Output MPI which holds normalized N1 if N1 is not normalized yet + * \param P Prime modulus + */ +#define INTERNAL_MPI_NORM(R, N1, N2, P) \ + do { \ + if (INTERNAL_MPI_IS_NORM(N1, P)) { \ + *R = &N1; \ + } else { \ + MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&N2, &N1, &P)); \ + *R = &N2; \ + } \ + } while(0) + +/** + * \brief Normalize Jacobian coordinates or Montgomery x/z coordinates, dependent on curve type. + * + * \param grp Pointer to the group representing the curve. + * + * \param pt pointer to the point to be normalized. This is an + * input/output parameter. + * + * \return 0 if successful. + */ +NU_STATIC int internal_ecp_normalize(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt); + +/** + * \brief Configure ECCOP operation, start it, and wait for its completion + * + * \param grp ECP group + * \param R Destination point + * \param m Integer by which to multiply P + * \param P Point to multiply by m + * \param n Integer by which to multiply Q + * \param Q Point to be multiplied by n + * \param eccop ECCOP code. Could be ECCOP_POINT_MUL/ADD/DOUBLE + * Dependent on passed-in eccop, only partial parameters among m/P/n/Q are needed and checked. + * ECCOP_POINT_MUL R = m*P + * ECCOP_POINT_ADD R = P + Q + * ECCOP_POINT_DOUBLE R = 2*P + * + * \return 0 if successful + * + * \note P/Q must be normalized (= affine). R would be normalized. + * + * \note m/n could be negative. + * + * \note ECC accelerator doesn't support R = 0, and we need to detect it additionally. + * For R = P + Q or R = 2*P, we can detect all R = 0 cases. + * For R = m*P, we can detect all R = 0 cases only if grp->N (order) is a prime. + * + * \note According to ECCOP operation, n is unnecessary. But to be consistent with R = m*P + n*Q, + * n is kept with unused modifier. + * + */ +NU_STATIC int internal_run_eccop(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *P, + MBED_UNUSED const mbedtls_mpi *n, + const mbedtls_ecp_point *Q, + uint32_t eccop); + +/** + * \brief Configure MODOP operation and wait for its completion + * + * \param r Destination MPI + * \param o1 Input MPI for first operand of MODOP + * \param o2 Input MPI for second operand of MODOP + * \param p Prime modulus + * \param pbits Bit number of p + * \param modop ECCOP code. Could be MODOP_ADD/SUB/MUL/DIV + * MODOP_ADD r = o1 + o2 mod p + * MODOP_SUB r = o1 - o2 mod p + * MODOP_MUL r = o1 * o2 mod p + * MODOP_DIV r = o1 / o2 mod p + * + * \return 0 if successful + * + * \note o1/o2 must be normalized (within [0, p - 1]). r would be normalized. + */ +NU_STATIC int internal_run_modop(mbedtls_mpi *r, + const mbedtls_mpi *o1, + const mbedtls_mpi *o2, + const mbedtls_mpi *p, + uint32_t pbits, + uint32_t modop); + +/** + * \brief Import X from ECC registers, little endian + * + * \param X Destination MPI + * \param eccreg Start of input ECC register + * \param eccreg_num Number of input ECC register + * + * \return 0 if successful + * + * \note Destination MPI is always non-negative. + */ +NU_STATIC int internal_mpi_read_eccreg( mbedtls_mpi *X, const volatile uint32_t *eccreg, size_t eccreg_num ); + +/** + * \brief Export X into ECC registers, little endian + * + * \param X Source MPI + * \param eccreg Start of ECC output registers + * \param eccreg_num Number of ECC output registers + * + * \return 0 if successful + * + * \note Source MPI cannot be negative. + * \note Fills the remaining MSB ECC registers with zeros if X doesn't cover all. + */ +NU_STATIC int internal_mpi_write_eccreg( const mbedtls_mpi *X, volatile uint32_t *eccreg, size_t eccreg_num ); + +unsigned char mbedtls_internal_ecp_grp_capable( const mbedtls_ecp_group *grp ) +{ + /* Support types + * 1. Short Weierstrass + * 2. Montgomery */ + mbedtls_ecp_curve_type curve_type = mbedtls_ecp_get_type(grp); + if (curve_type == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS || + curve_type == MBEDTLS_ECP_TYPE_MONTGOMERY) { + return 1; + } else { + return 0; + } +} + +int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) +{ + /* Behavior of mbedtls_internal_ecp_init()/mbedtls_internal_ecp_free() + * + * mbedtls_internal_ecp_init()/mbedtls_internal_ecp_free() are like pre-op/post-op calls + * and they guarantee: + * + * 1. Paired + * 2. No overlapping + * 3. Upper public function cannot return when ECP alter. is still activated. + */ + + /* Acquire ownership of ECC accelerator */ + crypto_ecc_acquire(); + + /* Initialize crypto module */ + crypto_init(); + + /* Enable ECC interrupt */ + ECC_ENABLE_INT(CRPT); + + return 0; +} + +void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp ) +{ + /* Disable ECC interrupt */ + ECC_DISABLE_INT(CRPT); + + /* Uninit crypto module */ + crypto_uninit(); + + /* Release ownership of ECC accelerator */ + crypto_ecc_release(); +} + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) +/** + * \brief Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_jac(). + * + * \param grp Pointer to the group representing the curve. + * + * \param pt Pointer to a point structure to randomize. + * + * \param f_rng The RNG function. This may be \c NULL if randomization + * of intermediate results isn't desired (discouraged). + * + * \param p_rng The RNG context to be passed to \p p_rng. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi l, ll; + size_t p_size; + int count = 0; + + p_size = ( grp->pbits + 7 ) / 8; + mbedtls_mpi_init( &l ); mbedtls_mpi_init( &ll ); + + /* Generate l such that 1 < l < p */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ) ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + /* Z = l * Z */ + MBEDTLS_MPI_CHK(internal_run_modop(&pt->Z, &pt->Z, &l, &grp->P, grp->pbits, MODOP_MUL)); + + /* X = l^2 * X */ + MBEDTLS_MPI_CHK(internal_run_modop(&ll, &l, &l, &grp->P, grp->pbits, MODOP_MUL)); + MBEDTLS_MPI_CHK(internal_run_modop(&pt->X, &pt->X, &ll, &grp->P, grp->pbits, MODOP_MUL)); + + /* Y = l^3 * Y */ + MBEDTLS_MPI_CHK(internal_run_modop(&ll, &ll, &l, &grp->P, grp->pbits, MODOP_MUL)); + MBEDTLS_MPI_CHK(internal_run_modop(&pt->Y, &pt->Y, &ll, &grp->P, grp->pbits, MODOP_MUL)); + +cleanup: + + mbedtls_mpi_free( &l ); + mbedtls_mpi_free( &ll ); + + return ret; +} +#endif + +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) +/** + * \brief Addition: R = P + Q, mixed affine-Jacobian coordinates. + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * We accept Q->Z being unset (saving memory in tables) as + * meaning 1. + * + * \param grp Pointer to the group representing the curve. + * + * \param R Pointer to a point structure to hold the result. + * + * \param P Pointer to the first summand, given with Jacobian + * coordinates + * + * \param Q Pointer to the second summand, given with affine + * coordinates. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_add_mixed( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point P_, Q_; + + mbedtls_ecp_point_init(&P_); + mbedtls_ecp_point_init(&Q_); + + /* P_ = normalized P */ + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&P_, P)); + MBEDTLS_MPI_CHK(mbedtls_internal_ecp_normalize_jac(grp, &P_)); + + /* Q_ = normalized Q */ + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&Q_, Q)); + /* NOTE: We accept Q->Z being unset (saving memory in tables) as meaning 1. + * + * Q->Z.p == NULL ==> Q->Z = 1 + * Q->Z.p != NULL && mbedtls_mpi_cmp_int(&Q->Z, 0) == 0 ==> Q->Z = 0 + * Q->Z.p != NULL && mbedtls_mpi_cmp_int(&Q->Z, 0) != 0 ==> Q->Z = 1 + */ + if (Q->Z.p != NULL && mbedtls_mpi_cmp_int(&Q->Z, 0) == 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Q_.Z, 0)); + } else { + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&Q_.Z, 1)); + } + + /* Run ECC point addition: R = P + Q */ + MBEDTLS_MPI_CHK(internal_run_eccop(grp, R, NULL, &P_, NULL, &Q_, ECCOP_POINT_ADD)); + +cleanup: + + mbedtls_ecp_point_free(&Q_); + mbedtls_ecp_point_free(&P_); + + return ret; +} +#endif + +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) +/** + * \brief Point doubling R = 2 P, Jacobian coordinates. + * + * \param grp Pointer to the group representing the curve. + * + * \param R Pointer to a point structure to hold the result. + * + * \param P Pointer to the point that has to be doubled, given with + * Jacobian coordinates. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_double_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, const mbedtls_ecp_point *P ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_point P_; + + mbedtls_ecp_point_init(&P_); + + /* P_ = normalized P */ + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&P_, P)); + MBEDTLS_MPI_CHK(mbedtls_internal_ecp_normalize_jac(grp, &P_)); + + /* Run ECC point doubling: R = 2*P */ + MBEDTLS_MPI_CHK(internal_run_eccop(grp, R, NULL, &P_, NULL, NULL, ECCOP_POINT_DOUBLE)); + +cleanup: + + mbedtls_ecp_point_free(&P_); + + return ret; +} +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) +/** + * \brief Normalize jacobian coordinates so that Z == 0 || Z == 1. + * + * \param grp Pointer to the group representing the curve. + * + * \param pt pointer to the point to be normalised. This is an + * input/output parameter. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_normalize_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt ) +{ + if (grp == NULL || pt == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Is a zero point + * + * Z = 0 + */ + if (mbedtls_mpi_cmp_int(&pt->Z, 0) == 0) { + return 0; + } + + /* Is a non-zero point which has been normalized + * + * Z = 1 + * 0 <= X < P + * 0 <= y < P + */ + if (mbedtls_mpi_cmp_int(&pt->Z, 1) == 0 && + mbedtls_mpi_cmp_int(&pt->X, 0) >= 0 && + mbedtls_mpi_cmp_mpi(&pt->X, &grp->P) < 0 && + mbedtls_mpi_cmp_int(&pt->Y, 0) >= 0 && + mbedtls_mpi_cmp_mpi(&pt->Y, &grp->P) < 0) { + return 0; + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi N, Zi, ZZi; + const mbedtls_mpi *Np; + + mbedtls_mpi_init(&N); + mbedtls_mpi_init(&Zi); + mbedtls_mpi_init(&ZZi); + + /* Use INTERNAL_MPI_NORM(Np, N1, N_, P) to get normalized MPI + * + * N_: Holds normalized MPI if the passed-in MPI N1 is not + * Np: Pointer to normalized MPI, which could be N1 or N_ + */ + + /* Zi = 1 / Z */ + mbedtls_mpi_lset(&Zi, 1); + INTERNAL_MPI_NORM(&Np, pt->Z, N, grp->P); + MBEDTLS_MPI_CHK(internal_run_modop(&Zi, &Zi, Np, &grp->P, grp->pbits, MODOP_DIV)); + + /* ZZi = 1 / Z^2 = Zi * Zi */ + MBEDTLS_MPI_CHK(internal_run_modop(&ZZi, &Zi, &Zi, &grp->P, grp->pbits, MODOP_MUL)); + + /* X = X / Z^2 = X * ZZi */ + INTERNAL_MPI_NORM(&Np, pt->X, N, grp->P); + MBEDTLS_MPI_CHK(internal_run_modop(&pt->X, Np, &ZZi, &grp->P, grp->pbits, MODOP_MUL)); + + /* Y = Y / Z^3 = Y * ZZi * Zi */ + INTERNAL_MPI_NORM(&Np, pt->Y, N, grp->P); + MBEDTLS_MPI_CHK(internal_run_modop(&pt->Y, Np, &ZZi, &grp->P, grp->pbits, MODOP_MUL)); + MBEDTLS_MPI_CHK(internal_run_modop(&pt->Y, &pt->Y, &Zi, &grp->P, grp->pbits, MODOP_MUL)); + + /* Z = 1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1)); + +cleanup: + + mbedtls_mpi_free(&ZZi); + mbedtls_mpi_free(&Zi); + mbedtls_mpi_free(&N); + + return ret; +} +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) +/** + * \brief Normalize jacobian coordinates of an array of (pointers to) + * points. + * + * \param grp Pointer to the group representing the curve. + * + * \param T Array of pointers to the points to normalise. + * + * \param t_len Number of elements in the array. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_normalize_jac_many(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t t_len) +{ + if (T == NULL || t_len == 0) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_ecp_point **ecp_point = T; + mbedtls_ecp_point **ecp_point_end = T + t_len; + + for (; ecp_point != ecp_point_end; ecp_point ++) { + MBEDTLS_MPI_CHK(mbedtls_internal_ecp_normalize_jac(grp, *ecp_point)); + } + +cleanup: + + return ret; +} +#endif + +#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + +#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) +/** + * \brief Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), + * for Montgomery curves in x/z coordinates. + * + * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 + * with + * d = X1 + * P = (X2, Z2) + * Q = (X3, Z3) + * R = (X4, Z4) + * S = (X5, Z5) + * and eliminating temporary variables tO, ..., t4. + * + * \param grp Pointer to the group representing the curve. + * + * \param R Pointer to a point structure to hold the result of 2P. + * + * \param S Pointer to a point structure to hold the result of P + Q. + * + * \param P Pointer to a point structure for P + Q and 2P, given with Jacobian + * coordinates + * + * \param Q Pointer to a point structure for P + Q, given with affine + * coordinates. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_double_add_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, mbedtls_ecp_point *S, const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d ) +{ + /* Mbed TLS's implementation for Montgomery curve has optimized and + * becomes incompatible with ECC H/W, for example, on mbedtls_mpi A/B. */ + #error "Incompatible with ECC HW. Undefine MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT in mbedtls_device.h" +} +#endif + +#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) +/** + * \brief Randomize projective x/z coordinates: + * (X, Z) -> (l X, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_mxz(). + * + * \param grp Pointer to the group representing the curve. + * + * \param P Pointer to a point structure to randomize. + * + * \param f_rng The RNG function. This may be \c NULL if randomization + * of intermediate results isn't desired (discouraged). + * + * \param p_rng The RNG context to be passed to \p p_rng. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi l; + size_t p_size; + int count = 0; + + p_size = ( grp->pbits + 7 ) / 8; + mbedtls_mpi_init( &l ); + + /* Generate l such that 1 < l < p */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ) ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + /* X = l * X */ + MBEDTLS_MPI_CHK(internal_run_modop(&P->X, &P->X, &l, &grp->P, grp->pbits, MODOP_MUL)); + + /* Z = l * Z */ + MBEDTLS_MPI_CHK(internal_run_modop(&P->Z, &P->Z, &l, &grp->P, grp->pbits, MODOP_MUL)); + +cleanup: + + mbedtls_mpi_free( &l ); + + return( ret ); +} +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) +/** + * \brief Normalize Montgomery x/z coordinates: X = X/Z, Z = 1. + * + * \param grp pointer to the group representing the curve + * + * \param P pointer to the point to be normalised. This is an + * input/output parameter. + * + * \return 0 if successful + */ +int mbedtls_internal_ecp_normalize_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt ) +{ + if (grp == NULL || pt == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Is a zero point + * + * Z = 0 + */ + if (mbedtls_mpi_cmp_int(&pt->Z, 0) == 0) { + return 0; + } + + /* Is a non-zero point which has been normalized + * + * Z = 1 + * 0 <= X < P + * + * NOTE: Y not used + */ + if (mbedtls_mpi_cmp_int(&pt->Z, 1) == 0 && + mbedtls_mpi_cmp_int(&pt->X, 0) >= 0 && + mbedtls_mpi_cmp_mpi(&pt->X, &grp->P) < 0) { + return 0; + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_mpi N, Zi; + const mbedtls_mpi *Np; + + mbedtls_mpi_init(&N); + mbedtls_mpi_init(&Zi); + + /* Use INTERNAL_MPI_NORM(Np, N1, N_, P) to get normalized MPI + * + * N_: Holds normalized MPI if the passed-in MPI N1 is not + * Np: Pointer to normalized MPI, which could be N1 or N_ + */ + + /* Zi = 1 / Z */ + mbedtls_mpi_lset(&Zi, 1); + INTERNAL_MPI_NORM(&Np, pt->Z, N, grp->P); + MBEDTLS_MPI_CHK(internal_run_modop(&Zi, &Zi, Np, &grp->P, grp->pbits, MODOP_DIV)); + + /* X = X / Z = X * Zi */ + INTERNAL_MPI_NORM(&Np, pt->X, N, grp->P); + MBEDTLS_MPI_CHK(internal_run_modop(&pt->X, Np, &Zi, &grp->P, grp->pbits, MODOP_MUL)); + + /* Z = 1 */ + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1)); + +cleanup: + + mbedtls_mpi_free(&Zi); + mbedtls_mpi_free(&N); + + return ret; +} +#endif + +#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ + +NU_STATIC int internal_ecp_normalize(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt) +{ + mbedtls_ecp_curve_type curve_type = mbedtls_ecp_get_type(grp); + if (curve_type == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + return mbedtls_internal_ecp_normalize_jac(grp, pt); + } else if (curve_type == MBEDTLS_ECP_TYPE_MONTGOMERY) { + return mbedtls_internal_ecp_normalize_mxz(grp, pt); + } else { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +} + +NU_STATIC int internal_run_eccop(const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *P, + MBED_UNUSED const mbedtls_mpi *n, + const mbedtls_ecp_point *Q, + uint32_t eccop) +{ + /* Check necessary arguments for all ECC operations */ + if (grp == NULL || R == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Check grp->P is positive */ + if (mbedtls_mpi_cmp_int(&grp->P, 0) <= 0) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Check supported maximum key bits */ + if (grp->pbits > NU_ECC_MAXKEYBITS) { + return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + bool ecc_done; + + mbedtls_mpi N_; + const mbedtls_mpi *Np; + + mbedtls_mpi_init(&N_); + + /* Use INTERNAL_MPI_NORM(Np, N1, N_, P) to get normalized MPI + * + * N_: Holds normalized MPI if the passed-in MPI N1 is not + * Np: Pointer to normalized MPI, which could be N1 or N_ + */ + + /* Check necessary arguments and handle special cases for specified ECC operation + * + * ECCOP_POINT_MUL R = m*P + * ECCOP_POINT_ADD R = P + Q + * ECCOP_POINT_DOUBLE R = 2*P + * + * ECC accelerator doesn't support R = 0, and we need to detect it. + */ + if (eccop == ECCOP_POINT_MUL) { + /* R = m*P */ + if (m == NULL || P == NULL) { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + /* R = 0*P = 0 or R = P = 0 */ + if (mbedtls_mpi_cmp_int(m, 0) == 0 || mbedtls_mpi_cmp_int(&P->Z, 0) == 0) { + ret = mbedtls_ecp_set_zero(R); + goto cleanup; + } + + /* R = 1*P */ + if (mbedtls_mpi_cmp_int(m, 1) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); + MBEDTLS_MPI_CHK(internal_ecp_normalize(grp, R)); + goto cleanup; + } + + /* R = m*P = (multiple of order)*G = 0 */ + /* NOTE: If grp->N (order) is a prime, we could detect R = 0 for all m*P cases + * by just checking if m is a multiple of grp->N. Otherwise, sigh. */ + /* TODO: Find an approach to detecting R = 0 for all m*P cases */ + INTERNAL_MPI_NORM(&Np, *m, N_, grp->N); + if (mbedtls_mpi_cmp_int(Np, 0) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_set_zero(R)); + goto cleanup; + } + } else if (eccop == ECCOP_POINT_ADD) { + /* R = P + Q */ + if (P == NULL || Q == NULL) { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + /* R = 0 + Q = Q */ + if (mbedtls_mpi_cmp_int(&P->Z, 0) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, Q)); + MBEDTLS_MPI_CHK(internal_ecp_normalize(grp, R)); + goto cleanup; + } + + /* R = P + 0 = P */ + if (mbedtls_mpi_cmp_int(&Q->Z, 0) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); + MBEDTLS_MPI_CHK(internal_ecp_normalize(grp, R)); + goto cleanup; + } + + /* R = P + Q = P + (-P) = 0 */ + MBEDTLS_MPI_CHK(internal_run_modop(&N_, &P->Y, &Q->Y, &grp->P, grp->pbits, MODOP_ADD)); + if (mbedtls_mpi_cmp_int(&N_, 0) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_set_zero(R)); + goto cleanup; + } + } else if (eccop == ECCOP_POINT_DOUBLE) { + /* R = 2*P */ + if (P == NULL) { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + /* R = 2*0 = 0 */ + if (mbedtls_mpi_cmp_int(&P->Z, 0) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_set_zero(R)); + goto cleanup; + } + + /* R = 2*P = P + P = P + (-P) = 0 */ + MBEDTLS_MPI_CHK(internal_run_modop(&N_, &P->Y, &P->Y, &grp->P, grp->pbits, MODOP_ADD)); + if (mbedtls_mpi_cmp_int(&N_, 0) == 0) { + MBEDTLS_MPI_CHK(mbedtls_ecp_set_zero(R)); + goto cleanup; + } + } else { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + /* Configure ECC curve coefficients A/B */ + /* Special case for A = -3 */ + if (grp->A.p == NULL) { + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&N_, -3)); + INTERNAL_MPI_NORM(&Np, N_, N_, grp->P); + } else { + INTERNAL_MPI_NORM(&Np, grp->A, N_, grp->P); + } + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_A, NU_ECC_BIGNUM_MAXWORD)); + INTERNAL_MPI_NORM(&Np, grp->B, N_, grp->P); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_B, NU_ECC_BIGNUM_MAXWORD)); + + /* Configure ECC prime modulus */ + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(&grp->P, (uint32_t *) CRPT->ECC_N, NU_ECC_BIGNUM_MAXWORD)); + + /* Configure ECC scalar for point multiplication + * + * Normalize m to within [1, order - 1] which ECCOP_POINT_MUL supports + * Special cases R = 0 should have been detected out above. + */ + if (eccop == ECCOP_POINT_MUL) { + INTERNAL_MPI_NORM(&Np, *m, N_, grp->N); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_K, NU_ECC_BIGNUM_MAXWORD)); + } + + /* Configure ECC point (X1, Y1) */ + INTERNAL_MPI_NORM(&Np, P->X, N_, grp->P); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_X1, NU_ECC_BIGNUM_MAXWORD)); + INTERNAL_MPI_NORM(&Np, P->Y, N_, grp->P); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_Y1, NU_ECC_BIGNUM_MAXWORD)); + + /* Configure ECC points (X2, Y2) */ + if (eccop == ECCOP_POINT_ADD) { + INTERNAL_MPI_NORM(&Np, Q->X, N_, grp->P); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_X2, NU_ECC_BIGNUM_MAXWORD)); + INTERNAL_MPI_NORM(&Np, Q->Y, N_, grp->P); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_Y2, NU_ECC_BIGNUM_MAXWORD)); + } + + /* ECC curve type */ + mbedtls_ecp_curve_type curve_type = mbedtls_ecp_get_type(grp); + uint32_t curve_sel = 0; + switch (curve_type) { + case MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS: + curve_sel = 0; // Short Weierstrass + break; + + case MBEDTLS_ECP_TYPE_MONTGOMERY: + curve_sel = CRPT_ECC_CTL_CSEL_Msk; // Montgomery + break; + + default: + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + /* Configure for point operation */ + uint32_t ecc_ctl = 0 | + CRPT_ECC_CTL_START_Msk | // Start + CRPT_ECC_CTL_FSEL_Msk | // Prime field (GF(p)) + eccop | // Point operation + curve_sel | // Curve selection + (grp->pbits << CRPT_ECC_CTL_CURVEM_Pos) | // Key length of elliptic curve + 0; + + crypto_ecc_prestart(); + CRPT->ECC_CTL = ecc_ctl; + ecc_done = crypto_ecc_wait(); + + MBEDTLS_MPI_CHK(ecc_done ? 0 : MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED); + + /* (X1, Y1) hold the normalized result. */ + MBEDTLS_MPI_CHK(internal_mpi_read_eccreg(&R->X, (uint32_t *) CRPT->ECC_X1, NU_ECC_BIGNUM_MAXWORD)); + MBEDTLS_MPI_CHK(internal_mpi_read_eccreg(&R->Y, (uint32_t *) CRPT->ECC_Y1, NU_ECC_BIGNUM_MAXWORD)); + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1)); + +cleanup: + + mbedtls_mpi_free(&N_); + + return ret; +} + +NU_STATIC int internal_run_modop(mbedtls_mpi *r, + const mbedtls_mpi *o1, + const mbedtls_mpi *o2, + const mbedtls_mpi *p, + uint32_t pbits, + uint32_t modop) +{ + if (r == NULL || + o1 == NULL || + o2 == NULL || + p == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Check o1/o2 are not negative */ + if (mbedtls_mpi_cmp_int(o1, 0) < 0 || + mbedtls_mpi_cmp_int(o2, 0) < 0) { + return MBEDTLS_ERR_MPI_NEGATIVE_VALUE; + } + + /* Check p is positive */ + if (mbedtls_mpi_cmp_int(p, 0) <= 0) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Check supported maximum key bits */ + if (pbits > NU_ECC_MAXKEYBITS) { + return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; + } + + /* Check MODOP operations are legal */ + if (modop != MODOP_DIV && + modop != MODOP_MUL && + modop != MODOP_ADD && + modop != MODOP_SUB) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + /* Check divisor is not zero in MODOP_DIV operation */ + if (modop == MODOP_DIV && mbedtls_mpi_cmp_int(o2, 0) == 0) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + bool ecc_done; + + mbedtls_mpi N_; + const mbedtls_mpi *Np; + + mbedtls_mpi_init(&N_); + + /* Use INTERNAL_MPI_NORM(Np, N1, N_, P) to get normalized MPI + * + * N_: Holds normalized MPI if the passed-in MPI N1 is not + * Np: Pointer to normalized MPI, which could be N1 or N_ + */ + + if (modop == MODOP_MUL || + modop == MODOP_ADD || + modop == MODOP_SUB) { + INTERNAL_MPI_NORM(&Np, *o1, N_, *p); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_X1, NU_ECC_BIGNUM_MAXWORD)); + INTERNAL_MPI_NORM(&Np, *o2, N_, *p); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_Y1, NU_ECC_BIGNUM_MAXWORD)); + } else if (modop == MODOP_DIV) { + INTERNAL_MPI_NORM(&Np, *o2, N_, *p); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_X1, NU_ECC_BIGNUM_MAXWORD)); + INTERNAL_MPI_NORM(&Np, *o1, N_, *p); + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(Np, (uint32_t *) CRPT->ECC_Y1, NU_ECC_BIGNUM_MAXWORD)); + } else { + MBEDTLS_MPI_CHK(MBEDTLS_ERR_ECP_BAD_INPUT_DATA); + } + + MBEDTLS_MPI_CHK(internal_mpi_write_eccreg(p, (uint32_t *) CRPT->ECC_N, NU_ECC_BIGNUM_MAXWORD)); + + /* Configure for modulus operation */ + uint32_t ecc_ctl = 0 | + CRPT_ECC_CTL_START_Msk | // Start + CRPT_ECC_CTL_FSEL_Msk | // Prime field (GF(p)) + ECCOP_MODULE | // No point operation + modop | // Modulus operation + (pbits << CRPT_ECC_CTL_CURVEM_Pos) | // Key length of elliptic curve + 0; + + crypto_ecc_prestart(); + CRPT->ECC_CTL = ecc_ctl; + ecc_done = crypto_ecc_wait(); + + MBEDTLS_MPI_CHK(ecc_done ? 0 : MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED); + + /* X1 holds the result. */ + MBEDTLS_MPI_CHK(internal_mpi_read_eccreg(r, (uint32_t *) CRPT->ECC_X1, NU_ECC_BIGNUM_MAXWORD)); + +cleanup: + + mbedtls_mpi_free(&N_); + + return ret; +} + +NU_STATIC int internal_mpi_read_eccreg(mbedtls_mpi *x, const volatile uint32_t *eccreg, size_t eccreg_num) +{ + if (x == NULL) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i, n; + + for (n = eccreg_num; n > 0; n --) { + if (eccreg[n - 1] != 0) { + break; + } + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_lset(x, 0)); + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(x, WORDS_TO_LIMBS(n))); + + for (i = 0; i < n; i ++) { + x->p[i / wiL] |= ((mbedtls_mpi_uint) eccreg[i]) << ((i % wiL) << 5); + } + +cleanup: + + return ret; +} + +NU_STATIC int internal_mpi_write_eccreg( const mbedtls_mpi *x, volatile uint32_t *eccreg, size_t eccreg_num ) +{ + if (x == NULL) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(x, 0) < 0) { + return MBEDTLS_ERR_MPI_NEGATIVE_VALUE; + } + + size_t i, n; + + /* How many words needed? */ + n = (mbedtls_mpi_size(x) + sizeof (uint32_t) - 1) / sizeof (uint32_t); + + if (eccreg_num < n) { + return MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL; + } + + /* Fill non-zero part */ + for (i = 0; i < n; i ++) { + eccreg[i] = (uint32_t) (x->p[i / wiL] >> ((i % wiL) << 5)); + } + + /* Zeroize remaining part + * + * crypto_zeroize32() has excluded optimization doubt, so we can safely set H/W registers to 0 via it. + */ + crypto_zeroize32((uint32_t *) eccreg + n, eccreg_num - n); + + return 0; +} + +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ +#endif /* ! MBEDTLS_ECP_ALT */ +#endif /* MBEDTLS_ECP_C */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/mbedtls_device.h b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/mbedtls_device.h new file mode 100644 index 0000000000..04049bd0f7 --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/mbedtls_device.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBEDTLS_DEVICE_H +#define MBEDTLS_DEVICE_H + +#define MBEDTLS_SHA1_ALT +#define MBEDTLS_SHA256_ALT +#define MBEDTLS_SHA512_ALT + +//#define MBEDTLS_AES_ALT + +#define MBEDTLS_ECP_INTERNAL_ALT +/* Support for Weierstrass curves with Jacobi representation */ +#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT +#define MBEDTLS_ECP_ADD_MIXED_ALT +#define MBEDTLS_ECP_DOUBLE_JAC_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +/* Support for curves with Montgomery arithmetic */ +//#define MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT +#define MBEDTLS_ECP_RANDOMIZE_MXZ_ALT +#define MBEDTLS_ECP_NORMALIZE_MXZ_ALT + +//#define MBEDTLS_RSA_ALT + +#endif /* MBEDTLS_DEVICE_H */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/rsa/rsa_alt.c b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/rsa/rsa_alt.c new file mode 100644 index 0000000000..8f414f586f --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/rsa/rsa_alt.c @@ -0,0 +1 @@ +/* TODO */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/rsa/rsa_alt.h b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/rsa/rsa_alt.h new file mode 100644 index 0000000000..8f414f586f --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/rsa/rsa_alt.h @@ -0,0 +1 @@ +/* TODO */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha1_alt.c b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha1_alt.c new file mode 100644 index 0000000000..b79130f87f --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha1_alt.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbedtls/sha1.h" + +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_SHA1_ALT) + +#include "crypto-misc.h" +#include "nu_bitutil.h" +#include "string.h" + +void mbedtls_sha1_init(mbedtls_sha1_context *ctx) +{ + crypto_sha_init(&ctx->hw_ctx, SHA_MODE_SHA1); +} + +void mbedtls_sha1_free(mbedtls_sha1_context *ctx) +{ + if (ctx == NULL) { + return; + } + + crypto_sha_free(&ctx->hw_ctx); +} + +void mbedtls_sha1_clone(mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src) +{ + // Corner case: Destination/source contexts are the same + if (dst == src) { + return; + } + + memcpy(dst, src, sizeof(mbedtls_sha1_context)); +} + +/* + * SHA-1 context setup + */ +int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx) +{ + if (ctx == NULL) { + return MBEDTLS_ERR_SHA1_BAD_INPUT_DATA; + } + + return crypto_sha_starts(&ctx->hw_ctx, 0); +} + +/* + * SHA-1 process buffer + */ +int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen) +{ + if (ctx == NULL || (input == NULL && ilen == 0)) { + return MBEDTLS_ERR_SHA1_BAD_INPUT_DATA; + } + + return crypto_sha_update(&ctx->hw_ctx, input, ilen); +} + +/* + * SHA-1 final digest + */ +int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx, unsigned char output[20]) +{ + if (ctx == NULL || output == NULL) { + return MBEDTLS_ERR_SHA1_BAD_INPUT_DATA; + } + + return crypto_sha_finish(&ctx->hw_ctx, output, 20); +} + +int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, const unsigned char data[64]) +{ + if (ctx == NULL || data == NULL) { + return MBEDTLS_ERR_SHA1_BAD_INPUT_DATA; + } + + return crypto_sha_update(&ctx->hw_ctx, data, 64); +} + +#endif /* MBEDTLS_SHA1_ALT */ +#endif /* MBEDTLS_SHA1_C */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha1_alt.h b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha1_alt.h new file mode 100644 index 0000000000..3c4efdac82 --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha1_alt.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBEDTLS_SHA1_ALT_H +#define MBEDTLS_SHA1_ALT_H + +#include "mbedtls/sha1.h" + +#if defined(MBEDTLS_SHA1_ALT) + +#include "sha_alt_hw.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct mbedtls_sha1_context_s; + +/** + * \brief SHA-1 context structure + */ +typedef struct mbedtls_sha1_context_s { + crypto_sha_context hw_ctx; +} +mbedtls_sha1_context; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-1 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + * + * \returns error code + */ +int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns error code + */ +int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + * + * \returns error code + */ +int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx, unsigned char output[20] ); + +/* Internal use */ +int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief SHA-1 context setup + * + * \deprecated Superseded by mbedtls_sha1_starts_ret() in 2.7.0 + * + * \param ctx The SHA-1 context to be initialized. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \deprecated Superseded by mbedtls_sha1_update_ret() in 2.7.0 + * + * \param ctx The SHA-1 context. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_update( mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \deprecated Superseded by mbedtls_sha1_finish_ret() in 2.7.0 + * + * \param ctx The SHA-1 context. + * \param output The SHA-1 checksum result. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, + unsigned char output[20] ); + +/** + * \brief SHA-1 process data block (internal use only) + * + * \deprecated Superseded by mbedtls_internal_sha1_process() in 2.7.0 + * + * \param ctx The SHA-1 context. + * \param data The data block being processed. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_SHA1_ALT */ + +#endif /* sha1_alt.h */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha256_alt.c b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha256_alt.c new file mode 100644 index 0000000000..82beab6dbe --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha256_alt.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbedtls/sha256.h" + +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_SHA256_ALT) + +#include "crypto-misc.h" +#include "nu_bitutil.h" +#include "string.h" + +void mbedtls_sha256_init(mbedtls_sha256_context *ctx) +{ + crypto_sha_init(&ctx->hw_ctx, SHA_MODE_SHA256); +} + +void mbedtls_sha256_free(mbedtls_sha256_context *ctx) +{ + if (ctx == NULL) { + return; + } + + crypto_sha_free(&ctx->hw_ctx); +} + +void mbedtls_sha256_clone(mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src) +{ + // Corner case: Destination/source contexts are the same + if (dst == src) { + return; + } + + memcpy(dst, src, sizeof(mbedtls_sha256_context)); +} + +/* + * SHA-256 context setup + */ +int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224) +{ + if (ctx == NULL) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } + + return crypto_sha_starts(&ctx->hw_ctx, is224); +} + +/* + * SHA-256 process buffer + */ +int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen) +{ + if (ctx == NULL || (input == NULL && ilen == 0)) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } + + return crypto_sha_update(&ctx->hw_ctx, input, ilen); +} + +/* + * SHA-256 final digest + */ +int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx, unsigned char output[32]) +{ + if (ctx == NULL || output == NULL) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } + + return crypto_sha_finish(&ctx->hw_ctx, output, ctx->hw_ctx.is224_384 ? 28 : 32); +} + +int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, const unsigned char data[64]) +{ + if (ctx == NULL || data == NULL) { + return MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + } + + return crypto_sha_update(&ctx->hw_ctx, data, 64); +} + +#endif /* MBEDTLS_SHA256_ALT */ +#endif /* MBEDTLS_SHA256_C */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha256_alt.h b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha256_alt.h new file mode 100644 index 0000000000..bd8669a438 --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha256_alt.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBEDTLS_SHA256_ALT_H +#define MBEDTLS_SHA256_ALT_H + +#include "mbedtls/sha256.h" + +#if defined(MBEDTLS_SHA256_ALT) + +#include "sha_alt_hw.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct mbedtls_sha256_context_s; + +/** + * \brief SHA-256 context structure + */ +typedef struct mbedtls_sha256_context_s { + crypto_sha_context hw_ctx; +} +mbedtls_sha256_context; + +/** + * \brief Initialize SHA-256 context + * + * \param ctx SHA-256 context to be initialized + */ +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ); + +/** + * \brief Clear SHA-256 context + * + * \param ctx SHA-256 context to be cleared + */ +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-256 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ); + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + * + * \returns error code + */ +int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 ); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns error code + */ +int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-224/256 checksum result + * + * \returns error code + */ +int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx, unsigned char output[32] ); + +/* Internal use */ +int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function starts a SHA-256 checksum calculation. + * + * \deprecated Superseded by mbedtls_sha256_starts_ret() in 2.7.0. + * + * \param ctx The SHA-256 context to initialize. + * \param is224 Determines which function to use. + *
  • 0: Use SHA-256.
  • + *
  • 1: Use SHA-224.
+ */ +MBEDTLS_DEPRECATED void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, + int is224 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-256 checksum calculation. + * + * \deprecated Superseded by mbedtls_sha256_update_ret() in 2.7.0. + * + * \param ctx The SHA-256 context to initialize. + * \param input The buffer holding the data. + * \param ilen The length of the input data. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_update( mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-256 operation, and writes + * the result to the output buffer. + * + * \deprecated Superseded by mbedtls_sha256_finish_ret() in 2.7.0. + * + * \param ctx The SHA-256 context. + * \param output The SHA-224or SHA-256 checksum result. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, + unsigned char output[32] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-256 computation. This function is for + * internal use only. + * + * \deprecated Superseded by mbedtls_internal_sha256_process() in 2.7.0. + * + * \param ctx The SHA-256 context. + * \param data The buffer holding one block of data. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_SHA256_ALT */ + +#endif /* sha256_alt.h */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha512_alt.c b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha512_alt.c new file mode 100644 index 0000000000..c6592d42e8 --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha512_alt.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbedtls/sha512.h" + +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_SHA512_ALT) + +#include "crypto-misc.h" +#include "nu_bitutil.h" +#include "string.h" + +void mbedtls_sha512_init(mbedtls_sha512_context *ctx) +{ + crypto_sha_init(&ctx->hw_ctx, SHA_MODE_SHA512); +} + +void mbedtls_sha512_free(mbedtls_sha512_context *ctx) +{ + if (ctx == NULL) { + return; + } + + crypto_sha_free(&ctx->hw_ctx); +} + +void mbedtls_sha512_clone(mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src) +{ + // Corner case: Destination/source contexts are the same + if (dst == src) { + return; + } + + memcpy(dst, src, sizeof(mbedtls_sha512_context)); +} + +/* + * SHA-512 context setup + */ +int mbedtls_sha512_starts_ret(mbedtls_sha512_context *ctx, int is384) +{ + if (ctx == NULL) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } + + return crypto_sha_starts(&ctx->hw_ctx, is384); +} + +/* + * SHA-512 process buffer + */ +int mbedtls_sha512_update_ret(mbedtls_sha512_context *ctx, const unsigned char *input, size_t ilen) +{ + if (ctx == NULL || (input == NULL && ilen == 0)) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } + + return crypto_sha_update(&ctx->hw_ctx, input, ilen); +} + +/* + * SHA-512 final digest + */ +int mbedtls_sha512_finish_ret(mbedtls_sha512_context *ctx, unsigned char output[64]) +{ + if (ctx == NULL || output == NULL) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } + + return crypto_sha_finish(&ctx->hw_ctx, output, ctx->hw_ctx.is224_384 ? 48 : 64); +} + +int mbedtls_internal_sha512_process(mbedtls_sha512_context *ctx, const unsigned char data[128]) +{ + if (ctx == NULL || data == NULL) { + return MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + } + + return crypto_sha_update(&ctx->hw_ctx, data, 128); +} + +#endif /* MBEDTLS_SHA512_ALT */ +#endif /* MBEDTLS_SHA512_C */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha512_alt.h b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha512_alt.h new file mode 100644 index 0000000000..b6decc2f41 --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha512_alt.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBEDTLS_SHA512_ALT_H +#define MBEDTLS_SHA512_ALT_H + +#include "mbedtls/sha512.h" + +#if defined(MBEDTLS_SHA512_ALT) + +#include "sha_alt_hw.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct mbedtls_sha512_context_s; + +/** + * \brief SHA-512 context structure + */ +typedef struct mbedtls_sha512_context_s { + crypto_sha_context hw_ctx; +} +mbedtls_sha512_context; + +/** + * \brief Initialize SHA-512 context + * + * \param ctx SHA-512 context to be initialized + */ +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ); + +/** + * \brief Clear SHA-512 context + * + * \param ctx SHA-512 context to be cleared + */ +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-512 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ); + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + * + * \returns error code + */ +int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 ); + +/** + * \brief SHA-512 process buffer + * + * \param ctx SHA-512 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns error code + */ +int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-512 final digest + * + * \param ctx SHA-512 context + * \param output SHA-384/512 checksum result + * + * \returns error code + */ +int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, unsigned char output[64] ); + +/* Internal use */ +int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, const unsigned char data[128] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function starts a SHA-384 or SHA-512 checksum + * calculation. + * + * \deprecated Superseded by mbedtls_sha512_starts_ret() in 2.7.0 + * + * \param ctx The SHA-512 context to initialize. + * \param is384 Determines which function to use. + *
  • 0: Use SHA-512.
  • + *
  • 1: Use SHA-384.
+ */ +MBEDTLS_DEPRECATED void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, + int is384 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-512 checksum calculation. + * + * \deprecated Superseded by mbedtls_sha512_update_ret() in 2.7.0 + * + * \param ctx The SHA-512 context. + * \param input The buffer holding the data. + * \param ilen The length of the input data. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_update( mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-512 operation, and writes + * the result to the output buffer. + * + * \deprecated Superseded by mbedtls_sha512_finish_ret() in 2.7.0 + * + * \param ctx The SHA-512 context. + * \param output The SHA-384 or SHA-512 checksum result. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, + unsigned char output[64] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-512 computation. This function is for + * internal use only. + * + * \deprecated Superseded by mbedtls_internal_sha512_process() in 2.7.0 + * + * \param ctx The SHA-512 context. + * \param data The buffer holding one block of data. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_process( mbedtls_sha512_context *ctx, + const unsigned char data[128] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_SHA512_ALT */ + +#endif /* sha512_alt.h */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha_alt_hw.c b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha_alt_hw.c new file mode 100644 index 0000000000..996315a428 --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha_alt_hw.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbedtls/sha1.h" +#include "mbedtls/sha256.h" +#include "mbedtls/sha512.h" + +#if defined(MBEDTLS_SHA1_C) || defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_SHA1_ALT) || defined(MBEDTLS_SHA256_ALT) || defined(MBEDTLS_SHA512_ALT) + +#include "nu_bitutil.h" +#include "nu_timer.h" +#include "mbed_assert.h" +#include "mbed_error.h" +#include "crypto-misc.h" + +#include + +/* SHA context for DMA */ +static struct { + MBED_ALIGN(4) + uint8_t block_imd[NU_CRYPTO_SHA_MAXSIZE_DMABLOCKRUN_BYTES]; // Intermediate data block in DMA mode + uint32_t fbinfo_imd[NU_CRYPTO_SHA_MAXSIZE_FBINFO_WORDS]; // Intermediate feedback information in DMA cascade mode + + const uint8_t *block_act; // Actual of above + uint32_t *fbinfo_act; // Actual of above +} dma_ctx_inst; + +/* Manage SHA H/W + * + * We follow the rules below to manage SHA H/W to share among contexts: + * 1. Go DMA cascade mode to support context save & restore. + * 2. Initialize/un-initialize crypto H/W at first context init/last context free. + * 3. All code involving SHA H/W are in between crypto_sha_acquire()/crypto_sha_release(). + * 4. Interrupt is enabled (SHA_ENABLE_INT()/SHA_DISABLE_INT()) only during real SHA H/W operation. + */ + +void crypto_sha_init(crypto_sha_context *ctx, uint32_t type) +{ + MBED_ASSERT(type == SHA_MODE_SHA1 || + type == SHA_MODE_SHA256 || + type == SHA_MODE_SHA512); + + /* Clean SHA context */ + crypto_zeroize(ctx, sizeof(*ctx)); + + /* SHA operation mode */ + ctx->type = type; + ctx->opmode = type; + + /* Mbed TLS error code for the SHA type */ + switch (type) { + case SHA_MODE_SHA1: + ctx->digestsize = 20; + ctx->err_hw_accel = MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED; + ctx->err_bad_input = MBEDTLS_ERR_SHA1_BAD_INPUT_DATA; + break; + + case SHA_MODE_SHA256: + ctx->digestsize = 32; + ctx->err_hw_accel = MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED; + ctx->err_bad_input = MBEDTLS_ERR_SHA256_BAD_INPUT_DATA; + break; + + case SHA_MODE_SHA512: + ctx->digestsize = 64; + ctx->err_hw_accel = MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED; + ctx->err_bad_input = MBEDTLS_ERR_SHA512_BAD_INPUT_DATA; + break; + + default: + MBED_ASSERT(0); + } + + /* Acquire ownership of SHA H/W */ + crypto_sha_acquire(); + + /* SHA H/W DMA buffer has the following requirements: + * (1) Word-aligned buffer base address + * (2) Word-aligned buffer size + * (3) Located in 0x20000000-0x2FFFFFFF region */ + if ((! crypto_dma_buff_compat(dma_ctx_inst.block_imd, sizeof(dma_ctx_inst.block_imd), 4)) || + (! crypto_dma_buff_compat(dma_ctx_inst.fbinfo_imd, sizeof(dma_ctx_inst.fbinfo_imd), 4))) { + error("Buffer for SHA H/W DMA requires to be word-aligned and located in 0x20000000-0x2FFFFFFF region."); + } + + /* Initialize crypto module */ + crypto_init(); + + /* Release ownership of SHA H/W */ + crypto_sha_release(); +} + +void crypto_sha_free(crypto_sha_context *ctx) +{ + if (ctx == NULL) { + return; + } + + /* Acquire ownership of SHA H/W */ + crypto_sha_acquire(); + + /* Un-initialize crypto module */ + crypto_uninit(); + + /* Release ownership of SHA H/W */ + crypto_sha_release(); + + /* Clean SHA context */ + crypto_zeroize(ctx, sizeof(*ctx)); +} + +int crypto_sha_starts(crypto_sha_context *ctx, int is224_384) +{ + MBED_ASSERT(ctx != NULL); + + /* NOTE: mbedtls may call mbedtls_shaXXX_starts multiple times and then call the ending mbedtls_shaXXX_finish. Guard from it. */ + /* NOTE: In DMA cascade mode, re-configure SHA H/W instead of at start */ + + ctx->total = 0; + ctx->buffer_left = 0; + + switch (ctx->type) { + case SHA_MODE_SHA1: + ctx->blocksize = 64; + ctx->blocksize_mask = 0x3F; + break; + + case SHA_MODE_SHA256: + ctx->blocksize = 64; + ctx->blocksize_mask = 0x3F; + ctx->opmode = is224_384 ? SHA_MODE_SHA224 : SHA_MODE_SHA256; + ctx->digestsize = is224_384 ? 28 : 32; + break; + + case SHA_MODE_SHA512: + ctx->blocksize = 128; + ctx->blocksize_mask = 0x7F; + ctx->opmode = is224_384 ? SHA_MODE_SHA384 : SHA_MODE_SHA512; + ctx->digestsize = is224_384 ? 48 : 64; + break; + + default: + MBED_ASSERT(0); + } + + ctx->is224_384 = is224_384; + + return 0; +} + +int crypto_sha_update(crypto_sha_context *ctx, const unsigned char *input, size_t ilen) +{ + MBED_ASSERT(ctx != NULL); + + if (ilen == 0) { + return 0; + } + + MBED_ASSERT(input != NULL); + + int rc = 0; + + /* One complete block = above left + new input */ + size_t fill = ctx->blocksize - ctx->buffer_left; + if (ctx->buffer_left && ilen >= fill) { + memcpy((void *) (ctx->buffer + ctx->buffer_left), input, fill); + input += fill; + ilen -= fill; + ctx->buffer_left += fill; + MBED_ASSERT(ctx->buffer_left == ctx->blocksize); + rc = crypto_sha_update_nobuf(ctx, ctx->buffer, ctx->buffer_left, (ctx->total == 0), 0); + if (rc != 0) { + return rc; + } + ctx->total += ctx->buffer_left; + ctx->buffer_left = 0; + } + + /* Complete blocks in block runs */ + while (ilen >= NU_CRYPTO_SHA_MAXSIZE_DMABLOCKRUN_BYTES) { + rc = crypto_sha_update_nobuf(ctx, input, NU_CRYPTO_SHA_MAXSIZE_DMABLOCKRUN_BYTES, (ctx->total == 0), 0); + if (rc != 0) { + return rc; + } + ctx->total += NU_CRYPTO_SHA_MAXSIZE_DMABLOCKRUN_BYTES; + input += NU_CRYPTO_SHA_MAXSIZE_DMABLOCKRUN_BYTES; + ilen -= NU_CRYPTO_SHA_MAXSIZE_DMABLOCKRUN_BYTES; + } + + /* Complete blocks modulus block run */ + fill = ilen - (ilen % ctx->blocksize); + MBED_ASSERT((fill % ctx->blocksize) == 0); + if (fill) { + rc = crypto_sha_update_nobuf(ctx, input, fill, (ctx->total == 0), 0); + if (rc != 0) { + return rc; + } + ctx->total += fill; + input += fill; + ilen -= fill; + } + + /* Left incomplete block */ + if (ilen > 0) { + MBED_ASSERT(ilen < ctx->blocksize); + fill = ilen; + memcpy((void *) (ctx->buffer + ctx->buffer_left), input, fill); + input += fill; + ilen -= fill; + ctx->buffer_left += fill; + } + + MBED_ASSERT(ilen == 0); + + return rc; +} + +int crypto_sha_update_nobuf(crypto_sha_context *ctx, const unsigned char *input, size_t ilen, int isfirst, int islast) +{ + MBED_ASSERT(ctx != NULL); + + /* Accept only: + * 1. Last block which may be incomplete + * 2. Non-last block(s) which must be complete */ + MBED_ASSERT(islast || (ilen % ctx->blocksize) == 0); + + int rc = 0; + + /* Acquire ownership of SHA H/W */ + crypto_sha_acquire(); + + /* Enable SHA interrupt */ + SHA_ENABLE_INT(CRPT); + + /* Use intermediate buffer when incompatible with SHA H/W DMA buffer */ + if (!crypto_dma_buff_compat(input, ilen, 1)) { + memcpy(dma_ctx_inst.block_imd, input, ilen); + dma_ctx_inst.block_act = dma_ctx_inst.block_imd; + } else { + dma_ctx_inst.block_act = input; + } + if (!crypto_dma_buff_compat(ctx->fbinfo, sizeof(ctx->fbinfo), 4)) { + memcpy(dma_ctx_inst.fbinfo_imd, ctx->fbinfo, sizeof(ctx->fbinfo)); + dma_ctx_inst.fbinfo_act = dma_ctx_inst.fbinfo_imd; + } else { + dma_ctx_inst.fbinfo_act = ctx->fbinfo; + } + + SHA_Open(CRPT, ctx->opmode, SHA_IN_SWAP, 0); + SHA_SetDMATransfer(CRPT, (uint32_t) dma_ctx_inst.block_act, ilen); + + /* Address of feedback information input/output */ + CRPT->HMAC_FBADDR = (uint32_t) dma_ctx_inst.fbinfo_act; + + /* Continue above and re-configure further */ + uint32_t hmac_ctl = CRPT->HMAC_CTL | + CRPT_HMAC_CTL_START_Msk | // Start SHA/HMAC engine + (isfirst ? CRPT_HMAC_CTL_DMAFIRST_Msk : 0) | // SHA/HMAC first block in cascade function + (islast ? CRPT_HMAC_CTL_DMALAST_Msk : 0) | // SHA/HMAC last block + CRPT_HMAC_CTL_DMACSCAD_Msk | // Enable SHA/HMAC engine DMA with cascade mode + CRPT_HMAC_CTL_DMAEN_Msk | // Enable SHA/HMAC engine DMA + (isfirst ? 0 : CRPT_HMAC_CTL_FBIN_Msk) | // Feedback input to SHA/HMAC via DMA automatically + // FBIN doesn't make sense for the first block, on which + // SHA H/W isn't fool-proof. Enable FBIN for the first block + // will crash SHA H/W. + (islast ? 0 : CRPT_HMAC_CTL_FBOUT_Msk) | // Feedback output from SHA/HMAC via DMA automatically + // FBOUT is unnecessary for the last block. + 0; + + crypto_sha_prestart(); + CRPT->HMAC_CTL = hmac_ctl; + rc = crypto_sha_wait() ? 0 : ctx->err_hw_accel; + + /* On using intermediate buffer, restore output feedback information */ + if (rc == 0 && + (uint32_t) ctx->fbinfo != (uint32_t) dma_ctx_inst.fbinfo_act) { + memcpy(ctx->fbinfo, dma_ctx_inst.fbinfo_act, sizeof(ctx->fbinfo)); + } + + /* Disable SHA interrupt */ + SHA_DISABLE_INT(CRPT); + + /* Release ownership of SHA H/W */ + crypto_sha_release(); + + return rc; +} + +int crypto_sha_finish(crypto_sha_context *ctx, unsigned char output[], size_t olen) +{ + MBED_ASSERT(ctx != NULL); + MBED_ASSERT(output != NULL); + MBED_ASSERT(olen != 0 && olen == ctx->digestsize); + + int rc = 0; + + /* NOTE: Per real test, SHA H/W can support zero data, so we needn't + * special handling for it. */ + rc = crypto_sha_update_nobuf(ctx, ctx->buffer, ctx->buffer_left, (ctx->total == 0), 1); + if (rc != 0) { + return rc; + } + ctx->total += ctx->buffer_left; + ctx->buffer_left = 0; + rc = crypto_sha_getdigest(output, ctx->digestsize); + if (rc != 0) { + return rc; + } + + return rc; +} + +int crypto_sha_getdigest(unsigned char output[], size_t olen) +{ + MBED_ASSERT(output != NULL); + MBED_ASSERT(olen != 0 && (olen % 4) == 0); + + uint32_t *in_pos = (uint32_t *) &CRPT->HMAC_DGST[0]; + unsigned char *out_pos = output; + uint32_t rmn = olen; + + while (rmn) { + uint32_t val = *in_pos ++; + nu_set32_be(out_pos, val); + out_pos += 4; + rmn -= 4; + } + + return 0; +} + +#endif /* MBEDTLS_SHA1_ALT || MBEDTLS_SHA256_ALT || MBEDTLS_SHA512_ALT */ +#endif /* MBEDTLS_SHA1_C || MBEDTLS_SHA256_C || MBEDTLS_SHA512_C */ diff --git a/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha_alt_hw.h b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha_alt_hw.h new file mode 100644 index 0000000000..43219d701b --- /dev/null +++ b/connectivity/drivers/mbedtls/TARGET_NUVOTON/TARGET_M460/sha/sha_alt_hw.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBEDTLS_SHA_ALT_HW_H +#define MBEDTLS_SHA_ALT_HW_H + +#if defined(MBEDTLS_SHA1_ALT) || defined(MBEDTLS_SHA256_ALT) || defined(MBEDTLS_SHA512_ALT) + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Max size of SHA block in bytes + * + * SHA-160/224/256: 64 bytes + * SHA-384/512: 128 bytes + * + * \note Support SHA1/2 only, no SHA3 + */ +#define NU_CRYPTO_SHA_MAXSIZE_BLOCK_BYTES 128 + +/** + * \brief Max size of SHA DMA block run in bytes + * + * \note DMA cascade mode requires block-aligned except for the last block. + * \note This also defines DMA intermediary buffer size. + */ +#define NU_CRYPTO_SHA_MAXSIZE_DMABLOCKRUN_BYTES \ + (NU_CRYPTO_SHA_MAXSIZE_BLOCK_BYTES * 4) + +/** + * \brief Max size of SHA feedback information in words, used in DMA cascade mode + * + * SHA1/2: 54 words + * SHA3: 88 words + * + * \note Support SHA1/2 only, no SHA3 + * \note According to spec, reserve 54 words for SHA1/2. But per real + * test, SHA H/W will overwrite beyond 54 words. Workaround by + * reserving 88 words anyway. + */ +#define NU_CRYPTO_SHA_MAXSIZE_FBINFO_WORDS 88 + +/** + * \brief SHA context structure + * + * \note SHA type/opmode + * 1. For type, borrow from opmode defines and can only be SHA_MODE_SHA1/SHA256/SHA512. + * 2. Initialize opmode/digestsize dependent on type + * 3. For SHA_MODE_SHA256/512, opmode will change to SHA_MODE_SHA224/384 + * when is224_384 is non-zero in the call to crypto_sha_starts(). + * 4. Following above, for opmode being SHA_MODE_SHA224/384, change digestsize to 28/48 + */ +typedef struct { + /* These fields will initialize at crypto_sha_init() */ + uint32_t type; /*!< SHA type */ + uint32_t opmode; /*!< SHA operation mode */ + uint32_t digestsize; /*!< SHA digest size */ + int err_hw_accel; /*!< Mbed TLS error code for the SHA type */ + int err_bad_input; /*!< Mbed TLS error code for the SHA type */ + + /* These fields will initialize at crypto_sha_starts() */ + uint32_t total; /*!< number of bytes processed */ + union { + uint8_t buffer[NU_CRYPTO_SHA_MAXSIZE_BLOCK_BYTES]; /*!< data block being processed. Max of SHA-1/SHA-256/SHA-512 */ + uint32_t buffer_u32[NU_CRYPTO_SHA_MAXSIZE_BLOCK_BYTES/4]; /*!< make buffer word aligned */ + }; + uint16_t buffer_left; + uint16_t blocksize; /*!< block size */ + uint32_t blocksize_mask; /*!< block size mask */ + int is224_384; /*!< 0 => SHA-256/SHA-512, else SHA-224/384 */ + uint32_t fbinfo[NU_CRYPTO_SHA_MAXSIZE_FBINFO_WORDS]; /*!< feedback information in DMA cascade mode */ +} +crypto_sha_context; + +void crypto_sha_init(crypto_sha_context *ctx, uint32_t type); +void crypto_sha_free(crypto_sha_context *ctx); +int crypto_sha_starts(crypto_sha_context *ctx, int is224_384); +int crypto_sha_update(crypto_sha_context *ctx, const unsigned char *input, size_t ilen); +int crypto_sha_update_nobuf(crypto_sha_context *ctx, const unsigned char *input, size_t ilen, int isfirst, int islast); +int crypto_sha_finish(crypto_sha_context *ctx, unsigned char output[], size_t olen); +int crypto_sha_getdigest(unsigned char output[], size_t olen); + +#if defined(MBEDTLS_SHA1_ALT) + +void mbedtls_sha1_hw_init( crypto_sha_context *ctx ); +void mbedtls_sha1_hw_free( crypto_sha_context *ctx ); +int mbedtls_sha1_hw_starts( crypto_sha_context *ctx ); +int mbedtls_sha1_hw_update( crypto_sha_context *ctx, const unsigned char *input, size_t ilen ); +int mbedtls_sha1_hw_finish( crypto_sha_context *ctx, unsigned char output[20] ); +int mbedtls_sha1_hw_process( crypto_sha_context *ctx, const unsigned char data[64] ); + +#endif /* MBEDTLS_SHA1_ALT */ + +#if defined(MBEDTLS_SHA256_ALT) + +void mbedtls_sha256_hw_init( crypto_sha_context *ctx ); +void mbedtls_sha256_hw_free( crypto_sha_context *ctx ); +int mbedtls_sha256_hw_starts( crypto_sha_context *ctx, int is224 ); +int mbedtls_sha256_hw_update( crypto_sha_context *ctx, const unsigned char *input, + size_t ilen ); +int mbedtls_sha256_hw_finish( crypto_sha_context *ctx, unsigned char output[32] ); +int mbedtls_sha256_hw_process( crypto_sha_context *ctx, const unsigned char data[64] ); + +#endif /* MBEDTLS_SHA256_ALT */ + +#if defined(MBEDTLS_SHA512_ALT) + +void mbedtls_sha512_hw_init( crypto_sha_context *ctx ); +void mbedtls_sha512_hw_free( crypto_sha_context *ctx ); +int mbedtls_sha512_hw_starts( crypto_sha_context *ctx, int is384 ); +int mbedtls_sha512_hw_update( crypto_sha_context *ctx, const unsigned char *input, + size_t ilen ); +int mbedtls_sha512_hw_finish( crypto_sha_context *ctx, unsigned char output[64] ); +int mbedtls_sha512_hw_process( crypto_sha_context *ctx, const unsigned char data[128] ); + +#endif /* MBEDTLS_SHA512_ALT */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_SHA1_ALT || MBEDTLS_SHA256_ALT || MBEDTLS_SHA512_ALT */ + +#endif /* sha_alt.h */ diff --git a/targets/TARGET_NUVOTON/TARGET_M460/CMakeLists.txt b/targets/TARGET_NUVOTON/TARGET_M460/CMakeLists.txt index bba46ac0a8..2714ef9ea9 100644 --- a/targets/TARGET_NUVOTON/TARGET_M460/CMakeLists.txt +++ b/targets/TARGET_NUVOTON/TARGET_M460/CMakeLists.txt @@ -14,6 +14,8 @@ target_sources(mbed-m460 analogin_api.c analogout_api.c + crypto/crypto-misc.cpp + device/startup_M460.c device/system_M460.c device/StdDriver/src/m460_acmp.c @@ -83,6 +85,7 @@ target_sources(mbed-m460 target_include_directories(mbed-m460 INTERFACE . + crypto device device/Reg device/StdDriver/inc diff --git a/targets/TARGET_NUVOTON/TARGET_M460/crypto/crypto-misc.cpp b/targets/TARGET_NUVOTON/TARGET_M460/crypto/crypto-misc.cpp new file mode 100644 index 0000000000..9c0d1e915d --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_M460/crypto/crypto-misc.cpp @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cmsis.h" +#include "mbed_assert.h" +#include "mbed_atomic.h" +#include "mbed_critical.h" +#include "mbed_error.h" +#include +#include "nu_modutil.h" +#include "nu_bitutil.h" +#include "crypto-misc.h" +#include "platform/SingletonPtr.h" +#include "platform/PlatformMutex.h" + +/* Consideration for choosing proper synchronization mechanism + * + * We choose mutex to synchronize access to crypto ACC. We can guarantee: + * (1) No deadlock + * We just lock mutex for a short sequence of operations rather than the whole lifetime + * of crypto context. + * (2) No priority inversion + * Mutex supports priority inheritance and it is enabled. + */ + +/* Mutex for crypto PRNG ACC management */ +static SingletonPtr crypto_prng_mutex; + +/* Mutex for crypto AES ACC management */ +static SingletonPtr crypto_aes_mutex; + +/* Mutex for crypto SHA ACC management */ +static SingletonPtr crypto_sha_mutex; + +/* Mutex for crypto ECC ACC management */ +static SingletonPtr crypto_ecc_mutex; + +/* Mutex for crypto RSA ACC management */ +static SingletonPtr crypto_rsa_mutex; + +/* Crypto init counter. Crypto keeps active as it is non-zero. */ +static uint16_t crypto_init_counter = 0U; + +/* Crypto done flags */ +#define NU_CRYPTO_DONE_OK BIT0 // Done with OK +#define NU_CRYPTO_DONE_ERR BIT1 // Done with error + +/* Track if PRNG H/W operation is done */ +static volatile uint16_t crypto_prng_done; +/* Track if AES H/W operation is done */ +static volatile uint16_t crypto_aes_done; +/* Track if SHA H/W operation is done */ +static volatile uint16_t crypto_sha_done; +/* Track if ECC H/W operation is done */ +static volatile uint16_t crypto_ecc_done; +/* Track if RSA H/W operation is done */ +static volatile uint16_t crypto_rsa_done; + +static void crypto_submodule_prestart(volatile uint16_t *submodule_done); +static bool crypto_submodule_wait(volatile uint16_t *submodule_done); + +/* As crypto init counter changes from 0 to 1: + * + * 1. Enable crypto clock + * 2. Enable crypto interrupt + */ +void crypto_init(void) +{ + core_util_critical_section_enter(); + if (crypto_init_counter == USHRT_MAX) { + core_util_critical_section_exit(); + error("Crypto clock enable counter would overflow (> USHRT_MAX)"); + } + core_util_atomic_incr_u16(&crypto_init_counter, 1); + if (crypto_init_counter == 1) { + SYS_UnlockReg(); // Unlock protected register + CLK_EnableModuleClock(CRPT_MODULE); + SYS_ResetModule(CRPT_RST); + SYS_LockReg(); // Lock protected register + + NVIC_EnableIRQ(CRPT_IRQn); + } + core_util_critical_section_exit(); +} + +/* As crypto init counter changes from 1 to 0: + * + * 1. Disable crypto interrupt + * 2. Disable crypto clock + */ +void crypto_uninit(void) +{ + core_util_critical_section_enter(); + if (crypto_init_counter == 0) { + core_util_critical_section_exit(); + error("Crypto clock enable counter would underflow (< 0)"); + } + core_util_atomic_decr_u16(&crypto_init_counter, 1); + if (crypto_init_counter == 0) { + NVIC_DisableIRQ(CRPT_IRQn); + + SYS_UnlockReg(); // Unlock protected register + CLK_DisableModuleClock(CRPT_MODULE); + SYS_LockReg(); // Lock protected register + } + core_util_critical_section_exit(); +} + +/* Implementation that should never be optimized out by the compiler */ +void crypto_zeroize(void *v, size_t n) +{ + volatile unsigned char *p = (volatile unsigned char*) v; + while (n--) { + *p++ = 0; + } +} + +/* Implementation that should never be optimized out by the compiler */ +void crypto_zeroize32(uint32_t *v, size_t n) +{ + volatile uint32_t *p = (volatile uint32_t*) v; + while (n--) { + *p++ = 0; + } +} + +void crypto_prng_acquire(void) +{ + /* Don't check return code of Mutex::lock(void) + * + * This function treats RTOS errors as fatal system errors, so it can only return osOK. + * Use of the return value is deprecated, as the return is expected to become void in + * the future. + */ + crypto_prng_mutex->lock(); +} + +void crypto_prng_release(void) +{ + crypto_prng_mutex->unlock(); +} + +void crypto_aes_acquire(void) +{ + /* Don't check return code of Mutex::lock(void) */ + crypto_aes_mutex->lock(); +} + +void crypto_aes_release(void) +{ + crypto_aes_mutex->unlock(); +} + +void crypto_sha_acquire(void) +{ + /* Don't check return code of Mutex::lock(void) */ + crypto_sha_mutex->lock(); +} + +void crypto_sha_release(void) +{ + crypto_sha_mutex->unlock(); +} + +void crypto_ecc_acquire(void) +{ + /* Don't check return code of Mutex::lock(void) */ + crypto_ecc_mutex->lock(); +} + +void crypto_ecc_release(void) +{ + crypto_ecc_mutex->unlock(); +} + +void crypto_rsa_acquire(void) +{ + /* Don't check return code of Mutex::lock(void) */ + crypto_rsa_mutex->lock(); +} + +void crypto_rsa_release(void) +{ + crypto_rsa_mutex->unlock(); +} + +void crypto_prng_prestart(void) +{ + crypto_submodule_prestart(&crypto_prng_done); +} + +bool crypto_prng_wait(void) +{ + return crypto_submodule_wait(&crypto_prng_done); +} + +void crypto_aes_prestart(void) +{ + crypto_submodule_prestart(&crypto_aes_done); +} + +bool crypto_aes_wait(void) +{ + return crypto_submodule_wait(&crypto_aes_done); +} + +void crypto_sha_prestart(void) +{ + crypto_submodule_prestart(&crypto_sha_done); +} + +bool crypto_sha_wait(void) +{ + return crypto_submodule_wait(&crypto_sha_done); +} + +void crypto_ecc_prestart(void) +{ + crypto_submodule_prestart(&crypto_ecc_done); +} + +bool crypto_ecc_wait(void) +{ + return crypto_submodule_wait(&crypto_ecc_done); +} + +void crypto_rsa_prestart(void) +{ + crypto_submodule_prestart(&crypto_rsa_done); +} + +bool crypto_rsa_wait(void) +{ + return crypto_submodule_wait(&crypto_rsa_done); +} + +bool crypto_dma_buff_compat(const void *buff, size_t buff_size, size_t size_aligned_to) +{ + uint32_t buff_ = (uint32_t) buff; + + return (((buff_ & 0x03) == 0) && /* Word-aligned buffer base address */ + ((buff_size & (size_aligned_to - 1)) == 0) && /* Crypto submodule dependent buffer size alignment */ + (((buff_ >> 28) == 0x2) && (buff_size <= (0x30000000 - buff_)))); /* 0x20000000-0x2FFFFFFF */ +} + +/* Overlap cases + * + * 1. in_buff in front of out_buff: + * + * in in_end + * | | + * |||||||||||||||| + * |||||||||||||||| + * | | + * out out_end + * + * 2. out_buff in front of in_buff: + * + * in in_end + * | | + * |||||||||||||||| + * |||||||||||||||| + * | | + * out out_end + */ +bool crypto_dma_buffs_overlap(const void *in_buff, size_t in_buff_size, const void *out_buff, size_t out_buff_size) +{ + uint32_t in = (uint32_t) in_buff; + uint32_t in_end = in + in_buff_size; + uint32_t out = (uint32_t) out_buff; + uint32_t out_end = out + out_buff_size; + + bool overlap = (in <= out && out < in_end) || (out <= in && in < out_end); + + return overlap; +} + +static void crypto_submodule_prestart(volatile uint16_t *submodule_done) +{ + *submodule_done = 0; + + /* Ensure memory accesses above are completed before DMA is started + * + * Replacing __DSB() with __DMB() is also OK in this case. + * + * Refer to "multi-master systems" section with DMA in: + * https://static.docs.arm.com/dai0321/a/DAI0321A_programming_guide_memory_barriers_for_m_profile.pdf + */ + __DSB(); +} + +static bool crypto_submodule_wait(volatile uint16_t *submodule_done) +{ + while (! *submodule_done); + + /* Ensure while loop above and subsequent code are not reordered */ + __DSB(); + + if ((*submodule_done & NU_CRYPTO_DONE_OK)) { + /* Done with OK */ + return true; + } else if ((*submodule_done & NU_CRYPTO_DONE_ERR)) { + /* Done with error */ + return false; + } + + return false; +} + +/* Crypto interrupt handler */ +extern "C" void CRPT_IRQHandler() +{ + uint32_t intsts; + + /* PRNG */ + if ((intsts = PRNG_GET_INT_FLAG(CRPT)) != 0) { + /* Check interrupt flags */ + if (intsts & CRPT_INTSTS_PRNGIF_Msk) { + /* Done with OK */ + crypto_prng_done |= NU_CRYPTO_DONE_OK; + } else if (intsts & CRPT_INTSTS_PRNGEIF_Msk) { + /* Done with error */ + crypto_prng_done |= NU_CRYPTO_DONE_ERR; + } + /* Clear interrupt flag */ + PRNG_CLR_INT_FLAG(CRPT); + } + + /* AES */ + if ((intsts = AES_GET_INT_FLAG(CRPT)) != 0) { + /* Check interrupt flags */ + if (intsts & CRPT_INTSTS_AESIF_Msk) { + /* Done with OK */ + crypto_aes_done |= NU_CRYPTO_DONE_OK; + } else if (intsts & CRPT_INTSTS_AESEIF_Msk) { + /* Done with error */ + crypto_aes_done |= NU_CRYPTO_DONE_ERR; + } + /* Clear interrupt flag */ + AES_CLR_INT_FLAG(CRPT); + } + + /* SHA */ + if ((intsts = SHA_GET_INT_FLAG(CRPT)) != 0) { + /* Check interrupt flags */ + if (intsts & CRPT_INTSTS_HMACIF_Msk) { + /* Done with OK */ + crypto_sha_done |= NU_CRYPTO_DONE_OK; + } else if (intsts & CRPT_INTSTS_HMACEIF_Msk) { + /* Done with error */ + crypto_sha_done |= NU_CRYPTO_DONE_ERR; + } + /* Clear interrupt flag */ + SHA_CLR_INT_FLAG(CRPT); + } + + /* ECC */ + if ((intsts = ECC_GET_INT_FLAG(CRPT)) != 0) { + /* Check interrupt flags */ + if (intsts & CRPT_INTSTS_ECCIF_Msk) { + /* Done with OK */ + crypto_ecc_done |= NU_CRYPTO_DONE_OK; + } else if (intsts & CRPT_INTSTS_ECCEIF_Msk) { + /* Done with error */ + crypto_ecc_done |= NU_CRYPTO_DONE_ERR; + } + /* Clear interrupt flag */ + ECC_CLR_INT_FLAG(CRPT); + } + + /* RSA */ + if ((intsts = RSA_GET_INT_FLAG(CRPT)) != 0) { + /* Check interrupt flags */ + if (intsts & CRPT_INTSTS_RSAIF_Msk) { + /* Done with OK */ + crypto_rsa_done |= NU_CRYPTO_DONE_OK; + } else if (intsts & CRPT_INTSTS_RSAEIF_Msk) { + /* Done with error */ + crypto_rsa_done |= NU_CRYPTO_DONE_ERR; + } + /* Clear interrupt flag */ + RSA_CLR_INT_FLAG(CRPT); + } +} diff --git a/targets/TARGET_NUVOTON/TARGET_M460/crypto/crypto-misc.h b/targets/TARGET_NUVOTON/TARGET_M460/crypto/crypto-misc.h new file mode 100644 index 0000000000..cf9c06f3f9 --- /dev/null +++ b/targets/TARGET_NUVOTON/TARGET_M460/crypto/crypto-misc.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2022, Nuvoton Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_CRYPTO_MISC_H +#define MBED_CRYPTO_MISC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Init/Uninit crypto module */ +void crypto_init(void); +void crypto_uninit(void); + +/* Clear buffer to zero + * Implementation that should never be optimized out by the compiler */ +void crypto_zeroize(void *v, size_t n); +void crypto_zeroize32(uint32_t *v, size_t n); + +/* Acquire/release ownership of crypto sub-module + * + * \note "acquire" is blocking until ownership is acquired + * + * \note "acquire"/"release" must be paired. + * + * \note Recursive "acquire" is allowed because the underlying synchronization + * primitive mutex supports it. + */ +void crypto_prng_acquire(void); +void crypto_prng_release(void); +void crypto_aes_acquire(void); +void crypto_aes_release(void); +void crypto_sha_acquire(void); +void crypto_sha_release(void); +void crypto_ecc_acquire(void); +void crypto_ecc_release(void); +void crypto_rsa_acquire(void); +void crypto_rsa_release(void); + +/* Flow control between crypto/xxx start and crypto/xxx ISR + * + * crypto_xxx_prestart/crypto_xxx_wait encapsulate control flow between crypto/xxx start and crypto/xxx ISR. + * + * crypto_xxx_prestart will also address synchronization issue with memory barrier instruction. + * + * On finish, return of crypto_xxx_wait indicates success or not: + * true if successful + * false if failed + * + * Example: Start AES H/W and wait for its finish + * crypto_aes_prestart(); + * AES_Start(); + * crypto_aes_wait(); + */ +void crypto_prng_prestart(void); +bool crypto_prng_wait(void); +void crypto_aes_prestart(void); +bool crypto_aes_wait(void); +void crypto_sha_prestart(void); +bool crypto_sha_wait(void); +void crypto_ecc_prestart(void); +bool crypto_ecc_wait(void); +void crypto_rsa_prestart(void); +bool crypto_rsa_wait(void); + + +/* Check if buffer can be used for crypto DMA. It has the following requirements: + * (1) Word-aligned buffer base address + * (2) Crypto submodule (AES, SHA, etc.) dependent buffer size alignment. Must be 2 power. + * (3) Located in 0x20000000-0x2FFFFFFF region + */ +bool crypto_dma_buff_compat(const void *buff, size_t buff_size, size_t size_aligned_to); + +/* Check if input/output buffers are overlapped */ +bool crypto_dma_buffs_overlap(const void *in_buff, size_t in_buff_size, const void *out_buff, size_t out_buff_size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/targets/targets.json b/targets/targets.json index 148e7ed8ed..be50a57278 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -7503,6 +7503,9 @@ "inherits": [ "MCU_M460" ], + "macros_add": [ + "MBEDTLS_CONFIG_HW_SUPPORT" + ], "supported_form_factors": [ "ARDUINO_UNO" ],