#include "precomp.h"
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEcDsaTruncateHash(
_In_ PCSYMCRYPT_ECURVE pCurve,
_In_reads_bytes_( cbHashValue ) PCBYTE pbHashValue,
SIZE_T cbHashValue,
UINT32 flags,
_Out_ PSYMCRYPT_MODELEMENT peMsghash,
_Out_ PSYMCRYPT_INT piTmp,
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
SIZE_T cbScratch )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
UINT32 uiBitsizeOfTmp = 0;
UINT32 uiBitsizeOfGroup = 0;
if ( (flags & ~SYMCRYPT_FLAG_ECDSA_NO_TRUNCATION) != 0 )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
uiBitsizeOfGroup = SymCryptEcurveBitsizeofGroupOrder( pCurve );
if (cbHashValue*8 > uiBitsizeOfGroup)
{
cbHashValue = (uiBitsizeOfGroup + 7)/8;
}
scError = SymCryptIntSetValue( pbHashValue, cbHashValue, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piTmp );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
uiBitsizeOfTmp = (UINT32)cbHashValue * 8;
if ( ( flags & SYMCRYPT_FLAG_ECDSA_NO_TRUNCATION ) == 0)
{
if ( uiBitsizeOfTmp > uiBitsizeOfGroup )
{
SymCryptIntDivPow2( piTmp, uiBitsizeOfTmp - uiBitsizeOfGroup, piTmp );
}
}
SymCryptIntToModElement( piTmp, pCurve->GOrd, peMsghash, pbScratch, cbScratch );
cleanup:
return scError;
}
#define SYMCRYPT_MAX_ECDSA_SIGNATURE_COUNT (100)
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEcDsaSignEx(
_In_ PCSYMCRYPT_ECKEY pKey,
_In_reads_bytes_( cbHashValue ) PCBYTE pbHashValue,
SIZE_T cbHashValue,
_In_opt_ PCSYMCRYPT_INT piK,
SYMCRYPT_NUMBER_FORMAT format,
UINT32 flags,
_Out_writes_bytes_( cbSignature ) PBYTE pbSignature,
SIZE_T cbSignature )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PBYTE pbScratch = NULL;
SIZE_T cbScratch = 0;
SIZE_T cbScratchInternal = 0;
PBYTE pCurr = NULL;
PCSYMCRYPT_ECURVE pCurve = pKey->pCurve;
PSYMCRYPT_INT piTmp = NULL;
PSYMCRYPT_INT piMul = NULL;
PSYMCRYPT_ECPOINT poKG = NULL;
PSYMCRYPT_MODELEMENT peMsghash = NULL;
PSYMCRYPT_MODELEMENT peSigC = NULL;
PSYMCRYPT_MODELEMENT peSigD = NULL;
PSYMCRYPT_MODELEMENT peTmp = NULL;
PBYTE pbX = NULL;
UINT32 nDigitsInt = 0;
UINT32 nDigitsMul = 0;
UINT32 cbInt = 0;
UINT32 cbMul = 0;
UINT32 cbKG = 0;
UINT32 cbRs = 0;
UINT32 cbX = 0;
UINT32 signatureCount = 0;
UINT32 allowedFlags = SYMCRYPT_FLAG_ECDSA_NO_TRUNCATION | SYMCRYPT_FLAG_DATA_PUBLIC;
UINT32 publicFlag = flags & SYMCRYPT_FLAG_DATA_PUBLIC;
UINT32 truncationFlag = flags & SYMCRYPT_FLAG_ECDSA_NO_TRUNCATION;
if ( ((pKey->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDSA) == 0) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( ((flags & ~(allowedFlags)) != 0) ||
(!pKey->hasPrivateKey) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
nDigitsInt = pCurve->GOrdDigits;
nDigitsMul = SymCryptEcurveDigitsofScalarMultiplier(pCurve);
cbInt = SymCryptSizeofIntFromDigits( nDigitsInt );
cbMul = SymCryptSizeofIntFromDigits( nDigitsMul );
cbKG = SymCryptSizeofEcpointFromCurve( pCurve );
cbRs = SymCryptSizeofModElementFromModulus( pCurve->GOrd );
cbX = SymCryptEcurveSizeofFieldElement( pCurve );
cbScratchInternal = SYMCRYPT_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS( pCurve );
cbScratchInternal = SYMCRYPT_MAX( cbScratchInternal, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->GOrdDigits ) );
cbScratchInternal = SYMCRYPT_MAX( cbScratchInternal, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) );
cbScratchInternal = SYMCRYPT_MAX( cbScratchInternal, SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( pCurve->GOrdDigits ) );
cbScratchInternal = SYMCRYPT_MAX( cbScratchInternal, SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) );
cbScratch = cbScratchInternal + cbInt + cbMul + cbKG + 4*cbRs + cbX;
pbScratch = SymCryptCallbackAlloc( cbScratch );
if ( pbScratch == NULL )
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
pCurr = pbScratch + cbScratchInternal;
piTmp = SymCryptIntCreate( pCurr, cbInt, nDigitsInt );
pCurr += cbInt;
piMul = SymCryptIntCreate( pCurr, cbMul, nDigitsMul );
pCurr += cbMul;
poKG = SymCryptEcpointCreate( pCurr, cbKG, pCurve );
pCurr += cbKG;
peMsghash = SymCryptModElementCreate( pCurr, cbRs, pCurve->GOrd );
pCurr += cbRs;
peSigC = SymCryptModElementCreate( pCurr, cbRs, pCurve->GOrd );
pCurr += cbRs;
peSigD = SymCryptModElementCreate( pCurr, cbRs, pCurve->GOrd );
pCurr += cbRs;
peTmp = SymCryptModElementCreate( pCurr, cbRs, pCurve->GOrd );
pCurr += cbRs;
pbX = pCurr;
SYMCRYPT_ASSERT( piTmp != NULL);
SYMCRYPT_ASSERT( piMul != NULL);
SYMCRYPT_ASSERT( poKG != NULL);
SYMCRYPT_ASSERT( peMsghash != NULL);
SYMCRYPT_ASSERT( peSigC != NULL);
SYMCRYPT_ASSERT( peSigD != NULL);
SYMCRYPT_ASSERT( peTmp != NULL);
scError = SymCryptEcDsaTruncateHash(
pCurve,
pbHashValue,
cbHashValue,
truncationFlag,
peMsghash,
piTmp,
pbScratch,
cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
while( TRUE )
{
if ( piK == NULL )
{
SymCryptEcpointSetRandom( pCurve, piMul, poKG, pbScratch, cbScratchInternal );
SymCryptIntToModElement( piMul, pCurve->GOrd, peTmp, pbScratch, cbScratchInternal );
}
else
{
if( SymCryptIntIsEqualUint32( piK, 0 ) ||
!SymCryptIntIsLessThan( piK, SymCryptIntFromModulus( pCurve->GOrd ) ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
SymCryptIntCopy( piK, piMul );
SymCryptIntToModElement( piMul, pCurve->GOrd, peTmp, pbScratch, cbScratchInternal );
scError = SymCryptEcpointScalarMul( pCurve, piMul, NULL, 0, poKG, pbScratch, cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
}
scError = SymCryptModInv( pCurve->GOrd, peTmp, peTmp, publicFlag, pbScratch, cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
scError = SymCryptEcpointGetValue(
pCurve,
poKG,
SYMCRYPT_NUMBER_FORMAT_MSB_FIRST,
SYMCRYPT_ECPOINT_FORMAT_X,
pbX,
cbX,
publicFlag,
pbScratch,
cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
scError = SymCryptModElementSetValue( pbX, cbX, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pCurve->GOrd, peSigC, pbScratch, cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
SymCryptIntToModElement( pKey->piPrivateKey, pCurve->GOrd, peSigD, pbScratch, cbScratchInternal );
for (UINT32 i=0; i<pCurve->coFactorPower; i++)
{
SymCryptModAdd( pCurve->GOrd, peSigD, peSigD, peSigD, pbScratch, cbScratchInternal );
}
SymCryptModMul( pCurve->GOrd, peSigC, peSigD, peSigD, pbScratch, cbScratchInternal );
SymCryptModAdd( pCurve->GOrd, peMsghash, peSigD, peSigD, pbScratch, cbScratchInternal );
SymCryptModMul( pCurve->GOrd, peSigD, peTmp, peSigD, pbScratch, cbScratchInternal );
if ( !( SymCryptModElementIsZero( pCurve->GOrd, peSigC ) |
SymCryptModElementIsZero( pCurve->GOrd, peSigD ) ) )
{
break;
}
if (piK != NULL)
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
signatureCount++;
if ( signatureCount >= SYMCRYPT_MAX_ECDSA_SIGNATURE_COUNT )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
}
scError = SymCryptModElementGetValue( pCurve->GOrd, peSigC, pbSignature, cbSignature / 2, format, pbScratch, cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
scError = SymCryptModElementGetValue( pCurve->GOrd, peSigD, pbSignature + cbSignature / 2, cbSignature / 2, format, pbScratch, cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
cleanup:
if ( pbScratch != NULL )
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
if (scError != SYMCRYPT_NO_ERROR)
{
SymCryptWipe( pbSignature, cbSignature );
}
return scError;
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEcDsaSign(
_In_ PCSYMCRYPT_ECKEY pKey,
_In_reads_bytes_( cbHashValue ) PCBYTE pbHashValue,
SIZE_T cbHashValue,
SYMCRYPT_NUMBER_FORMAT format,
UINT32 flags,
_Out_writes_bytes_( cbSignature ) PBYTE pbSignature,
SIZE_T cbSignature )
{
if ( (flags & ~SYMCRYPT_FLAG_ECDSA_NO_TRUNCATION) != 0 )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
if( !pKey->hasPrivateKey || !(pKey->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDSA) )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
SYMCRYPT_RUN_KEY_GEN_PCT(
SymCryptEcDsaPct,
pKey,
SYMCRYPT_PCT_ECDSA );
return SymCryptEcDsaSignEx( pKey, pbHashValue, cbHashValue, NULL, format, flags, pbSignature, cbSignature );
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEcDsaVerify(
_In_ PCSYMCRYPT_ECKEY pKey,
_In_reads_bytes_( cbHashValue ) PCBYTE pbHashValue,
SIZE_T cbHashValue,
_In_reads_bytes_( cbSignature ) PCBYTE pbSignature,
SIZE_T cbSignature,
SYMCRYPT_NUMBER_FORMAT format,
UINT32 flags )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PBYTE pbScratch = NULL;
SIZE_T cbScratch = 0;
SIZE_T cbScratchInternal = 0;
PBYTE pCurr = NULL;
BOOLEAN fValidSignature = FALSE;
PCSYMCRYPT_ECURVE pCurve = pKey->pCurve;
PSYMCRYPT_INT piTmp = NULL;
PSYMCRYPT_INT piMul1 = NULL;
PSYMCRYPT_INT piMul2 = NULL;
PSYMCRYPT_ECPOINT poQ1 = NULL;
PSYMCRYPT_ECPOINT poQ2 = NULL;
PSYMCRYPT_MODELEMENT peMsghash = NULL;
PSYMCRYPT_MODELEMENT peSigC = NULL;
PSYMCRYPT_MODELEMENT peSigD = NULL;
PSYMCRYPT_MODELEMENT peTmp = NULL;
PBYTE pbX = NULL;
PCSYMCRYPT_ECPOINT poTable[2] = { 0 };
PCSYMCRYPT_INT piTable[2] = { 0 };
UINT32 nDigitsInt = 0;
UINT32 nDigitsMul = 0;
UINT32 cbInt = 0;
UINT32 cbMul = 0;
UINT32 cbKG = 0;
UINT32 cbRs = 0;
UINT32 cbX = 0;
if ( ((pKey->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDSA) == 0) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( (flags & ~SYMCRYPT_FLAG_ECDSA_NO_TRUNCATION) != 0 )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
nDigitsInt = SYMCRYPT_MAX( pCurve->FModDigits, pCurve->GOrdDigits );
nDigitsInt = SYMCRYPT_MAX( nDigitsInt, SymCryptDigitsFromBits( (UINT32)cbSignature * 4 ) );
nDigitsMul = SymCryptEcurveDigitsofScalarMultiplier(pCurve);
cbInt = SymCryptSizeofIntFromDigits( nDigitsInt );
cbMul = SymCryptSizeofIntFromDigits( nDigitsMul );
cbKG = SymCryptSizeofEcpointFromCurve( pCurve );
cbRs = SymCryptSizeofModElementFromModulus( pCurve->GOrd );
cbX = SymCryptEcurveSizeofFieldElement( pCurve );
cbScratchInternal = SYMCRYPT_SCRATCH_BYTES_FOR_MULTI_SCALAR_ECURVE_OPERATIONS( pCurve, 2 );
cbScratchInternal = SYMCRYPT_MAX( cbScratchInternal, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->GOrdDigits ) );
cbScratchInternal = SYMCRYPT_MAX( cbScratchInternal, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pCurve->FModDigits ) );
cbScratchInternal = SYMCRYPT_MAX( cbScratchInternal, SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( pCurve->GOrdDigits ) );
cbScratchInternal = SYMCRYPT_MAX( cbScratchInternal, SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) );
cbScratchInternal = SYMCRYPT_MAX( cbScratchInternal, SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS( pCurve ) );
cbScratch = cbScratchInternal + cbInt + 2*cbMul + 2*cbKG + 4*cbRs + cbX;
pbScratch = SymCryptCallbackAlloc( cbScratch );
if ( pbScratch == NULL )
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
pCurr = pbScratch + cbScratchInternal;
piTmp = SymCryptIntCreate( pCurr, cbInt, nDigitsInt );
pCurr += cbInt;
piMul1 = SymCryptIntCreate( pCurr, cbMul, nDigitsMul );
pCurr += cbMul;
piMul2 = SymCryptIntCreate( pCurr, cbMul, nDigitsMul );
pCurr += cbMul;
poQ1 = SymCryptEcpointCreate( pCurr, cbKG, pCurve );
pCurr += cbKG;
poQ2 = SymCryptEcpointCreate( pCurr, cbKG, pCurve );
pCurr += cbKG;
peMsghash = SymCryptModElementCreate( pCurr, cbRs, pCurve->GOrd );
pCurr += cbRs;
peSigC = SymCryptModElementCreate( pCurr, cbRs, pCurve->GOrd );
pCurr += cbRs;
peSigD = SymCryptModElementCreate( pCurr, cbRs, pCurve->GOrd );
pCurr += cbRs;
peTmp = SymCryptModElementCreate( pCurr, cbRs, pCurve->GOrd );
pCurr += cbRs;
pbX = pCurr;
SYMCRYPT_ASSERT( piTmp != NULL);
SYMCRYPT_ASSERT( piMul1 != NULL);
SYMCRYPT_ASSERT( piMul2 != NULL);
SYMCRYPT_ASSERT( poQ1 != NULL);
SYMCRYPT_ASSERT( poQ2 != NULL);
SYMCRYPT_ASSERT( peMsghash != NULL);
SYMCRYPT_ASSERT( peSigC != NULL);
SYMCRYPT_ASSERT( peSigD != NULL);
SYMCRYPT_ASSERT( peTmp != NULL);
scError = SymCryptIntSetValue( pbSignature, cbSignature / 2, format, piTmp );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( !SymCryptIntIsLessThan( piTmp, SymCryptIntFromModulus( pCurve->GOrd ) ) )
{
goto cleanup;
}
SymCryptIntToModElement( piTmp, pCurve->GOrd, peSigC, pbScratch, cbScratchInternal );
if (SymCryptModElementIsZero( pCurve->GOrd, peSigC ))
{
goto cleanup;
}
scError = SymCryptIntSetValue( pbSignature + cbSignature / 2, cbSignature / 2, format, piTmp );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( !SymCryptIntIsLessThan( piTmp, SymCryptIntFromModulus( pCurve->GOrd ) ) )
{
goto cleanup;
}
SymCryptIntToModElement( piTmp, pCurve->GOrd, peSigD, pbScratch, cbScratchInternal );
if (SymCryptModElementIsZero( pCurve->GOrd, peSigD ))
{
goto cleanup;
}
scError = SymCryptModInv( pCurve->GOrd, peSigD, peSigD, SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratchInternal );
if( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
scError = SymCryptEcDsaTruncateHash(
pCurve,
pbHashValue,
cbHashValue,
flags,
peMsghash,
piTmp,
pbScratch,
cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
SymCryptModMul( pCurve->GOrd, peMsghash, peSigD, peMsghash, pbScratch, cbScratchInternal );
SymCryptModMul( pCurve->GOrd, peSigC, peSigD, peTmp, pbScratch, cbScratchInternal );
SymCryptModElementToInt( pCurve->GOrd, peMsghash, piMul1, pbScratch, cbScratchInternal );
SymCryptModElementToInt( pCurve->GOrd, peTmp, piMul2, pbScratch, cbScratchInternal );
piTable[0] = piMul1;
piTable[1] = piMul2;
poTable[0] = NULL;
poTable[1] = pKey->poPublicKey;
scError = SymCryptEcpointMultiScalarMul( pCurve, piTable, poTable, 2, SYMCRYPT_FLAG_DATA_PUBLIC, poQ1, pbScratch, cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( SymCryptEcpointIsZero( pCurve, poQ1, pbScratch, cbScratchInternal ) )
{
goto cleanup;
}
scError = SymCryptEcpointGetValue( pCurve, poQ1, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, SYMCRYPT_ECPOINT_FORMAT_X, pbX, cbX, SYMCRYPT_FLAG_DATA_PUBLIC, pbScratch, cbScratchInternal);
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
scError = SymCryptIntSetValue( pbX, cbX, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piTmp );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
SymCryptIntToModElement( piTmp, pCurve->GOrd, peTmp, pbScratch, cbScratchInternal );
if (SymCryptModElementIsEqual( pCurve->GOrd, peSigC, peTmp ))
{
fValidSignature = TRUE;
}
cleanup:
if (!fValidSignature)
{
scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE;
}
if ( pbScratch != NULL )
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}