📄 kg_rsa.c
字号:
/****************************************************************************
* *
* cryptlib RSA Key Generation/Checking Routines *
* Copyright Peter Gutmann 1997-2004 *
* *
****************************************************************************/
#include <stdlib.h>
#define PKC_CONTEXT /* Indicate that we're working with PKC context */
#if defined( INC_ALL )
#include "crypt.h"
#include "context.h"
#include "keygen.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "context.h"
#include "keygen.h"
#else
#include "crypt.h"
#include "context/context.h"
#include "context/keygen.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Generate an RSA Key *
* *
****************************************************************************/
/* We use F4 as the default public exponent e unless the user chooses to
override this with some other value. The older (X.509v1) recommended
value of 3 is insecure for general use and more recent work indicates that
values like 17 (used by PGP) are also insecure against the Hastad attack.
We could work around this by using 41 or 257 as the exponent, however
current best practice favours F4 unless you're doing banking standards, in
which case you set e=2 (EMV) and use raw, unpadded RSA (HBCI) to make it
easier for students to break your banking security as a homework exercise.
Since some systems may be using 16-bit bignum component values, we use an
exponent of 257 for these cases to ensure that it fits in a single
component value */
#ifndef RSA_PUBLIC_EXPONENT
#ifdef SIXTEEN_BIT
#define RSA_PUBLIC_EXPONENT 257
#else
#define RSA_PUBLIC_EXPONENT 65537L
#endif /* 16-bit bignum components */
#endif /* RSA_PUBLIC_EXPONENT */
/* Adjust p and q if necessary to ensure that the CRT decrypt works */
static int fixCRTvalues( PKC_INFO *pkcInfo, const BOOLEAN fixPKCSvalues )
{
BIGNUM *p = &pkcInfo->rsaParam_p, *q = &pkcInfo->rsaParam_q;
/* Make sure that p > q, which is required for the CRT decrypt */
if( BN_cmp( p, q ) >= 0 )
return( CRYPT_OK );
/* Swap the values p and q and, if necessary, the PKCS parameters e1
and e2 that depend on them (e1 = d mod (p - 1) and
e2 = d mod (q - 1)), and recompute u = qInv mod p */
BN_swap( p, q );
if( !fixPKCSvalues )
return( CRYPT_OK );
BN_swap( &pkcInfo->rsaParam_exponent1, &pkcInfo->rsaParam_exponent2 );
return( BN_mod_inverse( &pkcInfo->rsaParam_u, q, p,
pkcInfo->bnCTX ) != NULL ? \
CRYPT_OK : CRYPT_ERROR_FAILED );
}
/* Evaluate the Montgomery forms for public and private components */
static int getRSAMontgomery( PKC_INFO *pkcInfo, const BOOLEAN isPublicKey )
{
/* Evaluate the public value */
if( !BN_MONT_CTX_set( &pkcInfo->rsaParam_mont_n, &pkcInfo->rsaParam_n,
pkcInfo->bnCTX ) )
return( CRYPT_ERROR_FAILED );
if( isPublicKey )
return( CRYPT_OK );
/* Evaluate the private values */
return( BN_MONT_CTX_set( &pkcInfo->rsaParam_mont_p, &pkcInfo->rsaParam_p,
pkcInfo->bnCTX ) && \
BN_MONT_CTX_set( &pkcInfo->rsaParam_mont_q, &pkcInfo->rsaParam_q,
pkcInfo->bnCTX ) ? \
CRYPT_OK : CRYPT_ERROR_FAILED );
}
/* Generate an RSA key pair into an encryption context */
int generateRSAkey( CONTEXT_INFO *contextInfoPtr, const int keySizeBits )
{
PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
BIGNUM *d = &pkcInfo->rsaParam_d, *p = &pkcInfo->rsaParam_p;
BIGNUM *q = &pkcInfo->rsaParam_q;
BIGNUM *tmp = &pkcInfo->tmp1;
int pBits, qBits, bnStatus = BN_STATUS, status;
/* Determine how many bits to give to each of p and q */
pBits = ( keySizeBits + 1 ) / 2;
qBits = keySizeBits - pBits;
pkcInfo->keySizeBits = pBits + qBits;
/* Generate the primes p and q and set them up so that the CRT decrypt
will work */
BN_set_word( &pkcInfo->rsaParam_e, RSA_PUBLIC_EXPONENT );
status = generatePrime( pkcInfo, p, pBits, RSA_PUBLIC_EXPONENT,
contextInfoPtr );
if( cryptStatusOK( status ) )
status = generatePrime( pkcInfo, q, qBits, RSA_PUBLIC_EXPONENT,
contextInfoPtr );
if( cryptStatusOK( status ) )
status = fixCRTvalues( pkcInfo, FALSE );
if( cryptStatusError( status ) )
return( status );
/* Compute d = eInv mod (p - 1)(q - 1), e1 = d mod (p - 1), and
e2 = d mod (q - 1) */
CK( BN_sub_word( p, 1 ) );
CK( BN_sub_word( q, 1 ) );
CK( BN_mul( tmp, p, q, pkcInfo->bnCTX ) );
CKPTR( BN_mod_inverse( d, &pkcInfo->rsaParam_e, tmp, pkcInfo->bnCTX ) );
CK( BN_mod( &pkcInfo->rsaParam_exponent1, d,
p, pkcInfo->bnCTX ) );
CK( BN_mod( &pkcInfo->rsaParam_exponent2, d, q, pkcInfo->bnCTX ) );
CK( BN_add_word( p, 1 ) );
CK( BN_add_word( q, 1 ) );
if( bnStatusError( bnStatus ) )
return( getBnStatus( bnStatus ) );
/* Compute n = pq, and u = qInv mod p */
CK( BN_mul( &pkcInfo->rsaParam_n, p, q, pkcInfo->bnCTX ) );
CKPTR( BN_mod_inverse( &pkcInfo->rsaParam_u, q, p, pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) )
return( getBnStatus( bnStatus ) );
/* Evaluate the Montgomery forms */
return( getRSAMontgomery( pkcInfo, FALSE ) );
}
/****************************************************************************
* *
* Initialise/Check an RSA Key *
* *
****************************************************************************/
/* Perform validity checks on the private key. We have to make the PKC_INFO
data non-const because the bignum code wants to modify some of the values
as it's working with them */
static BOOLEAN checkRSAPrivateKeyComponents( PKC_INFO *pkcInfo )
{
BIGNUM *n = &pkcInfo->rsaParam_n, *e = &pkcInfo->rsaParam_e;
BIGNUM *d = &pkcInfo->rsaParam_d, *p = &pkcInfo->rsaParam_p;
BIGNUM *q = &pkcInfo->rsaParam_q;
BIGNUM *p1 = &pkcInfo->tmp1, *q1 = &pkcInfo->tmp2, *tmp = &pkcInfo->tmp3;
const BN_ULONG eWord = BN_get_word( e );
int bnStatus = BN_STATUS;
/* Calculate p - 1, q - 1 */
CKPTR( BN_copy( p1, p ) );
CK( BN_sub_word( p1, 1 ) );
CKPTR( BN_copy( q1, q ) );
CK( BN_sub_word( q1, 1 ) );
if( bnStatusError( bnStatus ) )
return( FALSE );
/* Verify that n = p * q */
CK( BN_mul( tmp, p, q, pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) || BN_cmp( n, tmp ) != 0 )
return( FALSE );
/* Verify that ( d * e ) mod p-1 == 1 and ( d * e ) mod q-1 == 1. Some
implementations don't store d since it's not needed when the CRT
shortcut is used, so we can only perform this check if d is present */
if( !BN_is_zero( d ) )
{
CK( BN_mod_mul( tmp, d, e, p1, pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) || !BN_is_one( tmp ) )
return( FALSE );
CK( BN_mod_mul( tmp, d, e, q1, pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) || !BN_is_one( tmp ) )
return( FALSE );
}
/* Verify that ( q * u ) mod p == 1 */
CK( BN_mod_mul( tmp, q, &pkcInfo->rsaParam_u, p, pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) || !BN_is_one( tmp ) )
return( FALSE );
/* A very small number of systems/compilers can't handle 32 * 32 -> 64
ops, which means that we have to use 16-bit bignum components. For
the common case where e = F4, the value won't fit into a bignum
component, so we have to use the full BN_mod() form of the checks
that are carried out further on */
#ifdef SIXTEEN_BIT
CK( BN_mod( tmp, p1, e, pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) || BN_is_zero( tmp ) )
return( FALSE );
CK( BN_mod( tmp, q1, e, pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) || BN_is_zero( tmp ) )
return( FALSE );
return( TRUE );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -