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

📄 lib_dsa.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 2 页
字号:
	CRYPT_PKCINFO_DLP *dsaKey;
	static const CAPABILITY_INFO capabilityInfo = { CRYPT_ALGO_DSA, 0, NULL,
													64, 128, 512, 0 };
	DLP_PARAMS dlpParams;
	BYTE buffer[ 128 ];
	int status;

	/* Set up the key components */
	if( ( dsaKey = ( CRYPT_PKCINFO_DLP * ) malloc( sizeof( CRYPT_PKCINFO_DLP ) ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	cryptInitComponents( dsaKey, CRYPT_KEYTYPE_PRIVATE );
	cryptSetComponent( dsaKey->p, dlpTestKey.p, dlpTestKey.pLen );
	cryptSetComponent( dsaKey->q, dlpTestKey.q, dlpTestKey.qLen );
	cryptSetComponent( dsaKey->g, dlpTestKey.g, dlpTestKey.gLen );
	cryptSetComponent( dsaKey->y, dlpTestKey.y, dlpTestKey.yLen );
	cryptSetComponent( dsaKey->x, dlpTestKey.x, dlpTestKey.xLen );

	/* Initialise the BigNum information and components */
	memset( &cryptInfo, 0, sizeof( CRYPT_INFO ) );
	cryptInfo.ctxPKC.param1 = BN_new();
	cryptInfo.ctxPKC.param2 = BN_new();
	cryptInfo.ctxPKC.param3 = BN_new();
	cryptInfo.ctxPKC.param4 = BN_new();
	cryptInfo.ctxPKC.param5 = BN_new();
	cryptInfo.capabilityInfo = &capabilityInfo;

	/* Perform the test sign/sig.check of the FIPS 186 test values */
	setDLPParams( &dlpParams, shaM, 20, buffer, 128 )
	dlpParams.inLen2 = -999;
	status = dsaInitKey( &cryptInfo, dsaKey, CRYPT_UNUSED );
	if( !cryptStatusError( status ) )
		status = dsaSign( &cryptInfo, ( BYTE * ) &dlpParams, 
						  sizeof( DLP_PARAMS ) );
	if( !cryptStatusError( status ) )
		{
		const int sigSize = dlpParams.outLen;

		setDLPParams( &dlpParams, shaM, 20, NULL, 0 )
		dlpParams.inParam2 = buffer;
		dlpParams.inLen2 = sigSize;
		status = dsaSigCheck( &cryptInfo, ( BYTE * ) &dlpParams, 
							  sizeof( DLP_PARAMS ) );
		}
	if( cryptStatusError( status ) )
		status = CRYPT_ERROR;

	/* Clean up */
	cryptDestroyComponents( dsaKey );
	BN_clear_free( cryptInfo.ctxPKC.param1 );
	BN_clear_free( cryptInfo.ctxPKC.param2 );
	BN_clear_free( cryptInfo.ctxPKC.param3 );
	BN_clear_free( cryptInfo.ctxPKC.param4 );
	BN_clear_free( cryptInfo.ctxPKC.param5 );
	zeroise( &cryptInfo, sizeof( CRYPT_INFO ) );
	free( dsaKey );

	return( status );
	}

/****************************************************************************
*																			*
*							Init/Shutdown Routines							*
*																			*
****************************************************************************/

/* Not needed for the DSA routines */

/****************************************************************************
*																			*
*							DSA En/Decryption Routines						*
*																			*
****************************************************************************/

/* Since DSA signature generation produces two values and the cryptEncrypt()
   model only provides for passing a byte string in and out (or, more
   specifically, the internal bignum data can't be exported to the outside
   world), we need to encode the resulting data into a flat format.  This is
   done by encoding the output as an X9.31 Dss-Sig record:

	Dss-Sig ::= SEQUENCE {
		r	INTEGER,
		s	INTEGER
		}

   The input is the 160-bit hash, usually SHA but possibly also RIPEMD-160.

   Signature checking is even uglier, since we need to pass in the hash as
   well as the composite signature (in effect we need to do what
   cryptCheckSignature() does).  We do this by appending the 160-bit hash to
   the composite signature when we call cryptDecrypt() */

/* The size of each DSA signature component - 160 bits */

#define DSA_SIGPART_SIZE	20

/* Sign a single block of data  */

int dsaSign( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
	{
	DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
	BN_CTX *bnCTX;
	BIGNUM *p = cryptInfo->ctxPKC.dlpParam_p;
	BIGNUM *q = cryptInfo->ctxPKC.dlpParam_q;
	BIGNUM *g = cryptInfo->ctxPKC.dlpParam_g;
	BIGNUM *x = cryptInfo->ctxPKC.dlpParam_x;
	BIGNUM *hash, *k, *r, *s, *kInv;
	int status;

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

	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 also means we can use the FIPS 186 
	   self-test value for k).  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 * ) kVal, DSA_SIGPART_SIZE, k );
	else
		{
		/* Generate the random value k.  FIPS 186 requires (Appendix 3)
		   that this be done with:

			k = G(t,KKEY) mod q

		   where G(t,c) produces a 160-bit output, however this produces a
		   slight bias in k which leaks a small amount of the private key in
		   each signature.  Because of this we start with a value which is
		   32 bits larger than q and then do the reduction, eliminating the
		   bias */
		status = generateBignum( k, bytesToBits( DSA_SIGPART_SIZE ) + 32,
								 0, 0 );
		if( cryptStatusError( status ) )
			{
			BN_clear_free( k );
			BN_CTX_free( bnCTX );
			return( status );
			}
		}
	BN_mod( k, k, q, bnCTX );	/* Reduce k to the correct range */

	/* Initialise the bignums */
	hash = BN_new();
	r = BN_new();
	s = BN_new();

	/* Move the data from the buffer into a bignum */
	BN_bin2bn( ( BYTE * ) dlpParams->inParam1, DSA_SIGPART_SIZE, hash );

	/* r = ( g ^ k mod p ) mod q */
	BN_mod_exp( r, g, k, p, bnCTX );
	BN_mod( r, r, q, bnCTX );

	/* s = k^-1 * ( hash + x * r ) mod q */
	kInv = BN_mod_inverse( k, q, bnCTX );	/* temp = k^-1 mod q */
/*	BN_mul( s, x, r );					// s = x * r */
	BN_mod_mul( s, x, r, q, bnCTX );	/* s = ( x * r ) mod q */
	BN_add( s, s, hash );				/* s = s + hash */
	if( BN_cmp( s, q ) > 0 )			/* if s > q */
		BN_sub( s, s, q );				/*   s = s - q (fast mod) */
	BN_mod_mul( s, s, kInv, q, bnCTX );	/* s = k^-1 * ( hash + x * r ) mod q */

	/* Encode the result as a DL data block */
	status = encodeDLValues( dlpParams->outParam, dlpParams->outLen, r, s,
							 dlpParams->formatType );
	if( !cryptStatusError( status ) )
		dlpParams->outLen = status;

	/* Destroy sensitive data */
	BN_clear_free( kInv );
	BN_clear_free( s );
	BN_clear_free( r );
	BN_clear_free( k );
	BN_clear_free( hash );

	BN_CTX_free( bnCTX );

	return( cryptStatusError( status ) ? status : CRYPT_OK );
	}

/* Signature check a single block of data */

int dsaSigCheck( CRYPT_INFO *cryptInfo, BYTE *buffer, int noBytes )
	{
	DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
	BN_CTX *bnCTX;
	BIGNUM *p = cryptInfo->ctxPKC.dlpParam_p;
	BIGNUM *q = cryptInfo->ctxPKC.dlpParam_q;
	BIGNUM *g = cryptInfo->ctxPKC.dlpParam_g;
	BIGNUM *y = cryptInfo->ctxPKC.dlpParam_y;
	BIGNUM *r, *s;
	int status;

	assert( noBytes == sizeof( DLP_PARAMS ) );
	assert( dlpParams->inParam1 != NULL && dlpParams->inLen1 == 20 );
	assert( dlpParams->inParam2 != NULL && \
			( ( dlpParams->formatType == CRYPT_FORMAT_CRYPTLIB && \
				dlpParams->inLen2 >= 46 ) || \
			  ( dlpParams->formatType == CRYPT_FORMAT_PGP && \
				dlpParams->inLen2 == 44 ) ) );
	assert( dlpParams->outParam == NULL && dlpParams->outLen == 0 );

	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->inParam2, dlpParams->inLen2, &r, &s,
							 dlpParams->formatType );
	if( cryptStatusError( status ) )
		{
		BN_CTX_free( bnCTX );
		return( status );
		}
	if( BN_cmp( r, q ) >= 0 || BN_cmp( s, q ) >= 0 )
		status = CRYPT_ERROR_BADDATA;
	else
		{
		BIGNUM *u1, *v;

		u1 = BN_new();

		BN_bin2bn( ( BYTE * ) dlpParams->inParam1, DSA_SIGPART_SIZE, u1 );

#if 0
		v = BN_new();

		/* w = s^-1 mod q */
		s = BN_mod_inverse( s, q, bnCTX );	/* w = s^-1 mod q */

		/* u1 = ( hash * w ) mod q */
		BN_mod_mul( u1, u1, s, q, bnCTX );	/* u1 = ( hash * w ) mod q */

		/* u2 = ( r * w ) mod q */
		BN_mod_mul( s, r, s, q, bnCTX );	/* u2 = ( r * w ) mod q */

		/* v = ( ( ( g^u1 ) * ( y^u2 ) ) mod p ) mod q.  We need to use
		   an extra temp variable here because BN_mod_exp() params 1 and
		   3 must differ, and BN_mod() params 1 and 2 must differ */
		BN_mod_exp( v, g, u1, p, bnCTX );	/* u1' = ( g ^ u1 ) mod p */
		BN_mod_exp( u1, y, s, p, bnCTX );	/* u2' = ( y ^ u2 ) mod p */
		BN_mod_mul( v, v, u1, p, bnCTX );	/* v = ( u1' * u2' ) mod p */
		BN_mod( s, v, q, bnCTX );			/* v = v mod q */

		/* if r == v signature is good */
		if( BN_cmp( r, s ) && cryptStatusOK( status ) )
#else
		/* w = s^-1 mod q */
		v = BN_mod_inverse( s, q, bnCTX );	/* w = s^-1 mod q */

		/* u1 = ( hash * w ) mod q */
		BN_mod_mul( u1, u1, v, q, bnCTX );	/* u1 = ( hash * w ) mod q */

		/* u2 = ( r * w ) mod q */
		BN_mod_mul( v, r, v, q, bnCTX );	/* u2 = ( r * w ) mod q */

		/* v = ( ( ( g^u1 ) * ( y^u2 ) ) mod p ) mod q.  We need to use
		   an extra temp variable here because BN_mod_exp() params 1 and
		   3 must differ, and BN_mod() params 1 and 2 must differ */
		BN_mod_exp( s, g, u1, p, bnCTX );	/* u1' = ( g ^ u1 ) mod p */
		BN_mod_exp( u1, y, v, p, bnCTX );	/* u2' = ( y ^ u2 ) mod p */
		BN_mod_mul( s, s, u1, p, bnCTX );	/* v = ( u1' * u2' ) mod p */
		BN_mod( v, s, q, bnCTX );			/* v = v mod q */

		/* if r == v signature is good */
		if( BN_cmp( r, v ) && cryptStatusOK( status ) )
#endif
			status = CRYPT_ERROR_SIGNATURE;

		BN_clear_free( v );
		BN_clear_free( u1 );
		}

	/* Destroy sensitive data */
	BN_clear_free( s );
	BN_clear_free( r );

	BN_CTX_free( bnCTX );

	return( status );
	}

/****************************************************************************
*																			*
*							DSA Key Management Routines						*
*																			*
****************************************************************************/

/* Load DSA public/private key components into an encryption context */

int dsaInitKey( CRYPT_INFO *cryptInfo, const void *key, const int keyLength )
	{
	CRYPT_PKCINFO_DLP *dsaKey = ( CRYPT_PKCINFO_DLP * ) key;
	BOOLEAN calculateY = FALSE;
	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 = dsaKey->isPublicKey;

		BN_bin2bn( dsaKey->p, bitsToBytes( dsaKey->pLen ),
				   cryptInfo->ctxPKC.dlpParam_p );
		BN_bin2bn( dsaKey->q, bitsToBytes( dsaKey->qLen ),
				   cryptInfo->ctxPKC.dlpParam_q );
		BN_bin2bn( dsaKey->g, bitsToBytes( dsaKey->gLen ),
				   cryptInfo->ctxPKC.dlpParam_g );
		if( dsaKey->yLen == 0 && !dsaKey->isPublicKey )
			/* No y available, generate it ourselves */
			calculateY = TRUE;
		else
			BN_bin2bn( dsaKey->y, bitsToBytes( dsaKey->yLen ),
					   cryptInfo->ctxPKC.dlpParam_y );
		if( !dsaKey->isPublicKey )
			BN_bin2bn( dsaKey->x, bitsToBytes( dsaKey->xLen ),
				   cryptInfo->ctxPKC.dlpParam_x );
		}

	/* Some sources (specifically PKCS #11) don't make y available for
	   private keys, so if the caller is trying to load a private key with a
	   zero y value, we calculate it for them */
	if( calculateY )
		{
		BN_CTX *bnCTX;

		if( BN_is_zero( cryptInfo->ctxPKC.dlpParam_p ) || \
			BN_is_zero( cryptInfo->ctxPKC.dlpParam_q ) || \
			BN_is_zero( cryptInfo->ctxPKC.dlpParam_g ) )
			/* We have to perform this redundant check now because we can't
			   safely calculate y without it */
			return( CRYPT_ARGERROR_STR1 );
		if( ( bnCTX = BN_CTX_new() ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		BN_mod_exp( cryptInfo->ctxPKC.dlpParam_y, cryptInfo->ctxPKC.dlpParam_g,
					cryptInfo->ctxPKC.dlpParam_x, cryptInfo->ctxPKC.dlpParam_p, bnCTX );
		BN_CTX_free( bnCTX );
		}

	/* Check the parameters and calculate the key ID */
	status = checkDLParams( cryptInfo, FALSE );
	if( cryptStatusError( status ) )
		return( status );
	cryptInfo->ctxPKC.keySizeBits = BN_num_bits( cryptInfo->ctxPKC.dlpParam_p );
	return( calculateKeyID( cryptInfo ) );
	}

/* Generate a DSA key into an encryption context */

int dsaGenerateKey( CRYPT_INFO *cryptInfo, const int keySizeBits )
	{
	int status;

	status = generateDLPKey( cryptInfo, ( keySizeBits / 64 ) * 64, 160,
							 TRUE );
	if( cryptStatusError( status ) )
		return( status );
	return( calculateKeyID( cryptInfo ) );
	}

⌨️ 快捷键说明

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