⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lib_elg.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 2 页
字号:

	/* 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 + -