#include "precomp.h"
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDhSecretAgreement(
_In_ PCSYMCRYPT_DLKEY pkPrivate,
_In_ PCSYMCRYPT_DLKEY 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;
PBYTE pbScratchInternal = NULL;
SIZE_T cbScratchInternal = 0;
PCSYMCRYPT_DLGROUP pDlgroup = NULL;
PSYMCRYPT_MODELEMENT peRes = NULL;
UINT32 cbModelement = 0;
UINT32 nBitsOfExp = 0;
if ( ((pkPrivate->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DH) == 0) ||
((pkPublic->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DH) == 0) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( (flags != 0) || (!pkPrivate->fHasPrivateKey) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( SymCryptDlgroupIsSame( pkPrivate->pDlgroup, pkPublic->pDlgroup ) )
{
pDlgroup = pkPrivate->pDlgroup;
}
else
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if (cbAgreedSecret != SymCryptDlkeySizeofPublicKey( pkPrivate ))
{
scError = SYMCRYPT_WRONG_BLOCK_SIZE;
goto cleanup;
}
cbModelement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
cbScratch = cbModelement +
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP( pDlgroup->nDigitsOfP ),
SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( pDlgroup->nDigitsOfP ));
pbScratch = SymCryptCallbackAlloc( cbScratch );
if ( pbScratch == NULL )
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
pbScratchInternal = pbScratch;
cbScratchInternal = cbScratch;
peRes = SymCryptModElementCreate( pbScratchInternal, cbModelement, pDlgroup->pmP );
pbScratchInternal += cbModelement;
cbScratchInternal -= cbModelement;
SYMCRYPT_ASSERT( peRes != NULL);
if (pkPrivate->fPrivateModQ)
{
nBitsOfExp = pkPrivate->nBitsPriv;
}
else
{
nBitsOfExp = pDlgroup->nBitsOfP;
}
SymCryptModExp(
pDlgroup->pmP,
pkPublic->pePublicKey,
pkPrivate->piPrivateKey,
nBitsOfExp,
0,
peRes,
pbScratchInternal,
cbScratchInternal );
if ( SymCryptModElementIsZero( pDlgroup->pmP, peRes ) )
{
scError = SYMCRYPT_INVALID_BLOB;
goto cleanup;
}
scError = SymCryptModElementGetValue(
pDlgroup->pmP,
peRes,
pbAgreedSecret,
cbAgreedSecret,
format,
pbScratchInternal,
cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
cleanup:
if ( pbScratch != NULL )
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}