mirror of
https://github.com/yuzu-emu/mbedtls
synced 2024-11-24 11:58:15 +00:00
a0b67c2f3e
When using a primality testing function the tolerable error rate depends on the scheme in question, the required security strength and wether it is used for key generation or parameter validation. To support all use cases we need more flexibility than what the old API provides.
492 lines
14 KiB
C
492 lines
14 KiB
C
/*
|
|
* Helper functions for the RSA module
|
|
*
|
|
* Copyright (C) 2006-2017, 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.
|
|
*
|
|
* This file is part of mbed TLS (https://tls.mbed.org)
|
|
*
|
|
*/
|
|
|
|
#if !defined(MBEDTLS_CONFIG_FILE)
|
|
#include "mbedtls/config.h"
|
|
#else
|
|
#include MBEDTLS_CONFIG_FILE
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_RSA_C)
|
|
|
|
#include "mbedtls/rsa.h"
|
|
#include "mbedtls/bignum.h"
|
|
#include "mbedtls/rsa_internal.h"
|
|
|
|
/*
|
|
* Compute RSA prime factors from public and private exponents
|
|
*
|
|
* Summary of algorithm:
|
|
* Setting F := lcm(P-1,Q-1), the idea is as follows:
|
|
*
|
|
* (a) For any 1 <= X < N with gcd(X,N)=1, we have X^F = 1 modulo N, so X^(F/2)
|
|
* is a square root of 1 in Z/NZ. Since Z/NZ ~= Z/PZ x Z/QZ by CRT and the
|
|
* square roots of 1 in Z/PZ and Z/QZ are +1 and -1, this leaves the four
|
|
* possibilities X^(F/2) = (+-1, +-1). If it happens that X^(F/2) = (-1,+1)
|
|
* or (+1,-1), then gcd(X^(F/2) + 1, N) will be equal to one of the prime
|
|
* factors of N.
|
|
*
|
|
* (b) If we don't know F/2 but (F/2) * K for some odd (!) K, then the same
|
|
* construction still applies since (-)^K is the identity on the set of
|
|
* roots of 1 in Z/NZ.
|
|
*
|
|
* The public and private key primitives (-)^E and (-)^D are mutually inverse
|
|
* bijections on Z/NZ if and only if (-)^(DE) is the identity on Z/NZ, i.e.
|
|
* if and only if DE - 1 is a multiple of F, say DE - 1 = F * L.
|
|
* Splitting L = 2^t * K with K odd, we have
|
|
*
|
|
* DE - 1 = FL = (F/2) * (2^(t+1)) * K,
|
|
*
|
|
* so (F / 2) * K is among the numbers
|
|
*
|
|
* (DE - 1) >> 1, (DE - 1) >> 2, ..., (DE - 1) >> ord
|
|
*
|
|
* where ord is the order of 2 in (DE - 1).
|
|
* We can therefore iterate through these numbers apply the construction
|
|
* of (a) and (b) above to attempt to factor N.
|
|
*
|
|
*/
|
|
int mbedtls_rsa_deduce_primes( mbedtls_mpi const *N,
|
|
mbedtls_mpi const *E, mbedtls_mpi const *D,
|
|
mbedtls_mpi *P, mbedtls_mpi *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 */
|
|
|
|
mbedtls_mpi T; /* Holds largest odd divisor of DE - 1 */
|
|
mbedtls_mpi 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( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
|
|
|
|
if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 ||
|
|
mbedtls_mpi_cmp_int( D, 1 ) <= 0 ||
|
|
mbedtls_mpi_cmp_mpi( D, N ) >= 0 ||
|
|
mbedtls_mpi_cmp_int( E, 1 ) <= 0 ||
|
|
mbedtls_mpi_cmp_mpi( E, N ) >= 0 )
|
|
{
|
|
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
|
|
}
|
|
|
|
/*
|
|
* Initializations and temporary changes
|
|
*/
|
|
|
|
mbedtls_mpi_init( &K );
|
|
mbedtls_mpi_init( &T );
|
|
|
|
/* T := DE - 1 */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, D, E ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &T, &T, 1 ) );
|
|
|
|
if( ( order = (uint16_t) mbedtls_mpi_lsb( &T ) ) == 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* After this operation, T holds the largest odd divisor of DE - 1. */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &T, order ) );
|
|
|
|
/*
|
|
* Actual work
|
|
*/
|
|
|
|
/* Skip trying 2 if N == 1 mod 8 */
|
|
attempt = 0;
|
|
if( N->p[0] % 8 == 1 )
|
|
attempt = 1;
|
|
|
|
for( ; attempt < num_primes; ++attempt )
|
|
{
|
|
mbedtls_mpi_lset( &K, primes[attempt] );
|
|
|
|
/* Check if gcd(K,N) = 1 */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( P, &K, N ) );
|
|
if( mbedtls_mpi_cmp_int( P, 1 ) != 0 )
|
|
continue;
|
|
|
|
/* Go through K^T + 1, K^(2T) + 1, K^(4T) + 1, ...
|
|
* and check whether they have nontrivial GCD with N. */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &K, &K, &T, N,
|
|
Q /* temporarily use Q for storing Montgomery
|
|
* multiplication helper values */ ) );
|
|
|
|
for( iter = 1; iter <= order; ++iter )
|
|
{
|
|
/* If we reach 1 prematurely, there's no point
|
|
* in continuing to square K */
|
|
if( mbedtls_mpi_cmp_int( &K, 1 ) == 0 )
|
|
break;
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &K, &K, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( P, &K, N ) );
|
|
|
|
if( mbedtls_mpi_cmp_int( P, 1 ) == 1 &&
|
|
mbedtls_mpi_cmp_mpi( P, N ) == -1 )
|
|
{
|
|
/*
|
|
* Have found a nontrivial divisor P of N.
|
|
* Set Q := N / P.
|
|
*/
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( Q, NULL, N, P ) );
|
|
goto cleanup;
|
|
}
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, &K, &K ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, N ) );
|
|
}
|
|
|
|
/*
|
|
* If we get here, then either we prematurely aborted the loop because
|
|
* we reached 1, or K holds primes[attempt]^(DE - 1) mod N, which must
|
|
* be 1 if D,E,N were consistent.
|
|
* Check if that's the case and abort if not, to avoid very long,
|
|
* yet eventually failing, computations if N,D,E were not sane.
|
|
*/
|
|
if( mbedtls_mpi_cmp_int( &K, 1 ) != 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
|
|
|
|
cleanup:
|
|
|
|
mbedtls_mpi_free( &K );
|
|
mbedtls_mpi_free( &T );
|
|
return( ret );
|
|
}
|
|
|
|
/*
|
|
* Given P, Q and the public exponent E, deduce D.
|
|
* This is essentially a modular inversion.
|
|
*/
|
|
int mbedtls_rsa_deduce_private_exponent( mbedtls_mpi const *P,
|
|
mbedtls_mpi const *Q,
|
|
mbedtls_mpi const *E,
|
|
mbedtls_mpi *D )
|
|
{
|
|
int ret = 0;
|
|
mbedtls_mpi K, L;
|
|
|
|
if( D == NULL || mbedtls_mpi_cmp_int( D, 0 ) != 0 )
|
|
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
|
|
|
|
if( mbedtls_mpi_cmp_int( P, 1 ) <= 0 ||
|
|
mbedtls_mpi_cmp_int( Q, 1 ) <= 0 ||
|
|
mbedtls_mpi_cmp_int( E, 0 ) == 0 )
|
|
{
|
|
return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
|
|
}
|
|
|
|
mbedtls_mpi_init( &K );
|
|
mbedtls_mpi_init( &L );
|
|
|
|
/* Temporarily put K := P-1 and L := Q-1 */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, Q, 1 ) );
|
|
|
|
/* Temporarily put D := gcd(P-1, Q-1) */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( D, &K, &L ) );
|
|
|
|
/* K := LCM(P-1, Q-1) */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, &K, &L ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &K, NULL, &K, D ) );
|
|
|
|
/* Compute modular inverse of E in LCM(P-1, Q-1) */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( D, E, &K ) );
|
|
|
|
cleanup:
|
|
|
|
mbedtls_mpi_free( &K );
|
|
mbedtls_mpi_free( &L );
|
|
|
|
return( ret );
|
|
}
|
|
|
|
/*
|
|
* Check that RSA CRT parameters are in accordance with core parameters.
|
|
*/
|
|
int mbedtls_rsa_validate_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q,
|
|
const mbedtls_mpi *D, const mbedtls_mpi *DP,
|
|
const mbedtls_mpi *DQ, const mbedtls_mpi *QP )
|
|
{
|
|
int ret = 0;
|
|
|
|
mbedtls_mpi K, L;
|
|
mbedtls_mpi_init( &K );
|
|
mbedtls_mpi_init( &L );
|
|
|
|
/* Check that DP - D == 0 mod P - 1 */
|
|
if( DP != NULL )
|
|
{
|
|
if( P == NULL )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
|
|
goto cleanup;
|
|
}
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &L, DP, D ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &L, &L, &K ) );
|
|
|
|
if( mbedtls_mpi_cmp_int( &L, 0 ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
/* Check that DQ - D == 0 mod Q - 1 */
|
|
if( DQ != NULL )
|
|
{
|
|
if( Q == NULL )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
|
|
goto cleanup;
|
|
}
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, Q, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &L, DQ, D ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &L, &L, &K ) );
|
|
|
|
if( mbedtls_mpi_cmp_int( &L, 0 ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
/* Check that QP * Q - 1 == 0 mod P */
|
|
if( QP != NULL )
|
|
{
|
|
if( P == NULL || Q == NULL )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
|
|
goto cleanup;
|
|
}
|
|
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, QP, Q ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, P ) );
|
|
if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
/* Wrap MPI error codes by RSA check failure error code */
|
|
if( ret != 0 &&
|
|
ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED &&
|
|
ret != MBEDTLS_ERR_RSA_BAD_INPUT_DATA )
|
|
{
|
|
ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
}
|
|
|
|
mbedtls_mpi_free( &K );
|
|
mbedtls_mpi_free( &L );
|
|
|
|
return( ret );
|
|
}
|
|
|
|
/*
|
|
* Check that core RSA parameters are sane.
|
|
*/
|
|
int mbedtls_rsa_validate_params( const mbedtls_mpi *N, const mbedtls_mpi *P,
|
|
const mbedtls_mpi *Q, const mbedtls_mpi *D,
|
|
const mbedtls_mpi *E,
|
|
int (*f_rng)(void *, unsigned char *, size_t),
|
|
void *p_rng )
|
|
{
|
|
int ret = 0;
|
|
mbedtls_mpi K, L;
|
|
|
|
mbedtls_mpi_init( &K );
|
|
mbedtls_mpi_init( &L );
|
|
|
|
/*
|
|
* Step 1: If PRNG provided, check that P and Q are prime
|
|
*/
|
|
|
|
#if defined(MBEDTLS_GENPRIME)
|
|
/*
|
|
* When generating keys, the strongest security we support aims for an error
|
|
* rate of at most 2^-100 and we are aiming for the same certainty here as
|
|
* well.
|
|
*/
|
|
if( f_rng != NULL && P != NULL &&
|
|
( ret = mbedtls_mpi_is_prime_ext( P, 50, f_rng, p_rng ) ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( f_rng != NULL && Q != NULL &&
|
|
( ret = mbedtls_mpi_is_prime_ext( Q, 50, f_rng, p_rng ) ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
#else
|
|
((void) f_rng);
|
|
((void) p_rng);
|
|
#endif /* MBEDTLS_GENPRIME */
|
|
|
|
/*
|
|
* Step 2: Check that 1 < N = P * Q
|
|
*/
|
|
|
|
if( P != NULL && Q != NULL && N != NULL )
|
|
{
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, P, Q ) );
|
|
if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 ||
|
|
mbedtls_mpi_cmp_mpi( &K, N ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Step 3: Check and 1 < D, E < N if present.
|
|
*/
|
|
|
|
if( N != NULL && D != NULL && E != NULL )
|
|
{
|
|
if ( mbedtls_mpi_cmp_int( D, 1 ) <= 0 ||
|
|
mbedtls_mpi_cmp_int( E, 1 ) <= 0 ||
|
|
mbedtls_mpi_cmp_mpi( D, N ) >= 0 ||
|
|
mbedtls_mpi_cmp_mpi( E, N ) >= 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Step 4: Check that D, E are inverse modulo P-1 and Q-1
|
|
*/
|
|
|
|
if( P != NULL && Q != NULL && D != NULL && E != NULL )
|
|
{
|
|
if( mbedtls_mpi_cmp_int( P, 1 ) <= 0 ||
|
|
mbedtls_mpi_cmp_int( Q, 1 ) <= 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Compute DE-1 mod P-1 */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, D, E ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, P, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, &L ) );
|
|
if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Compute DE-1 mod Q-1 */
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, D, E ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, Q, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, &L ) );
|
|
if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 )
|
|
{
|
|
ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
mbedtls_mpi_free( &K );
|
|
mbedtls_mpi_free( &L );
|
|
|
|
/* Wrap MPI error codes by RSA check failure error code */
|
|
if( ret != 0 && ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED )
|
|
{
|
|
ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
|
|
}
|
|
|
|
return( ret );
|
|
}
|
|
|
|
int mbedtls_rsa_deduce_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q,
|
|
const mbedtls_mpi *D, mbedtls_mpi *DP,
|
|
mbedtls_mpi *DQ, mbedtls_mpi *QP )
|
|
{
|
|
int ret = 0;
|
|
mbedtls_mpi K;
|
|
mbedtls_mpi_init( &K );
|
|
|
|
/* DP = D mod P-1 */
|
|
if( DP != NULL )
|
|
{
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( DP, D, &K ) );
|
|
}
|
|
|
|
/* DQ = D mod Q-1 */
|
|
if( DQ != NULL )
|
|
{
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, Q, 1 ) );
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( DQ, D, &K ) );
|
|
}
|
|
|
|
/* QP = Q^{-1} mod P */
|
|
if( QP != NULL )
|
|
{
|
|
MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( QP, Q, P ) );
|
|
}
|
|
|
|
cleanup:
|
|
mbedtls_mpi_free( &K );
|
|
|
|
return( ret );
|
|
}
|
|
|
|
#endif /* MBEDTLS_RSA_C */
|