📄 ctx_ecdsa.c
字号:
/****************************************************************************
* *
* cryptlib ECDSA Encryption Routines *
* Copyright Matthias Bruestle and Peter Gutmann 2006-2007 *
* *
****************************************************************************/
#define PKC_CONTEXT /* Indicate that we're working with PKC context */
#if defined( INC_ALL )
#include "crypt.h"
#include "context.h"
/* #include "ecp.h" */
#else
#include "crypt.h"
#include "context/context.h"
/* #include "context/ecp.h" */
#endif /* Compiler-specific includes */
#ifdef USE_ECC
/****************************************************************************
* *
* Algorithm Self-test *
* *
****************************************************************************/
/* Test the ECDSA implementation using the test vectors from GEC 2:
Test Vectors for SEC 1, Working Draft, September, 1999, Version 0.3
Because a lot of the high-level encryption routines don't exist yet, we
cheat a bit and set up a dummy encryption context with just enough
information for the following code to work */
#define ECDSA_TESTVECTOR_SIZE 20
static const FAR_BSS CRYPT_PKCINFO_ECC ecdsaTestKey = {
0,
/* p */
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x7F, 0xFF, 0xFF, 0xFF },
160,
/* a */
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x7F, 0xFF, 0xFF, 0xFC },
160,
/* b */
{ 0x1C, 0x97, 0xBE, 0xFC, 0x54, 0xBD, 0x7A, 0x8B,
0x65, 0xAC, 0xF8, 0x9F, 0x81, 0xD4, 0xD4, 0xAD,
0xC5, 0x65, 0xFA, 0x45 },
160,
/* gx */
{ 0x4A, 0x96, 0xB5, 0x68, 0x8E, 0xF5, 0x73, 0x28,
0x46, 0x64, 0x69, 0x89, 0x68, 0xC3, 0x8B, 0xB9,
0x13, 0xCB, 0xFC, 0x82 },
160,
/* gy */
{ 0x23, 0xA6, 0x28, 0x55, 0x31, 0x68, 0x94, 0x7D,
0x59, 0xDC, 0xC9, 0x12, 0x04, 0x23, 0x51, 0x37,
0x7A, 0xC5, 0xFB, 0x32 },
160,
/* gr */
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xF4, 0xC8, 0xF9, 0x27, 0xAE,
0xD3, 0xCA, 0x75, 0x22, 0x57 },
160,
/* gh */
{ 0x01 },
1,
/* qx */
{ 0x51, 0xB4, 0x49, 0x6F, 0xEC, 0xC4, 0x06, 0xED,
0x0E, 0x75, 0xA2, 0x4A, 0x3C, 0x03, 0x20, 0x62,
0x51, 0x41, 0x9D, 0xC0 },
160,
/* qy */
{ 0xC2, 0x8D, 0xCB, 0x4B, 0x73, 0xA5, 0x14, 0xB4,
0x68, 0xD7, 0x93, 0x89, 0x4F, 0x38, 0x1C, 0xCC,
0x17, 0x56, 0xAA, 0x6C },
160,
/* d */
{ 0xAA, 0x37, 0x4F, 0xFC, 0x3C, 0xE1, 0x44, 0xE6,
0xB0, 0x73, 0x30, 0x79, 0x72, 0xCB, 0x6D, 0x57,
0xB2, 0xA4, 0xE9, 0x82 },
160,
};
/* SHA-1 hash of "abc" */
static const FAR_BSS BYTE shaM[] = {
0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A,
0xBA, 0x3E, 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C,
0x9C, 0xD0, 0xD8, 0x9D
};
/* If we're doing a self-test using the GEC2 values we use the following
fixed k data rather than a randomly-generated value. */
static const FAR_BSS BYTE kVal[] = {
0x7B, 0x01, 0x2D, 0xB7, 0x68, 0x1A, 0x3F, 0x28,
0xB9, 0x18, 0x5C, 0x8B, 0x2A, 0xC5, 0xD5, 0x28,
0xDE, 0xCD, 0x52, 0xDA,
};
/* Signature:
r=CE2873E5BE449563391FEB47DDCBA2DC16379191
s=3480EC1371A091A464B31CE47DF0CB8AA2D98B54 */
static BOOLEAN pairwiseConsistencyTest( CONTEXT_INFO *contextInfoPtr )
{
return( CRYPT_ERROR_NOTAVAIL );
}
static int selfTest( void )
{
CONTEXT_INFO contextInfo;
PKC_INFO contextData, *pkcInfo = &contextData;
int status;
/* Initialise the key components */
status = staticInitContext( &contextInfo, CONTEXT_PKC,
getECDSACapability(), &contextData,
sizeof( PKC_INFO ), NULL );
if( cryptStatusError( status ) )
return( CRYPT_ERROR_FAILED );
pairwiseConsistencyTest( NULL ); /* Keep compiler happy */
/* Clean up */
staticDestroyContext( &contextInfo );
return( CRYPT_ERROR_NOTAVAIL );
}
/****************************************************************************
* *
* Create/Check a Signature *
* *
****************************************************************************/
/* Since ECDSA 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, which is
also used for ECDSA:
Dss-Sig ::= SEQUENCE {
r INTEGER,
s INTEGER
} */
/* Sign a single block of data */
static int sign( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
{
PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
BN_CTX *bnCtx = pkcInfo->bnCTX;
DLP_PARAMS *eccParams = ( DLP_PARAMS * ) buffer;
BIGNUM *p = &pkcInfo->eccParam_p, *a = &pkcInfo->eccParam_a;
BIGNUM *b = &pkcInfo->eccParam_b, *gx = &pkcInfo->eccParam_gx;
BIGNUM *gy = &pkcInfo->eccParam_gy, *d = &pkcInfo->eccParam_d;
BIGNUM *gr = &pkcInfo->eccParam_r;
BIGNUM *hash = &pkcInfo->tmp1, *k = &pkcInfo->tmp2, *r = &pkcInfo->tmp3;
BIGNUM *s = &pkcInfo->tmp4;
S_ECP_CTX ctx;
S_POINT kg;
int bnStatus = BN_STATUS, status;
printf( "sign( noBytes=%d )\n", noBytes ); // eZ
assert( noBytes == sizeof( DLP_PARAMS ) );
assert( eccParams->inParam1 != NULL );
assert( eccParams->inParam2 == NULL && \
( eccParams->inLen2 == 0 || eccParams->inLen2 == -999 ) );
assert( eccParams->outParam != NULL && \
eccParams->outLen >= ( 2 + CRYPT_MAX_ECCSIZE ) * 2 );
printf( "sign( P1 )\n" ); // eZ
BN_CTX_start( bnCtx );
// hash = BN_CTX_get( bnCtx );
// k = BN_CTX_get( bnCtx );
// Can you hide all this in a ecpCtxInit() that initialises a S_ECP_CTX from
// a BN_CTX + pkcInfo?
ctx.t1 = BN_CTX_get( bnCtx );
ctx.t2 = BN_CTX_get( bnCtx );
ctx.t3 = BN_CTX_get( bnCtx );
ctx.t4 = BN_CTX_get( bnCtx );
ctx.p1.x = BN_CTX_get( bnCtx );
ctx.p1.y = BN_CTX_get( bnCtx );
ctx.p2.x = BN_CTX_get( bnCtx );
ctx.p2.y = BN_CTX_get( bnCtx );
ctx.p3.x = BN_CTX_get( bnCtx );
ctx.p3.y = BN_CTX_get( bnCtx );
ctx.pkc = pkcInfo;
// Same here, with ecpPointInit() instead.
kg.x = BN_CTX_get( bnCtx );
kg.y = BN_CTX_get( bnCtx );
printf( "sign( P2 )\n" ); // eZ
// r = BN_CTX_get( bnCtx );
// CKPTR( s = BN_CTX_get( bnCtx ) );
// if( bnStatusError( bnStatus ) )
// {
// status = getBnStatus( bnStatus );
// goto retreat;
// }
printf( "sign( P3 )\n" ); // eZ
if( !ecp_init( &ctx, 0 ) )
{
BN_CTX_end( bnCtx );
return( CRYPT_ERROR_FAILED );
}
printf( "sign( P4 )\n" ); // eZ
while( TRUE )
{
/* 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 GEC2 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( eccParams->inLen2 == -999 )
BN_bin2bn( ( BYTE * ) kVal, ECDSA_TESTVECTOR_SIZE, k );
else
{
/* Generate the random value k from [1...r-1], i.e. a random
value mod r. Using a random value of the same length as r
would produce 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 r and then do the
reduction, eliminating the bias */
status = generateBignum( k, BN_num_bits( gr ) + 32, 0, 0 );
if( cryptStatusError( status ) )
break;
}
printf( "sign( P5 )\n" ); // eZ
if( contextInfoPtr->flags & CONTEXT_SIDECHANNELPROTECTION )
{
/* Use constant-time modexp() to protect the secret random value
from timing channels */
BN_set_flags( k, BN_FLG_EXP_CONSTTIME );
}
printf( "sign( P5b )\n" ); // eZ
//printf( " k = %s\n", BN_num_bits( k ) ); // eZ
//printf( " gr = %s\n", BN_num_bits( gr ) ); // eZ
CK( BN_mod( k, k, gr, /* Reduce k to the correct range */
pkcInfo->bnCTX ) );
if( bnStatusError( bnStatus ) )
{
status = getBnStatus( bnStatus );
break;
}
printf( "sign( P5c )\n" ); // eZ
/* If the result is zero, try again. Admittedly the chances of this
are infinitesimally small (typically 2^-160 or less), but
someone's bound to complain if we don't check */
if( BN_is_zero( k ) )
continue;
printf( "sign( P6 )\n" ); // eZ
/* Move the data from the buffer into a bignum */
BN_bin2bn( ( BYTE * ) eccParams->inParam1, eccParams->inLen1, hash );
/* Compute the point (x1, y1) = kG */
CKPTR( BN_copy( kg.x, gx ) );
CKPTR( BN_copy( kg.y, gy ) );
if( bnStatusError( bnStatus ) )
{
status = CRYPT_ERROR_FAILED;
break;
}
printf( "sign( P7 )\n" ); // eZ
/* Convert kG to an integer r using r = p((x1, y1)) mod n = x1 mod n */
if( !ecp_pt_smul_naf( &ctx, &kg, k ) )
{
status = CRYPT_ERROR_FAILED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -