📄 lib_elg.c
字号:
/* Encode the result as a DL data block */
length = encodeDLValues( buffer, r, s );
/* Destroy sensitive data */
BN_clear_free( kInv );
BN_clear_free( tmp );
BN_clear_free( k );
BN_clear_free( r );
BN_clear_free( s );
BN_clear_free( phi_p );
BN_CTX_free( bnCTX );
return( ( status == -1 ) ? CRYPT_ERROR_FAILED : length );
}
/* Signature check a single block of data */
int elgamalSigCheck( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
{
BN_CTX *bnCTX;
BIGNUM *p = cryptInfo->ctxPKC.dlpParam_p;
BIGNUM *g = cryptInfo->ctxPKC.dlpParam_g;
BIGNUM *y = cryptInfo->ctxPKC.dlpParam_y;
BIGNUM *r, *s;
int status;
if( ( bnCTX = BN_CTX_new() ) == NULL )
return( CRYPT_ERROR_MEMORY );
/* Decode the values from a DL data block and make sure r and s are
valid */
status = decodeDLValues( buffer + ELGAMAL_SIGPART_SIZE, noBytes, &r, &s );
if( cryptStatusError( status ) )
{
BN_CTX_free( bnCTX );
return( status );
}
/* Verify that 0 < r < p. If this check isn't done, an adversary can
forge signatures given one existing valid signature for a key */
if( BN_is_zero( r ) || BN_cmp( r, p ) >= 0 )
status = CRYPT_ERROR_SIGNATURE;
else
{
BIGNUM *hash, *u1, *u2;
hash = BN_new();
u1 = BN_new();
u2 = BN_new();
BN_bin2bn( buffer, ELGAMAL_SIGPART_SIZE, hash );
/* u1 = ( y^r * r^s ) mod p */
BN_mod_exp( u1, y, r, p, bnCTX ); /* y' = ( y^r ) mod p */
BN_mod_exp( r, r, s, p, bnCTX ); /* r' = ( r^s ) mod p */
BN_mod_mul( u1, u1, r, p, bnCTX ); /* u1 = ( y' * r' ) mod p */
/* u2 = g^hash mod p */
BN_mod_exp( u2, g, hash, p, bnCTX );
/* if u1 == u2, signature is good */
if( BN_cmp( u1, u2 ) && cryptStatusOK( status ) )
status = CRYPT_ERROR_SIGNATURE;
BN_clear_free( hash );
BN_clear_free( u2 );
BN_clear_free( u1 );
}
/* Destroy sensitive data */
BN_clear_free( r );
BN_clear_free( s );
BN_CTX_free( bnCTX );
return( status );
}
#endif /* 0 */
/****************************************************************************
* *
* Elgamal En/Decryption Routines *
* *
****************************************************************************/
/* Encrypt a single block of data */
int elgamalEncrypt( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
{
DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
BN_CTX *bnCTX;
BIGNUM *p = cryptInfo->ctxPKC.dlpParam_p;
BIGNUM *g = cryptInfo->ctxPKC.dlpParam_g;
BIGNUM *y = cryptInfo->ctxPKC.dlpParam_y;
BIGNUM *tmp, *k, *r, *s, *phi_p;
const int length = bitsToBytes( cryptInfo->ctxPKC.keySizeBits );
int status;
assert( noBytes == sizeof( DLP_PARAMS ) );
assert( dlpParams->inParam1 != NULL && dlpParams->inLen1 == length );
assert( dlpParams->inParam2 == NULL && \
( dlpParams->inLen2 == 0 || dlpParams->inLen2 == -999 ) );
assert( dlpParams->outParam != NULL && dlpParams->outLen >= ( length * 2 ) );
if( ( bnCTX = BN_CTX_new() ) == NULL )
return( CRYPT_ERROR_MEMORY );
/* Generate the secret random value k. During the initial self-test
the random data pool may not exist yet, and may in fact never exist in
a satisfactory condition if there isn't enough randomness present in
the system to generate cryptographically strong random numbers. To
bypass this problem, if the caller passes in an second length
parameter of -999 (which is extremely unlikely to be set that way by
accident, corresponding to neither the default of 0 or some other
special-case value such as CRYPT_UNUSED), we know it's an internal
self-test call and use a fixed bit pattern for k which avoids having
to call generateBignum(). This is a somewhat ugly use of 'magic
numbers', but it's safe because this function can only be called
internally, so all we need to trap is accidental use of the parameter
which is normally unused */
k = BN_new();
if( dlpParams->inLen2 == -999 )
BN_bin2bn( ( BYTE * ) kRandomVal, length, k );
else
{
/* Generate the random value k, with the same 32-bit adjustment used
in the DSA code to avoid bias in the output */
status = generateBignum( k, bytesToBits( length ) + 32, 0x80, 0 );
if( cryptStatusError( status ) )
{
BN_clear_free( k );
BN_CTX_free( bnCTX );
return( status );
}
}
/* Initialise the bignums */
tmp = BN_new();
r = BN_new();
s = BN_new();
phi_p = BN_new();
/* Generate phi( p ) and use it to get k, k < p-1 and k relatively prime
to p-1. Since (p-1)/2 is prime, the initial choice for k will be
divisible by (p-1)/2 with probability 2/(p-1), so we'll do at most two
gcd operations with very high probability. A k of (p-3)/2 will be
chosen with probability 3/(p-1), and all other numbers from 1 to p-1
will be chosen with probability 2/(p-1), giving a nearly uniform
distribution of exponents */
BN_copy( phi_p, p );
BN_sub_word( phi_p, 1 ); /* phi( p ) = p - 1 */
BN_mod( k, k, phi_p, bnCTX ); /* Reduce k to the correct range */
BN_gcd( s, k, phi_p, bnCTX );
while( !BN_is_one( s ) )
{
BN_sub_word( k, 1 );
BN_gcd( s, k, phi_p, bnCTX );
}
/* Move the input data into a bignum */
BN_bin2bn( ( BYTE * ) dlpParams->inParam1, length, tmp );
/* s = ( y^k * M ) mod p */
BN_mod_exp( r, y, k, p, bnCTX ); /* y' = y^k mod p */
BN_mod_mul( s, r, tmp, p, bnCTX ); /* s = y'M mod p */
/* r = g^k mod p */
BN_mod_exp( r, g, k, p, bnCTX );
/* Encode the result as a DL data block */
status = encodeDLValues( dlpParams->outParam, dlpParams->outLen, r, s,
dlpParams->formatType );
if( !cryptStatusError( status ) )
{
dlpParams->outLen = status;
status = CRYPT_OK; /* encodeDLValues() returns a byte count */
}
/* Destroy sensitive data */
BN_clear_free( tmp );
BN_clear_free( k );
BN_clear_free( r );
BN_clear_free( s );
BN_clear_free( phi_p );
BN_CTX_free( bnCTX );
return( status );
}
/* Decrypt a single block of data */
int elgamalDecrypt( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
{
DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
BN_CTX *bnCTX;
BIGNUM *p = cryptInfo->ctxPKC.dlpParam_p;
BIGNUM *x = cryptInfo->ctxPKC.dlpParam_x;
BIGNUM *tmp, *r, *s;
const int length = bitsToBytes( cryptInfo->ctxPKC.keySizeBits );
int status;
assert( noBytes == sizeof( DLP_PARAMS ) );
assert( dlpParams->inParam1 != NULL && dlpParams->inLen1 >= ( length * 2 ) );
assert( dlpParams->inParam2 == NULL && dlpParams->inLen2 == 0 );
assert( dlpParams->outParam != NULL && dlpParams->outLen >= length );
if( ( bnCTX = BN_CTX_new() ) == NULL )
return( CRYPT_ERROR_MEMORY );
/* Decode the values from a DL data block and make sure r and s are
valid */
status = decodeDLValues( dlpParams->inParam1, dlpParams->inLen1, &r, &s,
dlpParams->formatType );
if( cryptStatusError( status ) )
{
BN_CTX_free( bnCTX );
return( status );
}
/* M = ( s / ( r^x ) ) mod p */
BN_mod_exp( r, r, x, p, bnCTX ); /* r' = r^x */
tmp = BN_mod_inverse( r, p, bnCTX ); /* r'' = r'^-1 */
BN_mod_mul( s, s, tmp, p, bnCTX ); /* s = s * r'^-1 mod p */
/* Copy the result to the output 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 */
memset( dlpParams->outParam, 0, 16 );
BN_bn2bin( s, dlpParams->outParam + ( length - BN_num_bytes( s ) ) );
dlpParams->outLen = length;
BN_clear_free( tmp );
BN_clear_free( r );
BN_clear_free( s );
BN_CTX_free( bnCTX );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Elgamal Key Management Routines *
* *
****************************************************************************/
/* Load Elgamal public/private key components into an encryption context */
int elgamalInitKey( CRYPT_INFO *cryptInfo, const void *key, const int keyLength )
{
CRYPT_PKCINFO_DLP *egKey = ( CRYPT_PKCINFO_DLP * ) key;
int status;
/* 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 = egKey->isPublicKey;
/* Load the key components into the bignums */
BN_bin2bn( egKey->p, bitsToBytes( egKey->pLen ),
cryptInfo->ctxPKC.dlpParam_p );
BN_bin2bn( egKey->g, bitsToBytes( egKey->gLen ),
cryptInfo->ctxPKC.dlpParam_g );
BN_bin2bn( egKey->q, bitsToBytes( egKey->qLen ),
cryptInfo->ctxPKC.dlpParam_q );
BN_bin2bn( egKey->y, bitsToBytes( egKey->yLen ),
cryptInfo->ctxPKC.dlpParam_y );
if( !egKey->isPublicKey )
BN_bin2bn( egKey->x, bitsToBytes( egKey->xLen ),
cryptInfo->ctxPKC.dlpParam_x );
}
/* Check the parameters and calculate the key ID */
status = checkDLParams( cryptInfo, TRUE );
if( cryptStatusError( status ) )
return( status );
cryptInfo->ctxPKC.keySizeBits = BN_num_bits( cryptInfo->ctxPKC.dlpParam_p );
return( calculateKeyID( cryptInfo ) );
}
/* Generate an Elgamal key into an encryption context */
int elgamalGenerateKey( CRYPT_INFO *cryptInfo, const int keySizeBits )
{
int status;
status = generateDLPKey( cryptInfo, keySizeBits, CRYPT_USE_DEFAULT,
TRUE );
if( cryptStatusError( status ) )
return( status );
return( calculateKeyID( cryptInfo ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -