#include "precomp.h"
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDsaTruncateHash(
_In_ PCSYMCRYPT_DLGROUP pDlgroup,
_In_reads_bytes_( cbHashValue ) PCBYTE pbHashValue,
SIZE_T cbHashValue,
UINT32 flags,
_Out_ PSYMCRYPT_MODELEMENT peMsghash,
_Out_ PSYMCRYPT_INT piIntLarge,
_Out_ PSYMCRYPT_INT piIntQ,
_Out_writes_bytes_( cbScratch ) PBYTE pbScratch,
SIZE_T cbScratch )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
UNREFERENCED_PARAMETER( flags );
scError = SymCryptIntSetValue( pbHashValue, cbHashValue, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, piIntLarge );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if (SymCryptIntBitsizeOfValue(piIntLarge) > pDlgroup->nBitsOfQ)
{
SymCryptIntDivPow2( piIntLarge, SymCryptIntBitsizeOfValue(piIntLarge) - pDlgroup->nBitsOfQ, piIntLarge );
}
scError = SymCryptIntCopyMixedSize( piIntLarge, piIntQ );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
SymCryptIntToModElement( piIntQ, pDlgroup->pmQ, peMsghash, pbScratch, cbScratch );
cleanup:
return scError;
}
#define SYMCRYPT_MAX_DSA_SIGNATURE_COUNT (100)
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDsaSignEx(
_In_ PCSYMCRYPT_DLKEY 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;
PBYTE pbScratchInternal = NULL;
SIZE_T cbScratchInternal = 0;
SIZE_T cbScratchInputK = 0;
PCSYMCRYPT_DLGROUP pDlgroup = pKey->pDlgroup;
UINT32 nDigitsOfP = pDlgroup->nDigitsOfP;
UINT32 nDigitsOfQ = pDlgroup->nDigitsOfQ;
UINT32 ndIntLarge = 0;
UINT32 cbIntLarge = 0;
UINT32 cbIntQ = 0;
UINT32 cbIntP = 0;
UINT32 cbModelementP = 0;
UINT32 cbModelementQ = 0;
PSYMCRYPT_INT piIntLarge = NULL;
PSYMCRYPT_INT piIntP = NULL;
PSYMCRYPT_INT piIntQ = NULL;
PSYMCRYPT_MODELEMENT peRmodP = NULL;
PSYMCRYPT_MODELEMENT peMsghash = NULL;
PSYMCRYPT_MODELEMENT peRmodQ = NULL;
PSYMCRYPT_MODELEMENT peK = NULL;
PSYMCRYPT_MODELEMENT peS = NULL;
UINT32 signatureCount = 0;
UNREFERENCED_PARAMETER( flags );
if ( ((pKey->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DSA) == 0) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if ((!pDlgroup->fHasPrimeQ) ||
(!pKey->fHasPrivateKey) ||
(!pKey->fPrivateModQ) ||
(pDlgroup->isSafePrimeGroup))
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
ndIntLarge = SymCryptDigitsFromBits( (UINT32)cbHashValue * 8 );
cbIntLarge = SymCryptSizeofIntFromDigits(ndIntLarge);
cbIntQ = SymCryptSizeofIntFromDigits(nDigitsOfQ);
cbIntP = SymCryptSizeofIntFromDigits(nDigitsOfP);
cbModelementP = SymCryptSizeofModElementFromModulus( pDlgroup-> pmP );
cbModelementQ = SymCryptSizeofModElementFromModulus( pDlgroup-> pmQ );
cbScratchInputK = (piK==NULL)?0:SYMCRYPT_SCRATCH_BYTES_FOR_INT_DIVMOD(SymCryptIntDigitsizeOfObject(piK),nDigitsOfQ);
cbScratch = cbIntLarge + cbIntQ + cbIntP + cbModelementP + 4*cbModelementQ +
SYMCRYPT_MAX( cbScratchInputK,
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigitsOfQ ),
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigitsOfP ),
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP( nDigitsOfP ),
SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( nDigitsOfQ ) ))));
pbScratch = SymCryptCallbackAlloc( cbScratch );
if (pbScratch==NULL)
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
pbScratchInternal = pbScratch;
cbScratchInternal = cbScratch;
piIntLarge = SymCryptIntCreate(pbScratchInternal, cbIntLarge, ndIntLarge); pbScratchInternal += cbIntLarge; cbScratchInternal -= cbIntLarge;
piIntQ = SymCryptIntCreate(pbScratchInternal, cbIntQ, nDigitsOfQ); pbScratchInternal += cbIntQ; cbScratchInternal -= cbIntQ;
piIntP = SymCryptIntCreate(pbScratchInternal, cbIntP, nDigitsOfP); pbScratchInternal += cbIntP; cbScratchInternal -= cbIntP;
peRmodP = SymCryptModElementCreate(pbScratchInternal, cbModelementP, pDlgroup->pmP); pbScratchInternal += cbModelementP; cbScratchInternal -= cbModelementP;
peMsghash = SymCryptModElementCreate(pbScratchInternal, cbModelementQ, pDlgroup->pmQ); pbScratchInternal += cbModelementQ; cbScratchInternal -= cbModelementQ;
peRmodQ = SymCryptModElementCreate(pbScratchInternal, cbModelementQ, pDlgroup->pmQ); pbScratchInternal += cbModelementQ; cbScratchInternal -= cbModelementQ;
peK = SymCryptModElementCreate(pbScratchInternal, cbModelementQ, pDlgroup->pmQ); pbScratchInternal += cbModelementQ; cbScratchInternal -= cbModelementQ;
peS = SymCryptModElementCreate(pbScratchInternal, cbModelementQ, pDlgroup->pmQ); pbScratchInternal += cbModelementQ; cbScratchInternal -= cbModelementQ;
scError = SymCryptDsaTruncateHash(
pDlgroup,
pbHashValue,
cbHashValue,
flags,
peMsghash,
piIntLarge,
piIntQ,
pbScratchInternal,
cbScratchInternal );
if (scError!=SYMCRYPT_NO_ERROR)
{
goto cleanup;
}
while( TRUE )
{
if (piK==NULL)
{
SymCryptModSetRandom(
pDlgroup->pmQ,
peK,
SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE|SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE,
pbScratchInternal,
cbScratchInternal );
SymCryptModElementToInt(
pDlgroup->pmQ,
peK,
piIntQ,
pbScratchInternal,
cbScratchInternal );
}
else
{
SymCryptIntDivMod(
piK,
SymCryptDivisorFromModulus( pDlgroup->pmQ ),
NULL,
piIntQ,
pbScratchInternal,
cbScratchInternal );
SymCryptIntToModElement(
piIntQ,
pDlgroup->pmQ,
peK,
pbScratchInternal,
cbScratchInternal );
if (SymCryptModElementIsZero(pDlgroup->pmQ, peK))
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
}
SymCryptModExp(
pDlgroup->pmP,
pDlgroup->peG,
piIntQ,
pDlgroup->nBitsOfQ,
0,
peRmodP,
pbScratchInternal,
cbScratchInternal );
SymCryptModElementToInt(
pDlgroup->pmP,
peRmodP,
piIntP,
pbScratchInternal,
cbScratchInternal );
SymCryptIntDivMod(
piIntP,
SymCryptDivisorFromModulus( pDlgroup->pmQ ),
NULL,
piIntQ,
pbScratchInternal,
cbScratchInternal );
SymCryptIntToModElement(
piIntQ,
pDlgroup->pmQ,
peRmodQ,
pbScratchInternal,
cbScratchInternal );
scError = SymCryptModInv(
pDlgroup->pmQ,
peK,
peK,
0,
pbScratchInternal,
cbScratchInternal );
if( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
SymCryptIntToModElement(
pKey->piPrivateKey,
pDlgroup->pmQ,
peS,
pbScratchInternal,
cbScratchInternal );
SymCryptModMul(
pDlgroup->pmQ,
peS,
peRmodQ,
peS,
pbScratchInternal,
cbScratchInternal );
SymCryptModAdd(
pDlgroup->pmQ,
peS,
peMsghash,
peS,
pbScratchInternal,
cbScratchInternal );
SymCryptModMul(
pDlgroup->pmQ,
peK,
peS,
peS,
pbScratchInternal,
cbScratchInternal );
if ( !( SymCryptModElementIsZero( pDlgroup->pmQ, peRmodQ ) |
SymCryptModElementIsZero( pDlgroup->pmQ, peS ) ) )
{
break;
}
if (piK != NULL)
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
signatureCount++;
if ( signatureCount >= SYMCRYPT_MAX_DSA_SIGNATURE_COUNT )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
}
scError = SymCryptModElementGetValue(
pDlgroup->pmQ,
peRmodQ,
pbSignature,
cbSignature / 2,
format,
pbScratchInternal,
cbScratchInternal );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
scError = SymCryptModElementGetValue(
pDlgroup->pmQ,
peS,
pbSignature + cbSignature / 2,
cbSignature / 2,
format,
pbScratchInternal,
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
SymCryptDsaSign(
_In_ PCSYMCRYPT_DLKEY 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 )
{
return SymCryptDsaSignEx( pKey, pbHashValue, cbHashValue, NULL, format, flags, pbSignature, cbSignature );
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptDsaVerify(
_In_ PCSYMCRYPT_DLKEY 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;
BOOLEAN fValidSignature = FALSE;
PBYTE pbScratch = NULL;
SIZE_T cbScratch = 0;
PBYTE pbScratchInternal = NULL;
SIZE_T cbScratchInternal = 0;
PCSYMCRYPT_DLGROUP pDlgroup = pKey->pDlgroup;
UINT32 nDigitsOfP = pDlgroup->nDigitsOfP;
UINT32 nDigitsOfQ = pDlgroup->nDigitsOfQ;
UINT32 ndIntLarge = 0;
UINT32 cbIntLarge = 0;
UINT32 cbIntQ = 0;
UINT32 cbIntP = 0;
UINT32 cbModelementP = 0;
UINT32 cbModelementQ = 0;
PSYMCRYPT_MODELEMENT peBases[2] = { NULL, NULL };
PSYMCRYPT_INT piIntLarge = NULL;
PSYMCRYPT_INT piIntP = NULL;
PSYMCRYPT_INT piIntQ[2] = { NULL, NULL };
PSYMCRYPT_MODELEMENT peResP = NULL;
PSYMCRYPT_MODELEMENT peR = NULL;
PSYMCRYPT_MODELEMENT peS = NULL;
PSYMCRYPT_MODELEMENT peT = NULL;
UNREFERENCED_PARAMETER( flags );
if ( ((pKey->fAlgorithmInfo & SYMCRYPT_FLAG_DLKEY_DSA) == 0) )
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
if (!pDlgroup->fHasPrimeQ || pDlgroup->isSafePrimeGroup)
{
scError = SYMCRYPT_INVALID_ARGUMENT;
goto cleanup;
}
ndIntLarge = SymCryptDigitsFromBits( (UINT32)cbHashValue * 8 );
ndIntLarge = SYMCRYPT_MAX( ndIntLarge, SymCryptDigitsFromBits( (UINT32)cbSignature * 4 ) );
cbIntLarge = SymCryptSizeofIntFromDigits(ndIntLarge);
cbIntQ = SymCryptSizeofIntFromDigits(nDigitsOfQ);
cbIntP = SymCryptSizeofIntFromDigits(nDigitsOfP);
cbModelementP = SymCryptSizeofModElementFromModulus( pDlgroup-> pmP );
cbModelementQ = SymCryptSizeofModElementFromModulus( pDlgroup-> pmQ );
cbScratch = cbIntLarge + cbIntP + 2*cbIntQ + cbModelementP + 3*cbModelementQ +
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_INT_DIVMOD(nDigitsOfP,nDigitsOfQ),
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigitsOfQ ),
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS( nDigitsOfP ),
SYMCRYPT_MAX( SYMCRYPT_SCRATCH_BYTES_FOR_MODMULTIEXP( SymCryptModulusDigitsizeOfObject(pDlgroup->pmP), 2, pDlgroup->nBitsOfQ ),
SYMCRYPT_SCRATCH_BYTES_FOR_MODINV( nDigitsOfQ ) ))));
pbScratch = SymCryptCallbackAlloc( cbScratch );
if (pbScratch==NULL)
{
scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
pbScratchInternal = pbScratch;
cbScratchInternal = cbScratch;
piIntLarge = SymCryptIntCreate(pbScratchInternal, cbIntLarge, ndIntLarge); pbScratchInternal += cbIntLarge; cbScratchInternal -= cbIntLarge;
piIntP = SymCryptIntCreate(pbScratchInternal, cbIntP, nDigitsOfP); pbScratchInternal += cbIntP; cbScratchInternal -= cbIntP;
piIntQ[0] = SymCryptIntCreate(pbScratchInternal, cbIntQ, nDigitsOfQ); pbScratchInternal += cbIntQ; cbScratchInternal -= cbIntQ;
piIntQ[1] = SymCryptIntCreate(pbScratchInternal, cbIntQ, nDigitsOfQ); pbScratchInternal += cbIntQ; cbScratchInternal -= cbIntQ;
peResP = SymCryptModElementCreate(pbScratchInternal, cbModelementP, pDlgroup->pmP); pbScratchInternal += cbModelementP; cbScratchInternal -= cbModelementP;
peR = SymCryptModElementCreate(pbScratchInternal, cbModelementQ, pDlgroup->pmQ); pbScratchInternal += cbModelementQ; cbScratchInternal -= cbModelementQ;
peS = SymCryptModElementCreate(pbScratchInternal, cbModelementQ, pDlgroup->pmQ); pbScratchInternal += cbModelementQ; cbScratchInternal -= cbModelementQ;
peT = SymCryptModElementCreate(pbScratchInternal, cbModelementQ, pDlgroup->pmQ); pbScratchInternal += cbModelementQ; cbScratchInternal -= cbModelementQ;
scError = SymCryptIntSetValue( pbSignature, cbSignature / 2, format, piIntLarge );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( !SymCryptIntIsLessThan( piIntLarge, SymCryptIntFromModulus( pDlgroup->pmQ ) ) )
{
goto cleanup;
}
scError = SymCryptIntCopyMixedSize( piIntLarge, piIntQ[0] );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
SymCryptIntToModElement( piIntQ[0], pDlgroup->pmQ, peR, pbScratchInternal, cbScratchInternal );
if (SymCryptModElementIsZero( pDlgroup->pmQ, peR ))
{
goto cleanup;
}
scError = SymCryptIntSetValue( pbSignature + cbSignature / 2, cbSignature / 2, format, piIntLarge );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
if ( !SymCryptIntIsLessThan( piIntLarge, SymCryptIntFromModulus( pDlgroup->pmQ ) ) )
{
goto cleanup;
}
scError = SymCryptIntCopyMixedSize( piIntLarge, piIntQ[0] );
if ( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
SymCryptIntToModElement( piIntQ[0], pDlgroup->pmQ, peS, pbScratchInternal, cbScratchInternal );
if (SymCryptModElementIsZero( pDlgroup->pmQ, peS ))
{
goto cleanup;
}
scError = SymCryptModInv( pDlgroup->pmQ, peS, peS, SYMCRYPT_FLAG_DATA_PUBLIC, pbScratchInternal, cbScratchInternal );
if( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
scError = SymCryptDsaTruncateHash(
pDlgroup,
pbHashValue,
cbHashValue,
flags,
peT,
piIntLarge,
piIntQ[0],
pbScratchInternal,
cbScratchInternal );
if (scError!=SYMCRYPT_NO_ERROR)
{
goto cleanup;
}
SymCryptModMul(
pDlgroup->pmQ,
peT,
peS,
peT,
pbScratchInternal,
cbScratchInternal );
SymCryptModElementToInt(
pDlgroup->pmQ,
peT,
piIntQ[0],
pbScratchInternal,
cbScratchInternal );
SymCryptModMul(
pDlgroup->pmQ,
peR,
peS,
peT,
pbScratchInternal,
cbScratchInternal );
SymCryptModElementToInt(
pDlgroup->pmQ,
peT,
piIntQ[1],
pbScratchInternal,
cbScratchInternal );
peBases[0] = pDlgroup->peG;
peBases[1] = pKey->pePublicKey;
scError = SymCryptModMultiExp(
pDlgroup->pmP,
peBases,
piIntQ,
2,
pDlgroup->nBitsOfQ,
SYMCRYPT_FLAG_DATA_PUBLIC,
peResP,
pbScratchInternal,
cbScratchInternal );
if (scError!=SYMCRYPT_NO_ERROR)
{
goto cleanup;
}
SymCryptModElementToInt(
pDlgroup->pmP,
peResP,
piIntP,
pbScratchInternal,
cbScratchInternal );
SymCryptIntDivMod(
piIntP,
SymCryptDivisorFromModulus( pDlgroup->pmQ ),
NULL,
piIntQ[0],
pbScratchInternal,
cbScratchInternal );
SymCryptIntToModElement(
piIntQ[0],
pDlgroup->pmQ,
peT,
pbScratchInternal,
cbScratchInternal );
if (SymCryptModElementIsEqual( pDlgroup->pmQ, peT, peR ))
{
fValidSignature = TRUE;
}
cleanup:
if (!fValidSignature)
{
scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE;
}
if ( pbScratch != NULL )
{
SymCryptWipe( pbScratch, cbScratch );
SymCryptCallbackFree( pbScratch );
}
return scError;
}