|
|
/////////////////////////////////////////////////////////////////////////////
// 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 ); }
|