#include "precomp.h"
PSYMCRYPT_ECKEY
SYMCRYPT_CALL
SymCryptEckeyAllocate( _In_ PCSYMCRYPT_ECURVE pCurve )
{
PVOID p;
SIZE_T cb;
PSYMCRYPT_ECKEY res = NULL;
cb = SymCryptSizeofEckeyFromCurve( pCurve );
p = SymCryptCallbackAlloc( cb );
if ( p==NULL )
{
goto cleanup;
}
res = SymCryptEckeyCreate( p, cb, pCurve );
cleanup:
return res;
}
VOID
SYMCRYPT_CALL
SymCryptEckeyFree( _Out_ PSYMCRYPT_ECKEY pkObj )
{
SYMCRYPT_CHECK_MAGIC( pkObj );
SymCryptEckeyWipe( pkObj );
SymCryptCallbackFree( pkObj );
}
UINT32
SYMCRYPT_CALL
SymCryptSizeofEckeyFromCurve( _In_ PCSYMCRYPT_ECURVE pCurve )
{
return sizeof(SYMCRYPT_ECKEY) + SymCryptSizeofEcpointFromCurve( pCurve ) + SymCryptSizeofIntFromDigits(SymCryptEcurveDigitsofScalarMultiplier(pCurve));
}
PSYMCRYPT_ECKEY
SYMCRYPT_CALL
SymCryptEckeyCreate(
_Out_writes_bytes_( cbBuffer ) PBYTE pbBuffer,
SIZE_T cbBuffer,
PCSYMCRYPT_ECURVE pCurve )
{
PSYMCRYPT_ECKEY pkObj = NULL;
UINT32 privateKeyDigits = SymCryptEcurveDigitsofScalarMultiplier(pCurve);
SIZE_T cbPublicKey = SymCryptSizeofEcpointFromCurve( pCurve );
SIZE_T cbPrivateKey = SymCryptSizeofIntFromDigits( privateKeyDigits );
UNREFERENCED_PARAMETER( cbBuffer );
SYMCRYPT_ASSERT( pCurve != NULL );
SYMCRYPT_ASSERT( cbBuffer >= SymCryptSizeofEckeyFromCurve( pCurve ) );
SYMCRYPT_ASSERT( cbBuffer >= sizeof(SYMCRYPT_ECKEY) +
cbPublicKey +
cbPrivateKey );
SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
pkObj = (PSYMCRYPT_ECKEY) pbBuffer;
pkObj->fAlgorithmInfo = 0;
pkObj->hasPrivateKey = FALSE;
pkObj->pCurve = pCurve;
pkObj->poPublicKey = SymCryptEcpointCreate(
pbBuffer + sizeof(SYMCRYPT_ECKEY),
cbPublicKey,
pCurve );
SYMCRYPT_ASSERT( pkObj->poPublicKey != NULL );
pkObj->piPrivateKey = SymCryptIntCreate(
pbBuffer + sizeof(SYMCRYPT_ECKEY) + cbPublicKey,
cbPrivateKey,
privateKeyDigits );
SYMCRYPT_ASSERT( pkObj->piPrivateKey );
SYMCRYPT_SET_MAGIC( pkObj );
return pkObj;
}
VOID
SYMCRYPT_CALL
SymCryptEckeyWipePrivateState(
_Inout_ PSYMCRYPT_ECKEY pkEckey )
{
SymCryptIntSetValueUint32( 0, pkEckey->piPrivateKey );
pkEckey->hasPrivateKey = FALSE;
}
VOID
SYMCRYPT_CALL
SymCryptEckeyWipe( _Out_ PSYMCRYPT_ECKEY pkDst )
{
SymCryptWipe( pkDst, SymCryptSizeofEckeyFromCurve( pkDst->pCurve ) );
}
VOID
SymCryptEckeyCopy(
_In_ PCSYMCRYPT_ECKEY pkSrc,
_Out_ PSYMCRYPT_ECKEY pkDst )
{
if( pkSrc != pkDst )
{
pkDst->fAlgorithmInfo = pkSrc->fAlgorithmInfo;
pkDst->hasPrivateKey = pkSrc->hasPrivateKey;
SymCryptEcpointCopy( pkSrc->pCurve, pkSrc->poPublicKey, pkDst->poPublicKey );
SymCryptIntCopy( pkSrc->piPrivateKey, pkDst->piPrivateKey );
}
}
UINT32
SYMCRYPT_CALL
SymCryptEckeySizeofPublicKey(
_In_ PCSYMCRYPT_ECKEY pkEckey,
_In_ SYMCRYPT_ECPOINT_FORMAT ecPointFormat )
{
return SymCryptEcpointFormatNumberofElements[ecPointFormat] * SymCryptEcurveSizeofFieldElement( pkEckey->pCurve );
}
UINT32
SYMCRYPT_CALL
SymCryptEckeySizeofPrivateKey( _In_ PCSYMCRYPT_ECKEY pkEckey )
{
return SymCryptEcurveSizeofScalarMultiplier( pkEckey->pCurve );
}
BOOLEAN
SYMCRYPT_CALL
SymCryptEckeyHasPrivateKey( _In_ PCSYMCRYPT_ECKEY pkEckey )
{
return pkEckey->hasPrivateKey;
}
#define SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION (0x1)
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEckeyPerformPublicKeyValidation(
_In_ PCSYMCRYPT_ECKEY pEckey,
_In_ UINT32 flags,
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
SIZE_T cbScratch )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PCSYMCRYPT_ECURVE pCurve = pEckey->pCurve;
PSYMCRYPT_ECPOINT poNPub = NULL;
UINT32 cbNPub = SymCryptSizeofEcpointFromCurve( pCurve );
SYMCRYPT_ASSERT( cbScratch >= SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_ECKEY_ECURVE_OPERATIONS( pCurve ) );
SYMCRYPT_ASSERT( cbScratch >= cbNPub );
if ( SymCryptEcpointIsZero( pCurve, pEckey->poPublicKey, pbScratch, cbScratch ) )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
if ( !SYMCRYPT_CURVE_IS_MONTGOMERY_TYPE(pCurve) &&
!SymCryptEcpointOnCurve( pCurve, pEckey->poPublicKey, pbScratch, cbScratch ) )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
if ( (flags & SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION) != 0 )
{
if ( SymCryptIntIsEqualUint32( pCurve->H, 1 ) )
{
}
else
{
poNPub = SymCryptEcpointCreate( pbScratch, cbNPub, pCurve );
pbScratch += cbNPub;
cbScratch -= cbNPub;
SYMCRYPT_ASSERT( poNPub != NULL );
scError = SymCryptEcpointScalarMul(
pCurve,
SymCryptIntFromModulus( pCurve->GOrd ),
pEckey->poPublicKey,
0,
poNPub,
pbScratch,
cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
return scError;
}
if ( !SymCryptEcpointIsZero( pCurve, poNPub, pbScratch, cbScratch ) )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
}
}
return SYMCRYPT_NO_ERROR;
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEckeySetValue(
_In_reads_bytes_( cbPrivateKey )
PCBYTE pbPrivateKey,
SIZE_T cbPrivateKey,
_In_reads_bytes_( cbPublicKey )
PCBYTE pbPublicKey,
SIZE_T cbPublicKey,
SYMCRYPT_NUMBER_FORMAT numFormat,
SYMCRYPT_ECPOINT_FORMAT ecPointFormat,
UINT32 flags,
_Inout_ PSYMCRYPT_ECKEY pEckey )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PBYTE pbScratch = NULL;
UINT32 cbScratch = 0;
PBYTE pbScratchInternal = NULL;
UINT32 cbScratchInternal = 0;
PCSYMCRYPT_ECURVE pCurve = pEckey->pCurve;
PSYMCRYPT_ECPOINT poTmp = NULL;
UINT32 cbTmp = 0;
PSYMCRYPT_INT piTmpInteger = NULL;
UINT32 cbTmpInteger = 0;
PSYMCRYPT_MODELEMENT peTmpModElement = NULL;
UINT32 cbTmpModElement = pCurve->cbModElement;
UINT32 privateKeyDigits = SymCryptEcurveDigitsofScalarMultiplier(pCurve);
UINT32 fValidatePublicKeyOrder = SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION;
UINT32 algorithmFlags = SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH;
UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION | algorithmFlags;
if ( ( ( flags & ~allowedFlags ) != 0 ) ||
( ( flags & algorithmFlags ) == 0 ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) &&
( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) != 0 ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) != 0 )
{
fValidatePublicKeyOrder = 0;
}
if ( ( ( cbPrivateKey == 0 ) && ( cbPublicKey == 0 ) ) ||
( ( cbPrivateKey != 0 ) && ( cbPrivateKey != SymCryptEcurveSizeofScalarMultiplier( pEckey->pCurve ) ) ) ||
( ( cbPublicKey != 0 ) && ( cbPublicKey != SymCryptEckeySizeofPublicKey( pEckey, ecPointFormat ) ) ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
cbScratch = SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_ECKEY_ECURVE_OPERATIONS( pCurve );
pbScratch = SymCryptCallbackAlloc( cbScratch );
if ( pbScratch == NULL )
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
if ( pbPrivateKey != NULL )
{
pbScratchInternal = pbScratch;
cbScratchInternal = cbScratch;
cbTmpInteger = SymCryptSizeofIntFromDigits( privateKeyDigits );
piTmpInteger = SymCryptIntCreate( pbScratchInternal, cbTmpInteger, privateKeyDigits );
SYMCRYPT_ASSERT( piTmpInteger != NULL );
pbScratchInternal += cbTmpInteger;
cbScratchInternal -= cbTmpInteger;
peTmpModElement = SymCryptModElementCreate( pbScratchInternal, cbTmpModElement, pCurve->GOrd );
SYMCRYPT_ASSERT( peTmpModElement != NULL );
pbScratchInternal += cbTmpModElement;
cbScratchInternal -= cbTmpModElement;
scError = SymCryptIntSetValue( pbPrivateKey, cbPrivateKey, numFormat, piTmpInteger );
if (scError != SYMCRYPT_NO_ERROR)
{
goto cleanup;
}
if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 )
{
if ( pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL )
{
if ( !SymCryptIntIsLessThan( piTmpInteger, SymCryptIntFromModulus( pCurve->GOrd ) ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
}
if ( (pCurve->coFactorPower>0) &&
(pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_DIVH_TIMESH) &&
(SymCryptIntGetBits( piTmpInteger, 0, pCurve->coFactorPower) != 0) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( (pCurve->HighBitRestrictionNumOfBits>0) &&
(SymCryptIntGetBits(
piTmpInteger,
pCurve->HighBitRestrictionPosition,
pCurve->HighBitRestrictionNumOfBits) != pCurve->HighBitRestrictionValue) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
}
if (pCurve->coFactorPower>0)
{
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_DIVH_TIMESH)
{
SymCryptIntDivPow2( piTmpInteger, pCurve->coFactorPower, piTmpInteger );
}
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL)
{
SymCryptIntToModElement( piTmpInteger, pCurve->GOrd, peTmpModElement, pbScratchInternal, cbScratchInternal );
SymCryptModDivPow2( pCurve->GOrd, peTmpModElement, pCurve->coFactorPower, peTmpModElement, pbScratchInternal, cbScratchInternal );
SymCryptModElementToInt( pCurve->GOrd, peTmpModElement, piTmpInteger, pbScratchInternal, cbScratchInternal );
}
}
SymCryptIntDivMod(
piTmpInteger,
SymCryptDivisorFromModulus(pCurve->GOrd),
NULL,
piTmpInteger,
pbScratchInternal,
cbScratchInternal );
if (SymCryptIntIsEqualUint32( piTmpInteger, 0 ))
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
SymCryptIntCopy( piTmpInteger, pEckey->piPrivateKey );
pEckey->hasPrivateKey = TRUE;
}
if ( pbPublicKey != NULL )
{
scError = SymCryptEcpointSetValue(
pCurve,
pbPublicKey,
cbPublicKey,
numFormat,
ecPointFormat,
pEckey->poPublicKey,
SYMCRYPT_FLAG_DATA_PUBLIC,
pbScratch,
cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 )
{
scError = SymCryptEckeyPerformPublicKeyValidation(
pEckey,
fValidatePublicKeyOrder,
pbScratch,
cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
}
}
if ( (pbPublicKey==NULL) ||
( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) &&
(pbPrivateKey!=NULL) && (pbPublicKey!=NULL) ) )
{
pbScratchInternal = pbScratch;
cbScratchInternal = cbScratch;
poTmp = pEckey->poPublicKey;
if ( pbPublicKey != NULL )
{
cbTmp = SymCryptSizeofEcpointFromCurve( pCurve );
poTmp = SymCryptEcpointCreate( pbScratchInternal, cbTmp, pCurve );
pbScratchInternal += cbTmp;
cbScratchInternal -= cbTmp;
}
SYMCRYPT_ASSERT( poTmp != NULL );
scError = SymCryptEcpointScalarMul(
pCurve,
pEckey->piPrivateKey,
NULL,
SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL,
poTmp,
pbScratchInternal,
cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( pbPublicKey != NULL )
{
if ( !SymCryptEcpointIsEqual( pCurve, poTmp, pEckey->poPublicKey, 0, pbScratchInternal, cbScratchInternal ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
}
else if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 )
{
scError = SymCryptEckeyPerformPublicKeyValidation(
pEckey,
fValidatePublicKeyOrder,
pbScratch,
cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
}
}
pEckey->fAlgorithmInfo = flags;
if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 )
{
if ( ( flags & SYMCRYPT_FLAG_ECKEY_ECDSA ) != 0 )
{
SYMCRYPT_RUN_SELFTEST_ONCE(
SymCryptEcDsaSelftest,
SYMCRYPT_SELFTEST_ALGORITHM_ECDSA );
pEckey->fAlgorithmInfo |= SYMCRYPT_PCT_ECDSA;
}
if ( ( flags & SYMCRYPT_FLAG_ECKEY_ECDH ) != 0 )
{
SYMCRYPT_RUN_SELFTEST_ONCE(
SymCryptEcDhSecretAgreementSelftest,
SYMCRYPT_SELFTEST_ALGORITHM_ECDH );
}
}
cleanup:
if ( pbScratch != NULL )
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEckeyGetValue(
_In_ PCSYMCRYPT_ECKEY pEckey,
_Out_writes_bytes_( cbPrivateKey )
PBYTE pbPrivateKey,
SIZE_T cbPrivateKey,
_Out_writes_bytes_( cbPublicKey )
PBYTE pbPublicKey,
SIZE_T cbPublicKey,
SYMCRYPT_NUMBER_FORMAT numFormat,
SYMCRYPT_ECPOINT_FORMAT ecPointFormat,
UINT32 flags )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PBYTE pbScratch = NULL;
UINT32 cbScratch = 0;
PBYTE pbScratchInternal = NULL;
UINT32 cbScratchInternal = 0;
PCSYMCRYPT_ECURVE pCurve = pEckey->pCurve;
PSYMCRYPT_INT piTmpInteger = NULL;
UINT32 cbTmpInteger = 0;
PSYMCRYPT_MODELEMENT peTmpModElement = NULL;
UINT32 cbTmpModElement = pCurve->cbModElement;
UINT32 privateKeyDigits = SymCryptEcurveDigitsofScalarMultiplier(pCurve);
SYMCRYPT_ASSERT( (cbPrivateKey==0) || (cbPrivateKey == SymCryptEcurveSizeofScalarMultiplier( pEckey->pCurve )) );
SYMCRYPT_ASSERT( (cbPublicKey==0) || (cbPublicKey == SymCryptEckeySizeofPublicKey( pEckey, ecPointFormat)) );
if (flags != 0)
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
cbScratch = SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_ECKEY_ECURVE_OPERATIONS( pCurve );
pbScratch = SymCryptCallbackAlloc( cbScratch );
if ( pbScratch == NULL )
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
pbScratchInternal = pbScratch;
cbScratchInternal = cbScratch;
cbTmpInteger = SymCryptSizeofIntFromDigits( privateKeyDigits );
piTmpInteger = SymCryptIntCreate( pbScratchInternal, cbTmpInteger, privateKeyDigits );
SYMCRYPT_ASSERT( piTmpInteger != NULL );
pbScratchInternal += cbTmpInteger;
cbScratchInternal -= cbTmpInteger;
peTmpModElement = SymCryptModElementCreate( pbScratchInternal, cbTmpModElement, pCurve->GOrd );
SYMCRYPT_ASSERT( peTmpModElement != NULL );
pbScratchInternal += cbTmpModElement;
cbScratchInternal -= cbTmpModElement;
if ((cbPrivateKey == 0) && (cbPublicKey == 0))
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if (cbPrivateKey != 0)
{
if (!pEckey->hasPrivateKey)
{
scError = SYMCRYPT_INVALID_BLOB;
goto cleanup;
}
if ( ((pEckey->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDSA) != 0) &&
((pEckey->fAlgorithmInfo & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0) )
{
SYMCRYPT_RUN_KEY_GEN_PCT(
SymCryptEcDsaPct,
pEckey,
SYMCRYPT_PCT_ECDSA );
}
SymCryptIntCopy( pEckey->piPrivateKey, piTmpInteger );
if (pCurve->coFactorPower>0)
{
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL)
{
SymCryptIntMulPow2( piTmpInteger, pCurve->coFactorPower, piTmpInteger );
SymCryptIntDivMod(
piTmpInteger,
SymCryptDivisorFromModulus(pCurve->GOrd),
NULL,
piTmpInteger,
pbScratchInternal,
cbScratchInternal );
}
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_DIVH_TIMESH)
{
SymCryptIntMulPow2( piTmpInteger, pCurve->coFactorPower, piTmpInteger );
}
}
scError = SymCryptIntGetValue( piTmpInteger, pbPrivateKey, cbPrivateKey, numFormat );
if (scError != SYMCRYPT_NO_ERROR)
{
goto cleanup;
}
}
if (cbPublicKey != 0)
{
scError = SymCryptEcpointGetValue(
pCurve,
pEckey->poPublicKey,
numFormat,
ecPointFormat,
pbPublicKey,
cbPublicKey,
SYMCRYPT_FLAG_DATA_PUBLIC,
pbScratch,
cbScratch );
}
cleanup:
if ( pbScratch != NULL )
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}
#define SYMCRYPT_ECPOINT_SET_RANDOM_MAX_TRIES (1000)
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEckeySetRandom(
_In_ UINT32 flags,
_Inout_ PSYMCRYPT_ECKEY pEckey )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PBYTE pbScratch = NULL;
UINT32 cbScratch = 0;
PBYTE pbScratchInternal = NULL;
UINT32 cbScratchInternal = 0;
PCSYMCRYPT_ECURVE pCurve = pEckey->pCurve;
PSYMCRYPT_ECPOINT poTmp = NULL;
UINT32 cbTmp = 0;
INT32 cntr = SYMCRYPT_ECPOINT_SET_RANDOM_MAX_TRIES;
PSYMCRYPT_MODELEMENT peScalar = NULL;
PSYMCRYPT_INT piScalar = NULL;
UINT32 cbScalar = 0;
UINT32 highBitRestrictionPosition = pCurve->HighBitRestrictionPosition;
UINT32 algorithmFlags = SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH;
UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | algorithmFlags;
if ( ( ( flags & ~allowedFlags ) != 0 ) ||
( ( flags & algorithmFlags ) == 0 ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
cbScratch = SYMCRYPT_INTERNAL_SCRATCH_BYTES_FOR_ECKEY_ECURVE_OPERATIONS( pCurve );
pbScratch = SymCryptCallbackAlloc( cbScratch );
if ( pbScratch == NULL )
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
pbScratchInternal = pbScratch;
cbScratchInternal = cbScratch;
peScalar = SymCryptModElementCreate( pbScratchInternal, pCurve->cbModElement, pCurve->GOrd );
SYMCRYPT_ASSERT( peScalar != NULL );
pbScratchInternal += pCurve->cbModElement;
cbScratchInternal -= pCurve->cbModElement;
cbScalar = SymCryptSizeofIntFromDigits( SymCryptEcurveDigitsofScalarMultiplier(pCurve) );
piScalar = SymCryptIntCreate( pbScratchInternal, cbScalar, SymCryptEcurveDigitsofScalarMultiplier(pCurve) );
pbScratchInternal += cbScalar;
cbScratchInternal -= cbScalar;
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_DIVH_TIMESH)
{
highBitRestrictionPosition -= pCurve->coFactorPower;
}
do
{
SymCryptModSetRandom(
pCurve->GOrd,
peScalar,
(SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE|SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE),
pbScratchInternal,
cbScratchInternal );
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL)
{
for (UINT32 i=0; i<pCurve->coFactorPower; i++)
{
SymCryptModAdd( pCurve->GOrd, peScalar, peScalar, peScalar, pbScratchInternal, cbScratchInternal );
}
}
SymCryptModElementToInt( pCurve->GOrd, peScalar, piScalar, pbScratchInternal, cbScratchInternal );
if (pCurve->HighBitRestrictionNumOfBits > 0)
{
SymCryptIntSetBits(
piScalar,
pCurve->HighBitRestrictionValue,
highBitRestrictionPosition,
pCurve->HighBitRestrictionNumOfBits );
if ( SymCryptIntIsLessThan(
piScalar,
SymCryptIntFromModulus( pCurve->GOrd )) )
{
break;
}
}
else
{
break;
}
cntr--;
}
while (cntr>0);
if (cntr <= 0)
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
SymCryptIntToModElement( piScalar, pCurve->GOrd, peScalar, pbScratchInternal, cbScratchInternal );
if (pCurve->PrivateKeyDefaultFormat == SYMCRYPT_ECKEY_PRIVATE_FORMAT_CANONICAL)
{
SymCryptModDivPow2( pCurve->GOrd, peScalar, pCurve->coFactorPower, peScalar, pbScratchInternal, cbScratchInternal );
}
SymCryptModElementToInt( pCurve->GOrd, peScalar, pEckey->piPrivateKey, pbScratchInternal, cbScratchInternal );
scError = SymCryptEcpointScalarMul(
pCurve,
pEckey->piPrivateKey,
NULL,
SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL,
pEckey->poPublicKey,
pbScratch,
cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
{
scError = SymCryptEckeyPerformPublicKeyValidation(
pEckey,
SYMCRYPT_FLAG_ECKEY_PUBLIC_KEY_ORDER_VALIDATION,
pbScratch,
cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
}
pEckey->hasPrivateKey = TRUE;
pEckey->fAlgorithmInfo = flags;
if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
{
if( ( flags & SYMCRYPT_FLAG_ECKEY_ECDSA ) != 0 )
{
SYMCRYPT_RUN_SELFTEST_ONCE(
SymCryptEcDsaSelftest,
SYMCRYPT_SELFTEST_ALGORITHM_ECDSA );
}
if( ( flags & SYMCRYPT_FLAG_ECKEY_ECDH ) != 0 )
{
SYMCRYPT_RUN_SELFTEST_ONCE(
SymCryptEcDhSecretAgreementSelftest,
SYMCRYPT_SELFTEST_ALGORITHM_ECDH );
pbScratchInternal = pbScratch;
cbScratchInternal = cbScratch;
cbTmp = SymCryptSizeofEcpointFromCurve( pCurve );
poTmp = SymCryptEcpointCreate( pbScratchInternal, cbTmp, pCurve );
pbScratchInternal += cbTmp;
cbScratchInternal -= cbTmp;
SYMCRYPT_ASSERT( poTmp != NULL );
scError = SymCryptEcpointScalarMul(
pCurve,
pEckey->piPrivateKey,
NULL,
SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL,
poTmp,
pbScratchInternal,
cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
SYMCRYPT_FIPS_ASSERT( SymCryptEcpointIsEqual( pCurve, poTmp, pEckey->poPublicKey, 0, pbScratchInternal, cbScratchInternal ) );
}
}
cleanup:
if ( pbScratch != NULL )
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEckeyExtendKeyUsage(
_Inout_ PSYMCRYPT_ECKEY pEckey,
UINT32 flags )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
UINT32 algorithmFlags = SYMCRYPT_FLAG_ECKEY_ECDSA | SYMCRYPT_FLAG_ECKEY_ECDH;
if ( ( ( flags & ~algorithmFlags ) != 0 ) ||
( ( flags & algorithmFlags ) == 0) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
pEckey->fAlgorithmInfo |= flags;
cleanup:
return scError;
}