📄 lib_rsa.c
字号:
for( i = 0; i < length; i++ )
if( buffer[ i ] )
break;
if( length - i < 56 )
return( CRYPT_ERROR_BADDATA );
if( ( bnCTX = BN_CTX_new() ) == NULL )
return( CRYPT_ERROR_MEMORY );
/* Move the data from the buffer into a bignum, perform the modexp, and
move the result back into the buffer. Since the bignum code performs
leading-zero truncation, we have to adjust where we copy the result to
in the buffer to take into account extra zero bytes which aren't
extracted from the bignum */
n = BN_new();
BN_bin2bn( buffer, length, n );
zeroise( buffer, length ); /* Clear buffer while data is in bignum */
BN_mod_exp_mont( n, n, cryptInfo->ctxPKC.rsaParam_e,
cryptInfo->ctxPKC.rsaParam_n, bnCTX,
cryptInfo->ctxPKC.rsaParam_mont_n );
BN_bn2bin( n, buffer + ( length - BN_num_bytes( n ) ) );
BN_clear_free( n );
BN_CTX_free( bnCTX );
return( ( status == -1 ) ? CRYPT_ERROR_FAILED : status );
}
/* Use the Chinese Remainder Theorem shortcut for RSA decryption/signature
generation. M is the output plaintext message, C is the input ciphertext
message, d is the secret decryption exponent, p and q are the prime
factors of n, u is the multiplicative inverse of q, mod p. n, the common
modulus, is not used because of the Chinese Remainder Theorem shortcut */
int rsaDecrypt( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
{
BN_CTX *bnCTX;
BIGNUM *p = cryptInfo->ctxPKC.rsaParam_p;
BIGNUM *q = cryptInfo->ctxPKC.rsaParam_q;
BIGNUM *u = cryptInfo->ctxPKC.rsaParam_u;
BIGNUM *e1 = cryptInfo->ctxPKC.rsaParam_exponent1;
BIGNUM *e2 = cryptInfo->ctxPKC.rsaParam_exponent2;
BIGNUM *data, *p2, *q2;
const int length = bitsToBytes( cryptInfo->ctxPKC.keySizeBits );
int i, status = 0;
assert( noBytes == length );
/* Make sure we're not being fed suspiciously short data quantities */
for( i = 0; i < length; i++ )
if( buffer[ i ] )
break;
if( length - i < 56 )
return( CRYPT_ERROR_BADDATA );
if( ( bnCTX = BN_CTX_new() ) == NULL )
return( CRYPT_ERROR_MEMORY );
/* Initialise the bignums */
p2 = BN_new();
q2 = BN_new();
data = BN_new();
BN_bin2bn( buffer, length, data );
zeroise( buffer, length ); /* Clear buffer while data is in bignum */
/* Rather than decrypting by computing modexp with full mod n precision,
compute a shorter modexp with mod p and mod q precision:
p2 = ( ( C mod p ) ** exponent1 ) mod p
q2 = ( ( C mod q ) ** exponent2 ) mod q */
BN_mod( p2, data, p, bnCTX ); /* p2 = C mod p */
BN_mod_exp_mont( p2, p2, e1, p, bnCTX, cryptInfo->ctxPKC.rsaParam_mont_p );
BN_mod( q2, data, q, bnCTX ); /* q2 = C mod q */
BN_mod_exp_mont( q2, q2, e2, q, bnCTX, cryptInfo->ctxPKC.rsaParam_mont_q );
/* p2 = p2 - q2; if p2 < 0 then p2 = p2 + p */
BN_sub( p2, p2, q2 );
if( p2->neg )
BN_add( p2, p2, p );
/* M = ( ( ( p2 * u ) mod p ) * q ) + q2 */
BN_mod_mul( data, p2, u, p, bnCTX );/* data = ( p2 * u ) mod p */
BN_mul( p2, data, q ); /* p2 = data * q (bn can't reuse data) */
BN_add( data, p2, q2 ); /* data = p2 + q2 */
/* Copy the result to the output buffer and destroy sensitive data.
Since the bignum code performs leading-zero truncation, we have to
adjust where we copy the result to in the buffer to take into account
extra zero bytes which aren't extracted from the bignum */
BN_bn2bin( data, buffer + ( length - BN_num_bytes( data ) ) );
BN_clear_free( p2 );
BN_clear_free( q2 );
BN_clear_free( data );
BN_CTX_free( bnCTX );
return( ( status == -1 ) ? CRYPT_ERROR_FAILED : status );
}
/****************************************************************************
* *
* RSA Key Management Routines *
* *
****************************************************************************/
/* Load RSA public/private key components into an encryption context */
int rsaInitKey( CRYPT_INFO *cryptInfo, const void *key, const int keyLength )
{
CRYPT_PKCINFO_RSA *rsaKey = ( CRYPT_PKCINFO_RSA * ) key;
BN_CTX *bnCTX;
int status = CRYPT_OK;
/* Load the key component from the external representation into the
internal BigNums unless we're doing an internal load */
if( keyLength != sizeof( PKCINFO_LOADINTERNAL ) )
{
cryptInfo->ctxPKC.isPublicKey = rsaKey->isPublicKey;
BN_bin2bn( rsaKey->n, bitsToBytes( rsaKey->nLen ),
cryptInfo->ctxPKC.rsaParam_n );
BN_bin2bn( rsaKey->e, bitsToBytes( rsaKey->eLen ),
cryptInfo->ctxPKC.rsaParam_e );
if( !rsaKey->isPublicKey )
{
BN_bin2bn( rsaKey->d, bitsToBytes( rsaKey->dLen ),
cryptInfo->ctxPKC.rsaParam_d );
BN_bin2bn( rsaKey->p, bitsToBytes( rsaKey->pLen ),
cryptInfo->ctxPKC.rsaParam_p );
BN_bin2bn( rsaKey->q, bitsToBytes( rsaKey->qLen ),
cryptInfo->ctxPKC.rsaParam_q );
BN_bin2bn( rsaKey->u, bitsToBytes( rsaKey->uLen ),
cryptInfo->ctxPKC.rsaParam_u );
BN_bin2bn( rsaKey->e1, bitsToBytes( rsaKey->e1Len ),
cryptInfo->ctxPKC.rsaParam_exponent1 );
BN_bin2bn( rsaKey->e2, bitsToBytes( rsaKey->e2Len ),
cryptInfo->ctxPKC.rsaParam_exponent2 );
}
}
/* Make sure the necessary key parameters have been initialised */
if( BN_is_zero( cryptInfo->ctxPKC.rsaParam_n ) || \
BN_is_zero( cryptInfo->ctxPKC.rsaParam_e ) )
return( CRYPT_ARGERROR_STR1 );
if( !cryptInfo->ctxPKC.isPublicKey )
{
if( BN_is_zero( cryptInfo->ctxPKC.rsaParam_p ) || \
BN_is_zero( cryptInfo->ctxPKC.rsaParam_q ) )
return( CRYPT_ARGERROR_STR1 );
if( BN_is_zero( cryptInfo->ctxPKC.rsaParam_d ) && \
BN_is_zero( cryptInfo->ctxPKC.rsaParam_exponent1 ) )
/* Either d or e1 et al must be present, d isn't needed if we
have e1 et al and e1 et al can be reconstructed from d */
return( CRYPT_ARGERROR_STR1 );
}
/* Make sure the key paramters are valid: n > 504 (nominally 512 bits,
but some certs contain somewhat shorter keys), e > 2,
|p-q| > 128 bits */
if( BN_num_bits( cryptInfo->ctxPKC.rsaParam_n ) <= 504 || \
BN_lt_word( cryptInfo->ctxPKC.rsaParam_e, 3 ) )
return( CRYPT_ARGERROR_STR1 );
if( !cryptInfo->ctxPKC.isPublicKey )
{
BIGNUM *tmp;
/* Make sure the two differ by at least 128 bits */
tmp = BN_new();
BN_copy( tmp, cryptInfo->ctxPKC.rsaParam_p );
BN_sub( tmp, tmp, cryptInfo->ctxPKC.rsaParam_q );
if( BN_num_bits( tmp ) < 128 )
status = CRYPT_ARGERROR_STR1;
BN_clear_free( tmp );
if( cryptStatusError( status ) )
return( status );
}
if( ( bnCTX = BN_CTX_new() ) == NULL )
return( CRYPT_ERROR_MEMORY );
/* If we're not using PKCS keys which have exponent1 = d mod ( p - 1 )
and exponent2 = d mod ( q - 1 ) precalculated, evaluate them now.
If there's no u precalculated, evaluate it now */
if( !cryptInfo->ctxPKC.isPublicKey )
{
if( BN_is_zero( cryptInfo->ctxPKC.rsaParam_exponent1 ) )
{
BIGNUM *d = cryptInfo->ctxPKC.rsaParam_d;
BIGNUM *exponent1 = cryptInfo->ctxPKC.rsaParam_exponent1;
BIGNUM *exponent2 = cryptInfo->ctxPKC.rsaParam_exponent2;
BN_copy( exponent1, cryptInfo->ctxPKC.rsaParam_p );
BN_sub_word( exponent1, 1 ); /* exponent1 = p - 1 */
BN_mod( exponent1, d, exponent1, bnCTX );
/* exponent1 = d mod ( p - 1 ) ) */
BN_copy( exponent2, cryptInfo->ctxPKC.rsaParam_q );
BN_sub_word( exponent2, 1 ); /* exponent2 = q - 1 */
BN_mod( exponent2, d, exponent2, bnCTX );
/* exponent2 = d mod ( q - 1 ) ) */
/* Check that everything went OK */
status = ( status == -1 ) ? CRYPT_ARGERROR_STR1 : CRYPT_OK;
}
if( cryptStatusOK( status ) && \
BN_is_zero( cryptInfo->ctxPKC.rsaParam_u ) )
{
BN_clear_free( cryptInfo->ctxPKC.rsaParam_u );
cryptInfo->ctxPKC.rsaParam_u = \
BN_mod_inverse( cryptInfo->ctxPKC.rsaParam_q,
cryptInfo->ctxPKC.rsaParam_p, bnCTX );
}
if( cryptStatusError( status ) )
{
BN_CTX_free( bnCTX );
return( status );
}
}
/* Make sure that p and q are set up correctly for the CRT decryption and
precompute the Montgomery values */
if( !cryptInfo->ctxPKC.isPublicKey )
fixCRTvalues( &cryptInfo->ctxPKC, TRUE, bnCTX );
status = precomputeMontgomery( &cryptInfo->ctxPKC, bnCTX );
/* Now that we've got the various other values set up, perform further
validity checks on the private key */
if( cryptStatusOK( status ) && !cryptInfo->ctxPKC.isPublicKey && \
!checkPrivateKeyComponents( &cryptInfo->ctxPKC, bnCTX ) )
status = CRYPT_ARGERROR_STR1;
BN_CTX_free( bnCTX );
/* Set the keysize and generate a key ID for this key */
cryptInfo->ctxPKC.keySizeBits = BN_num_bits( cryptInfo->ctxPKC.rsaParam_n );
if( cryptStatusOK( status ) )
status = calculateKeyID( cryptInfo );
return( status );
}
/****************************************************************************
* *
* RSA Key Generation Routines *
* *
****************************************************************************/
/* Generate an RSA key pair into an encryption context */
int rsaGenerateKey( CRYPT_INFO *cryptInfo, const int keySizeBits )
{
BN_CTX *bnCTX;
BIGNUM *tmp;
int pBits, qBits, status;
/* Determine how many bits to give to each of p and q */
pBits = ( keySizeBits + 1 ) / 2;
qBits = keySizeBits - pBits;
cryptInfo->ctxPKC.keySizeBits = pBits + qBits;
/* Set up assorted status information */
cryptInfo->ctxPKC.isPublicKey = FALSE;
if( ( bnCTX = BN_CTX_new() ) == NULL )
return( CRYPT_ERROR_MEMORY );
/* Generate the primes p and q and set them up so the CRT decrypt will
work */
BN_set_word( cryptInfo->ctxPKC.rsaParam_e, PUBLIC_EXPONENT );
status = generateRSAPrime( cryptInfo->ctxPKC.rsaParam_p, pBits,
PUBLIC_EXPONENT, cryptInfo );
if( cryptStatusOK( status ) )
status = generateRSAPrime( cryptInfo->ctxPKC.rsaParam_q, qBits,
PUBLIC_EXPONENT, cryptInfo );
if( cryptStatusError( status ) )
{
BN_CTX_free( bnCTX );
return( status );
}
fixCRTvalues( &cryptInfo->ctxPKC, FALSE, bnCTX );
/* If we managed to generate the primes OK, derive everything else from
them */
tmp = BN_new();
/* Compute d = eInv mod (p - 1)(q - 1), e1 = d mod (p - 1), and
e2 = d mod (q - 1) */
BN_sub_word( cryptInfo->ctxPKC.rsaParam_p, 1 );
BN_sub_word( cryptInfo->ctxPKC.rsaParam_q, 1 );
BN_mul( tmp, cryptInfo->ctxPKC.rsaParam_p, cryptInfo->ctxPKC.rsaParam_q );
BN_clear_free( cryptInfo->ctxPKC.rsaParam_d );
cryptInfo->ctxPKC.rsaParam_d = BN_mod_inverse( cryptInfo->ctxPKC.rsaParam_e,
tmp, bnCTX );
BN_mod( cryptInfo->ctxPKC.rsaParam_exponent1, cryptInfo->ctxPKC.rsaParam_d,
cryptInfo->ctxPKC.rsaParam_p, bnCTX );
BN_mod( cryptInfo->ctxPKC.rsaParam_exponent2, cryptInfo->ctxPKC.rsaParam_d,
cryptInfo->ctxPKC.rsaParam_q, bnCTX );
BN_add_word( cryptInfo->ctxPKC.rsaParam_p, 1 );
BN_add_word( cryptInfo->ctxPKC.rsaParam_q, 1 );
/* Compute n = pq, and u = qInv mod p */
BN_mul( cryptInfo->ctxPKC.rsaParam_n, cryptInfo->ctxPKC.rsaParam_p,
cryptInfo->ctxPKC.rsaParam_q );
BN_clear_free( cryptInfo->ctxPKC.rsaParam_u );
cryptInfo->ctxPKC.rsaParam_u = \
BN_mod_inverse( cryptInfo->ctxPKC.rsaParam_q,
cryptInfo->ctxPKC.rsaParam_p, bnCTX );
/* Precompute the Montgomery values */
status = precomputeMontgomery( &cryptInfo->ctxPKC, bnCTX );
BN_clear_free( tmp );
BN_CTX_free( bnCTX );
/* Generate a keyID for the new key */
if( cryptStatusOK( status ) )
status = calculateKeyID( cryptInfo );
#if 0 /* For generating test key data, use cryptAddRandom( "", 0 ); */
{
#include <stdio.h>
BYTE buffer[ CRYPT_MAX_PKCSIZE ];
int length, i;
length = BN_bn2bin( cryptInfo->ctxPKC.rsaParam_n, buffer );
printf( "\t/* n */\r\n\t%d,", BN_num_bits( cryptInfo->ctxPKC.rsaParam_n ) );
for( i = 0; i < length; i++ )
{ if( !( i % 8 ) ) printf( "\r\n\t " );
printf( "0x%02X, ", buffer[ i ] ); }
length = BN_bn2bin( cryptInfo->ctxPKC.rsaParam_e, buffer );
printf( "\r\n\r\n\t/* e */\r\n\t%d,", BN_num_bits( cryptInfo->ctxPKC.rsaParam_e ) );
for( i = 0; i < length; i++ )
{ if( !( i % 8 ) ) printf( "\r\n\t " );
printf( "0x%02X, ", buffer[ i ] ); }
length = BN_bn2bin( cryptInfo->ctxPKC.rsaParam_d, buffer );
printf( "\r\n\r\n\t/* d */\r\n\t%d,", BN_num_bits( cryptInfo->ctxPKC.rsaParam_d ) );
for( i = 0; i < length; i++ )
{ if( !( i % 8 ) ) printf( "\r\n\t " );
printf( "0x%02X, ", buffer[ i ] ); }
length = BN_bn2bin( cryptInfo->ctxPKC.rsaParam_p, buffer );
printf( "\r\n\r\n\t/* p */\r\n\t%d,", BN_num_bits( cryptInfo->ctxPKC.rsaParam_p ) );
for( i = 0; i < length; i++ )
{ if( !( i % 8 ) ) printf( "\r\n\t " );
printf( "0x%02X, ", buffer[ i ] ); }
length = BN_bn2bin( cryptInfo->ctxPKC.rsaParam_q, buffer );
printf( "\r\n\r\n\t/* q */\r\n\t%d,", BN_num_bits( cryptInfo->ctxPKC.rsaParam_q ) );
for( i = 0; i < length; i++ )
{ if( !( i % 8 ) ) printf( "\r\n\t " );
printf( "0x%02X, ", buffer[ i ] ); }
length = BN_bn2bin( cryptInfo->ctxPKC.rsaParam_u, buffer );
printf( "\r\n\r\n\t/* u */\r\n\t%d,", BN_num_bits( cryptInfo->ctxPKC.rsaParam_u ) );
for( i = 0; i < length; i++ )
{ if( !( i % 8 ) ) printf( "\r\n\t " );
printf( "0x%02X, ", buffer[ i ] ); }
length = BN_bn2bin( cryptInfo->ctxPKC.rsaParam_exponent1, buffer );
printf( "\r\n\r\n\t/* exponent1 */\r\n\t%d,", BN_num_bits( cryptInfo->ctxPKC.rsaParam_exponent1 ) );
for( i = 0; i < length; i++ )
{ if( !( i % 8 ) ) printf( "\r\n\t " );
printf( "0x%02X, ", buffer[ i ] ); }
length = BN_bn2bin( cryptInfo->ctxPKC.rsaParam_exponent2, buffer );
printf( "\r\n\r\n\t/* exponent2 */\r\n\t%d,", BN_num_bits( cryptInfo->ctxPKC.rsaParam_exponent2 ) );
for( i = 0; i < length; i++ )
{ if( !( i % 8 ) ) printf( "\r\n\t " );
printf( "0x%02X, ", buffer[ i ] ); }
puts( "\r\n\t};" );
}
#endif /* 0 */
return( status );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -