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

📄 ctx_elg.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
				pkcInfo->bnCTX );
	if( BN_cmp( s, tmp ) < 0 )			/* if hash < x * r */
		BN_add( s, s, phi_p );			/*   hash = hash + phi( p ) (fast mod) */
	BN_sub( s, s, tmp );				/* s = hash - x * r */
	BN_mod_mul( s, s, kInv, phi_p,		/* s = ( s * k^-1 ) mod phi( p ) */
				pkcInfo->bnCTX );

	/* Encode the result as a DL data block */
	length = encodeDLValues( buffer, r, s );

	return( ( status == -1 ) ? CRYPT_ERROR_FAILED : length );
	}

/* Signature check a single block of data */

static int sigCheck( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
	{
	PKC_INFO *pkcInfo = &contextInfoPtr->ctxPKC;
	BIGNUM *p = &pkcInfo->dlpParam_p, *g = &pkcInfo->dlpParam_g;
	BIGNUM *y = &pkcInfo->dlpParam_y;
	BIGNUM *r = &pkcInfo->tmp1, *s = &pkcInfo->tmp1;
	int	status;

	/* Decode the values from a DL data block and make sure that r and s are
	   valid */
	status = decodeDLValues( buffer + ELGAMAL_SIGPART_SIZE, noBytes, &r, &s );
	if( cryptStatusError( status ) )
		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();

		status = extractBignum( hash, buffer, ELGAMAL_SIGPART_SIZE, 
								&pkcInfo->dlpParam_p, FALSE );
		if( cryptStatusError( status ) )
			return( status );

		/* u1 = ( y^r * r^s ) mod p */
		BN_mod_exp_mont( u1, y, r, p,		/* y' = ( y^r ) mod p */
						 pkcInfo->bnCTX, &pkcInfo->dlpParam_mont_p );
		BN_mod_exp_mont( r, r, s, p, 		/* r' = ( r^s ) mod p */
						 pkcInfo->bnCTX, &pkcInfo->dlpParam_mont_p );
		BN_mod_mul_mont( u1, u1, r, p,		/* u1 = ( y' * r' ) mod p */
						 pkcInfo->bnCTX, &pkcInfo->dlpParam_mont_p );

		/* u2 = g^hash mod p */
		BN_mod_exp_mont( u2, g, hash, p, pkcInfo->bnCTX,
						 &pkcInfo->dlpParam_mont_p );

		/* 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 );
		}

	return( status );
	}
#endif /* 0 */

/****************************************************************************
*																			*
*						Encrypt/Decrypt a Data Block						*
*																			*
****************************************************************************/

/* Encrypt a single block of data.  We have to append the distinguisher 'Fn'
   to the name since some systems already have 'encrypt' and 'decrypt' in
   their standard headers */

static int encryptFn( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
	{
	PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
	DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
	BIGNUM *p = &pkcInfo->dlpParam_p, *g = &pkcInfo->dlpParam_g;
	BIGNUM *y = &pkcInfo->dlpParam_y;
	BIGNUM *tmp = &pkcInfo->tmp1, *k = &pkcInfo->tmp2;
	BIGNUM *r = &pkcInfo->tmp3, *s = &pkcInfo->dlpTmp1;
	BIGNUM *phi_p = &pkcInfo->dlpTmp2;
	const int length = bitsToBytes( pkcInfo->keySizeBits );
	int i, bnStatus = BN_STATUS, 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 >= ( 2 + length ) * 2 );

	/* Make sure that we're not being fed suspiciously short data 
	   quantities.  extractBignum() performs a more rigorous check, but we
	   use this as a lint filter before performing the relatively expensive
	   random bignum generation and preprocessing */
	for( i = 0; i < length; i++ )
		if( buffer[ i ] != 0 )
			break;
	if( length - i < MIN_PKCSIZE - 8 )
		return( CRYPT_ERROR_BADDATA );

	/* 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 a second length parameter
	   of -999, we know that it's an internal self-test call and use a fixed
	   bit pattern for k that 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 */
	if( dlpParams->inLen2 == -999 )
		status = extractBignum( k, ( BYTE * ) kRandomVal, length, 
								length, length, NULL, FALSE );
	else
		{
		/* Generate the random value k, with the same 32-bit adjustment used
		   in the DSA code to avoid bias in the output (the only real
		   difference is that we eventually reduce it mode phi(p) rather than
		   mod q) */
		status = generateBignum( k, bytesToBits( length ) + 32, 0x80, 0 );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* 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 */
	CKPTR( BN_copy( phi_p, p ) );
	CK( BN_sub_word( phi_p, 1 ) );		/* phi( p ) = p - 1 */
	CK( BN_mod( k, k, phi_p,			/* Reduce k to the correct range */
				pkcInfo->bnCTX ) );
	CK( BN_gcd( s, k, phi_p, pkcInfo->bnCTX ) );
	while( bnStatusOK( bnStatus ) && !BN_is_one( s ) )
		{
		CK( BN_sub_word( k, 1 ) );
		CK( BN_gcd( s, k, phi_p, pkcInfo->bnCTX ) );
		}
	if( bnStatusError( bnStatus ) )
		return( getBnStatus( bnStatus ) );

	/* Move the input data into a bignum */
	status = extractBignum( tmp, ( BYTE * ) dlpParams->inParam1, length,
							MIN_PKCSIZE - 8, CRYPT_MAX_PKCSIZE, p, FALSE );
	if( cryptStatusError( status ) )
		return( status );

	/* s = ( y^k * M ) mod p */
	CK( BN_mod_exp_mont( r, y, k, p,	/* y' = y^k mod p */
						 pkcInfo->bnCTX, &pkcInfo->dlpParam_mont_p ) );
	CK( BN_mod_mul( s, r, tmp, p,		/* s = y'M mod p */
					pkcInfo->bnCTX ) );

	/* r = g^k mod p */
	CK( BN_mod_exp_mont( r, g, k, p, pkcInfo->bnCTX,
						 &pkcInfo->dlpParam_mont_p ) );
	if( bnStatusError( bnStatus ) )
		return( getBnStatus( bnStatus ) );

	/* Encode the result as a DL data block */
	return( pkcInfo->encodeDLValuesFunction( dlpParams->outParam, 
							dlpParams->outLen, &dlpParams->outLen, r, s,
							dlpParams->formatType ) );
	}

/* Decrypt a single block of data */

static int decryptFn( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
	{
	PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
	DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
	BIGNUM *p = &pkcInfo->dlpParam_p, *x = &pkcInfo->dlpParam_x;
	BIGNUM *r = &pkcInfo->tmp1, *s = &pkcInfo->tmp2, *tmp = &pkcInfo->tmp3;
	const int length = bitsToBytes( pkcInfo->keySizeBits );
	int offset, dummy, bnStatus = BN_STATUS, status;

	assert( noBytes == sizeof( DLP_PARAMS ) );
	assert( dlpParams->inParam1 != NULL && \
			dlpParams->inLen1 >= ( 2 + ( length - 2 ) ) * 2 );
	assert( dlpParams->inParam2 == NULL && dlpParams->inLen2 == 0 );
	assert( dlpParams->outParam != NULL && dlpParams->outLen >= length );

	/* Decode the values from a DL data block and make sure that r and s are
	   valid, i.e. r, s = [1...p-1] */
	status = pkcInfo->decodeDLValuesFunction( dlpParams->inParam1, 
											  dlpParams->inLen1, r, s, p,
											  dlpParams->formatType );
	if( cryptStatusError( status ) )
		return( status );

	/* M = ( s / ( r^x ) ) mod p */
	CK( BN_mod_exp_mont( r, r, x, p,		/* r' = r^x */
						 pkcInfo->bnCTX, &pkcInfo->dlpParam_mont_p ) );
	CKPTR( BN_mod_inverse( tmp, r, p,		/* r'' = r'^-1 */
						   pkcInfo->bnCTX ) );
	CK( BN_mod_mul( s, s, tmp, p,			/* s = s * r'^-1 mod p */
					pkcInfo->bnCTX ) );
	if( bnStatusError( bnStatus ) )
		return( getBnStatus( bnStatus ) );

	/* Copy the result to the output.  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
	   that aren't extracted from the bignum.  In addition we can't use
	   the length returned from getBignumData() because this is the 
	   length of the zero-truncated result, not the full length */
	offset = length - BN_num_bytes( s );
	if( offset > 0 )
		memset( dlpParams->outParam, 0, offset );
	dlpParams->outLen = length;
	return( getBignumData( s, dlpParams->outParam + offset, 
						   dlpParams->outLen - offset, &dummy ) );
	}

/****************************************************************************
*																			*
*								Key Management								*
*																			*
****************************************************************************/

/* Load key components into an encryption context */

static int initKey( CONTEXT_INFO *contextInfoPtr, const void *key,
					const int keyLength )
	{
	PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
	int status;

#ifndef USE_FIPS140
	/* Load the key component from the external representation into the
	   internal bignums unless we're doing an internal load */
	if( key != NULL )
		{
		const CRYPT_PKCINFO_DLP *egKey = ( CRYPT_PKCINFO_DLP * ) key;

		/* Load the key components into the bignums */
		contextInfoPtr->flags |= ( egKey->isPublicKey ) ? \
							CONTEXT_FLAG_ISPUBLICKEY : CONTEXT_FLAG_ISPRIVATEKEY;
		status = extractBignum( &pkcInfo->dlpParam_p, egKey->p, 
								bitsToBytes( egKey->pLen ),
								DLPPARAM_MIN_P, DLPPARAM_MAX_P, NULL, TRUE );
		if( cryptStatusOK( status ) )
			status = extractBignum( &pkcInfo->dlpParam_g, egKey->g, 
									bitsToBytes( egKey->gLen ),
									DLPPARAM_MIN_G, DLPPARAM_MAX_G,
									&pkcInfo->dlpParam_p, FALSE );
		if( cryptStatusOK( status ) )
			status = extractBignum( &pkcInfo->dlpParam_q, egKey->q, 
									bitsToBytes( egKey->qLen ),
									DLPPARAM_MIN_Q, DLPPARAM_MAX_Q,
									&pkcInfo->dlpParam_p, FALSE );
		if( cryptStatusOK( status ) )
			status = extractBignum( &pkcInfo->dlpParam_y, egKey->y, 
									bitsToBytes( egKey->yLen ),
									DLPPARAM_MIN_Y, DLPPARAM_MAX_Y,
									&pkcInfo->dlpParam_p, TRUE );
		if( cryptStatusOK( status ) && !egKey->isPublicKey )
			status = extractBignum( &pkcInfo->dlpParam_x, egKey->x, 
									bitsToBytes( egKey->xLen ),
									DLPPARAM_MIN_X, DLPPARAM_MAX_X,
									&pkcInfo->dlpParam_p, FALSE );
		contextInfoPtr->flags |= CONTEXT_FLAG_PBO;
		if( cryptStatusError( status ) )
			return( status );
		}
#endif /* USE_FIPS140 */

	/* Complete the key checking and setup */
	status = initDLPkey( contextInfoPtr, FALSE );
	if( cryptStatusOK( status ) )
		/* PGP Elgamal keys don't follow X9.42 and are effectively PKCS #3
		   keys, so if the key is being instantiated from PGP key data and
		   doesn't have a q parameter, we mark it as a PKCS #3 key to
		   ensure that it doesn't fail the validity check for q != 0 */
		status = checkDLPkey( contextInfoPtr,
					( key == NULL && pkcInfo->openPgpKeyIDSet && \
					  BN_is_zero( &pkcInfo->dlpParam_q ) ) ? \
					TRUE : FALSE );
	if( cryptStatusOK( status ) )
		status = pkcInfo->calculateKeyIDFunction( contextInfoPtr );
	return( status );
	}

/* Generate a key into an encryption context */

static int generateKey( CONTEXT_INFO *contextInfoPtr, const int keySizeBits )
	{
	int status;

	status = generateDLPkey( contextInfoPtr, keySizeBits );
	if( cryptStatusOK( status ) &&
#ifndef USE_FIPS140
		( contextInfoPtr->flags & CONTEXT_FLAG_SIDECHANNELPROTECTION ) &&
#endif /* USE_FIPS140 */
		!pairwiseConsistencyTest( contextInfoPtr, TRUE ) )
		{
		assert( DEBUG_WARN );
		status = CRYPT_ERROR_FAILED;
		}
	if( cryptStatusOK( status ) )
		status = contextInfoPtr->ctxPKC->calculateKeyIDFunction( contextInfoPtr );
	return( status );
	}

/****************************************************************************
*																			*
*						Capability Access Routines							*
*																			*
****************************************************************************/

static const CAPABILITY_INFO FAR_BSS capabilityInfo = {
	CRYPT_ALGO_ELGAMAL, bitsToBytes( 0 ), "Elgamal", 7,
	MIN_PKCSIZE, bitsToBytes( 1024 ), CRYPT_MAX_PKCSIZE,
	selfTest, getDefaultInfo, NULL, NULL, initKey, generateKey, encryptFn, decryptFn
	};

const CAPABILITY_INFO *getElgamalCapability( void )
	{
	return( &capabilityInfo );
	}

#endif /* USE_ELGAMAL */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -