blob: a9d2057b475442a341d94431fe97370365063110 [file] [log] [blame]
/****************************************************************************
* arch/risc-v/src/esp32c3-legacy/esp32c3_rsa.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_ESP32C3_RSA_ACCELERATOR
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <debug.h>
#include <semaphore.h>
#include "riscv_internal.h"
#include "esp32c3_rsa.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ESP32C3_PKCS1_V15
#define RSA_EXPONENT_BLINDING 28
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: rsa_check_context
*
* Description:
* Checks whether the context fields are set in such a way
* that the RSA primitives will be able to execute without error.
*
* Input Parameters:
* ctx - The initialized RSA context to store the parameters in
* N - The RSA modulus
* NL - The Byte length of \p N
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int rsa_check_context(struct esp32c3_rsa_context_s const *ctx,
int is_priv, int blinding_needed)
{
#if !defined(ESP32C3_RSA_NO_CRT)
((void) blinding_needed);
#endif
if (ctx->len != esp32c3_mpi_size(&ctx->N) ||
ctx->len > ESP32C3_MPI_MAX_SIZE)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
/* 1. Modular exponentiation needs positive, odd moduli */
if (esp32c3_mpi_cmp_int(&ctx->N, 0) <= 0 ||
esp32c3_mpi_get_bit(&ctx->N, 0) == 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
#if !defined(ESP32C3_RSA_NO_CRT)
if (is_priv &&
(esp32c3_mpi_cmp_int(&ctx->P, 0) <= 0 ||
esp32c3_mpi_get_bit(&ctx->P, 0) == 0 ||
esp32c3_mpi_cmp_int(&ctx->Q, 0) <= 0 ||
esp32c3_mpi_get_bit(&ctx->Q, 0) == 0))
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
#endif /* !ESP32C3_RSA_NO_CRT */
/* 2. Exponents must be positive */
/* Always need E for public key operations */
if (esp32c3_mpi_cmp_int(&ctx->E, 0) <= 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
#if defined(ESP32C3_RSA_NO_CRT)
/* For private key operations, use D or DP & DQ as exponents */
if (is_priv && esp32c3_mpi_cmp_int(&ctx->D, 0) <= 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
#else
if (is_priv &&
(esp32c3_mpi_cmp_int(&ctx->DP, 0) <= 0 ||
esp32c3_mpi_cmp_int(&ctx->DQ, 0) <= 0))
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
#endif /* ESP32C3_RSA_NO_CRT */
#if defined(ESP32C3_RSA_NO_CRT)
if (is_priv && blinding_needed &&
(esp32c3_mpi_cmp_int(&ctx->P, 0) <= 0 ||
esp32c3_mpi_cmp_int(&ctx->Q, 0) <= 0))
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
#endif
#if !defined(ESP32C3_RSA_NO_CRT)
if (is_priv && esp32c3_mpi_cmp_int(&ctx->QP, 0) <= 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
#endif
return OK;
}
/****************************************************************************
* Name: rsa_prepare_blinding
*
* Description:
* Generate or update blinding values.
*
* Input Parameters:
* ctx - The initialized RSA context to store the parameters in.
* f_rng - The RNG function
* p_rng - The RNG context to pass to \p f_rng
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int rsa_prepare_blinding(struct esp32c3_rsa_context_s *ctx,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
int ret;
int count = 0;
struct esp32c3_mpi_s R;
esp32c3_mpi_init(&R);
if (ctx->VF.p != NULL)
{
/* We already have blinding values, just update them by squaring */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&ctx->VI, &ctx->VI, &ctx->VI),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&ctx->VI, &ctx->VI, &ctx->N),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&ctx->VF, &ctx->VF, &ctx->VF),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&ctx->VF, &ctx->VF, &ctx->N),
cleanup);
goto cleanup;
}
/* Unblinding value: VF = random number, invertible mod N */
do
{
if (count++ > 10)
{
ret = ESP32C3_ERR_RSA_RNG_FAILED;
goto cleanup;
}
ESP32C3_MPI_CHK(esp32c3_mpi_fill_random(&ctx->VF, ctx->len - 1,
f_rng, p_rng), cleanup);
/* Compute VF^-1 as R * (R VF)^-1 to avoid leaks from inv_mod. */
ESP32C3_MPI_CHK(esp32c3_mpi_fill_random(&R, ctx->len - 1,
f_rng, p_rng), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&ctx->VI, &ctx->VF, &R),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&ctx->VI, &ctx->VI, &ctx->N),
cleanup);
ret = esp32c3_mpi_inv_mod(&ctx->VI, &ctx->VI, &ctx->N);
if (ret != 0 && ret != ESP32C3_ERR_MPI_NOT_ACCEPTABLE)
{
goto cleanup;
}
}
while (ret == ESP32C3_ERR_MPI_NOT_ACCEPTABLE);
/* Finish the computation of VF^-1 = R * (R VF)^-1 */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&ctx->VI, &ctx->VI, &R),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&ctx->VI, &ctx->VI, &ctx->N),
cleanup);
/* Blinding value: VI = VF^(-e) mod N */
ESP32C3_MPI_CHK(esp32c3_mpi_exp_mod(&ctx->VI, &ctx->VI,
&ctx->E, &ctx->N, &ctx->RN),
cleanup);
cleanup:
esp32c3_mpi_free(&R);
return ret;
}
#if defined(ESP32C3_PKCS1_V15)
/* Implementation of the PKCS1-V1_5-ENCRYPT function */
static int esp32c3_rsa_pkcs1_v15_encrypt(struct esp32c3_rsa_context_s *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode, size_t ilen,
const unsigned char *input,
unsigned char *output)
{
size_t nb_pad;
size_t olen;
int ret;
unsigned char *p = output;
DEBUGASSERT(ctx != NULL);
DEBUGASSERT(mode == ESP32C3_RSA_PRIVATE ||
mode == ESP32C3_RSA_PUBLIC);
DEBUGASSERT(output != NULL);
DEBUGASSERT(input != NULL);
if (mode == ESP32C3_RSA_PRIVATE && ctx->padding != ESP32C3_RSA_PKCS_V15)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
olen = ctx->len;
/* first comparison checks for overflow */
if (ilen + 11 < ilen || olen < ilen + 11)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
nb_pad = olen - 3 - ilen;
*p++ = 0;
if (mode == ESP32C3_RSA_PUBLIC)
{
if (f_rng == NULL)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
*p++ = ESP32C3_RSA_CRYPT;
while (nb_pad-- > 0)
{
int rng_dl = 100;
do
{
ret = f_rng(p_rng, p, 1);
}
while (*p == 0 && --rng_dl && ret == 0);
/* Check if RNG failed to generate data */
if (rng_dl == 0 || ret != 0)
{
return (ESP32C3_ERR_RSA_RNG_FAILED + ret);
}
p++;
}
}
else
{
*p++ = ESP32C3_RSA_SIGN;
while (nb_pad-- > 0)
{
*p++ = 0xff;
}
}
*p++ = 0;
memcpy(p, input, ilen);
return ((mode == ESP32C3_RSA_PUBLIC)
? esp32c3_rsa_public(ctx, output, output)
: esp32c3_rsa_private(ctx, f_rng, p_rng, output, output));
}
#endif /* ESP32C3_PKCS1_V15 */
#if defined(ESP32C3_PKCS1_V15)
/****************************************************************************
* Name: all_or_nothing_int
*
* Description:
* Turn zero-or-nonzero into zero-or-all-bits-one, without branches.
*
* Input Parameters:
* value - The value to analyze.
*
* Returned Value:
* Zero if \p value is zero, otherwise all-bits-one.
*
****************************************************************************/
static unsigned all_or_nothing_int(unsigned value)
{
return (- ((value | - value) >> (sizeof(value) * 8 - 1)));
}
/****************************************************************************
* Name: size_greater_than
*
* Description:
* Check whether a size is out of bounds, without branches.
*
* Input Parameters:
* size - Size to check.
* max - Maximum desired value for \p size.
*
* Returned Value:
* \c 0 if `size <= max`, \c 1 if `size > max`.
*
****************************************************************************/
static unsigned size_greater_than(size_t size, size_t max)
{
/* Return the sign bit (1 for negative) of (max - size). */
return ((max - size) >> (sizeof(size_t) * 8 - 1));
}
/****************************************************************************
* Name: if_int
*
* Description:
* Choose between two integer values, without branches.
*
* Input Parameters:
* cond - Condition to test.
* if1 - Value to use if \p cond is nonzero.
* if0 - Value to use if \p cond is zero.
*
* Returned Value:
* \c if1 if \p cond is nonzero, otherwise \c if0.
*
****************************************************************************/
static unsigned if_int(unsigned cond, unsigned if1, unsigned if0)
{
unsigned mask = all_or_nothing_int(cond);
return ((mask & if1) | (~mask & if0));
}
/****************************************************************************
* Name: mem_move_to_left
*
* Description:
* Shift some data towards the left inside a buffer without leaking
* the length of the data through side channels.
*
* Input Parameters:
* start - Pointer to the start of the buffer.
* total - Total size of the buffer.
* offset - Offset from which to copy bytes.
*
* Returned Value:
* None.
*
****************************************************************************/
static void mem_move_to_left(void *start,
size_t total,
size_t offset)
{
volatile unsigned char *buf = start;
size_t i;
size_t n;
if (total == 0)
{
return;
}
for (i = 0; i < total; i++)
{
unsigned no_op = size_greater_than(total - offset, i);
for (n = 0; n < total - 1; n++)
{
unsigned char current = buf[n];
unsigned char next = buf[n + 1];
buf[n] = if_int(no_op, current, next);
}
buf[total - 1] = if_int(no_op, buf[total - 1], 0);
}
}
/* Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function */
static int esp32c3_rsa_pkcs1_v15_decrypt(struct esp32c3_rsa_context_s *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode, size_t *olen,
const unsigned char *input,
unsigned char *output,
size_t output_max_len)
{
int ret;
size_t ilen;
size_t i;
size_t plaintext_max_size;
unsigned char buf[ESP32C3_MPI_MAX_SIZE];
size_t pad_count = 0;
unsigned bad = 0;
unsigned char pad_done = 0;
size_t plaintext_size = 0;
unsigned output_too_large;
DEBUGASSERT(ctx != NULL);
DEBUGASSERT(mode == ESP32C3_RSA_PRIVATE ||
mode == ESP32C3_RSA_PUBLIC);
DEBUGASSERT(output_max_len == 0 || output != NULL);
DEBUGASSERT(input != NULL);
DEBUGASSERT(olen != NULL);
ilen = ctx->len;
plaintext_max_size = (output_max_len > ilen - 11 ?
ilen - 11 :
output_max_len);
if (mode == ESP32C3_RSA_PRIVATE && ctx->padding != ESP32C3_RSA_PKCS_V15)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
if (ilen < 16 || ilen > sizeof(buf))
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
ret = (mode == ESP32C3_RSA_PUBLIC)
? esp32c3_rsa_public(ctx, input, buf)
: esp32c3_rsa_private(ctx, f_rng, p_rng, input, buf);
if (ret != 0)
{
goto cleanup;
}
/* Check and get padding length in constant time */
bad |= buf[0];
if (mode == ESP32C3_RSA_PRIVATE)
{
/* Decode EME-PKCS1-v1_5 padding */
bad |= buf[1] ^ ESP32C3_RSA_CRYPT;
/* Read the whole buffer */
for (i = 2; i < ilen; i++)
{
pad_done |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1;
pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
}
}
else
{
/* Decode EMSA-PKCS1-v1_5 padding */
bad |= buf[1] ^ ESP32C3_RSA_SIGN;
/* Read the whole buffer */
for (i = 2; i < ilen; i++)
{
pad_done |= if_int(buf[i], 0, 1);
pad_count += if_int(pad_done, 0, 1);
bad |= if_int(pad_done, 0, buf[i] ^ 0xff);
}
}
/* If pad_done is still zero, there's no data, only unfinished padding. */
bad |= if_int(pad_done, 0, 1);
/* There must be at least 8 bytes of padding. */
bad |= size_greater_than(8, pad_count);
plaintext_size = if_int(bad,
(unsigned) plaintext_max_size,
(unsigned) (ilen - pad_count - 3));
output_too_large = size_greater_than(plaintext_size,
plaintext_max_size);
/* Set ret without branches to avoid timing attacks */
ret = - (int) if_int(bad, - ESP32C3_ERR_RSA_INVALID_PADDING,
if_int(output_too_large, - ESP32C3_ERR_RSA_OUTPUT_TOO_LARGE,
0));
/* If the padding is bad or the plaintext is too large, zero the data */
bad = all_or_nothing_int(bad | output_too_large);
for (i = 11; i < ilen; i++)
buf[i] &= ~bad;
/* If the plaintext is too large, truncate it to the buffer size. */
plaintext_size = if_int(output_too_large,
(unsigned) plaintext_max_size,
(unsigned) plaintext_size);
/* Move the plaintext to the leftmost position */
mem_move_to_left(buf + ilen - plaintext_max_size,
plaintext_max_size,
plaintext_max_size - plaintext_size);
/* Copy the decrypted plaintext into the output buffer */
memcpy(output, buf + ilen - plaintext_max_size, plaintext_max_size);
/* Report the amount of data we copied to the output buffer */
*olen = plaintext_size;
cleanup:
memset(buf, 0, sizeof(buf));
return ret;
}
#endif /* ESP32C3_PKCS1_V15 */
/****************************************************************************
* Name: esp32c3_rsa_deduce_primes
*
* Description:
* Compute RSA prime moduli P, Q from public modulus N=PQ
* and a pair of private and public key.
*
* Input Parameters:
* N - RSA modulus N = PQ, with P, Q to be found
* E - RSA public exponent
* D - RSA private exponent
* P - Pointer to MPI holding first prime factor of N on success
* Q - Pointer to MPI holding second prime factor of N on success
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp32c3_rsa_deduce_primes(struct esp32c3_mpi_s const *N,
struct esp32c3_mpi_s const *E, struct esp32c3_mpi_s const *D,
struct esp32c3_mpi_s *P, struct esp32c3_mpi_s *Q)
{
int ret = 0;
uint16_t attempt; /* Number of current attempt */
uint16_t iter; /* Number of squares computed in the current attempt */
uint16_t order; /* Order of 2 in DE - 1 */
struct esp32c3_mpi_s T; /* Holds largest odd divisor of DE - 1 */
struct esp32c3_mpi_s K; /* Temporary holding the current candidate */
const unsigned char primes[] =
{
2, 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
};
const size_t num_primes = sizeof(primes) / sizeof(*primes);
if (P == NULL || Q == NULL || P->p != NULL || Q->p != NULL)
{
return (ESP32C3_ERR_MPI_BAD_INPUT_DATA);
}
if (esp32c3_mpi_cmp_int(N, 0) <= 0 ||
esp32c3_mpi_cmp_int(D, 1) <= 0 ||
esp32c3_mpi_cmp_mpi(D, N) >= 0 ||
esp32c3_mpi_cmp_int(E, 1) <= 0 ||
esp32c3_mpi_cmp_mpi(E, N) >= 0)
{
return (ESP32C3_ERR_MPI_BAD_INPUT_DATA);
}
/* Initializations and temporary changes */
esp32c3_mpi_init(&K);
esp32c3_mpi_init(&T);
/* T := DE - 1 */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&T, D, E), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&T, &T, 1), cleanup);
if ((order = (uint16_t) esp32c3_mpi_lsb(&T)) == 0)
{
ret = ESP32C3_ERR_MPI_BAD_INPUT_DATA;
goto cleanup;
}
/* After this operation, T holds the largest odd divisor of DE - 1. */
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&T, order), cleanup);
/* Skip trying 2 if N == 1 mod 8 */
attempt = 0;
if (N->p[0] % 8 == 1)
{
attempt = 1;
}
for (; attempt < num_primes; ++attempt)
{
esp32c3_mpi_lset(&K, primes[attempt]);
/* Check if gcd(K,N) = 1 */
ESP32C3_MPI_CHK(esp32c3_mpi_gcd(P, &K, N), cleanup);
if (esp32c3_mpi_cmp_int(P, 1) != 0)
{
continue;
}
/* Go through K^T + 1, K^(2T) + 1, K^(4T) + 1, ... */
ESP32C3_MPI_CHK(esp32c3_mpi_exp_mod(&K, &K, &T, N, Q), cleanup);
for (iter = 1; iter <= order; ++iter)
{
/* Continuing to square K */
if (esp32c3_mpi_cmp_int(&K, 1) == 0)
{
break;
}
ESP32C3_MPI_CHK(esp32c3_mpi_add_int(&K, &K, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_gcd(P, &K, N), cleanup);
if (esp32c3_mpi_cmp_int(P, 1) == 1 &&
esp32c3_mpi_cmp_mpi(P, N) == -1)
{
/* Q := N / P */
ESP32C3_MPI_CHK(esp32c3_mpi_div_mpi(Q, NULL, N, P), cleanup);
goto cleanup;
}
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&K, &K, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&K, &K, &K), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&K, &K, N), cleanup);
}
if (esp32c3_mpi_cmp_int(&K, 1) != 0)
{
break;
}
}
ret = ESP32C3_ERR_MPI_BAD_INPUT_DATA;
cleanup:
esp32c3_mpi_free(&K);
esp32c3_mpi_free(&T);
return ret;
}
/****************************************************************************
* Name: esp32c3_rsa_deduce_private_exponent
*
* Description:
* Compute RSA private exponent from prime moduli and public key.
*
* Input Parameters:
* P First prime factor of RSA modulus
* Q Second prime factor of RSA modulus
* E RSA public exponent
* D Pointer to MPI holding the private exponent on success.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp32c3_rsa_deduce_private_exponent(struct esp32c3_mpi_s const *P,
struct esp32c3_mpi_s const *Q,
struct esp32c3_mpi_s const *E,
struct esp32c3_mpi_s *D)
{
int ret = 0;
struct esp32c3_mpi_s K;
struct esp32c3_mpi_s L;
if (D == NULL || esp32c3_mpi_cmp_int(D, 0) != 0)
{
return (ESP32C3_ERR_MPI_BAD_INPUT_DATA);
}
if (esp32c3_mpi_cmp_int(P, 1) <= 0 ||
esp32c3_mpi_cmp_int(Q, 1) <= 0 ||
esp32c3_mpi_cmp_int(E, 0) == 0)
{
return (ESP32C3_ERR_MPI_BAD_INPUT_DATA);
}
esp32c3_mpi_init(&K);
esp32c3_mpi_init(&L);
/* Temporarily put K := P-1 and L := Q-1 */
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&K, P, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&L, Q, 1), cleanup);
/* Temporarily put D := gcd(P-1, Q-1) */
ESP32C3_MPI_CHK(esp32c3_mpi_gcd(D, &K, &L), cleanup);
/* K := LCM(P-1, Q-1) */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&K, &K, &L), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_div_mpi(&K, NULL, &K, D), cleanup);
/* Compute modular inverse of E in LCM(P-1, Q-1) */
ESP32C3_MPI_CHK(esp32c3_mpi_inv_mod(D, E, &K), cleanup);
cleanup:
esp32c3_mpi_free(&K);
esp32c3_mpi_free(&L);
return ret;
}
/****************************************************************************
* Name: esp32c3_rsa_validate_crt
*
* Description:
* Check validity of core RSA parameters
*
* Input Parameters:
* P - First prime factor of RSA modulus
* Q - Second prime factor of RSA modulus
* D - RSA private exponent
* DP - MPI to check for D modulo P-1
* DQ - MPI to check for D modulo P-1
* QP - MPI to check for the modular inverse of Q modulo P.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp32c3_rsa_validate_crt(
const struct esp32c3_mpi_s *P,
const struct esp32c3_mpi_s *Q,
const struct esp32c3_mpi_s *D,
const struct esp32c3_mpi_s *DP,
const struct esp32c3_mpi_s *DQ,
const struct esp32c3_mpi_s *QP)
{
int ret = 0;
struct esp32c3_mpi_s K;
struct esp32c3_mpi_s L;
esp32c3_mpi_init(&K);
esp32c3_mpi_init(&L);
/* Check that DP - D == 0 mod P - 1 */
if (DP != NULL)
{
if (P == NULL)
{
ret = ESP32C3_ERR_RSA_BAD_INPUT_DATA;
goto cleanup;
}
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&K, P, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&L, DP, D), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&L, &L, &K), cleanup);
if (esp32c3_mpi_cmp_int(&L, 0) != 0)
{
ret = ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
/* Check that DQ - D == 0 mod Q - 1 */
if (DQ != NULL)
{
if (Q == NULL)
{
ret = ESP32C3_ERR_RSA_BAD_INPUT_DATA;
goto cleanup;
}
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&K, Q, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&L, DQ, D), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&L, &L, &K), cleanup);
if (esp32c3_mpi_cmp_int(&L, 0) != 0)
{
ret = ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
/* Check that QP * Q - 1 == 0 mod P */
if (QP != NULL)
{
if (P == NULL || Q == NULL)
{
ret = ESP32C3_ERR_RSA_BAD_INPUT_DATA;
goto cleanup;
}
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&K, QP, Q), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&K, &K, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&K, &K, P), cleanup);
if (esp32c3_mpi_cmp_int(&K, 0) != 0)
{
ret = ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
cleanup:
/* Wrap MPI error codes by RSA check failure error code */
if (ret != 0 &&
ret != ESP32C3_ERR_RSA_KEY_CHECK_FAILED &&
ret != ESP32C3_ERR_RSA_BAD_INPUT_DATA)
{
ret += ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
}
esp32c3_mpi_free(&K);
esp32c3_mpi_free(&L);
return ret;
}
/****************************************************************************
* Name: esp32c3_rsa_validate_params
*
* Description:
* Check validity of core RSA parameters
*
* Input Parameters:
* N - RSA modulus N = PQ
* P - First prime factor of N
* Q - Second prime factor of N
* D - RSA private exponent
* E - RSA public exponent
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp32c3_rsa_validate_params(const struct esp32c3_mpi_s *N,
const struct esp32c3_mpi_s *P,
const struct esp32c3_mpi_s *Q,
const struct esp32c3_mpi_s *D,
const struct esp32c3_mpi_s *E,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
int ret = 0;
struct esp32c3_mpi_s K;
struct esp32c3_mpi_s L;
esp32c3_mpi_init(&K);
esp32c3_mpi_init(&L);
/* Step 1: Check that 1 < N = P * Q */
if (P != NULL && Q != NULL && N != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&K, P, Q), cleanup);
if (esp32c3_mpi_cmp_int(N, 1) <= 0 ||
esp32c3_mpi_cmp_mpi(&K, N) != 0)
{
ret = ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
/* Step 2: Check and 1 < D, E < N if present */
if (N != NULL && D != NULL && E != NULL)
{
if (esp32c3_mpi_cmp_int(D, 1) <= 0 ||
esp32c3_mpi_cmp_int(E, 1) <= 0 ||
esp32c3_mpi_cmp_mpi(D, N) >= 0 ||
esp32c3_mpi_cmp_mpi(E, N) >= 0)
{
ret = ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
/* Step 3: Check that D, E are inverse modulo P-1 and Q-1 */
if (P != NULL && Q != NULL && D != NULL && E != NULL)
{
if (esp32c3_mpi_cmp_int(P, 1) <= 0 ||
esp32c3_mpi_cmp_int(Q, 1) <= 0)
{
ret = ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
/* Compute DE-1 mod P-1 */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&K, D, E), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&K, &K, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&L, P, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&K, &K, &L), cleanup);
if (esp32c3_mpi_cmp_int(&K, 0) != 0)
{
ret = ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
/* Compute DE-1 mod Q-1 */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&K, D, E), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&K, &K, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&L, Q, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&K, &K, &L), cleanup);
if (esp32c3_mpi_cmp_int(&K, 0) != 0)
{
ret = ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
goto cleanup;
}
}
cleanup:
esp32c3_mpi_free(&K);
esp32c3_mpi_free(&L);
/* Wrap MPI error codes by RSA check failure error code */
if (ret != 0 && ret != ESP32C3_ERR_RSA_KEY_CHECK_FAILED)
{
ret += ESP32C3_ERR_RSA_KEY_CHECK_FAILED;
}
return ret;
}
/****************************************************************************
* Name: esp32c3_rsa_deduce_crt
*
* Description:
* Generate RSA-CRT parameters
*
* Input Parameters:
* P - First prime factor of N
* Q - Second prime factor of N
* D - RSA private exponent
* DP - Output variable for D modulo P-1
* DQ - Output variable for D modulo Q-1
* QP - Output variable for the modular inverse of Q modulo P
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int esp32c3_rsa_deduce_crt(const struct esp32c3_mpi_s *P,
const struct esp32c3_mpi_s *Q,
const struct esp32c3_mpi_s *D,
struct esp32c3_mpi_s *DP,
struct esp32c3_mpi_s *DQ,
struct esp32c3_mpi_s *QP)
{
int ret = 0;
struct esp32c3_mpi_s K;
esp32c3_mpi_init(&K);
/* DP = D mod P-1 */
if (DP != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&K, P, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(DP, D, &K), cleanup);
}
/* DQ = D mod Q-1 */
if (DQ != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&K, Q, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(DQ, D, &K), cleanup);
}
/* QP = Q^{-1} mod P */
if (QP != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_inv_mod(QP, Q, P), cleanup);
}
cleanup:
esp32c3_mpi_free(&K);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_rsa_import
*
* Description:
* Imports a set of core parameters into an RSA context.
*
* Input Parameters:
* ctx - The initialized RSA context to store the parameters in
* N - The RSA modulus
* P - The first prime factor of \p N
* Q - The second prime factor of \p N
* D - The private exponent
* E - The public exponent
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_import(struct esp32c3_rsa_context_s *ctx,
const struct esp32c3_mpi_s *N,
const struct esp32c3_mpi_s *P, const struct esp32c3_mpi_s *Q,
const struct esp32c3_mpi_s *D, const struct esp32c3_mpi_s *E)
{
int ret;
DEBUGASSERT(ctx != NULL);
if ((N != NULL && (ret = esp32c3_mpi_copy(&ctx->N, N)) != 0) ||
(P != NULL && (ret = esp32c3_mpi_copy(&ctx->P, P)) != 0) ||
(Q != NULL && (ret = esp32c3_mpi_copy(&ctx->Q, Q)) != 0) ||
(D != NULL && (ret = esp32c3_mpi_copy(&ctx->D, D)) != 0) ||
(E != NULL && (ret = esp32c3_mpi_copy(&ctx->E, E)) != 0))
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA + ret);
}
if (N != NULL)
{
ctx->len = esp32c3_mpi_size(&ctx->N);
}
return OK;
}
/****************************************************************************
* Name: esp32c3_rsa_import_raw
*
* Description:
* Imports core RSA parameters into an RSA context.
*
* Input Parameters:
* ctx - The initialized RSA context to store the parameters in
* N - The RSA modulus
* NL - The Byte length of \p N
* P - The first prime factor of \p N
* PL - The Byte length of \p P
* Q - The second prime factor of \p N
* QL - The Byte length of \p Q
* D - The private exponent
* DL - The Byte length of \p D
* E - The public exponent
* EL - The Byte length of \p E
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_import_raw(struct esp32c3_rsa_context_s *ctx,
unsigned char const *N, size_t NL,
unsigned char const *P, size_t PL,
unsigned char const *Q, size_t QL,
unsigned char const *D, size_t DL,
unsigned char const *E, size_t EL)
{
int ret = 0;
DEBUGASSERT(ctx != NULL);
if (N != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_read_binary(&ctx->N, N, NL), cleanup);
ctx->len = esp32c3_mpi_size(&ctx->N);
}
if (P != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_read_binary(&ctx->P, P, PL), cleanup);
}
if (Q != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_read_binary(&ctx->Q, Q, QL), cleanup);
}
if (D != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_read_binary(&ctx->D, D, DL), cleanup);
}
if (E != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_read_binary(&ctx->E, E, EL), cleanup);
}
cleanup:
if (ret != 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA + ret);
}
return OK;
}
/****************************************************************************
* Name: esp32c3_rsa_complete
*
* Description:
* Completes an RSA context from a set of imported core parameters.
*
* Input Parameters:
* ctx - The initialized RSA context holding imported parameters
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_complete(struct esp32c3_rsa_context_s *ctx)
{
int ret = 0;
int have_n;
int have_p;
int have_q;
int have_d;
int have_e;
#if !defined(ESP32C3_RSA_NO_CRT)
int have_dp;
int have_dq;
int have_qp;
#endif
int n_missing;
int pq_missing;
int d_missing;
int is_pub;
int is_priv;
DEBUGASSERT(ctx != NULL);
have_n = (esp32c3_mpi_cmp_int(&ctx->N, 0) != 0);
have_p = (esp32c3_mpi_cmp_int(&ctx->P, 0) != 0);
have_q = (esp32c3_mpi_cmp_int(&ctx->Q, 0) != 0);
have_d = (esp32c3_mpi_cmp_int(&ctx->D, 0) != 0);
have_e = (esp32c3_mpi_cmp_int(&ctx->E, 0) != 0);
#if !defined(ESP32C3_RSA_NO_CRT)
have_dp = (esp32c3_mpi_cmp_int(&ctx->DP, 0) != 0);
have_dq = (esp32c3_mpi_cmp_int(&ctx->DQ, 0) != 0);
have_qp = (esp32c3_mpi_cmp_int(&ctx->QP, 0) != 0);
#endif
/* Check whether provided parameters are enough */
n_missing = have_p && have_q && have_d && have_e;
pq_missing = have_n && !have_p && !have_q && have_d && have_e;
d_missing = have_p && have_q && !have_d && have_e;
is_pub = have_n && !have_p && !have_q && !have_d && have_e;
/* These three alternatives are mutually exclusive */
is_priv = n_missing || pq_missing || d_missing;
if (!is_priv && !is_pub)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
/* Step 1: Deduce N if P, Q are provided */
if (!have_n && have_p && have_q)
{
if ((ret = esp32c3_mpi_mul_mpi(&ctx->N, &ctx->P,
&ctx->Q)) != 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA + ret);
}
ctx->len = esp32c3_mpi_size(&ctx->N);
}
/* Step 2: Deduce and verify all remaining core parameters */
if (pq_missing)
{
ret = esp32c3_rsa_deduce_primes(&ctx->N, &ctx->E, &ctx->D,
&ctx->P, &ctx->Q);
if (ret != 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA + ret);
}
}
else if (d_missing)
{
if ((ret = esp32c3_rsa_deduce_private_exponent(&ctx->P, &ctx->Q,
&ctx->E, &ctx->D)) != 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA + ret);
}
}
/* Step 3: Deduce all additional parameters to RSA implementation */
#if !defined(ESP32C3_RSA_NO_CRT)
if (is_priv && ! (have_dp && have_dq && have_qp))
{
ret = esp32c3_rsa_deduce_crt(&ctx->P, &ctx->Q, &ctx->D,
&ctx->DP, &ctx->DQ, &ctx->QP);
if (ret != 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA + ret);
}
}
#endif /* ESP32C3_RSA_NO_CRT */
/* Step 3: Basic sanity checks */
return (rsa_check_context(ctx, is_priv, 1));
}
/****************************************************************************
* Name: esp32c3_rsa_export_raw
*
* Description:
* Eexports core parameters of an RSA key in raw big-endian binary format.
*
* Input Parameters:
* ctx - The initialized RSA context
* N - The Byte array to store the RSA modulus
* NL - The size of the buffer for the modulus
* P - The Byte array to hold the first prime factor of \p N
* PL - The size of the buffer for the first prime factor
* Q - The Byte array to hold the second prime factor of \p N
* QL - The size of the buffer for the second prime factor
* D - The Byte array to hold the private exponent
* DL - The size of the buffer for the private exponent
* E - The Byte array to hold the public exponent
* EL - The size of the buffer for the public exponent
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_export_raw(const struct esp32c3_rsa_context_s *ctx,
unsigned char *N, size_t NL,
unsigned char *P, size_t PL,
unsigned char *Q, size_t QL,
unsigned char *D, size_t DL,
unsigned char *E, size_t EL)
{
int ret = 0;
int is_priv;
DEBUGASSERT(ctx != NULL);
/* Check if key is private or public */
is_priv = esp32c3_mpi_cmp_int(&ctx->N, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->P, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->Q, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->D, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->E, 0) != 0;
if (!is_priv)
{
/* It can't try to export private parameters for a public key */
if (P != NULL || Q != NULL || D != NULL)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
}
if (N != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_write_binary(&ctx->N, N, NL), cleanup);
}
if (P != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_write_binary(&ctx->P, P, PL), cleanup);
}
if (Q != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_write_binary(&ctx->Q, Q, QL), cleanup);
}
if (D != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_write_binary(&ctx->D, D, DL), cleanup);
}
if (E != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_write_binary(&ctx->E, E, EL), cleanup);
}
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_rsa_export
*
* Description:
* Exports the core parameters of an RSA key.
*
* Input Parameters:
* ctx - The initialized RSA context
* N - The MPI to hold the RSA modulus
* P - The MPI to hold the first prime factor of \p N
* Q - The MPI to hold the second prime factor of \p N
* D - The MPI to hold the private exponent
* E - The MPI to hold the public exponent
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_export(const struct esp32c3_rsa_context_s *ctx,
struct esp32c3_mpi_s *N,
struct esp32c3_mpi_s *P,
struct esp32c3_mpi_s *Q,
struct esp32c3_mpi_s *D,
struct esp32c3_mpi_s *E)
{
int ret;
int is_priv;
DEBUGASSERT(ctx != NULL);
/* Check if key is private or public */
is_priv =
esp32c3_mpi_cmp_int(&ctx->N, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->P, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->Q, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->D, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->E, 0) != 0;
if (!is_priv)
{
/* It can't try to export private parameters for a public key */
if (P != NULL || Q != NULL || D != NULL)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
}
/* Export all requested core parameters. */
if ((N != NULL && (ret = esp32c3_mpi_copy(N, &ctx->N)) != 0) ||
(P != NULL && (ret = esp32c3_mpi_copy(P, &ctx->P)) != 0) ||
(Q != NULL && (ret = esp32c3_mpi_copy(Q, &ctx->Q)) != 0) ||
(D != NULL && (ret = esp32c3_mpi_copy(D, &ctx->D)) != 0) ||
(E != NULL && (ret = esp32c3_mpi_copy(E, &ctx->E)) != 0))
{
return ret;
}
return OK;
}
/****************************************************************************
* Name: esp32c3_rsa_export_crt
*
* Description:
* Exports CRT parameters of a private RSA key.
*
* Input Parameters:
* ctx - The initialized RSA context
* DP - The MPI to hold \c D modulo `P-1`
* DQ - The MPI to hold \c D modulo `Q-1`
* QP - The MPI to hold modular inverse of \c Q modulo \c P
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_export_crt(const struct esp32c3_rsa_context_s *ctx,
struct esp32c3_mpi_s *DP,
struct esp32c3_mpi_s *DQ,
struct esp32c3_mpi_s *QP)
{
int ret;
int is_priv;
DEBUGASSERT(ctx != NULL);
/* Check if key is private or public */
is_priv = esp32c3_mpi_cmp_int(&ctx->N, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->P, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->Q, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->D, 0) != 0 &&
esp32c3_mpi_cmp_int(&ctx->E, 0) != 0;
if (!is_priv)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
#if !defined(ESP32C3_RSA_NO_CRT)
/* Export all requested blinding parameters. */
if ((DP != NULL && (ret = esp32c3_mpi_copy(DP, &ctx->DP)) != 0) ||
(DQ != NULL && (ret = esp32c3_mpi_copy(DQ, &ctx->DQ)) != 0) ||
(QP != NULL && (ret = esp32c3_mpi_copy(QP, &ctx->QP)) != 0))
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA + ret);
}
#else
if ((ret = esp32c3_rsa_deduce_crt(&ctx->P, &ctx->Q, &ctx->D,
DP, DQ, QP)) != 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA + ret);
}
#endif
return OK;
}
/****************************************************************************
* Name: esp32c3_rsa_init
*
* Description:
* Initializes an RSA context
*
* Input Parameters:
* ctx - The RSA context to initialize
* padding - The padding mode to use
* hash_id - The hash identifier of
*
* Returned Value:
* None.
*
****************************************************************************/
void esp32c3_rsa_init(struct esp32c3_rsa_context_s *ctx,
int padding,
int hash_id)
{
DEBUGASSERT(ctx != NULL);
DEBUGASSERT(padding == ESP32C3_RSA_PKCS_V15 ||
padding == ESP32C3_RSA_PKCS_V21);
memset(ctx, 0, sizeof(struct esp32c3_rsa_context_s));
esp32c3_rsa_set_padding(ctx, padding, hash_id);
}
/****************************************************************************
* Name: esp32c3_rsa_set_padding
*
* Description:
* Sets padding for an already initialized RSA context.
*
* Input Parameters:
* ctx - The initialized RSA context to be configured
* padding - The padding mode to use
* hash_id - The hash identifier
*
* Returned Value:
* None.
*
****************************************************************************/
void esp32c3_rsa_set_padding(struct esp32c3_rsa_context_s *ctx,
int padding, int hash_id)
{
DEBUGASSERT(ctx != NULL);
DEBUGASSERT(padding == ESP32C3_RSA_PKCS_V15 ||
padding == ESP32C3_RSA_PKCS_V21);
ctx->padding = padding;
ctx->hash_id = hash_id;
}
/****************************************************************************
* Name: esp32c3_rsa_get_len
*
* Description:
* Exports CRT parameters of a private RSA key.
*
* Input Parameters:
* ctx - The initialized RSA context
*
* Returned Value:
* length of the RSA modulus in Bytes.
*
****************************************************************************/
size_t esp32c3_rsa_get_len(const struct esp32c3_rsa_context_s *ctx)
{
return (ctx->len);
}
/****************************************************************************
* Name: esp32c3_rsa_check_pubkey
*
* Description:
* checks if a context contains at least an RSA public key..
*
* Input Parameters:
* ctx - The initialized RSA context to check
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_check_pubkey(const struct esp32c3_rsa_context_s *ctx)
{
DEBUGASSERT(ctx != NULL);
if (rsa_check_context(ctx, 0 /* public */, 0 /* no blinding */) != 0)
{
return (ESP32C3_ERR_RSA_KEY_CHECK_FAILED);
}
if (esp32c3_mpi_bitlen(&ctx->N) < 128)
{
return (ESP32C3_ERR_RSA_KEY_CHECK_FAILED);
}
if (esp32c3_mpi_get_bit(&ctx->E, 0) == 0 ||
esp32c3_mpi_bitlen(&ctx->E) < 2 ||
esp32c3_mpi_cmp_mpi(&ctx->E, &ctx->N) >= 0)
{
return (ESP32C3_ERR_RSA_KEY_CHECK_FAILED);
}
return OK;
}
/****************************************************************************
* Name: esp32c3_rsa_check_privkey
*
* Description:
* Checks if a context contains at least an RSA private key
* and perform basic consistency checks.
*
* Input Parameters:
* ctx - The initialized RSA context to check
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_check_privkey(const struct esp32c3_rsa_context_s *ctx)
{
DEBUGASSERT(ctx != NULL);
if (esp32c3_rsa_check_pubkey(ctx) != 0 ||
rsa_check_context(ctx, 1 /* private */, 1 /* blinding */) != 0)
{
return (ESP32C3_ERR_RSA_KEY_CHECK_FAILED);
}
if (esp32c3_rsa_validate_params(&ctx->N, &ctx->P, &ctx->Q,
&ctx->D, &ctx->E, NULL, NULL) != 0)
{
return (ESP32C3_ERR_RSA_KEY_CHECK_FAILED);
}
#if !defined(ESP32C3_RSA_NO_CRT)
else if (esp32c3_rsa_validate_crt(&ctx->P, &ctx->Q, &ctx->D,
&ctx->DP, &ctx->DQ, &ctx->QP) != 0)
{
return (ESP32C3_ERR_RSA_KEY_CHECK_FAILED);
}
#endif
return OK;
}
/****************************************************************************
* Name: esp32c3_rsa_check_pub_priv
*
* Description:
* Checks a public-private RSA key pair. It checks each of the contexts,
* and makes sure they match.
*
* Input Parameters:
* pub - The initialized RSA context holding the public key
* prv - The initialized RSA context holding the private key
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_check_pub_priv(const struct esp32c3_rsa_context_s *pub,
const struct esp32c3_rsa_context_s *prv)
{
DEBUGASSERT(pub != NULL);
DEBUGASSERT(prv != NULL);
if (esp32c3_rsa_check_pubkey(pub) != 0 ||
esp32c3_rsa_check_privkey(prv) != 0)
{
return (ESP32C3_ERR_RSA_KEY_CHECK_FAILED);
}
if (esp32c3_mpi_cmp_mpi(&pub->N, &prv->N) != 0 ||
esp32c3_mpi_cmp_mpi(&pub->E, &prv->E) != 0)
{
return (ESP32C3_ERR_RSA_KEY_CHECK_FAILED);
}
return OK;
}
/****************************************************************************
* Name: esp32c3_rsa_public
*
* Description:
* Performs an RSA public key operation.
*
* Input Parameters:
* ctx - The initialized RSA context to use
* input - The input buffer
* output - The output buffer
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_public(struct esp32c3_rsa_context_s *ctx,
const unsigned char *input,
unsigned char *output)
{
int ret;
size_t olen;
struct esp32c3_mpi_s T;
DEBUGASSERT(ctx != NULL);
DEBUGASSERT(input != NULL);
DEBUGASSERT(output != NULL);
if (rsa_check_context(ctx, 0 /* public */, 0 /* no blinding */))
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
esp32c3_mpi_init(&T);
ESP32C3_MPI_CHK(esp32c3_mpi_read_binary(&T, input, ctx->len), cleanup);
if (esp32c3_mpi_cmp_mpi(&T, &ctx->N) >= 0)
{
ret = ESP32C3_ERR_MPI_BAD_INPUT_DATA;
goto cleanup;
}
olen = ctx->len;
ESP32C3_MPI_CHK(esp32c3_mpi_exp_mod(&T, &T, &ctx->E, &ctx->N, &ctx->RN),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_write_binary(&T, output, olen), cleanup);
cleanup:
esp32c3_mpi_free(&T);
if (ret != 0)
{
return (ESP32C3_ERR_RSA_PUBLIC_FAILED + ret);
}
return OK;
}
/****************************************************************************
* Name: esp32c3_rsa_private
*
* Description:
* Performs an RSA private key operation.
*
* Input Parameters:
* ctx - The initialized RSA context to use
* f_rng - The RNG function
* p_rng - The RNG context to pass to \p f_rng
* input - The input buffer
* output - The output buffer
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_private(struct esp32c3_rsa_context_s *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
const unsigned char *input,
unsigned char *output)
{
int ret;
size_t olen;
/* Temporary holding the result */
struct esp32c3_mpi_s T;
/* Temporaries holding P-1, Q-1 and the exponent blinding factor */
struct esp32c3_mpi_s P1, Q1, R;
#if !defined(ESP32C3_RSA_NO_CRT)
/* Temporaries holding the results mod p resp. mod q. */
struct esp32c3_mpi_s TP, TQ;
/* Temporaries holding the blinded exponents */
struct esp32c3_mpi_s dp_blind, dq_blind;
/* Pointers to actual exponents to be used */
struct esp32c3_mpi_s *DP = &ctx->DP;
struct esp32c3_mpi_s *DQ = &ctx->DQ;
#else
/* Temporary holding the blinded exponent */
struct esp32c3_mpi_s d_blind;
/* Pointer to actual exponent to be used */
struct esp32c3_mpi_s *D = &ctx->D;
#endif /* ESP32C3_RSA_NO_CRT */
/* Temporaries holding the initial input */
struct esp32c3_mpi_s I, C;
DEBUGASSERT(ctx != NULL);
DEBUGASSERT(input != NULL);
DEBUGASSERT(output != NULL);
if (rsa_check_context(ctx, 1, f_rng != NULL) != 0)
{
return (ESP32C3_ERR_RSA_BAD_INPUT_DATA);
}
/* MPI Initialization */
esp32c3_mpi_init(&T);
esp32c3_mpi_init(&P1);
esp32c3_mpi_init(&Q1);
esp32c3_mpi_init(&R);
if (f_rng != NULL)
{
#if defined(ESP32C3_RSA_NO_CRT)
esp32c3_mpi_init(&d_blind);
#else
esp32c3_mpi_init(&dp_blind);
esp32c3_mpi_init(&dq_blind);
#endif
}
#if !defined(ESP32C3_RSA_NO_CRT)
esp32c3_mpi_init(&TP); esp32c3_mpi_init(&TQ);
#endif
esp32c3_mpi_init(&I);
esp32c3_mpi_init(&C);
/* End of MPI initialization */
ESP32C3_MPI_CHK(esp32c3_mpi_read_binary(&T, input, ctx->len), cleanup);
if (esp32c3_mpi_cmp_mpi(&T, &ctx->N) >= 0)
{
ret = ESP32C3_ERR_MPI_BAD_INPUT_DATA;
goto cleanup;
}
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&I, &T), cleanup);
if (f_rng != NULL)
{
/* Blinding T = T * VI mod N */
ESP32C3_MPI_CHK(rsa_prepare_blinding(ctx, f_rng, p_rng), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&T, &T, &ctx->VI), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&T, &T, &ctx->N), cleanup);
/* Exponent blinding */
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&P1, &ctx->P, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(&Q1, &ctx->Q, 1), cleanup);
#if defined(ESP32C3_RSA_NO_CRT)
/* d_blind = (P - 1) * (Q - 1) * R + D */
ESP32C3_MPI_CHK(esp32c3_mpi_fill_random(&R, RSA_EXPONENT_BLINDING,
f_rng, p_rng), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&d_blind, &P1, &Q1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&d_blind, &d_blind, &R), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(&d_blind, &d_blind, &ctx->D),
cleanup);
D = &d_blind;
#else
/* dp_blind = (P - 1) * R + DP */
ESP32C3_MPI_CHK(esp32c3_mpi_fill_random(&R, RSA_EXPONENT_BLINDING,
f_rng, p_rng), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&dp_blind, &P1, &R), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(&dp_blind, &dp_blind,
&ctx->DP), cleanup);
DP = &dp_blind;
/* dq_blind = (Q - 1) * R + DQ */
ESP32C3_MPI_CHK(esp32c3_mpi_fill_random(&R, RSA_EXPONENT_BLINDING,
f_rng, p_rng), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&dq_blind, &Q1, &R), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(&dq_blind, &dq_blind,
&ctx->DQ), cleanup);
DQ = &dq_blind;
#endif /* ESP32C3_RSA_NO_CRT */
}
#if defined(ESP32C3_RSA_NO_CRT)
ESP32C3_MPI_CHK(esp32c3_mpi_exp_mod(&T, &T, D, &ctx->N, &ctx->RN),
cleanup);
#else
/* TP = input ^ dP mod P and TQ = input ^ dQ mod Q */
ESP32C3_MPI_CHK(esp32c3_mpi_exp_mod(&TP, &T, DP, &ctx->P, &ctx->RP),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_exp_mod(&TQ, &T, DQ, &ctx->Q, &ctx->RQ),
cleanup);
/* T = (TP - TQ) * (Q^-1 mod P) mod P */
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&T, &TP, &TQ), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&TP, &T, &ctx->QP), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&T, &TP, &ctx->P), cleanup);
/* T = TQ + T * Q */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&TP, &T, &ctx->Q), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(&T, &TQ, &TP), cleanup);
#endif /* ESP32C3_RSA_NO_CRT */
if (f_rng != NULL)
{
/* Unblind T = T * VF mod N */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&T, &T, &ctx->VF), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&T, &T, &ctx->N), cleanup);
}
/* Verify the result to prevent glitching attacks. */
ESP32C3_MPI_CHK(esp32c3_mpi_exp_mod(&C, &T, &ctx->E,
&ctx->N, &ctx->RN), cleanup);
if (esp32c3_mpi_cmp_mpi(&C, &I) != 0)
{
ret = ESP32C3_ERR_RSA_VERIFY_FAILED;
goto cleanup;
}
olen = ctx->len;
ESP32C3_MPI_CHK(esp32c3_mpi_write_binary(&T, output, olen), cleanup);
cleanup:
esp32c3_mpi_free(&P1);
esp32c3_mpi_free(&Q1);
esp32c3_mpi_free(&R);
if (f_rng != NULL)
{
#if defined(ESP32C3_RSA_NO_CRT)
esp32c3_mpi_free(&d_blind);
#else
esp32c3_mpi_free(&dp_blind);
esp32c3_mpi_free(&dq_blind);
#endif
}
esp32c3_mpi_free(&T);
#if !defined(ESP32C3_RSA_NO_CRT)
esp32c3_mpi_free(&TP); esp32c3_mpi_free(&TQ);
#endif
esp32c3_mpi_free(&C);
esp32c3_mpi_free(&I);
if (ret != 0)
{
return (ESP32C3_ERR_RSA_PRIVATE_FAILED + ret);
}
return OK;
}
/****************************************************************************
* Name: esp32c3_rsa_encrypt
*
* Description:
* Adds the message padding, then performs an RSA operation. It is the
* generic wrapper for performing a PKCS#1 encryption operation using the
* \p mode from the context.
*
* Input Parameters:
* ctx - The initialized RSA context to use
* f_rng - The RNG to use
* p_rng - The RNG context to be passed to \p f_rng
* mode - The mode of operation
* ilen - The length of the plaintext in Bytes
* input - The input data to encrypt
* output - The output buffer
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_encrypt(struct esp32c3_rsa_context_s *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode, size_t ilen,
const unsigned char *input,
unsigned char *output)
{
DEBUGASSERT(ctx != NULL);
DEBUGASSERT(mode == ESP32C3_RSA_PRIVATE ||
mode == ESP32C3_RSA_PUBLIC);
DEBUGASSERT(output != NULL);
DEBUGASSERT(input != NULL);
switch (ctx->padding)
{
#if defined(ESP32C3_PKCS1_V15)
case ESP32C3_RSA_PKCS_V15:
return esp32c3_rsa_pkcs1_v15_encrypt(ctx, f_rng, p_rng, mode, ilen,
input, output);
#endif
default:
return (ESP32C3_ERR_RSA_INVALID_PADDING);
}
}
/****************************************************************************
* Name: esp32c3_rsa_decrypt
*
* Description:
* Performs an RSA operation, then removes the message padding.
*
* Input Parameters:
* ctx - The initialized RSA context to use
* f_rng - The RNG function
* p_rng - The RNG context to be passed to \p f_rng
* mode - The mode of operation
* olen - The point which to store the length of the plaintext
* input - The ciphertext buffer
* output - The buffer used to hold the plaintext
* output_max_len - The length in Bytes of the output buffer \p output
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_decrypt(struct esp32c3_rsa_context_s *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode, size_t *olen,
const unsigned char *input,
unsigned char *output,
size_t output_max_len)
{
DEBUGASSERT(ctx != NULL);
DEBUGASSERT(mode == ESP32C3_RSA_PRIVATE ||
mode == ESP32C3_RSA_PUBLIC);
DEBUGASSERT(output_max_len == 0 || output != NULL);
DEBUGASSERT(input != NULL);
DEBUGASSERT(olen != NULL);
switch (ctx->padding)
{
#if defined(ESP32C3_PKCS1_V15)
case ESP32C3_RSA_PKCS_V15:
return esp32c3_rsa_pkcs1_v15_decrypt(ctx, f_rng, p_rng, mode, olen,
input, output, output_max_len);
#endif
default:
return (ESP32C3_ERR_RSA_INVALID_PADDING);
}
}
/****************************************************************************
* Name: esp32c3_rsa_copy
*
* Description:
* Copies the components of an RSA context.
*
* Input Parameters:
* dst - The destination context
* src - The source context
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_rsa_copy(struct esp32c3_rsa_context_s *dst,
const struct esp32c3_rsa_context_s *src)
{
int ret;
DEBUGASSERT(dst != NULL);
DEBUGASSERT(src != NULL);
dst->ver = src->ver;
dst->len = src->len;
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->N, &src->N), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->E, &src->E), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->D, &src->D), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->P, &src->P), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->Q, &src->Q), cleanup);
#if !defined(ESP32C3_RSA_NO_CRT)
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->DP, &src->DP), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->DQ, &src->DQ), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->QP, &src->QP), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->RP, &src->RP), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->RQ, &src->RQ), cleanup);
#endif
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->RN, &src->RN), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->VI, &src->VI), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&dst->VF, &src->VF), cleanup);
dst->padding = src->padding;
dst->hash_id = src->hash_id;
cleanup:
if (ret != 0)
{
esp32c3_rsa_free(dst);
}
return ret;
}
/****************************************************************************
* Name: esp32c3_rsa_free
*
* Description:
* Frees the components of an RSA key.
*
* Input Parameters:
* ctx - The RSA context to free
*
* Returned Value:
* None.
*
****************************************************************************/
void esp32c3_rsa_free(struct esp32c3_rsa_context_s *ctx)
{
if (ctx == NULL)
{
return;
}
esp32c3_mpi_free(&ctx->VI);
esp32c3_mpi_free(&ctx->VF);
esp32c3_mpi_free(&ctx->RN);
esp32c3_mpi_free(&ctx->D);
esp32c3_mpi_free(&ctx->Q);
esp32c3_mpi_free(&ctx->P);
esp32c3_mpi_free(&ctx->E);
esp32c3_mpi_free(&ctx->N);
#if !defined(ESP32C3_RSA_NO_CRT)
esp32c3_mpi_free(&ctx->RQ);
esp32c3_mpi_free(&ctx->RP);
esp32c3_mpi_free(&ctx->QP);
esp32c3_mpi_free(&ctx->DQ);
esp32c3_mpi_free(&ctx->DP);
#endif /* ESP32C3_RSA_NO_CRT */
}
#endif