#include "precomp.h"
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptEcDhSecretAgreement(
_In_ PCSYMCRYPT_ECKEY pkPrivate,
_In_ PCSYMCRYPT_ECKEY pkPublic,
SYMCRYPT_NUMBER_FORMAT format,
UINT32 flags,
_Out_writes_( cbAgreedSecret ) PBYTE pbAgreedSecret,
SIZE_T cbAgreedSecret )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PBYTE pbScratch = NULL;
SIZE_T cbScratch = 0;
SIZE_T cbScratchInternal = 0;
PBYTE pCurr = NULL;
PCSYMCRYPT_ECURVE pCurve = NULL;
PSYMCRYPT_ECPOINT poQ = NULL;
PBYTE pbX = NULL;
UINT32 cbQ = 0;
UINT32 cbX = 0;
if ( ((pkPrivate->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDH) == 0) ||
((pkPublic->fAlgorithmInfo & SYMCRYPT_FLAG_ECKEY_ECDH) == 0) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( (flags != 0) ||
(!pkPrivate->hasPrivateKey) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( SymCryptEcurveIsSame( pkPrivate->pCurve, pkPublic->pCurve ) )
{
pCurve = pkPrivate->pCurve;
}
else
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
cbQ = SymCryptSizeofEcpointFromCurve( pCurve );
cbX = SymCryptEcurveSizeofFieldElement( pCurve );
if (cbAgreedSecret != cbX)
{
scError = SYMCRYPT_WRONG_BLOCK_SIZE;
goto cleanup;
}
cbScratchInternal = SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_ECURVE_OPERATIONS(pCurve),
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_SCALAR_ECURVE_OPERATIONS( pCurve ),
SYMCRYPT_SCRATCH_BYTES_FOR_GETSET_VALUE_ECURVE_OPERATIONS( pCurve ) ));
cbScratch = cbScratchInternal + cbQ + cbX;
pbScratch = SymCryptCallbackAlloc( cbScratch );
if ( pbScratch == NULL )
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
pCurr = pbScratch + cbScratchInternal;
poQ = SymCryptEcpointCreate( pCurr, cbQ, pCurve );
pCurr += cbQ;
pbX = pCurr;
SYMCRYPT_ASSERT( poQ != NULL);
if (SymCryptEcpointIsZero(pCurve, pkPublic->poPublicKey, pbScratch, cbScratchInternal))
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
scError = SymCryptEcpointScalarMul(
pCurve,
pkPrivate->piPrivateKey,
pkPublic->poPublicKey,
SYMCRYPT_FLAG_ECC_LL_COFACTOR_MUL,
poQ,
pbScratch,
cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( SymCryptEcpointIsZero(
pCurve,
poQ,
pbScratch,
cbScratchInternal ) )
{
scError = SYMCRYPT_INVALID_BLOB;
goto cleanup;
}
scError = SymCryptEcpointGetValue( pCurve, poQ, format, SYMCRYPT_ECPOINT_FORMAT_X, pbX, cbX, 0, pbScratch, cbScratchInternal);
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
memcpy( pbAgreedSecret, pbX, cbX);
cleanup:
if ( pbScratch != NULL )
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}