Team Fortress 2 Source Code as on 22/4/2020
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.

202 lines
4.1 KiB

  1. // osrng.cpp - written and placed in the public domain by Wei Dai
  2. // Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool.
  3. #include "pch.h"
  4. #ifndef CRYPTOPP_IMPORTS
  5. #include "osrng.h"
  6. #ifdef OS_RNG_AVAILABLE
  7. #include "rng.h"
  8. #ifdef CRYPTOPP_WIN32_AVAILABLE
  9. #ifndef _WIN32_WINNT
  10. #define _WIN32_WINNT 0x0400
  11. #endif
  12. #include <windows.h>
  13. #include <wincrypt.h>
  14. #endif
  15. #ifdef CRYPTOPP_UNIX_AVAILABLE
  16. #include <errno.h>
  17. #include <fcntl.h>
  18. #include <unistd.h>
  19. #endif
  20. NAMESPACE_BEGIN(CryptoPP)
  21. #if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE)
  22. OS_RNG_Err::OS_RNG_Err(const std::string &operation)
  23. : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " +
  24. #ifdef CRYPTOPP_WIN32_AVAILABLE
  25. "0x" + IntToString(GetLastError(), 16)
  26. #else
  27. IntToString(errno)
  28. #endif
  29. )
  30. {
  31. }
  32. #endif
  33. #ifdef NONBLOCKING_RNG_AVAILABLE
  34. #ifdef CRYPTOPP_WIN32_AVAILABLE
  35. MicrosoftCryptoProvider::MicrosoftCryptoProvider()
  36. {
  37. //if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
  38. // throw OS_RNG_Err("CryptAcquireContext");
  39. }
  40. MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
  41. {
  42. //CryptReleaseContext(m_hProvider, 0);
  43. }
  44. #endif
  45. NonblockingRng::NonblockingRng()
  46. {
  47. #ifndef CRYPTOPP_WIN32_AVAILABLE
  48. m_fd = open("/dev/urandom",O_RDONLY);
  49. if (m_fd == -1)
  50. throw OS_RNG_Err("open /dev/urandom");
  51. #endif
  52. }
  53. NonblockingRng::~NonblockingRng()
  54. {
  55. #ifndef CRYPTOPP_WIN32_AVAILABLE
  56. close(m_fd);
  57. #endif
  58. }
  59. void NonblockingRng::GenerateBlock(byte *output, size_t size)
  60. {
  61. #ifdef CRYPTOPP_WIN32_AVAILABLE
  62. //# ifdef WORKAROUND_MS_BUG_Q258000
  63. // const MicrosoftCryptoProvider &m_Provider = Singleton<MicrosoftCryptoProvider>().Ref();
  64. //# endif
  65. // if (!CryptGenRandom(m_Provider.GetProviderHandle(), (DWORD)size, output))
  66. // throw OS_RNG_Err("CryptGenRandom");
  67. static BOOL (__stdcall * s_pfnRtlGenRandom)( PVOID, ULONG ) = 0;
  68. if ( !s_pfnRtlGenRandom )
  69. {
  70. HMODULE hModAdvApi = ::LoadLibraryA( "advapi32.dll" );
  71. if ( hModAdvApi )
  72. s_pfnRtlGenRandom = (BOOL(__stdcall*)(PVOID,ULONG)) GetProcAddress( hModAdvApi, "SystemFunction036" );
  73. }
  74. _ReadWriteBarrier();
  75. if ( !s_pfnRtlGenRandom || s_pfnRtlGenRandom( output, size ) == 0 )
  76. throw OS_RNG_Err("RtlGenRandom");
  77. #else
  78. while (size)
  79. {
  80. ssize_t len = read(m_fd, output, size);
  81. if (len < 0)
  82. {
  83. // /dev/urandom reads CAN give EAGAIN errors! (maybe EINTR as well)
  84. if (errno != EINTR && errno != EAGAIN)
  85. throw OS_RNG_Err("read /dev/urandom");
  86. continue;
  87. }
  88. output += len;
  89. size -= len;
  90. }
  91. #endif
  92. }
  93. #endif
  94. // *************************************************************
  95. #ifdef BLOCKING_RNG_AVAILABLE
  96. #ifndef CRYPTOPP_BLOCKING_RNG_FILENAME
  97. #ifdef __OpenBSD__
  98. #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/srandom"
  99. #else
  100. #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/random"
  101. #endif
  102. #endif
  103. BlockingRng::BlockingRng()
  104. {
  105. m_fd = open(CRYPTOPP_BLOCKING_RNG_FILENAME,O_RDONLY);
  106. if (m_fd == -1)
  107. throw OS_RNG_Err("open " CRYPTOPP_BLOCKING_RNG_FILENAME);
  108. }
  109. BlockingRng::~BlockingRng()
  110. {
  111. close(m_fd);
  112. }
  113. void BlockingRng::GenerateBlock(byte *output, size_t size)
  114. {
  115. while (size)
  116. {
  117. // on some systems /dev/random will block until all bytes
  118. // are available, on others it returns immediately
  119. ssize_t len = read(m_fd, output, size);
  120. if (len < 0)
  121. {
  122. // /dev/random reads CAN give EAGAIN errors! (maybe EINTR as well)
  123. if (errno != EINTR && errno != EAGAIN)
  124. throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME);
  125. continue;
  126. }
  127. size -= len;
  128. output += len;
  129. if (size)
  130. sleep(1);
  131. }
  132. }
  133. #endif
  134. // *************************************************************
  135. void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size)
  136. {
  137. #ifdef NONBLOCKING_RNG_AVAILABLE
  138. if (blocking)
  139. #endif
  140. {
  141. #ifdef BLOCKING_RNG_AVAILABLE
  142. BlockingRng rng;
  143. rng.GenerateBlock(output, size);
  144. #endif
  145. }
  146. #ifdef BLOCKING_RNG_AVAILABLE
  147. if (!blocking)
  148. #endif
  149. {
  150. #ifdef NONBLOCKING_RNG_AVAILABLE
  151. NonblockingRng rng;
  152. rng.GenerateBlock(output, size);
  153. #endif
  154. }
  155. }
  156. void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
  157. {
  158. SecByteBlock seed(seedSize);
  159. OS_GenerateRandomBlock(blocking, seed, seedSize);
  160. IncorporateEntropy(seed, seedSize);
  161. }
  162. NAMESPACE_END
  163. #endif
  164. #endif