Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

321 lines
10 KiB

  1. //This file and the functions are copied from Schannel project and included in
  2. //this project without modification.
  3. #ifndef _WIN32_WINNT
  4. #define _WIN32_WINNT 0x0400
  5. #endif
  6. //#include <spbase.h>
  7. #include <windows.h>
  8. #include "rng.h"
  9. #include <rc4.h>
  10. #include <sha.h>
  11. unsigned char g_rgbStaticBits[A_SHA_DIGEST_LEN];
  12. static DWORD g_dwRC4BytesUsed = RC4_REKEY_PARAM; // initially force rekey
  13. static struct RC4_KEYSTRUCT g_rc4key;
  14. static BOOL RandomFillBuffer(BYTE *pbBuffer, DWORD *pdwLength);
  15. static void AppendRand(PRAND_CONTEXT prandContext, void* pv, DWORD dwSize);
  16. #if defined(OS_WINCE) && !defined (WINCE_GLOBAL_ALLOC_DEFINED)
  17. #define ZeroMemory( _p_, _s_ ) memset( (_p_), 0, (_s_) )
  18. #define FillMemory( _p_, _s_, _c_ ) memset( (_p_), (_c_), (_s_) )
  19. #define CopyMemory( _d_, _s_, _c_ ) memcpy( (_d_), (_s_), (_c_) )
  20. #endif // OS_WINCE
  21. /*****************************************************************************/
  22. VOID TSInitializeRNG(VOID)
  23. {
  24. ZeroMemory( g_rgbStaticBits, sizeof( g_rgbStaticBits ) );
  25. g_dwRC4BytesUsed = RC4_REKEY_PARAM;
  26. return;
  27. }
  28. /*****************************************************************************/
  29. VOID legacyInitializeRNG(VOID)
  30. {
  31. ZeroMemory( g_rgbStaticBits, sizeof( g_rgbStaticBits ) );
  32. g_dwRC4BytesUsed = RC4_REKEY_PARAM;
  33. return;
  34. }
  35. /*****************************************************************************/
  36. #ifndef NOGENRANDOM
  37. int GenRandom(PVOID Reserved,
  38. UCHAR *pbBuffer,
  39. size_t dwLength)
  40. {
  41. GenerateRandomBits(pbBuffer, dwLength);
  42. return TRUE;
  43. }
  44. #endif
  45. /************************************************************************/
  46. /* GenerateRandomBits generates a specified number of random bytes and */
  47. /* places them into the specified buffer. */
  48. /************************************************************************/
  49. /* */
  50. /* Pseudocode logic flow: */
  51. /* */
  52. /* if (bits streamed > threshold) */
  53. /* { */
  54. /* Gather_Bits() */
  55. /* SHAMix_Bits(User, Gathered, Static -> Static) */
  56. /* RC4Key(Static -> newRC4Key) */
  57. /* SHABits(Static -> Static) // hash after RC4 key generation */
  58. /* } */
  59. /* else */
  60. /* { */
  61. /* SHAMix_Bits(User, Static -> Static) */
  62. /* } */
  63. /* */
  64. /* RC4(newRC4Key -> outbuf) */
  65. /* bits streamed += sizeof(outbuf) */
  66. /* */
  67. /************************************************************************/
  68. VOID legacyGenerateRandomBits(PUCHAR pbBuffer,
  69. ULONG dwLength)
  70. {
  71. DWORD dwBytesThisPass;
  72. DWORD dwFilledBytes = 0;
  73. // break request into chunks that we rekey between
  74. while(dwFilledBytes < dwLength)
  75. {
  76. dwBytesThisPass = dwLength - dwFilledBytes;
  77. RandomFillBuffer(pbBuffer + dwFilledBytes, &dwBytesThisPass);
  78. dwFilledBytes += dwBytesThisPass;
  79. }
  80. }
  81. /*****************************************************************************/
  82. static BOOL RandomFillBuffer(BYTE *pbBuffer, DWORD *pdwLength)
  83. {
  84. // Variables from loading and storing the registry...
  85. DWORD cbDataLen;
  86. RAND_CONTEXT randContext;
  87. randContext.dwBitsFilled = 0;
  88. cbDataLen = A_SHA_DIGEST_LEN;
  89. legacyGatherRandomBits(&randContext);
  90. if(g_dwRC4BytesUsed >= RC4_REKEY_PARAM) {
  91. // if we need to rekey
  92. // Mix all bits
  93. {
  94. A_SHA_CTX SHACtx;
  95. A_SHAInit(&SHACtx);
  96. // SHA the static bits
  97. A_SHAUpdate(&SHACtx, g_rgbStaticBits, A_SHA_DIGEST_LEN);
  98. // SHA the gathered bits
  99. A_SHAUpdate(&SHACtx, randContext.rgbBitBuffer, randContext.dwBitsFilled);
  100. // SHA the user-supplied bits
  101. A_SHAUpdate(&SHACtx, pbBuffer, *pdwLength);
  102. // output back out to static bits
  103. A_SHAFinal(&SHACtx, g_rgbStaticBits);
  104. }
  105. // Create RC4 key
  106. g_dwRC4BytesUsed = 0;
  107. rc4_key(&g_rc4key, A_SHA_DIGEST_LEN, g_rgbStaticBits);
  108. // Mix RC4 key bits around
  109. {
  110. A_SHA_CTX SHACtx;
  111. A_SHAInit(&SHACtx);
  112. // SHA the static bits
  113. A_SHAUpdate(&SHACtx, g_rgbStaticBits, A_SHA_DIGEST_LEN);
  114. // output back out to static bits
  115. A_SHAFinal(&SHACtx, g_rgbStaticBits);
  116. }
  117. } else {
  118. // Use current RC4 key, but capture any user-supplied bits.
  119. // Mix input bits
  120. {
  121. A_SHA_CTX SHACtx;
  122. A_SHAInit(&SHACtx);
  123. // SHA the static bits
  124. A_SHAUpdate(&SHACtx, g_rgbStaticBits, A_SHA_DIGEST_LEN);
  125. // SHA the user-supplied bits
  126. A_SHAUpdate(&SHACtx, pbBuffer, *pdwLength);
  127. // output back out to static bits
  128. A_SHAFinal(&SHACtx, g_rgbStaticBits);
  129. }
  130. }
  131. // only use RC4_REKEY_PARAM bytes from each RC4 key
  132. {
  133. DWORD dwMaxPossibleBytes = RC4_REKEY_PARAM - g_dwRC4BytesUsed;
  134. if(*pdwLength > dwMaxPossibleBytes) {
  135. *pdwLength = dwMaxPossibleBytes;
  136. }
  137. }
  138. FillMemory(pbBuffer, *pdwLength, 0);
  139. rc4(&g_rc4key, *pdwLength, pbBuffer);
  140. g_dwRC4BytesUsed += *pdwLength;
  141. return TRUE;
  142. }
  143. /*****************************************************************************/
  144. void legacyGatherRandomBits(PRAND_CONTEXT prandContext)
  145. {
  146. DWORD dwTmp;
  147. WORD wTmp;
  148. BYTE bTmp;
  149. // ** indicates US DoD's specific recommendations for password generation
  150. // proc id
  151. dwTmp = GetCurrentProcessId();
  152. AppendRand(prandContext, &dwTmp, sizeof(dwTmp));
  153. // thread id
  154. dwTmp = GetCurrentThreadId();
  155. AppendRand(prandContext, &dwTmp, sizeof(dwTmp));
  156. // ** ticks since boot (system clock)
  157. dwTmp = GetTickCount();
  158. AppendRand(prandContext, &dwTmp, sizeof(dwTmp));
  159. // cursor position
  160. {
  161. POINT point;
  162. GetCursorPos(&point);
  163. bTmp = LOBYTE(point.x) ^ HIBYTE(point.x);
  164. AppendRand(prandContext, &bTmp, sizeof(BYTE));
  165. bTmp = LOBYTE(point.y) ^ HIBYTE(point.y);
  166. AppendRand(prandContext, &bTmp, sizeof(BYTE));
  167. }
  168. // ** system time, in ms, sec, min (date & time)
  169. {
  170. SYSTEMTIME sysTime;
  171. GetLocalTime(&sysTime);
  172. AppendRand(prandContext, &sysTime.wMilliseconds, sizeof(sysTime.wMilliseconds));
  173. bTmp = LOBYTE(sysTime.wSecond) ^ LOBYTE(sysTime.wMinute);
  174. AppendRand(prandContext, &bTmp, sizeof(BYTE));
  175. }
  176. // ** hi-res performance counter (system counters)
  177. {
  178. LARGE_INTEGER liPerfCount;
  179. if(QueryPerformanceCounter(&liPerfCount)) {
  180. bTmp = LOBYTE(LOWORD(liPerfCount.LowPart)) ^ LOBYTE(LOWORD(liPerfCount.HighPart));
  181. AppendRand(prandContext, &bTmp, sizeof(BYTE));
  182. bTmp = HIBYTE(LOWORD(liPerfCount.LowPart)) ^ LOBYTE(LOWORD(liPerfCount.HighPart));
  183. AppendRand(prandContext, &bTmp, sizeof(BYTE));
  184. bTmp = LOBYTE(HIWORD(liPerfCount.LowPart)) ^ LOBYTE(LOWORD(liPerfCount.HighPart));
  185. AppendRand(prandContext, &bTmp, sizeof(BYTE));
  186. bTmp = HIBYTE(HIWORD(liPerfCount.LowPart)) ^ LOBYTE(LOWORD(liPerfCount.HighPart));
  187. AppendRand(prandContext, &bTmp, sizeof(BYTE));
  188. }
  189. }
  190. // memory status
  191. {
  192. MEMORYSTATUS mstMemStat;
  193. mstMemStat.dwLength = sizeof(MEMORYSTATUS); // must-do
  194. GlobalMemoryStatus(&mstMemStat);
  195. wTmp = HIWORD(mstMemStat.dwAvailPhys); // low words seem to be always zero
  196. AppendRand(prandContext, &wTmp, sizeof(WORD));
  197. wTmp = HIWORD(mstMemStat.dwAvailPageFile);
  198. AppendRand(prandContext, &wTmp, sizeof(WORD));
  199. bTmp = LOBYTE(HIWORD(mstMemStat.dwAvailVirtual));
  200. AppendRand(prandContext, &bTmp, sizeof(BYTE));
  201. }
  202. #ifndef OS_WINCE
  203. // free disk clusters
  204. {
  205. DWORD dwSectorsPerCluster, dwBytesPerSector, dwNumberOfFreeClusters, dwTotalNumberOfClusters;
  206. if(GetDiskFreeSpace(NULL, &dwSectorsPerCluster, &dwBytesPerSector, &dwNumberOfFreeClusters, &dwTotalNumberOfClusters)) {
  207. AppendRand(prandContext, &dwNumberOfFreeClusters, sizeof(dwNumberOfFreeClusters));
  208. AppendRand(prandContext, &dwTotalNumberOfClusters, sizeof(dwTotalNumberOfClusters));
  209. AppendRand(prandContext, &dwBytesPerSector, sizeof(dwBytesPerSector));
  210. }
  211. }
  212. // last messages' timestamp
  213. {
  214. LONG lTime;
  215. lTime = GetMessageTime();
  216. AppendRand(prandContext, &lTime, sizeof(lTime));
  217. }
  218. {
  219. // **SystemID
  220. DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
  221. char lpBuf [MAX_COMPUTERNAME_LENGTH + 1];
  222. if(GetComputerNameA(lpBuf, &dwSize)) {
  223. // dwSize = len not including null termination
  224. AppendRand(prandContext, lpBuf, dwSize);
  225. }
  226. //
  227. // GetUserName can go and add a terminating NULL past the size
  228. // specified so send it a size one less than the buffer.
  229. //
  230. //
  231. dwSize = MAX_COMPUTERNAME_LENGTH;
  232. // **UserID
  233. if(GetUserNameA(lpBuf, &dwSize)) {
  234. // dwSize = len including null termination
  235. dwSize -= 1;
  236. AppendRand(prandContext, lpBuf, dwSize);
  237. }
  238. }
  239. #endif // OS_WINCE
  240. }
  241. /*****************************************************************************/
  242. static void AppendRand(PRAND_CONTEXT prandContext, void* pv, DWORD dwSize)
  243. {
  244. DWORD dwBitsLeft = (RAND_CTXT_LEN - prandContext->dwBitsFilled);
  245. if(dwBitsLeft > 0) {
  246. if(dwSize > dwBitsLeft) {
  247. dwSize = dwBitsLeft;
  248. }
  249. CopyMemory(prandContext->rgbBitBuffer + prandContext->dwBitsFilled, pv, dwSize);
  250. prandContext->dwBitsFilled += dwSize;
  251. }
  252. }