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