From 30be5f6eb5926e89a1b72988a1e3a6a1c1d3b517 Mon Sep 17 00:00:00 2001 From: liuhan Date: Fri, 5 Aug 2016 17:40:32 +0800 Subject: [PATCH] [t6001]: chip Use hardware acceleration of Encryption --- components/mbedtls/include/port/aes_alt.h | 260 +++ components/mbedtls/include/port/bignum_alt.h | 707 ++++++ components/mbedtls/include/port/sha1_alt.h | 93 + components/mbedtls/include/port/sha256_alt.h | 95 + components/mbedtls/include/port/sha512_alt.h | 92 + components/mbedtls/port/aes_alt.c | 306 +++ components/mbedtls/port/bignum_alt.c | 2100 ++++++++++++++++++ components/mbedtls/port/sha1_alt.c | 102 + components/mbedtls/port/sha256_alt.c | 107 + components/mbedtls/port/sha512_alt.c | 103 + 10 files changed, 3965 insertions(+) create mode 100644 components/mbedtls/include/port/aes_alt.h create mode 100644 components/mbedtls/include/port/bignum_alt.h create mode 100644 components/mbedtls/include/port/sha1_alt.h create mode 100644 components/mbedtls/include/port/sha256_alt.h create mode 100644 components/mbedtls/include/port/sha512_alt.h create mode 100644 components/mbedtls/port/aes_alt.c create mode 100644 components/mbedtls/port/bignum_alt.c create mode 100644 components/mbedtls/port/sha1_alt.c create mode 100644 components/mbedtls/port/sha256_alt.c create mode 100644 components/mbedtls/port/sha512_alt.c diff --git a/components/mbedtls/include/port/aes_alt.h b/components/mbedtls/include/port/aes_alt.h new file mode 100644 index 0000000000..d56c76ce47 --- /dev/null +++ b/components/mbedtls/include/port/aes_alt.h @@ -0,0 +1,260 @@ +/** + * \file aes_alt.h + * + * \brief AES block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * 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 AES_ALT_H +#define AES_ALT_H + +#include "c_types.h" +#include "rom/ets_sys.h" +#include "rom/aes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_AES_C + +/* padlock.c and aesni.c rely on these values! */ +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +#define ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +/** + * \brief AES context structure + * + * \note buf is able to hold 32 extra bytes, which can be used: + * - for alignment purposes if VIA padlock is used, and/or + * - to simplify key expansion in the 256-bit case by + * generating an extra round key + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t *rk; /*!< AES round keys */ + uint32_t buf[68]; /*!< unaligned data */ +}aes_context; + +typedef aes_context AES_CTX; + +/** + * \brief Initialize AES context + * + * \param ctx AES context to be initialized + */ +void aes_init( AES_CTX *ctx ); + +/** + * \brief Clear AES context + * + * \param ctx AES context to be cleared + */ +void aes_free( AES_CTX *ctx ); + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or ERR_AES_INVALID_KEY_LENGTH + */ +int aes_setkey_enc( AES_CTX *ctx, const unsigned char *key,unsigned int keybits ); + +/** + * \brief AES key schedule (decryption) + * + * \param ctx AES context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or ERR_AES_INVALID_KEY_LENGTH + */ +int aes_setkey_dec( AES_CTX *ctx, const unsigned char *key,unsigned int keybits ); + +/** + * \brief AES-ECB block encryption/decryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int aes_crypt_ecb( AES_CTX *ctx,int mode,const unsigned char input[16],unsigned char output[16] ); + +/** + * \brief AES-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or ERR_AES_INVALID_INPUT_LENGTH + */ +int aes_crypt_cbc( AES_CTX *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + + +/** + * \brief AES-CFB128 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int aes_crypt_cfb128( AES_CTX *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CFB8 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int aes_crypt_cfb8( AES_CTX *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. + * + * \param ctx AES context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int aes_crypt_ctr( AES_CTX *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); + + +/** + * \brief Internal AES block encryption function + * (Only exposed to allow overriding it, + * see AES_ENCRYPT_ALT) + * + * \param ctx AES context + * \param input Plaintext block + * \param output Output (ciphertext) block + */ +void aes_encrypt( AES_CTX *ctx, const unsigned char input[16],unsigned char output[16] ); + +/** + * \brief Internal AES block decryption function + * (Only exposed to allow overriding it, + * see AES_DECRYPT_ALT) + * + * \param ctx AES context + * \param input Ciphertext block + * \param output Output (plaintext) block + */ +void aes_decrypt( AES_CTX *ctx, const unsigned char input[16], unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#endif /* aes.h */ diff --git a/components/mbedtls/include/port/bignum_alt.h b/components/mbedtls/include/port/bignum_alt.h new file mode 100644 index 0000000000..64d492a989 --- /dev/null +++ b/components/mbedtls/include/port/bignum_alt.h @@ -0,0 +1,707 @@ +/** + * \file bignum_alt.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * 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 BIGNUM_ALT_H +#define BIGNUM_ALT_H + +#include "c_types.h" +#include "rom/ets_sys.h" +#include "rom/bigint.h" + +#define ESP_BIGNUM_ALT +#define MPI_DEBUG_ALT +#if defined(ESP_BIGNUM_ALT) + +#define ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ +#define ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ +#define ERR_MPI_ALLOC_FAILED -0x0010 /**< Memory allocation failed. */ + +#define MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 ) +#if defined(MPI_DEBUG_ALT) +#define mpi_printf ets_printf +#else +#define mpi_printf +#endif +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define MPI_MAX_LIMBS 10000 + +#if !defined(MPI_WINDOW_SIZE) +/* + * Maximum window size used for modular exponentiation. Default: 6 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 << MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 64 by default) + * + * Reduction in size, reduces speed. + */ +#define MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +#endif /* !MPI_WINDOW_SIZE */ + +#if !defined(MPI_MAX_SIZE) +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits ) + * + * Note: Calculations can results temporarily in larger MPIs. So the number + * of limbs required (MPI_MAX_LIMBS) is higher. + */ +#define MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ +#endif /* !MPI_MAX_SIZE */ + +#define MPI_MAX_BITS ( 8 * MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mpi_read_file() and writing to files with + * mpi_write_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + * Autosized at compile time for at least a 10 char label, a minimum radix + * of 10 (decimal) for a number of MPI_MAX_BITS size. + * + * This used to be statically sized to 1250 for a maximum of 4096 bit + * numbers (1234 decimal chars). + * + * Calculate using the formula: + * MPI_RW_BUFFER_SIZE = ceil(MPI_MAX_BITS / ln(10) * ln(2)) + + * LabelSize + 6 + */ +#define MPI_MAX_BITS_SCALE100 ( 100 * MPI_MAX_BITS ) +#define LN_2_DIV_LN_10_SCALE100 332 +#define MPI_RW_BUFFER_SIZE ( ((MPI_MAX_BITS_SCALE100 + LN_2_DIV_LN_10_SCALE100 - 1) / LN_2_DIV_LN_10_SCALE100) + 10 + 6 ) + +/* + * Define the base integer type, architecture-wise. + * + * 32-bit integers can be forced on 64-bit arches (eg. for testing purposes) + * by defining HAVE_INT32 and undefining HAVE_ASM + */ +#if ( ! defined(HAVE_INT32) && \ + defined(_MSC_VER) && defined(_M_AMD64) ) + #define HAVE_INT64 + typedef int64_t mpi_sint; + typedef uint64_t mpi_uint; +#else + #if ( ! defined(HAVE_INT32) && \ + defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__s390x__) || defined(__mips64) ) ) + #define HAVE_INT64 + typedef int64_t mpi_sint; + typedef uint64_t mpi_uint; + /* t_udbl defined as 128-bit unsigned int */ + typedef unsigned int t_udbl __attribute__((mode(TI))); + #define HAVE_UDBL + #else + #define HAVE_INT32 + typedef int32_t mpi_sint; + typedef uint32_t mpi_uint; + typedef uint64_t t_udbl; + #define HAVE_UDBL + #endif /* !HAVE_INT32 && __GNUC__ && 64-bit platform */ +#endif /* !HAVE_INT32 && _MSC_VER && _M_AMD64 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + mpi_uint *p; /*!< pointer to limbs */ +} +mpi; + +/** + * \brief Initialize one MPI (make internal references valid) + * This just makes it ready to be set or freed, + * but does not define a value for the MPI. + * + * \param X One MPI to initialize. + */ +void mpi_init( mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mpi_free( mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_grow( mpi *X, size_t nblimbs ); + +/** + * \brief Resize down, keeping at least the specified number of limbs + * + * \param X MPI to shrink + * \param nblimbs The minimum number of limbs to keep + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_shrink( mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI + * \param Y Source MPI + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_copy( mpi *X, const mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mpi_swap( mpi *X, mpi *Y ); + +/** + * \brief Safe conditional assignement X = Y if assign is 1 + * + * \param X MPI to conditionally assign to + * \param Y Value to be assigned + * \param assign 1: perform the assignment, 0: keep X's original value + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mpi_copy( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mpi_safe_cond_assign( mpi *X, const mpi *Y, unsigned char assign ); + +/** + * \brief Safe conditional swap X <-> Y if swap is 1 + * + * \param X First mpi value + * \param Y Second mpi value + * \param assign 1: perform the swap, 0: keep X and Y's original values + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mpi_swap( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mpi_safe_cond_swap( mpi *X, mpi *Y, unsigned char assign ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_lset( mpi *X, mpi_sint z ); + +/** + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mpi_get_bit( const mpi *X, size_t pos ); + +/** + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of zero-bits before the least significant + * '1' bit + * + * Note: Thus also the zero-based index of the least significant '1' bit + * + * \param X MPI to use + */ +size_t mpi_lsb( const mpi *X ); + +/** + * \brief Return the number of bits up to and including the most + * significant '1' bit' + * + * Note: Thus also the one-based index of the most significant '1' bit + * + * \param X MPI to use + */ +size_t mpi_bitlen( const mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mpi_size( const mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or a ERR_MPI_XXX error code + */ +int mpi_read_string( mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param buf Buffer to write the string to + * \param buflen Length of buf + * \param olen Length of the string written, including final NUL byte + * + * \return 0 if successful, or a ERR_MPI_XXX error code. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with buflen = 0 to obtain the + * minimum required buffer size in *olen. + */ +int mpi_write_string( const mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ); + +#if defined(FS_IO) +/** + * \brief Read X from an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, ERR_MPI_BUFFER_TOO_SMALL if + * the file read buffer is too small or a + * ERR_MPI_XXX error code + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or a ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ); +#endif /* FS_IO */ + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian. + * Always fills the whole buffer, which will start with zeros + * if the number is smaller. + * + * \param X Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_shift_l( mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_shift_r( mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mpi_cmp_int( const mpi *X, mpi_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Unsigned subtraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed subtraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_add_int( mpi *X, const mpi *A, mpi_sint b ); + +/** + * \brief Signed subtraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_sub_int( mpi *X, const mpi *A, mpi_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The unsigned integer value to multiply with + * + * \note b is unsigned + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_mul_int( mpi *X, const mpi *A, mpi_uint b ); + +/** + * \brief Division by mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, mpi_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * ERR_MPI_DIVISION_BY_ZERO if B == 0, + * ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination mpi_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * ERR_MPI_DIVISION_BY_ZERO if b == 0, + * ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mpi_mod_int( mpi_uint *r, const mpi *A, mpi_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * ERR_MPI_BAD_INPUT_DATA if N is negative or even or + * if E is negative + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ); + +/** + * \brief Fill an MPI X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_fill_random( mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * ERR_MPI_BAD_INPUT_DATA if N is negative or nil + ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mpi_is_prime( const mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits + * ( 3 <= nbits <= MPI_MAX_BITS ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * ERR_MPI_ALLOC_FAILED if memory allocation failed, + * ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif + +#endif + diff --git a/components/mbedtls/include/port/sha1_alt.h b/components/mbedtls/include/port/sha1_alt.h new file mode 100644 index 0000000000..9187986277 --- /dev/null +++ b/components/mbedtls/include/port/sha1_alt.h @@ -0,0 +1,93 @@ +/* + * copyright (c) 2010 - 2012 Espressif System + * + * esf Link List Descriptor + */ +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#include "c_types.h" +#include "rom/ets_sys.h" +#include "rom/sha.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_SHA1_C + +#define SHA1 0 + +/** + * \brief SHA-1 context structure + */ +typedef struct{ + SHA_CTX context; + int context_type; +} sha1_context; + +typedef sha1_context SHA1_CTX; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void sha1_init( SHA1_CTX *ctx ); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void sha1_free( SHA1_CTX *ctx ); + +/** + * \brief Clone (the state of) a SHA-1 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void sha1_clone( SHA1_CTX *dst, const SHA1_CTX *src ); + +void sha1_process(SHA1_CTX *ctx, const unsigned char data[64]); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void sha1_starts( SHA1_CTX *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_update( SHA1_CTX *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void sha1_finish( SHA1_CTX *ctx, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void sha1_output( const unsigned char *input, size_t ilen, unsigned char output[20] ); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/components/mbedtls/include/port/sha256_alt.h b/components/mbedtls/include/port/sha256_alt.h new file mode 100644 index 0000000000..bc661d3932 --- /dev/null +++ b/components/mbedtls/include/port/sha256_alt.h @@ -0,0 +1,95 @@ +/* + * copyright (c) 2010 - 2012 Espressif System + * + * esf Link List Descriptor + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include "c_types.h" +#include "rom/ets_sys.h" +#include "rom/sha.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_SHA256_C + +#define SHA256 SHA2_256 +#define SHA224 4 + +/** + * \brief SHA-256 context structure + */ +typedef struct{ + SHA_CTX context; + int context_type; +}sha256_context; + +typedef sha256_context SHA256_CTX; + +/** + * \brief Initialize SHA-256 context + * + * \param ctx SHA-256 context to be initialized + */ +void sha256_init( SHA256_CTX *ctx ); + +/** + * \brief Clear SHA-256 context + * + * \param ctx SHA-256 context to be cleared + */ +void sha256_free( SHA256_CTX *ctx ); +void sha256_process(SHA256_CTX *ctx, const unsigned char data[64]); + +/** + * \brief Clone (the state of) a SHA-256 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void sha256_clone( SHA256_CTX *dst, const SHA256_CTX *src ); + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha256_starts( SHA256_CTX *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 + */ +void sha256_update( SHA256_CTX *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 + */ +void sha256_finish( SHA256_CTX *ctx, unsigned char output[32] ); + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha256_output( const unsigned char *input, size_t ilen, unsigned char output[32], int is224 ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha256.h */ diff --git a/components/mbedtls/include/port/sha512_alt.h b/components/mbedtls/include/port/sha512_alt.h new file mode 100644 index 0000000000..a3e1c50c64 --- /dev/null +++ b/components/mbedtls/include/port/sha512_alt.h @@ -0,0 +1,92 @@ +/* + * copyright (c) 2010 - 2012 Espressif System + * + * esf Link List Descriptor + */ + +#ifndef _SHA512_H_ +#define _SHA512_H_ + +#include "c_types.h" +#include "rom/ets_sys.h" +#include "rom/sha.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_SHA512_C + +/** + * \brief SHA-512 context structure + */ +typedef struct{ + SHA_CTX context; + int context_type; +}sha512_context; + +typedef sha512_context SHA512_CTX; + +/** + * \brief Initialize SHA-512 context + * + * \param ctx SHA-512 context to be initialized + */ +void sha512_init( SHA512_CTX *ctx ); + +/** + * \brief Clear SHA-512 context + * + * \param ctx SHA-512 context to be cleared + */ +void sha512_free( SHA512_CTX *ctx ); + +/** + * \brief Clone (the state of) a SHA-512 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void sha512_clone( SHA512_CTX *dst, const SHA512_CTX *src ); + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha512_starts( SHA512_CTX *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 + */ +void sha512_update( SHA512_CTX *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 + */ +void sha512_finish( SHA512_CTX *ctx, unsigned char output[64] ); + +/** + * \brief Output = SHA-512( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha512_output( const unsigned char *input, size_t ilen, unsigned char output[64], int is384 ); + + +#ifdef __cplusplus +} +#endif + +#endif /* sha512.h */ diff --git a/components/mbedtls/port/aes_alt.c b/components/mbedtls/port/aes_alt.c new file mode 100644 index 0000000000..26699d82fb --- /dev/null +++ b/components/mbedtls/port/aes_alt.c @@ -0,0 +1,306 @@ + +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * 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. + * + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#include "port/aes_alt.h" + +#if defined(ESP_AES_C) + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void aes_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void aes_init( AES_CTX *ctx ) +{ + memset( ctx, 0, sizeof( AES_CTX ) ); + ets_aes_enable(); +} + +void aes_free( AES_CTX *ctx ) +{ + if( ctx == NULL ) + return; + + aes_zeroize( ctx, sizeof( AES_CTX ) ); + ets_aes_disable(); +} + +/* + * AES key schedule (encryption) + */ +int aes_setkey_enc( AES_CTX *ctx, const unsigned char *key, + unsigned int keybits ) +{ + enum AES_BITS keybit; + switch (keybits){ + case 128: + keybit = AES128; + break; + case 192: + keybit = AES192; + break; + case 256: + keybit = AES256; + break; + default : return( ERR_AES_INVALID_KEY_LENGTH ); + } + ets_aes_setkey_enc(key, keybit); + return 0; +} + +/* + * AES key schedule (decryption) + */ +int aes_setkey_dec( AES_CTX *ctx, const unsigned char *key, + unsigned int keybits ) +{ + enum AES_BITS keybit; + switch (keybits){ + case 128: + keybit = AES128; + break; + case 192: + keybit = AES192; + break; + case 256: + keybit = AES256; + break; + default : return( ERR_AES_INVALID_KEY_LENGTH ); + } + ets_aes_setkey_dec(key, keybit); + return 0; + +} + +/* + * AES-ECB block encryption + */ + +void aes_encrypt( AES_CTX *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + ets_aes_crypt(input, output); + return ; +} + + +/* + * AES-ECB block decryption + */ + +void aes_decrypt( AES_CTX *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + ets_aes_crypt(input, output); + return ; +} + + +/* + * AES-ECB block encryption/decryption + */ +int aes_crypt_ecb( AES_CTX *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + if( mode == AES_ENCRYPT ) + aes_encrypt( ctx, input, output ); + else + aes_decrypt( ctx, input, output ); + return 0; +} + + +/* + * AES-CBC buffer encryption/decryption + */ +int aes_crypt_cbc( AES_CTX *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( ERR_AES_INVALID_INPUT_LENGTH ); + + if( mode == AES_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + aes_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + aes_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + return 0; +} + +/* + * AES-CFB128 buffer encryption/decryption + */ +int aes_crypt_cfb128( AES_CTX *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return 0; +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int aes_crypt_cfb8( AES_CTX *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + + while( length-- ) + { + memcpy( ov, iv, 16 ); + aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); + + if( mode == AES_DECRYPT ) + ov[16] = *input; + + c = *output++ = (unsigned char)( iv[0] ^ *input++ ); + + if( mode == AES_ENCRYPT ) + ov[16] = c; + + memcpy( iv, ov + 1, 16 ); + } + + return 0; +} + +/* + * AES-CTR buffer encryption/decryption + */ +int aes_crypt_ctr( AES_CTX *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + aes_crypt_ecb( ctx, AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + return 0; +} + +#endif /* AES_ALT_C */ + diff --git a/components/mbedtls/port/bignum_alt.c b/components/mbedtls/port/bignum_alt.c new file mode 100644 index 0000000000..88901671c8 --- /dev/null +++ b/components/mbedtls/port/bignum_alt.c @@ -0,0 +1,2100 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * 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. + * + */ + +/* + * The following sources were referenced in the design of this Multi-precision + * Integer library: + * + * [1] Handbook of Applied Cryptography - 1997 + * Menezes, van Oorschot and Vanstone + * + * [2] Multi-Precision Math + * Tom St Denis + * https://github.com/libtom/libtommath/blob/develop/tommath.pdf + * + * [3] GNU Multi-Precision Arithmetic Library + * https://gmplib.org/manual/index.html + * + */ +#include "port/bignum_alt.h" + +#if defined(ESP_BIGNUM_ALT) +#include +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mpi_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define ciL (sizeof(mpi_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +#define MPI_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + +/* + * Convert between bits/chars and number of limbs + * Divide first in order to avoid potential overflows + */ +#define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) ) +#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) ) + +/* + * Initialize one MPI + */ +void mpi_init( mpi *X ) +{ + if( X == NULL ) + return; + + X->s = 1; + X->n = 0; + X->p = NULL; + ets_bigint_enable(); +} + +/* + * Unallocate one MPI + */ +void mpi_free( mpi *X ) +{ + if( X == NULL ) + return; + + if( X->p != NULL ) + { + mpi_zeroize( X->p, X->n * ciL ); + free( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; + ets_bigint_disable(); +} + +/* + * Enlarge to the specified number of limbs + */ +int mpi_grow( mpi *X, size_t nblimbs ) +{ + mpi_uint *p; + + if( nblimbs > MPI_MAX_LIMBS ) + return( ERR_MPI_ALLOC_FAILED ); + + if( X->n < nblimbs ) + { + if( ( p = calloc( nblimbs, ciL ) ) == NULL ) + return( ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + mpi_zeroize( X->p, X->n * ciL ); + free( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Resize down as much as possible, + * while keeping at least the specified number of limbs + */ +int mpi_shrink( mpi *X, size_t nblimbs ) +{ + mpi_uint *p; + size_t i; + + /* Actually resize up in this case */ + if( X->n <= nblimbs ) + return( mpi_grow( X, nblimbs ) ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + i++; + + if( i < nblimbs ) + i = nblimbs; + + if( ( p = calloc( i, ciL ) ) == NULL ) + return( ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, i * ciL ); + mpi_zeroize( X->p, X->n * ciL ); + free( X->p ); + } + + X->n = i; + X->p = p; + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mpi_copy( mpi *X, const mpi *Y ) +{ + int ret; + size_t i; + + if( X == Y ) + return( 0 ); + + if( Y->p == NULL ) + { + mpi_free( X ); + return( 0 ); + } + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + MPI_CHK( mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * ciL ); + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mpi_swap( mpi *X, mpi *Y ) +{ + mpi T; + + memcpy( &T, X, sizeof( mpi ) ); + memcpy( X, Y, sizeof( mpi ) ); + memcpy( Y, &T, sizeof( mpi ) ); +} + +/* + * Conditionally assign X = Y, without leaking information + * about whether the assignment was made or not. + * (Leaking information about the respective sizes of X and Y is ok however.) + */ +int mpi_safe_cond_assign( mpi *X, const mpi *Y, unsigned char assign ) +{ + int ret = 0; + size_t i; + + /* make sure assign is 0 or 1 in a time-constant manner */ + assign = (assign | (unsigned char)-assign) >> 7; + + MPI_CHK( mpi_grow( X, Y->n ) ); + + X->s = X->s * ( 1 - assign ) + Y->s * assign; + + for( i = 0; i < Y->n; i++ ) + X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign; + + for( ; i < X->n; i++ ) + X->p[i] *= ( 1 - assign ); + +cleanup: + return( ret ); +} + +/* + * Conditionally swap X and Y, without leaking information + * about whether the swap was made or not. + * Here it is not ok to simply swap the pointers, which whould lead to + * different memory access patterns when X and Y are used afterwards. + */ +int mpi_safe_cond_swap( mpi *X, mpi *Y, unsigned char swap ) +{ + int ret, s; + size_t i; + mpi_uint tmp; + + if( X == Y ) + return( 0 ); + + /* make sure swap is 0 or 1 in a time-constant manner */ + swap = (swap | (unsigned char)-swap) >> 7; + + MPI_CHK( mpi_grow( X, Y->n ) ); + MPI_CHK( mpi_grow( Y, X->n ) ); + + s = X->s; + X->s = X->s * ( 1 - swap ) + Y->s * swap; + Y->s = Y->s * ( 1 - swap ) + s * swap; + + + for( i = 0; i < X->n; i++ ) + { + tmp = X->p[i]; + X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap; + Y->p[i] = Y->p[i] * ( 1 - swap ) + tmp * swap; + } + +cleanup: + return( ret ); +} + +/* + * Set value from integer + */ +int mpi_lset( mpi *X, mpi_sint z ) +{ + int ret; + + MPI_CHK( mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Get a specific bit + */ +int mpi_get_bit( const mpi *X, size_t pos ) +{ + if( X->n * biL <= pos ) + return( 0 ); + + return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 ); +} + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + + if( val != 0 && val != 1 ) + return( ERR_MPI_BAD_INPUT_DATA ); + + if( X->n * biL <= pos ) + { + if( val == 0 ) + return( 0 ); + + MPI_CHK( mpi_grow( X, off + 1 ) ); + } + + X->p[off] &= ~( (mpi_uint) 0x01 << idx ); + X->p[off] |= (mpi_uint) val << idx; + +cleanup: + + return( ret ); +} + +/* + * Return the number of less significant zero-bits + */ +size_t mpi_lsb( const mpi *X ) +{ + size_t i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Count leading zero bits in a given integer + */ +static size_t clz( const mpi_uint x ) +{ + size_t j; + mpi_uint mask = (mpi_uint) 1 << (biL - 1); + + for( j = 0; j < biL; j++ ) + { + if( x & mask ) break; + + mask >>= 1; + } + + return j; +} + +/* + * Return the number of bits + */ +size_t mpi_bitlen( const mpi *X ) +{ + size_t i, j; + + if( X->n == 0 ) + return( 0 ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + j = biL - clz( X->p[i] ); + + return( ( i * biL ) + j ); +} + +/* + * Return the total size in bytes + */ +size_t mpi_size( const mpi *X ) +{ + return( ( mpi_bitlen( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( mpi_uint *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (mpi_uint) radix ) + return( ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mpi_read_string( mpi *X, int radix, const char *s ) +{ + int ret; + size_t i, j, slen, n; + mpi_uint d; + mpi T; + + if( radix < 2 || radix > 16 ) + return( ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &T ); + + slen = strlen( s ); + + if( radix == 16 ) + { + if( slen > MPI_SIZE_T_MAX >> 2 ) + return( ERR_MPI_BAD_INPUT_DATA ); + + n = BITS_TO_LIMBS( slen << 2 ); + + MPI_CHK( mpi_grow( X, n ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = slen, j = 0; i > 0; i--, j++ ) + { + if( i == 1 && s[i - 1] == '-' ) + { + X->s = -1; + break; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); + X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 ); + } + } + else + { + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = 0; i < slen; i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MPI_CHK( mpi_mul_int( &T, X, radix ) ); + + if( X->s == 1 ) + { + MPI_CHK( mpi_add_int( X, &T, d ) ); + } + else + { + MPI_CHK( mpi_sub_int( X, &T, d ) ); + } + } + } + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first + */ +static int mpi_write_hlp( mpi *X, int radix, char **p ) +{ + int ret; + mpi_uint r; + + if( radix < 2 || radix > 16 ) + return( ERR_MPI_BAD_INPUT_DATA ); + + MPI_CHK( mpi_mod_int( &r, X, radix ) ); + MPI_CHK( mpi_div_int( X, NULL, X, radix ) ); + + if( mpi_cmp_int( X, 0 ) != 0 ) + MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mpi_write_string( const mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ) +{ + int ret = 0; + size_t n; + char *p; + mpi T; + + if( radix < 2 || radix > 16 ) + return( ERR_MPI_BAD_INPUT_DATA ); + + n = mpi_bitlen( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + n += 3; + + if( buflen < n ) + { + *olen = n; + return( ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = buf; + mpi_init( &T ); + + if( X->s == -1 ) + *p++ = '-'; + + if( radix == 16 ) + { + int c; + size_t i, j, k; + + for( i = X->n, k = 0; i > 0; i-- ) + { + for( j = ciL; j > 0; j-- ) + { + c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; + + if( c == 0 && k == 0 && ( i + j ) != 2 ) + continue; + + *(p++) = "0123456789ABCDEF" [c / 16]; + *(p++) = "0123456789ABCDEF" [c % 16]; + k = 1; + } + } + } + else + { + MPI_CHK( mpi_copy( &T, X ) ); + + if( T.s == -1 ) + T.s = 1; + + MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); + } + + *p++ = '\0'; + *olen = p - buf; + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +/* + * Import X from unsigned binary data, big endian + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = buflen, j = 0; i > n; i--, j++ ) + X->p[j / ciL] |= ((mpi_uint) buf[i - 1]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ) +{ + size_t i, j, n; + + n = mpi_size( X ); + + if( buflen < n ) + return( ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mpi_shift_l( mpi *X, size_t count ) +{ + int ret; + size_t i, v0, t1; + mpi_uint r0 = 0, r1; + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mpi_bitlen( X ) + count; + + if( X->n * biL < i ) + MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n; i > v0; i-- ) + X->p[i - 1] = X->p[i - v0 - 1]; + + for( ; i > 0; i-- ) + X->p[i - 1] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mpi_shift_r( mpi *X, size_t count ) +{ + size_t i, v0, v1; + mpi_uint r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) + return mpi_lset( X, 0 ); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n; i > 0; i-- ) + { + r1 = X->p[i - 1] << (biL - v1); + X->p[i - 1] >>= v1; + X->p[i - 1] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -Y->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_int( const mpi *X, mpi_sint z ) +{ + mpi Y; + mpi_uint p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + mpi_uint *o, *p, c; + + if( X == B ) + { + const mpi *T = A; A = X; B = T; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned additions. + */ + X->s = 1; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, j ) ); + + o = B->p; p = X->p; c = 0; + + for( i = 0; i < j; i++, o++, p++ ) + { + *p += c; c = ( *p < c ); + *p += *o; c += ( *p < *o ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MPI_CHK( mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; p++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mpi subtraction + */ +static void mpi_sub_hlp( size_t n, mpi_uint *s, mpi_uint *d ) +{ + size_t i; + mpi_uint c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; i++; d++; + } +} + +/* + * Unsigned subtraction: X = |A| - |B| (HAC 14.9) + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ) +{ + mpi TB; + int ret; + size_t n; + + if( mpi_cmp_abs( A, B ) < 0 ) + return( ERR_MPI_NEGATIVE_VALUE ); + + mpi_init( &TB ); + + if( X == B ) + { + MPI_CHK( mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned subtractions. + */ + X->s = 1; + + ret = 0; + + for( n = B->n; n > 0; n-- ) + if( B->p[n - 1] != 0 ) + break; + + mpi_sub_hlp( n, B->p, X->p ); + +cleanup: + + mpi_free( &TB ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed subtraction: X = A - B + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mpi_add_int( mpi *X, const mpi *A, mpi_sint b ) +{ + mpi _B; + mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed subtraction: X = A - b + */ +int mpi_sub_int( mpi *X, const mpi *A, mpi_sint b ) +{ + mpi _B; + mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mpi multiplication + */ +static void mpi_mul_hlp( size_t i, mpi_uint *s, mpi_uint *d, mpi_uint b ) +{ + +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + size_t n = 0; + + mpi TA, TB; + + mpi_init( &TA ); mpi_init( &TB ); + + if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n; i > 0; i-- ) + if( A->p[i - 1] != 0 ) + break; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, i + j ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + n = j; +// for( i++; j > 0; j-- ) + mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] ); + + if (ets_bigint_mult_prepare(A->p, B->p, n)){ + ets_bigint_wait_finish(); + ets_bigint_mult_getz(X->p, n); + } else{ + mpi_printf("Baseline multiplication failed\n"); + } + + X->s = A->s * B->s; + +cleanup: + + mpi_free( &TB ); mpi_free( &TA ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mpi_mul_int( mpi *X, const mpi *A, mpi_uint b ) +{ + mpi _B; + mpi_uint p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Unsigned integer divide - double mpi_uint dividend, u1/u0, and + * mpi_uint divisor, d + */ +static mpi_uint int_div_int( mpi_uint u1, + mpi_uint u0, mpi_uint d, mpi_uint *r ) +{ +#if defined(HAVE_UDBL) + t_udbl dividend, quotient; +#else + const mpi_uint radix = (mpi_uint) 1 << biH; + const mpi_uint uint_halfword_mask = ( (mpi_uint) 1 << biH ) - 1; + mpi_uint d0, d1, q0, q1, rAX, r0, quotient; + mpi_uint u0_msw, u0_lsw; + size_t s; +#endif + + /* + * Check for overflow + */ + if( 0 == d || u1 >= d ) + { + if (r != NULL) *r = ~0; + + return ( ~0 ); + } + +#if defined(HAVE_UDBL) + dividend = (t_udbl) u1 << biL; + dividend |= (t_udbl) u0; + quotient = dividend / d; + if( quotient > ( (t_udbl) 1 << biL ) - 1 ) + quotient = ( (t_udbl) 1 << biL ) - 1; + + if( r != NULL ) + *r = (mpi_uint)( dividend - (quotient * d ) ); + + return (mpi_uint) quotient; +#else + + /* + * Algorithm D, Section 4.3.1 - The Art of Computer Programming + * Vol. 2 - Seminumerical Algorithms, Knuth + */ + + /* + * Normalize the divisor, d, and dividend, u0, u1 + */ + s = clz( d ); + d = d << s; + + u1 = u1 << s; + u1 |= ( u0 >> ( biL - s ) ) & ( -(mpi_sint)s >> ( biL - 1 ) ); + u0 = u0 << s; + + d1 = d >> biH; + d0 = d & uint_halfword_mask; + + u0_msw = u0 >> biH; + u0_lsw = u0 & uint_halfword_mask; + + /* + * Find the first quotient and remainder + */ + q1 = u1 / d1; + r0 = u1 - d1 * q1; + + while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) ) + { + q1 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + rAX = ( u1 * radix ) + ( u0_msw - q1 * d ); + q0 = rAX / d1; + r0 = rAX - q0 * d1; + + while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) ) + { + q0 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + if (r != NULL) + *r = ( rAX * radix + u0_lsw - q0 * d ) >> s; + + quotient = q1 * radix + q0; + + return quotient; +#endif +} + +/* + * Division by mpi: A = Q * B + R (HAC 14.20) + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, n, t, k; + mpi X, Y, Z, T1, T2; + + if( mpi_cmp_int( B, 0 ) == 0 ) + return( ERR_MPI_DIVISION_BY_ZERO ); + + mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z ); + mpi_init( &T1 ); mpi_init( &T2 ); + + if( mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) ); + if( R != NULL ) MPI_CHK( mpi_copy( R, A ) ); + return( 0 ); + } + + MPI_CHK( mpi_copy( &X, A ) ); + MPI_CHK( mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MPI_CHK( mpi_grow( &Z, A->n + 2 ) ); + MPI_CHK( mpi_lset( &Z, 0 ) ); + MPI_CHK( mpi_grow( &T1, 2 ) ); + MPI_CHK( mpi_grow( &T2, 3 ) ); + + k = mpi_bitlen( &Y ) % biL; + if( k < biL - 1 ) + { + k = biL - 1 - k; + MPI_CHK( mpi_shift_l( &X, k ) ); + MPI_CHK( mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + MPI_CHK( mpi_shift_l( &Y, biL * ( n - t ) ) ); + + while( mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + MPI_CHK( mpi_sub_mpi( &X, &X, &Y ) ); + } + MPI_CHK( mpi_shift_r( &Y, biL * ( n - t ) ) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { + Z.p[i - t - 1] = int_div_int( X.p[i], X.p[i - 1], + Y.p[t], NULL); + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MPI_CHK( mpi_lset( &T1, 0 ) ); + T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MPI_CHK( mpi_lset( &T2, 0 ) ); + T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2]; + T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MPI_CHK( mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mpi_cmp_int( &X, 0 ) < 0 ) + { + MPI_CHK( mpi_copy( &T1, &Y ) ); + MPI_CHK( mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + MPI_CHK( mpi_copy( Q, &Z ) ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + MPI_CHK( mpi_shift_r( &X, k ) ); + X.s = A->s; + MPI_CHK( mpi_copy( R, &X ) ); + + if( mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z ); + mpi_free( &T1 ); mpi_free( &T2 ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, mpi_sint b ) +{ + mpi _B; + mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + + if( mpi_cmp_int( B, 0 ) < 0 ) + return( ERR_MPI_NEGATIVE_VALUE ); + + MPI_CHK( mpi_div_mpi( NULL, R, A, B ) ); + + while( mpi_cmp_int( R, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( R, R, B ) ); + + while( mpi_cmp_mpi( R, B ) >= 0 ) + MPI_CHK( mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mpi_mod_int( mpi_uint *r, const mpi *A, mpi_sint b ) +{ + size_t i; + mpi_uint x, y, z; + + if( b == 0 ) + return( ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + return( ERR_MPI_NEGATIVE_VALUE ); + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n, y = 0; i > 0; i-- ) + { + x = A->p[i - 1]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if( A->s < 0 && y != 0 ) + y = b - y; + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( mpi_uint *mm, const mpi *N ) +{ + mpi_uint x, m0 = N->p[0]; + unsigned int i; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + + for( i = biL; i >= 8; i /= 2 ) + x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, mpi_uint mm, + const mpi *T ) +{ + size_t n, m; + mpi_uint *d = NULL; + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + if (ets_bigint_montgomery_mult_prepare(N->p, B->p, d, m, n, false)) { + ets_bigint_wait_finish(); + + ets_bigint_montgomery_mult_getz(A->p, n); + } else{ + mpi_printf("Montgomery multiplication failed\n"); + } + +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static void mpi_montred( mpi *A, const mpi *N, mpi_uint mm, const mpi *T ) +{ + mpi_uint z = 1; + mpi U; + + U.n = U.s = (int) z; + U.p = &z; + + mpi_montmul( A, &U, N, mm, T ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ) +{ + int ret; + size_t wbits, wsize, one = 1; + size_t i, j, nblimbs; + size_t bufsize, nbits; + mpi_uint ei, mm, state; + mpi RR, T, W[ 2 << MPI_WINDOW_SIZE ], Apos; + int neg; + + if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + return( ERR_MPI_BAD_INPUT_DATA ); + + if( mpi_cmp_int( E, 0 ) < 0 ) + return( ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mpi_init( &RR ); mpi_init( &T ); + mpi_init( &Apos ); + memset( W, 0, sizeof( W ) ); + + i = mpi_bitlen( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + if( wsize > MPI_WINDOW_SIZE ) + wsize = MPI_WINDOW_SIZE; + + j = N->n + 1; + MPI_CHK( mpi_grow( X, j ) ); + MPI_CHK( mpi_grow( &W[1], j ) ); + MPI_CHK( mpi_grow( &T, j * 2 ) ); + + /* + * Compensate for negative A (and correct at the end) + */ + neg = ( A->s == -1 ); + if( neg ) + { + MPI_CHK( mpi_copy( &Apos, A ) ); + Apos.s = 1; + A = &Apos; + } + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MPI_CHK( mpi_lset( &RR, 1 ) ); + MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); + MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mpi_cmp_mpi( A, N ) >= 0 ) + MPI_CHK( mpi_mod_mpi( &W[1], A, N ) ); + else + MPI_CHK( mpi_copy( &W[1], A ) ); + + mpi_montmul( &W[1], &RR, N, mm, &T ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MPI_CHK( mpi_copy( X, &RR ) ); + mpi_montred( X, N, mm, &T ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = one << ( wsize - 1 ); + + MPI_CHK( mpi_grow( &W[j], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + mpi_montmul( &W[j], &W[j], N, mm, &T ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < ( one << wsize ); i++ ) + { + MPI_CHK( mpi_grow( &W[i], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) ); + + mpi_montmul( &W[i], &W[1], N, mm, &T ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs == 0 ) + break; + + nblimbs--; + + bufsize = sizeof( mpi_uint ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + mpi_montmul( X, X, N, mm, &T ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= ( ei << ( wsize - nbits ) ); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + mpi_montmul( X, X, N, mm, &T ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + mpi_montmul( X, &W[wbits], N, mm, &T ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + mpi_montmul( X, X, N, mm, &T ); + + wbits <<= 1; + + if( ( wbits & ( one << wsize ) ) != 0 ) + mpi_montmul( X, &W[1], N, mm, &T ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + mpi_montred( X, N, mm, &T ); + + if( neg ) + { + X->s = -1; + MPI_CHK( mpi_add_mpi( X, N, X ) ); + } + +cleanup: + + for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ ) + mpi_free( &W[i] ); + + mpi_free( &W[1] ); mpi_free( &T ); mpi_free( &Apos ); + + if( _RR == NULL || _RR->p == NULL ) + mpi_free( &RR ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ) +{ + int ret; + size_t lz, lzt; + mpi TG, TA, TB; + + mpi_init( &TG ); mpi_init( &TA ); mpi_init( &TB ); + + MPI_CHK( mpi_copy( &TA, A ) ); + MPI_CHK( mpi_copy( &TB, B ) ); + + lz = mpi_lsb( &TA ); + lzt = mpi_lsb( &TB ); + + if( lzt < lz ) + lz = lzt; + + MPI_CHK( mpi_shift_r( &TA, lz ) ); + MPI_CHK( mpi_shift_r( &TB, lz ) ); + + TA.s = TB.s = 1; + + while( mpi_cmp_int( &TA, 0 ) != 0 ) + { + MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) ); + MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) ); + + if( mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) ); + MPI_CHK( mpi_shift_r( &TA, 1 ) ); + } + else + { + MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) ); + MPI_CHK( mpi_shift_r( &TB, 1 ) ); + } + } + + MPI_CHK( mpi_shift_l( &TB, lz ) ); + MPI_CHK( mpi_copy( G, &TB ) ); + +cleanup: + + mpi_free( &TG ); mpi_free( &TA ); mpi_free( &TB ); + + return( ret ); +} + +/* + * Fill X with size bytes of random. + * + * Use a temporary bytes representation to make sure the result is the same + * regardless of the platform endianness (useful when f_rng is actually + * deterministic, eg for tests). + */ +int mpi_fill_random( mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char buf[MPI_MAX_SIZE]; + + if( size > MPI_MAX_SIZE ) + return( ERR_MPI_BAD_INPUT_DATA ); + + MPI_CHK( f_rng( p_rng, buf, size ) ); + MPI_CHK( mpi_read_binary( X, buf, size ) ); + +cleanup: + return( ret ); +} + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ) +{ + int ret; + mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + + if( mpi_cmp_int( N, 0 ) <= 0 ) + return( ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 ); + mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV ); + mpi_init( &V1 ); mpi_init( &V2 ); + + MPI_CHK( mpi_gcd( &G, A, N ) ); + + if( mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MPI_CHK( mpi_mod_mpi( &TA, A, N ) ); + MPI_CHK( mpi_copy( &TU, &TA ) ); + MPI_CHK( mpi_copy( &TB, N ) ); + MPI_CHK( mpi_copy( &TV, N ) ); + + MPI_CHK( mpi_lset( &U1, 1 ) ); + MPI_CHK( mpi_lset( &U2, 0 ) ); + MPI_CHK( mpi_lset( &V1, 0 ) ); + MPI_CHK( mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &U1, 1 ) ); + MPI_CHK( mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &V1, 1 ) ); + MPI_CHK( mpi_shift_r( &V2, 1 ) ); + } + + if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); + MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); + MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mpi_cmp_int( &V1, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( &V1, &V1, N ) ); + + while( mpi_cmp_mpi( &V1, N ) >= 0 ) + MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) ); + + MPI_CHK( mpi_copy( X, &V1 ) ); + +cleanup: + + mpi_free( &TA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 ); + mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV ); + mpi_free( &V1 ); mpi_free( &V2 ); + + return( ret ); +} + +static const int small_prime[] = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Small divisors test (X must be positive) + * + * Return values: + * 0: no small factor (possible prime, more tests needed) + * 1: certain prime + * ERR_MPI_NOT_ACCEPTABLE: certain non-prime + * other negative: error + */ +static int mpi_check_small_factors( const mpi *X ) +{ + int ret = 0; + size_t i; + mpi_uint r; + + if( ( X->p[0] & 1 ) == 0 ) + return( ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 1 ); + + MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( ERR_MPI_NOT_ACCEPTABLE ); + } + +cleanup: + return( ret ); +} + +/* + * Miller-Rabin pseudo-primality test (HAC 4.24) + */ +static int mpi_miller_rabin( const mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count; + size_t i, j, k, n, s; + mpi W, R, T, A, RR; + + mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A ); + mpi_init( &RR ); + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MPI_CHK( mpi_sub_int( &W, X, 1 ) ); + s = mpi_lsb( &W ); + MPI_CHK( mpi_copy( &R, &W ) ); + MPI_CHK( mpi_shift_r( &R, s ) ); + + i = mpi_bitlen( X ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + MPI_CHK( mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + if( mpi_cmp_mpi( &A, &W ) >= 0 ) + { + j = mpi_bitlen( &A ) - mpi_bitlen( &W ); + MPI_CHK( mpi_shift_r( &A, j + 1 ) ); + } + A.p[0] |= 3; + + count = 0; + do { + MPI_CHK( mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + j = mpi_bitlen( &A ); + k = mpi_bitlen( &W ); + if (j > k) { + MPI_CHK( mpi_shift_r( &A, j - k ) ); + } + + if (count++ > 30) { + return ERR_MPI_NOT_ACCEPTABLE; + } + + } while ( mpi_cmp_mpi( &A, &W ) >= 0 || + mpi_cmp_int( &A, 1 ) <= 0 ); + + /* + * A = A^R mod |X| + */ + MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mpi_cmp_mpi( &A, &W ) == 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MPI_CHK( mpi_mul_mpi( &T, &A, &A ) ); + MPI_CHK( mpi_mod_mpi( &A, &T, X ) ); + + if( mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mpi_cmp_mpi( &A, &W ) != 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A ); + mpi_free( &RR ); + + return( ret ); +} + +/* + * Pseudo-primality test: small factors, then Miller-Rabin + */ +int mpi_is_prime( const mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mpi XX; + + XX.s = 1; + XX.n = X->n; + XX.p = X->p; + + if( mpi_cmp_int( &XX, 0 ) == 0 || + mpi_cmp_int( &XX, 1 ) == 0 ) + return( ERR_MPI_NOT_ACCEPTABLE ); + + if( mpi_cmp_int( &XX, 2 ) == 0 ) + return( 0 ); + + if( ( ret = mpi_check_small_factors( &XX ) ) != 0 ) + { + if( ret == 1 ) + return( 0 ); + + return( ret ); + } + + return( mpi_miller_rabin( &XX, f_rng, p_rng ) ); +} + +/* + * Prime number generation + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t k, n; + mpi_uint r; + mpi Y; + + if( nbits < 3 || nbits > MPI_MAX_BITS ) + return( ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + MPI_CHK( mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + + k = mpi_bitlen( X ); + if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits + 1 ) ); + + mpi_set_bit( X, nbits-1, 1 ); + + X->p[0] |= 1; + + if( dh_flag == 0 ) + { + while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + { + if( ret != ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( X, X, 2 ) ); + } + } + else + { + /* + * An necessary condition for Y and X = 2Y + 1 to be prime + * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). + * Make sure it is satisfied, while keeping X = 3 mod 4 + */ + + X->p[0] |= 2; + + MPI_CHK( mpi_mod_int( &r, X, 3 ) ); + if( r == 0 ) + MPI_CHK( mpi_add_int( X, X, 8 ) ); + else if( r == 1 ) + MPI_CHK( mpi_add_int( X, X, 4 ) ); + + /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ + MPI_CHK( mpi_copy( &Y, X ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + /* + * First, check small factors for X and Y + * before doing Miller-Rabin on any of them + */ + if( ( ret = mpi_check_small_factors( X ) ) == 0 && + ( ret = mpi_check_small_factors( &Y ) ) == 0 && + ( ret = mpi_miller_rabin( X, f_rng, p_rng ) ) == 0 && + ( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 ) + { + break; + } + + if( ret != ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + /* + * Next candidates. We want to preserve Y = (X-1) / 2 and + * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) + * so up Y by 6 and X by 12. + */ + MPI_CHK( mpi_add_int( X, X, 12 ) ); + MPI_CHK( mpi_add_int( &Y, &Y, 6 ) ); + } + } + +cleanup: + + mpi_free( &Y ); + + return( ret ); +} + + +#endif /* ESP_BIGNUM_ALT */ + diff --git a/components/mbedtls/port/sha1_alt.c b/components/mbedtls/port/sha1_alt.c new file mode 100644 index 0000000000..32a970704c --- /dev/null +++ b/components/mbedtls/port/sha1_alt.c @@ -0,0 +1,102 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * 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. + * + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#include "port/sha1_alt.h" + +#if defined(ESP_SHA1_C) +#include + +/* Implementation that should never be optimized out by the compiler */ +static void sha1_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void sha1_init( SHA1_CTX *ctx ) +{ + memset( ctx, 0, sizeof( SHA1_CTX ) ); + ets_sha_enable(); +} + +void sha1_free( SHA1_CTX *ctx ) +{ + if( ctx == NULL ) + return; + + sha1_zeroize( ctx, sizeof( SHA1_CTX ) ); + ets_sha_disable(); +} + +void sha1_clone( SHA1_CTX *dst, const SHA1_CTX *src ) +{ + *dst = *src; +} + +void sha1_process(SHA1_CTX *ctx, const unsigned char data[64]) +{ + +} + +/* + * SHA-1 context setup + */ +void sha1_starts( SHA1_CTX *ctx ) +{ + ets_sha_init(&ctx->context); + ctx->context_type = SHA1; +} + +/* + * SHA-1 process buffer + */ +void sha1_update( SHA1_CTX *ctx, const unsigned char *input, size_t ilen ) +{ + ets_sha_update(&ctx->context, ctx->context_type, input, ilen * 8); +} + +/* + * SHA-1 final digest + */ +void sha1_finish( SHA1_CTX *ctx, unsigned char output[20] ) +{ + ets_sha_finish(&ctx->context, ctx->context_type, output); +} + +/* + * output = SHA-1( input buffer ) + */ +void sha1_output( const unsigned char *input, size_t ilen, unsigned char output[20] ) +{ + SHA1_CTX ctx; + + sha1_init( &ctx ); + sha1_starts( &ctx ); + sha1_update( &ctx, input, ilen ); + sha1_finish( &ctx, output ); + sha1_free( &ctx ); +} + +#endif /* _SHA1_C */ + + diff --git a/components/mbedtls/port/sha256_alt.c b/components/mbedtls/port/sha256_alt.c new file mode 100644 index 0000000000..781cfa7a11 --- /dev/null +++ b/components/mbedtls/port/sha256_alt.c @@ -0,0 +1,107 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * 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. + * + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#include "port/sha256_alt.h" + +#if defined(ESP_SHA256_C) +#include + +/* Implementation that should never be optimized out by the compiler */ +static void sha256_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void sha256_init( SHA256_CTX *ctx ) +{ + memset( ctx, 0, sizeof( SHA256_CTX ) ); + ets_sha_enable(); +} + +void sha256_process(SHA256_CTX *ctx, const unsigned char data[64]) +{ + +} + +void sha256_free( SHA256_CTX *ctx ) +{ + if( ctx == NULL ) + return; + + sha256_zeroize( ctx, sizeof( SHA256_CTX ) ); + ets_sha_disable(); +} + +void sha256_clone( SHA256_CTX *dst, const SHA256_CTX *src ) +{ + *dst = *src; +} + +/* + * SHA-256 context setup + */ +void sha256_starts( SHA256_CTX *ctx, int is224 ) +{ + ets_sha_init(&ctx->context); + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->context_type = SHA256; + }else{ + /* SHA-224 */ + ctx->context_type = SHA224; + } +} + +/* + * SHA-256 process buffer + */ +void sha256_update( SHA256_CTX *ctx, const unsigned char *input, size_t ilen ) +{ + ets_sha_update(&ctx->context, ctx->context_type, input, ilen * 8); +} + +/* + * SHA-256 final digest + */ +void sha256_finish( SHA256_CTX *ctx, unsigned char output[32] ) +{ + ets_sha_finish(&ctx->context, ctx->context_type, output); +} + +/* + * output = SHA-256( input buffer ) + */ +void sha256_output( const unsigned char *input, size_t ilen, unsigned char output[32], int is224 ) +{ + SHA256_CTX ctx; + + sha256_init( &ctx ); + sha256_starts( &ctx, is224 ); + sha256_update( &ctx, input, ilen ); + sha256_finish( &ctx, output ); + sha256_free( &ctx ); +} + +#endif /* SHA256_C */ diff --git a/components/mbedtls/port/sha512_alt.c b/components/mbedtls/port/sha512_alt.c new file mode 100644 index 0000000000..9884dd8d1e --- /dev/null +++ b/components/mbedtls/port/sha512_alt.c @@ -0,0 +1,103 @@ +/* + * FIPS-180-2 compliant SHA-384/512 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * 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. + * + */ +/* + * The SHA-512 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ +#include "port/sha512_alt.h" + +#if defined(ESP_SHA512_C) +#include + +/* Implementation that should never be optimized out by the compiler */ +static void sha512_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void sha512_init( SHA512_CTX *ctx ) +{ + memset( ctx, 0, sizeof( SHA512_CTX ) ); + ets_sha_enable(); +} + +void sha512_free( SHA512_CTX *ctx ) +{ + if( ctx == NULL ) + return; + + sha512_zeroize( ctx, sizeof( SHA512_CTX ) ); + ets_sha_disable(); +} + +void sha512_clone( SHA512_CTX *dst, const SHA512_CTX *src ) +{ + *dst = *src; +} + +/* + * SHA-512 context setup + */ +void sha512_starts( SHA512_CTX *ctx, int is384 ) +{ + ets_sha_init(&ctx->context); + if( is384 == 0 ) + { + /* SHA-512 */ + ctx->context_type = SHA2_512; + } + else + { + /* SHA-384 */ + ctx->context_type = SHA2_384; + } +} + +/* + * SHA-512 process buffer + */ +void sha512_update( SHA512_CTX *ctx, const unsigned char *input,size_t ilen ) +{ + ets_sha_update(&ctx->context, ctx->context_type, input, ilen * 8); +} + +/* + * SHA-512 final digest + */ +void sha512_finish( SHA512_CTX *ctx, unsigned char output[64] ) +{ + ets_sha_finish(&ctx->context, ctx->context_type, output); +} + +/* + * output = SHA-512( input buffer ) + */ +void sha512_output( const unsigned char *input, size_t ilen,unsigned char output[64], int is384 ) +{ + SHA512_CTX ctx; + + sha512_init( &ctx ); + sha512_starts( &ctx, is384 ); + sha512_update( &ctx, input, ilen ); + sha512_finish( &ctx, output ); + sha512_free( &ctx ); +} + +#endif /* SHA512_C */