#include "precomp.h"
PSYMCRYPT_DLKEY
SYMCRYPT_CALL
SymCryptDlkeyAllocate( _In_ PCSYMCRYPT_DLGROUP pDlgroup )
{
PVOID p;
SIZE_T cb;
PSYMCRYPT_DLKEY res = NULL;
cb = SymCryptSizeofDlkeyFromDlgroup( pDlgroup );
p = SymCryptCallbackAlloc( cb );
if ( p==NULL )
{
goto cleanup;
}
res = SymCryptDlkeyCreate( p, cb, pDlgroup );
cleanup:
return res;
}
VOID
SYMCRYPT_CALL
SymCryptDlkeyFree( _Out_ PSYMCRYPT_DLKEY pkObj )
{
SYMCRYPT_CHECK_MAGIC( pkObj );
SymCryptDlkeyWipe( pkObj );
SymCryptCallbackFree( pkObj );
}
UINT32
SYMCRYPT_CALL
SymCryptSizeofDlkeyFromDlgroup( _In_ PCSYMCRYPT_DLGROUP pDlgroup )
{
return sizeof(SYMCRYPT_DLKEY) + SymCryptSizeofModElementFromModulus( pDlgroup->pmP ) + SymCryptSizeofIntFromDigits( pDlgroup->nDigitsOfP );
}
PSYMCRYPT_DLKEY
SYMCRYPT_CALL
SymCryptDlkeyCreate(
_Out_writes_bytes_( cbBuffer ) PBYTE pbBuffer,
SIZE_T cbBuffer,
_In_ PCSYMCRYPT_DLGROUP pDlgroup )
{
PSYMCRYPT_DLKEY pkRes = NULL;
UINT32 cbModElement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
SYMCRYPT_ASSERT( cbBuffer >= SymCryptSizeofDlkeyFromDlgroup( pDlgroup ) );
SYMCRYPT_ASSERT( cbBuffer >= sizeof(SYMCRYPT_DLKEY) + cbModElement );
UNREFERENCED_PARAMETER( cbBuffer );
SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
pkRes = (PSYMCRYPT_DLKEY) pbBuffer;
pkRes->fAlgorithmInfo = 0;
pkRes->pDlgroup = pDlgroup;
pkRes->fHasPrivateKey = FALSE;
pkRes->fPrivateModQ = FALSE;
pkRes->nBitsPriv = pDlgroup->nDefaultBitsPriv;
pbBuffer += sizeof(SYMCRYPT_DLKEY);
pkRes->pePublicKey = SymCryptModElementCreate( pbBuffer, cbModElement, pDlgroup->pmP );
if (pkRes->pePublicKey == NULL)
{
goto cleanup;
}
pbBuffer += cbModElement;
pkRes->pbPrivate = pbBuffer;
pkRes->piPrivateKey = NULL;
SYMCRYPT_SET_MAGIC( pkRes );
cleanup:
return pkRes;
}
VOID
SYMCRYPT_CALL
SymCryptDlkeyWipe( _Out_ PSYMCRYPT_DLKEY pkDst )
{
SymCryptWipe( (PBYTE) pkDst, SymCryptSizeofDlkeyFromDlgroup(pkDst->pDlgroup) );
}
VOID
SYMCRYPT_CALL
SymCryptDlkeyCopy(
_In_ PCSYMCRYPT_DLKEY pkSrc,
_Out_ PSYMCRYPT_DLKEY pkDst )
{
PCSYMCRYPT_DLGROUP pDlgroup = pkSrc->pDlgroup;
if( pkSrc != pkDst )
{
pkDst->fAlgorithmInfo = pkSrc->fAlgorithmInfo;
pkDst->fHasPrivateKey = pkSrc->fHasPrivateKey;
pkDst->fPrivateModQ = pkSrc->fPrivateModQ;
pkDst->nBitsPriv = pkSrc->nBitsPriv;
SymCryptModElementCopy( pDlgroup->pmP, pkSrc->pePublicKey, pkDst->pePublicKey );
SymCryptIntCopy( pkSrc->piPrivateKey, pkDst->piPrivateKey );
}
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDlkeySetPrivateKeyLength( _Inout_ PSYMCRYPT_DLKEY pkDlkey, UINT32 nBitsPriv, UINT32 flags )
{
if( nBitsPriv > pkDlkey->pDlgroup->nBitsOfQ ||
nBitsPriv < pkDlkey->pDlgroup->nMinBitsPriv ||
flags != 0 )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
pkDlkey->nBitsPriv = nBitsPriv;
return SYMCRYPT_NO_ERROR;
}
PCSYMCRYPT_DLGROUP
SYMCRYPT_CALL
SymCryptDlkeyGetGroup( _In_ PCSYMCRYPT_DLKEY pkDlkey )
{
return pkDlkey->pDlgroup;
}
UINT32
SYMCRYPT_CALL
SymCryptDlkeySizeofPublicKey( _In_ PCSYMCRYPT_DLKEY pkDlkey )
{
return pkDlkey->pDlgroup->cbPrimeP;
}
UINT32
SYMCRYPT_CALL
SymCryptDlkeySizeofPrivateKey( _In_ PCSYMCRYPT_DLKEY pkDlkey )
{
PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
if (pkDlkey->fPrivateModQ)
{
if (pDlgroup->fHasPrimeQ)
{
if (pkDlkey->nBitsPriv != pDlgroup->nBitsOfQ)
{
return (pkDlkey->nBitsPriv + 7) / 8;
}
else
{
return pDlgroup->cbPrimeQ;
}
}
else
{
return pDlgroup->cbPrimeP;
}
}
else
{
return pDlgroup->cbPrimeP;
}
}
BOOLEAN
SYMCRYPT_CALL
SymCryptDlkeyHasPrivateKey( _In_ PCSYMCRYPT_DLKEY pkDlkey )
{
return pkDlkey->fHasPrivateKey;
}
#define SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION (0x1)
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDlkeyPerformPublicKeyValidation(
_In_ PCSYMCRYPT_DLKEY pkDlkey,
_In_ UINT32 flags,
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
SIZE_T cbScratch )
{
PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
PSYMCRYPT_MODELEMENT peTmp = NULL;
PSYMCRYPT_MODELEMENT peTmpPublicKeyExpQ = NULL;
UINT32 cbModElement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
SYMCRYPT_ASSERT( cbScratch >= (2 * cbModElement) +
SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP(pDlgroup->nDigitsOfP) );
if ( SymCryptModElementIsZero( pDlgroup->pmP, pkDlkey->pePublicKey ) )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
peTmp = SymCryptModElementCreate( pbScratch, cbModElement, pDlgroup->pmP);
pbScratch += cbModElement;
cbScratch -= cbModElement;
SymCryptModElementSetValueNegUint32( 1, pDlgroup->pmP, peTmp, pbScratch, cbScratch );
if ( SymCryptModElementIsEqual( pDlgroup->pmP, pkDlkey->pePublicKey, peTmp ) )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
SymCryptModElementSetValueUint32( 1, pDlgroup->pmP, peTmp, pbScratch, cbScratch );
if ( SymCryptModElementIsEqual( pDlgroup->pmP, pkDlkey->pePublicKey, peTmp ) )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
if ( (flags & SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION) != 0 )
{
peTmpPublicKeyExpQ = SymCryptModElementCreate( pbScratch, cbModElement, pDlgroup->pmP);
pbScratch += cbModElement;
cbScratch -= cbModElement;
if ( !pDlgroup->fHasPrimeQ )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
SymCryptModExp(
pDlgroup->pmP,
pkDlkey->pePublicKey,
SymCryptIntFromModulus( pDlgroup->pmQ ),
pDlgroup->nBitsOfQ,
SYMCRYPT_FLAG_DATA_PUBLIC,
peTmpPublicKeyExpQ,
pbScratch,
cbScratch );
if ( !SymCryptModElementIsEqual( pDlgroup->pmP, peTmpPublicKeyExpQ, peTmp ) )
{
return SYMCRYPT_INVALID_ARGUMENT;
}
}
return SYMCRYPT_NO_ERROR;
}
#define DLKEY_GEN_RANDOM_GENERIC_LIMIT (1000)
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDlkeyGenerate(
_In_ UINT32 flags,
_Inout_ PSYMCRYPT_DLKEY pkDlkey )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PBYTE pbScratch = NULL;
SIZE_T cbScratch = 0;
PBYTE pbScratchInternal = NULL;
SIZE_T cbScratchInternal = 0;
PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
PSYMCRYPT_MODELEMENT pePrivateKey = NULL;
UINT32 cbPrivateKey = 0;
PSYMCRYPT_MODULUS pmPriv = NULL;
UINT32 nDigitsPriv = 0;
UINT32 nBitsPriv = 0;
UINT32 fFlagsForModSetRandom = 0;
BOOLEAN useModSetRandom = TRUE;
UINT32 nBytesPriv = 0;
UINT32 dwShiftBits;
BYTE privMask;
UINT32 cntr;
PSYMCRYPT_MODELEMENT peTmp = NULL;
UINT32 cbModElement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
UINT32 algorithmFlags = SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_DH;
UINT32 allowedFlags = SYMCRYPT_FLAG_DLKEY_GEN_MODP | SYMCRYPT_FLAG_KEY_NO_FIPS | algorithmFlags;
if ( ( ( flags & ~allowedFlags ) != 0 ) ||
( ( flags & algorithmFlags ) == 0 ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) &&
( (pDlgroup->isSafePrimeGroup && (flags & SYMCRYPT_FLAG_DLKEY_DSA)) ||
(!(pDlgroup->isSafePrimeGroup) && (flags & SYMCRYPT_FLAG_DLKEY_DH)) ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
pkDlkey->fPrivateModQ = (((flags & SYMCRYPT_FLAG_DLKEY_GEN_MODP)==0) && (pDlgroup->fHasPrimeQ));
if (pkDlkey->fPrivateModQ)
{
pmPriv = pDlgroup->pmQ;
nDigitsPriv = pDlgroup->nDigitsOfQ;
nBitsPriv = pDlgroup->nBitsOfQ;
fFlagsForModSetRandom = SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE | SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE;
if ( pDlgroup->isSafePrimeGroup && (pkDlkey->nBitsPriv != pDlgroup->nBitsOfQ) )
{
useModSetRandom = FALSE;
SYMCRYPT_ASSERT( pkDlkey->nBitsPriv < pDlgroup->nBitsOfQ );
nBitsPriv = pkDlkey->nBitsPriv;
nBytesPriv = (pkDlkey->nBitsPriv + 7) / 8;
}
}
else
{
if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
pmPriv = pDlgroup->pmP;
nDigitsPriv = pDlgroup->nDigitsOfP;
nBitsPriv = pDlgroup->nBitsOfP;
fFlagsForModSetRandom = SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE;
}
cbPrivateKey = SymCryptSizeofModElementFromModulus( pmPriv );
cbScratch = SYMCRYPT_MAX( cbPrivateKey + SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS(nDigitsPriv),
(2 * cbModElement) + SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP(pDlgroup->nDigitsOfP));
pbScratch = SymCryptCallbackAlloc( cbScratch );
if (pbScratch == NULL)
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
pkDlkey->piPrivateKey = SymCryptIntCreate( pkDlkey->pbPrivate, SymCryptSizeofIntFromDigits(nDigitsPriv), nDigitsPriv );
if (useModSetRandom)
{
pePrivateKey = SymCryptModElementCreate( pbScratch, cbPrivateKey, pmPriv );
pbScratchInternal = pbScratch + cbPrivateKey;
cbScratchInternal = cbScratch - cbPrivateKey;
SymCryptModSetRandom(
pmPriv,
pePrivateKey,
fFlagsForModSetRandom,
pbScratchInternal,
cbScratchInternal );
SymCryptModElementToInt(
pmPriv,
pePrivateKey,
pkDlkey->piPrivateKey,
pbScratchInternal,
cbScratchInternal );
}
else
{
SymCryptWipe( pbScratch + nBytesPriv, (nDigitsPriv * SYMCRYPT_FDEF_DIGIT_SIZE) - nBytesPriv );
dwShiftBits = (0u-nBitsPriv) & 7;
privMask = (BYTE)(0xff >> dwShiftBits);
for(cntr=0; cntr<DLKEY_GEN_RANDOM_GENERIC_LIMIT; cntr++)
{
SymCryptCallbackRandom( pbScratch, nBytesPriv );
pbScratch[nBytesPriv-1] &= privMask;
if( !SymCryptFdefRawIsEqualUint32( (PCUINT32)pbScratch, nDigitsPriv, 0 ) )
{
break;
}
}
if (cntr >= DLKEY_GEN_RANDOM_GENERIC_LIMIT)
{
SymCryptFatal( 'rndl' );
}
scError = SymCryptIntSetValue( pbScratch, nBytesPriv, SYMCRYPT_NUMBER_FORMAT_LSB_FIRST, pkDlkey->piPrivateKey );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
}
SymCryptModExp(
pDlgroup->pmP,
pDlgroup->peG,
pkDlkey->piPrivateKey,
nBitsPriv,
0,
pkDlkey->pePublicKey,
pbScratch,
cbScratch );
if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
{
scError = SymCryptDlkeyPerformPublicKeyValidation(
pkDlkey,
SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION,
pbScratch,
cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
}
pkDlkey->fHasPrivateKey = TRUE;
pkDlkey->fAlgorithmInfo = flags;
if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
{
if( ( flags & SYMCRYPT_FLAG_DLKEY_DSA ) != 0 )
{
SYMCRYPT_RUN_SELFTEST_ONCE(
SymCryptDsaSelftest,
SYMCRYPT_SELFTEST_ALGORITHM_DSA );
SYMCRYPT_RUN_KEY_GEN_PCT(
SymCryptDsaPct,
pkDlkey,
SYMCRYPT_PCT_DSA );
}
if( ( flags & SYMCRYPT_FLAG_DLKEY_DH ) != 0 )
{
SYMCRYPT_RUN_SELFTEST_ONCE(
SymCryptDhSecretAgreementSelftest,
SYMCRYPT_SELFTEST_ALGORITHM_DH );
pbScratchInternal = pbScratch;
cbScratchInternal = cbScratch;
peTmp = SymCryptModElementCreate( pbScratchInternal, cbModElement, pDlgroup->pmP );
pbScratchInternal += cbModElement;
cbScratchInternal -= cbModElement;
SymCryptModExp(
pDlgroup->pmP,
pDlgroup->peG,
pkDlkey->piPrivateKey,
nBitsPriv,
0,
peTmp,
pbScratchInternal,
cbScratchInternal );
SYMCRYPT_FIPS_ASSERT( SymCryptModElementIsEqual(pDlgroup->pmP, peTmp, pkDlkey->pePublicKey) );
}
}
cleanup:
if (pbScratch!=NULL)
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDlkeySetValue(
_In_reads_bytes_( cbPrivateKey ) PCBYTE pbPrivateKey,
SIZE_T cbPrivateKey,
_In_reads_bytes_( cbPublicKey ) PCBYTE pbPublicKey,
SIZE_T cbPublicKey,
SYMCRYPT_NUMBER_FORMAT numFormat,
UINT32 flags,
_Inout_ PSYMCRYPT_DLKEY pkDlkey )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PBYTE pbScratch = NULL;
UINT32 cbScratch = 0;
PBYTE pbScratchInternal = NULL;
UINT32 cbScratchInternal = 0;
PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
UINT32 nDigitsPriv = 0;
UINT32 nBitsPriv = 0;
PSYMCRYPT_MODELEMENT peTmp = NULL;
UINT32 cbModElement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
UINT32 fValidatePublicKeyOrder = SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION;
if ( ((pbPrivateKey==NULL) && (cbPrivateKey!=0)) ||
((pbPublicKey==NULL) && (cbPublicKey!=0)) ||
((pbPrivateKey==NULL) && (pbPublicKey==NULL)) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
UINT32 algorithmFlags = SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_DH;
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 ) &&
( (pDlgroup->isSafePrimeGroup && (flags & SYMCRYPT_FLAG_DLKEY_DSA)) ||
(!(pDlgroup->isSafePrimeGroup) && (flags & SYMCRYPT_FLAG_DLKEY_DH)) ) )
{
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;
}
cbScratch = SYMCRYPT_MAX( cbModElement + SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS(pDlgroup->nDigitsOfP),
(2 * cbModElement) + SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP(pDlgroup->nDigitsOfP) );
pbScratch = SymCryptCallbackAlloc( cbScratch );
if (pbScratch == NULL)
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
if ( pbPrivateKey != NULL )
{
pkDlkey->fPrivateModQ = ( (pDlgroup->fHasPrimeQ) &&
((cbPrivateKey < pDlgroup->cbPrimeQ) ||
((cbPrivateKey == pDlgroup->cbPrimeQ) && (pDlgroup->cbPrimeQ < pDlgroup->cbPrimeP)) ||
(pkDlkey->nBitsPriv != pDlgroup->nDefaultBitsPriv)) );
if ( pkDlkey->fPrivateModQ )
{
nDigitsPriv = pDlgroup->nDigitsOfQ;
nBitsPriv = pDlgroup->nBitsOfQ;
if ( pDlgroup->isSafePrimeGroup )
{
nBitsPriv = pkDlkey->nBitsPriv;
}
}
else
{
nDigitsPriv = pDlgroup->nDigitsOfP;
nBitsPriv = pDlgroup->nBitsOfP;
}
pkDlkey->piPrivateKey = SymCryptIntCreate( pkDlkey->pbPrivate, SymCryptSizeofIntFromDigits(nDigitsPriv), nDigitsPriv );
scError = SymCryptIntSetValue(
pbPrivateKey,
cbPrivateKey,
numFormat,
pkDlkey->piPrivateKey );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( SymCryptIntIsEqualUint32( pkDlkey->piPrivateKey, 0 ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 )
{
if ( !pDlgroup->fHasPrimeQ )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ( ( ( (nBitsPriv < pDlgroup->nBitsOfQ) &&
SymCryptIntBitsizeOfValue( pkDlkey->piPrivateKey ) > nBitsPriv ) ) ||
( (nBitsPriv >= pDlgroup->nBitsOfQ) &&
!SymCryptIntIsLessThan( pkDlkey->piPrivateKey, SymCryptIntFromModulus( pDlgroup->pmQ ) ) ) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
}
pkDlkey->fHasPrivateKey = TRUE;
}
if ( pbPublicKey != NULL )
{
scError = SymCryptModElementSetValue(
pbPublicKey,
cbPublicKey,
numFormat,
pDlgroup->pmP,
pkDlkey->pePublicKey,
pbScratch,
cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( (flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION) == 0 )
{
scError = SymCryptDlkeyPerformPublicKeyValidation(
pkDlkey,
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;
peTmp = pkDlkey->pePublicKey;
if ( pbPublicKey != NULL )
{
peTmp = SymCryptModElementCreate( pbScratchInternal, cbModElement, pDlgroup->pmP);
pbScratchInternal += cbModElement;
cbScratchInternal -= cbModElement;
}
SymCryptModExp(
pDlgroup->pmP,
pDlgroup->peG,
pkDlkey->piPrivateKey,
nBitsPriv,
0,
peTmp,
pbScratchInternal,
cbScratchInternal );
if ( pbPublicKey != NULL )
{
if ( !SymCryptModElementIsEqual(pDlgroup->pmP, peTmp, pkDlkey->pePublicKey) )
{
scError = SYMCRYPT_AUTHENTICATION_FAILURE;
goto cleanup;
}
}
else if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 )
{
scError = SymCryptDlkeyPerformPublicKeyValidation(
pkDlkey,
fValidatePublicKeyOrder,
pbScratch,
cbScratch );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
}
}
pkDlkey->fAlgorithmInfo = flags;
if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
{
if( ( flags & SYMCRYPT_FLAG_DLKEY_DSA ) != 0 )
{
SYMCRYPT_RUN_SELFTEST_ONCE(
SymCryptDsaSelftest,
SYMCRYPT_SELFTEST_ALGORITHM_DSA );
pkDlkey->fAlgorithmInfo |= SYMCRYPT_PCT_DSA;
}
if( ( flags & SYMCRYPT_FLAG_DLKEY_DH ) != 0 )
{
SYMCRYPT_RUN_SELFTEST_ONCE(
SymCryptDhSecretAgreementSelftest,
SYMCRYPT_SELFTEST_ALGORITHM_DH );
}
}
cleanup:
if (pbScratch!=NULL)
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDlkeyGetValue(
_In_ PCSYMCRYPT_DLKEY pkDlkey,
_Out_writes_bytes_( cbPrivateKey )
PBYTE pbPrivateKey,
SIZE_T cbPrivateKey,
_Out_writes_bytes_( cbPublicKey )
PBYTE pbPublicKey,
SIZE_T cbPublicKey,
SYMCRYPT_NUMBER_FORMAT numFormat,
UINT32 flags )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
PBYTE pbScratch = NULL;
UINT32 cbScratch = 0;
PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
UNREFERENCED_PARAMETER( flags );
if ( ((pbPrivateKey==NULL) && (cbPrivateKey!=0)) ||
((pbPublicKey==NULL) && (cbPublicKey!=0)) ||
((pbPrivateKey==NULL) && (pbPublicKey==NULL)) ||
((pbPrivateKey!=NULL) && !pkDlkey->fHasPrivateKey) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if (pbPrivateKey != NULL)
{
scError = SymCryptIntGetValue(
pkDlkey->piPrivateKey,
pbPrivateKey,
cbPrivateKey,
numFormat );
if (scError!=SYMCRYPT_NO_ERROR)
{
goto cleanup;
}
}
if (pbPublicKey != NULL)
{
cbScratch = SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS(pDlgroup->nDigitsOfP);
pbScratch = SymCryptCallbackAlloc( cbScratch );
if (pbScratch == NULL)
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
scError = SymCryptModElementGetValue(
pDlgroup->pmP,
pkDlkey->pePublicKey,
pbPublicKey,
cbPublicKey,
numFormat,
pbScratch,
cbScratch );
if (scError!=SYMCRYPT_NO_ERROR)
{
goto cleanup;
}
}
cleanup:
if (pbScratch!=NULL)
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDlkeyExtendKeyUsage(
_Inout_ PSYMCRYPT_DLKEY pkDlkey,
UINT32 flags )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
UINT32 algorithmFlags = SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_DH;
if ( ( ( flags & ~algorithmFlags ) != 0 ) ||
( ( flags & algorithmFlags ) == 0) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
pkDlkey->fAlgorithmInfo |= flags;
cleanup:
return scError;
}