📄 lib_dsa.c
字号:
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 + -