355 lines
9.8 KiB
C
355 lines
9.8 KiB
C
/////////////////////////////////////////////////////////////////////////////
|
|
// FILE : nt_rand.c //
|
|
// DESCRIPTION : Crypto CP interfaces: //
|
|
// CPGenRandom //
|
|
// AUTHOR : //
|
|
// HISTORY : //
|
|
// Jan 25 1995 larrys Changed from Nametag //
|
|
// Feb 23 1995 larrys Changed NTag_SetLastError to SetLastError //
|
|
// Apr 10 1995 larrys Fix comments //
|
|
// Oct 27 1995 rajeshk Added provider parameter to GenRandom call //
|
|
// Nov 3 1995 larrys Merge for NT checkin //
|
|
// Oct 14 1996 jeffspel Changed GenRandom to NewGenRandom //
|
|
// May 5 2000 dbarlow Clean up error return codes //
|
|
// //
|
|
// Copyright (C) 1993 - 2000, Microsoft Corporation //
|
|
// All Rights Reserved //
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <crypt.h>
|
|
|
|
#include "precomp.h"
|
|
#include "sha.h"
|
|
#include "rsa_fast.h"
|
|
#include "rsa_math.h"
|
|
#include "randlib.h"
|
|
|
|
static CONST BYTE DSSPRIVATEKEYINIT[] =
|
|
{ 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89,
|
|
0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76,
|
|
0xc3, 0xd2, 0xe1, 0xf0 };
|
|
|
|
static CONST BYTE DSSPERMSGINIT[] =
|
|
{ 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe,
|
|
0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0,
|
|
0x67, 0x45, 0x23, 0x01 };
|
|
|
|
static CONST BYTE MODULUS[] =
|
|
{ 0xf5, 0xc1, 0x56, 0xb1, 0xd5, 0x48, 0x42, 0x2e,
|
|
0xbd, 0xa5, 0x44, 0x41, 0xc7, 0x1c, 0x24, 0x08,
|
|
0x3f, 0x80, 0x3c, 0x90 };
|
|
|
|
static BYTE l_rgbRNGState[A_SHA_DIGEST_LEN];
|
|
|
|
|
|
//
|
|
// Function : AddSeeds
|
|
//
|
|
// Description : This function adds the 160 bit seeds pointed to by pdwSeed1
|
|
// and pdwSeed2, it also adds 1 to this sum and mods the sum by
|
|
// 2^160.
|
|
//
|
|
|
|
/*static*/ void
|
|
AddSeeds(
|
|
IN CONST DWORD *pdwSeed1,
|
|
IN OUT DWORD *pdwSeed2)
|
|
{
|
|
DWORD dwTmp;
|
|
DWORD dwOverflow = 1;
|
|
DWORD i;
|
|
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
dwTmp = dwOverflow + pdwSeed1[i];
|
|
dwOverflow = (dwOverflow > dwTmp);
|
|
pdwSeed2[i] = pdwSeed2[i] + dwTmp;
|
|
dwOverflow = ((dwTmp > pdwSeed2[i]) || dwOverflow);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Given SHA(message), compute SHA(message) mod qdigit.
|
|
Output is in the interval [0, qdigit-1].
|
|
Although SHA(message) may exceed qdigit,
|
|
it cannot exceed 2*qdigit since the leftmost bit
|
|
of qdigit is 1.
|
|
*/
|
|
|
|
/*static*/ void
|
|
SHA_mod_q(
|
|
CONST BYTE *pbHash, // In
|
|
CONST BYTE *pbQ, // In
|
|
BYTE *pbNewHash) // Out
|
|
{
|
|
BYTE rgbHash[A_SHA_DIGEST_LEN];
|
|
|
|
if (-1 != Compare((DWORD*)rgbHash, // hash is greater so subtract
|
|
(DWORD*)pbQ,
|
|
A_SHA_DIGEST_LEN / sizeof(DWORD)))
|
|
{
|
|
Sub((DWORD*)pbNewHash,
|
|
(DWORD*)rgbHash,
|
|
(DWORD*)pbQ,
|
|
A_SHA_DIGEST_LEN / sizeof(DWORD));
|
|
}
|
|
else
|
|
memcpy(pbNewHash, pbHash, A_SHA_DIGEST_LEN / sizeof(DWORD));
|
|
} /* SHA_mod_q */
|
|
|
|
|
|
//
|
|
// Function : RNG16BitStateCheck
|
|
//
|
|
// Description : This function compares each 160 bits of the buffer with
|
|
// the next 160 bits and if they are the same the function
|
|
// errors out. The IN buffer is expected to be A_SHA_DIGEST_LEN
|
|
// bytes long. The function fails if the RNG is gets the same
|
|
// input buffer of 160 bits twice in a row.
|
|
//
|
|
|
|
/*static*/ BOOL
|
|
RNG16BitStateCheck(
|
|
IN OUT DWORD *pdwOut,
|
|
IN DWORD *pdwIn,
|
|
IN DWORD cbNeeded)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
if (0 == memcmp(l_rgbRNGState, pdwIn, A_SHA_DIGEST_LEN))
|
|
{
|
|
memcpy(l_rgbRNGState, (BYTE*)pdwIn, A_SHA_DIGEST_LEN);
|
|
goto ErrorExit;
|
|
}
|
|
|
|
memcpy(l_rgbRNGState, (BYTE*)pdwIn, A_SHA_DIGEST_LEN);
|
|
memcpy((BYTE*)pdwOut, (BYTE*)pdwIn, cbNeeded);
|
|
fRet = TRUE;
|
|
|
|
ErrorExit:
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//
|
|
// Function : FIPS186Gen
|
|
//
|
|
// Description : FIPS 186 RNG, the seed is generated by calling NewGenRandom.
|
|
//
|
|
|
|
/*static*/ DWORD
|
|
FIPS186Gen(
|
|
IN HANDLE hRNGDriver,
|
|
IN BYTE **ppbContextSeed,
|
|
IN DWORD *pcbContextSeed,
|
|
IN CONST BYTE *pbInitValue, // this is t, must be 20 bytes
|
|
IN CONST BYTE *pbModulus, // this must be a 20 byte prime
|
|
IN OUT BYTE *pb,
|
|
IN DWORD cb)
|
|
{
|
|
DWORD dwReturn = ERROR_INTERNAL_ERROR;
|
|
DWORD rgdwSeed[A_SHA_DIGEST_LEN/sizeof(DWORD)]; // 160 bits
|
|
DWORD rgdwNewSeed[A_SHA_DIGEST_LEN/sizeof(DWORD)]; // 160 bits
|
|
A_SHA_CTX SHACtxt;
|
|
BYTE rgbBuf[A_SHA_DIGEST_LEN];
|
|
DWORD cbBuf;
|
|
BYTE *pbTmp = pb;
|
|
DWORD cbTmp = cb;
|
|
DWORD i;
|
|
DWORD dwSts;
|
|
DWORD cbContextSeed = 0;
|
|
|
|
if (ppbContextSeed && pcbContextSeed)
|
|
cbContextSeed = *pcbContextSeed;
|
|
|
|
while (cbTmp)
|
|
{
|
|
#ifdef USE_HW_RNG
|
|
#ifdef _M_IX86
|
|
// get a 160 bit random seed
|
|
if (INVALID_HANDLE_VALUE != hRNGDriver)
|
|
{
|
|
dwSts = HWRNGGenRandom(hRNGDriver,
|
|
(BYTE*)rgdwNewSeed,
|
|
sizeof(rgdwNewSeed));
|
|
if (ERROR_SUCCESS != dwSts)
|
|
{
|
|
dwReturn = dwSts;
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
else
|
|
#endif // _M_IX86
|
|
#endif // USE_HW_RNG
|
|
{
|
|
// get a 160 bit random seed
|
|
if (!NewGenRandom(ppbContextSeed, pcbContextSeed,
|
|
(BYTE*)rgdwNewSeed, sizeof(rgdwNewSeed)))
|
|
{
|
|
dwReturn = (DWORD)NTE_FAIL; // NewGenRandom doesn't set LastError.
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < A_SHA_DIGEST_LEN/sizeof(DWORD); i++)
|
|
rgdwSeed[i] ^= rgdwNewSeed[i];
|
|
|
|
A_SHAInit (&SHACtxt);
|
|
memcpy(SHACtxt.state, pbInitValue, A_SHA_DIGEST_LEN);
|
|
|
|
// perform the one way function
|
|
A_SHAUpdate(&SHACtxt, (BYTE*)rgdwSeed, sizeof(rgdwSeed));
|
|
if (cbContextSeed)
|
|
A_SHAUpdate(&SHACtxt, *ppbContextSeed, cbContextSeed);
|
|
A_SHAFinal(&SHACtxt, rgbBuf);
|
|
|
|
for (i = 0; i < cbContextSeed && i < A_SHA_DIGEST_LEN; i++)
|
|
(*ppbContextSeed)[i] ^= rgbBuf[i];
|
|
|
|
// continuous 16 bit state check
|
|
if (A_SHA_DIGEST_LEN < cbTmp)
|
|
cbBuf = A_SHA_DIGEST_LEN;
|
|
else
|
|
cbBuf = cbTmp;
|
|
|
|
if (!RNG16BitStateCheck((DWORD*)pbTmp, (DWORD*)rgbBuf, cbBuf))
|
|
{
|
|
dwReturn = (DWORD)NTE_FAIL;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
pbTmp += cbBuf;
|
|
cbTmp -= cbBuf;
|
|
if (0 == cbTmp)
|
|
break;
|
|
|
|
// modular reduction with modulus Q
|
|
SHA_mod_q(rgbBuf, pbModulus, (BYTE*)rgdwNewSeed);
|
|
|
|
// (1 + previous seed + new random) mod 2^160
|
|
AddSeeds(rgdwNewSeed, rgdwSeed);
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
ErrorExit:
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
DWORD
|
|
FIPS186GenRandom(
|
|
IN HANDLE *phRNGDriver,
|
|
IN BYTE **ppbContextSeed,
|
|
IN DWORD *pcbContextSeed,
|
|
IN OUT BYTE *pb,
|
|
IN DWORD cb)
|
|
{
|
|
return FIPS186Gen(*phRNGDriver, ppbContextSeed, pcbContextSeed,
|
|
DSSPRIVATEKEYINIT, MODULUS, pb, cb);
|
|
}
|
|
|
|
|
|
void
|
|
FIPS186GenRandomWithException(
|
|
IN HANDLE *phRNGDriver,
|
|
IN BYTE **ppbContextSeed,
|
|
IN DWORD *pcbContextSeed,
|
|
IN OUT BYTE *pb,
|
|
IN DWORD cb)
|
|
{
|
|
DWORD dwSts;
|
|
|
|
dwSts = FIPS186Gen(*phRNGDriver, ppbContextSeed, pcbContextSeed,
|
|
DSSPRIVATEKEYINIT, MODULUS, pb, cb);
|
|
if (ERROR_SUCCESS != dwSts)
|
|
{
|
|
// nasty way to cause an error but need either this
|
|
// or redo rsa32.lib
|
|
RaiseException((DWORD)NTE_FAIL, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
- CPGenRandom
|
|
-
|
|
* Purpose:
|
|
* Used to fill a buffer with random bytes
|
|
*
|
|
*
|
|
* Parameters:
|
|
* IN hUID - Handle to the user identifcation
|
|
* IN dwLen - Number of bytes of random data requested
|
|
* OUT pbBuffer - Pointer to the buffer where the random
|
|
* bytes are to be placed
|
|
*
|
|
* Returns:
|
|
*/
|
|
|
|
BOOL WINAPI
|
|
CPGenRandom(
|
|
IN HCRYPTPROV hUID,
|
|
IN DWORD dwLen,
|
|
OUT BYTE *pbBuffer)
|
|
{
|
|
DWORD dwReturn = ERROR_INTERNAL_ERROR;
|
|
PNTAGUserList pTmpUser;
|
|
BOOL fRet;
|
|
DWORD dwSts;
|
|
|
|
EntryPoint
|
|
// check the user identification
|
|
pTmpUser = NTLCheckList(hUID, USER_HANDLE);
|
|
if (NULL == pTmpUser)
|
|
{
|
|
dwReturn = (DWORD)NTE_BAD_UID;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
dwSts = FIPS186Gen(pTmpUser->hRNGDriver,
|
|
&pTmpUser->ContInfo.pbRandom,
|
|
&pTmpUser->ContInfo.ContLens.cbRandom,
|
|
DSSPRIVATEKEYINIT,
|
|
MODULUS,
|
|
pbBuffer,
|
|
dwLen);
|
|
if (ERROR_SUCCESS != dwSts)
|
|
{
|
|
dwReturn = dwSts;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
|
|
ErrorExit:
|
|
fRet = (ERROR_SUCCESS == dwReturn);
|
|
if (!fRet)
|
|
SetLastError(dwReturn);
|
|
return fRet;
|
|
}
|
|
|
|
//
|
|
// Function: NewGenRandom
|
|
//
|
|
// Description: Stub to eliminate the need to link with
|
|
// randlib.lib. Now using RtlGenRandom() instead.
|
|
//
|
|
// Returns: True for success. False for failure.
|
|
//
|
|
unsigned int
|
|
RSA32API
|
|
NewGenRandom(
|
|
IN OUT unsigned char **ppbRandSeed /*unused*/,
|
|
IN unsigned long *pcbRandSeed /*unused*/,
|
|
IN OUT unsigned char *pbBuffer,
|
|
IN unsigned long dwLength
|
|
)
|
|
{
|
|
return (unsigned int)RtlGenRandom( pbBuffer, dwLength );
|
|
}
|