📄 ctx_dsa.c
字号:
Dss-Sig ::= SEQUENCE {
r INTEGER,
s INTEGER
}
The input is the 160-bit hash, usually SHA but possibly also RIPEMD-160 */
/* The size of each DSA signature component - 160 bits */
#define DSA_SIGPART_SIZE 20
/* Sign a single block of data */
static int sign( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
{
PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
BIGNUM *p = &pkcInfo->dlpParam_p, *q = &pkcInfo->dlpParam_q;
BIGNUM *g = &pkcInfo->dlpParam_g, *x = &pkcInfo->dlpParam_x;
BIGNUM *hash = &pkcInfo->tmp1, *k = &pkcInfo->tmp2, *kInv = &pkcInfo->tmp3;
BIGNUM *r = &pkcInfo->dlpTmp1, *s = &pkcInfo->dlpTmp2;
int bnStatus = BN_STATUS, 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 >= ( 2 + DSA_SIGPART_SIZE ) * 2 );
/* 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
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 */
if( dlpParams->inLen2 == -999 )
status = extractBignum( k, ( BYTE * ) kVal, DSA_SIGPART_SIZE,
DSA_SIGPART_SIZE, DSA_SIGPART_SIZE, NULL,
FALSE );
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 that 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,
0x80, 0 );
}
if( cryptStatusError( status ) )
return( status );
if( contextInfoPtr->flags & CONTEXT_FLAG_SIDECHANNELPROTECTION )
{
/* Use constant-time modexp() to protect the secret random value
from timing channels. We could also use blinding, but neither of
these measures are actually terribly useful because we're using a
random exponent each time so the timing information isn't of much
use to an attacker */
BN_set_flags( k, BN_FLG_EXP_CONSTTIME );
}
CK( BN_mod( k, k, q, /* Reduce k to the correct range */
pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) )
return( getBnStatus( bnStatus ) );
/* Get the hash as a bignum. The range checking for the resulting value
is a bit odd, we need to take "the leftmost sizeof( q ) bits of the
hash" as the input, to handle this we require that the bit size of q
be at least as large as the (nominal) bit size of the hash */
if( dlpParams->inLen1 > BN_num_bytes( q ) )
return( CRYPT_ERROR_BADDATA );
status = extractBignum( hash, ( BYTE * ) dlpParams->inParam1,
DSA_SIGPART_SIZE, DSA_SIGPART_SIZE / 2,
DSA_SIGPART_SIZE, NULL, FALSE );
if( cryptStatusError( status ) )
return( status );
/* r = ( g ^ k mod p ) mod q */
CK( BN_mod_exp_mont( r, g, k, p, pkcInfo->bnCTX,
&pkcInfo->dlpParam_mont_p ) );
CK( BN_mod( r, r, q, pkcInfo->bnCTX ) );
/* s = k^-1 * ( hash + x * r ) mod q */
CKPTR( BN_mod_inverse( kInv, k, q, /* temp = k^-1 mod q */
pkcInfo->bnCTX ) );
CK( BN_mod_mul( s, x, r, q, /* s = ( x * r ) mod q */
pkcInfo->bnCTX ) );
CK( BN_add( s, s, hash ) ); /* s = s + hash */
if( BN_cmp( s, q ) > 0 ) /* if s > q */
CK( BN_sub( s, s, q ) ); /* s = s - q (fast mod) */
CK( BN_mod_mul( s, s, kInv, q, /* s = k^-1 * ( hash + x * r ) mod q */
pkcInfo->bnCTX ) );
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 ) );
}
/* Signature check a single block of data */
static int sigCheck( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
{
PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
DLP_PARAMS *dlpParams = ( DLP_PARAMS * ) buffer;
BIGNUM *p = &pkcInfo->dlpParam_p, *q = &pkcInfo->dlpParam_q;
BIGNUM *g = &pkcInfo->dlpParam_g, *y = &pkcInfo->dlpParam_y;
BIGNUM *r = &pkcInfo->tmp1, *s = &pkcInfo->tmp2;
BIGNUM *u1 = &pkcInfo->tmp3, *u2 = &pkcInfo->dlpTmp1; /* Doubles as w */
int bnStatus = BN_STATUS, status;
assert( noBytes == sizeof( DLP_PARAMS ) );
assert( dlpParams->inParam1 != NULL && dlpParams->inLen1 == 20 );
assert( dlpParams->inParam2 != NULL && \
( ( dlpParams->formatType == CRYPT_FORMAT_CRYPTLIB && \
( dlpParams->inLen2 >= 42 && dlpParams->inLen2 <= 128 ) ) || \
( dlpParams->formatType == CRYPT_FORMAT_PGP && \
( dlpParams->inLen2 >= 42 && dlpParams->inLen2 <= 44 ) ) || \
( dlpParams->formatType == CRYPT_IFORMAT_SSH && \
dlpParams->inLen2 == 40 ) ) );
assert( dlpParams->outParam == NULL && dlpParams->outLen == 0 );
/* Decode the values from a DL data block and make sure that r and s are
valid, i.e. r, s = [1...q-1] */
status = pkcInfo->decodeDLValuesFunction( dlpParams->inParam2,
dlpParams->inLen2, r, s, q,
dlpParams->formatType );
if( cryptStatusError( status ) )
return( status );
/* Get the hash as a bignum. The range checking for the resulting value
is a bit odd, we need to take "the leftmost sizeof( q ) bits of the
hash" as the input, to handle this we require that the bit size of q
be at least as large as the (nominal) bit size of the hash */
if( dlpParams->inLen1 > BN_num_bytes( q ) )
return( CRYPT_ERROR_BADDATA );
status = extractBignum( u1, ( BYTE * ) dlpParams->inParam1,
DSA_SIGPART_SIZE, DSA_SIGPART_SIZE / 2,
DSA_SIGPART_SIZE, NULL, FALSE );
if( cryptStatusError( status ) )
return( status );
/* w = s^-1 mod q */
CKPTR( BN_mod_inverse( u2, s, q, /* w = s^-1 mod q */
pkcInfo->bnCTX ) );
/* u1 = ( hash * w ) mod q */
CK( BN_mod_mul( u1, u1, u2, q, /* u1 = ( hash * w ) mod q */
pkcInfo->bnCTX ) );
/* u2 = ( r * w ) mod q */
CK( BN_mod_mul( u2, r, u2, q, /* u2 = ( r * w ) mod q */
pkcInfo->bnCTX ) );
/* v = ( ( ( g^u1 ) * ( y^u2 ) ) mod p ) mod q */
CK( BN_mod_exp2_mont( u2, g, u1, y, u2, p, pkcInfo->bnCTX,
&pkcInfo->dlpParam_mont_p ) );
CK( BN_mod( s, u2, q, pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) )
return( getBnStatus( bnStatus ) );
/* if r == s signature is good */
return( BN_cmp( r, s ) ? CRYPT_ERROR_SIGNATURE : CRYPT_OK );
}
/****************************************************************************
* *
* Key Management *
* *
****************************************************************************/
/* Load key components into an encryption context */
static int initKey( CONTEXT_INFO *contextInfoPtr, const void *key,
const int keyLength )
{
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 )
{
PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
const CRYPT_PKCINFO_DLP *dsaKey = ( CRYPT_PKCINFO_DLP * ) key;
contextInfoPtr->flags |= ( dsaKey->isPublicKey ) ? \
CONTEXT_FLAG_ISPUBLICKEY : CONTEXT_FLAG_ISPRIVATEKEY;
status = extractBignum( &pkcInfo->dlpParam_p, dsaKey->p,
bitsToBytes( dsaKey->pLen ),
DLPPARAM_MIN_P, DLPPARAM_MAX_P, NULL, TRUE );
if( cryptStatusOK( status ) )
status = extractBignum( &pkcInfo->dlpParam_q, dsaKey->q,
bitsToBytes( dsaKey->qLen ),
DLPPARAM_MIN_Q, DLPPARAM_MAX_Q,
&pkcInfo->dlpParam_p, FALSE );
if( cryptStatusOK( status ) )
status = extractBignum( &pkcInfo->dlpParam_g, dsaKey->g,
bitsToBytes( dsaKey->gLen ),
DLPPARAM_MIN_G, DLPPARAM_MAX_G,
&pkcInfo->dlpParam_p, FALSE );
if( cryptStatusOK( status ) )
status = extractBignum( &pkcInfo->dlpParam_y, dsaKey->y,
bitsToBytes( dsaKey->yLen ),
DLPPARAM_MIN_Y, DLPPARAM_MAX_Y,
&pkcInfo->dlpParam_p, TRUE );
if( cryptStatusOK( status ) && !dsaKey->isPublicKey )
status = extractBignum( &pkcInfo->dlpParam_x, dsaKey->x,
bitsToBytes( dsaKey->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 ) )
status = checkDLPkey( contextInfoPtr, FALSE );
if( cryptStatusOK( status ) )
status = contextInfoPtr->ctxPKC->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 / 64 ) * 64 );
if( cryptStatusOK( status ) &&
#ifndef USE_FIPS140
( contextInfoPtr->flags & CONTEXT_FLAG_SIDECHANNELPROTECTION ) &&
#endif /* USE_FIPS140 */
!pairwiseConsistencyTest( contextInfoPtr ) )
{
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_DSA, bitsToBytes( 0 ), "DSA", 3,
MIN_PKCSIZE, bitsToBytes( 1024 ), CRYPT_MAX_PKCSIZE,
selfTest, getDefaultInfo, NULL, NULL, initKey, generateKey,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, sign, sigCheck
};
const CAPABILITY_INFO *getDSACapability( void )
{
return( &capabilityInfo );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -