srandom.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. //
  19. // SecureRandomClass - Generate random values
  20. //
  21. #pragma warning(disable : 4514) // unreferenced inline function removed....
  22. #include "srandom.h"
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #ifdef _UNIX
  26. #include "osdep.h"
  27. #include <linux/kernel.h>
  28. #include <linux/sys.h>
  29. extern "C" {
  30. int sysinfo(struct sysinfo *info);
  31. }
  32. #else
  33. #include "win.h"
  34. #include <process.h>
  35. #endif
  36. #include <time.h>
  37. #include <assert.h>
  38. #include "sha.h"
  39. // Static class variables
  40. unsigned char SecureRandomClass::Seeds[SecureRandomClass::SeedLength];
  41. bool SecureRandomClass::Initialized=false;
  42. unsigned int SecureRandomClass::RandomCache[SecureRandomClass::SHADigestBytes / sizeof(unsigned int)];
  43. int SecureRandomClass::RandomCacheEntries=0;
  44. unsigned int SecureRandomClass::Counter=0;
  45. Random3Class SecureRandomClass::RandomHelper;
  46. SecureRandomClass::SecureRandomClass()
  47. {
  48. if (Initialized == false)
  49. {
  50. Generate_Seed();
  51. Initialized=true;
  52. }
  53. }
  54. SecureRandomClass::~SecureRandomClass()
  55. {
  56. }
  57. //
  58. // Add seed values to our pool of randomness
  59. //
  60. void SecureRandomClass::Add_Seeds(unsigned char *values, int length)
  61. {
  62. for (int i=0; i<length; i++)
  63. {
  64. Seeds[0]^=values[i];
  65. // Rotate the seeds to the left
  66. unsigned char uctemp=Seeds[SeedLength-1];
  67. for (int j=SeedLength-1; j>=1; j--)
  68. Seeds[j]=Seeds[j-1];
  69. Seeds[0]=uctemp;
  70. }
  71. // We have a better seed pool now so trigger new random values
  72. RandomCacheEntries=0;
  73. }
  74. //
  75. // Get a 32bit random value
  76. //
  77. unsigned long SecureRandomClass::Randval(void)
  78. {
  79. if (RandomCacheEntries == 0)
  80. {
  81. SHAEngine sha;
  82. char digest[SHADigestBytes]; // SHA produces a 20 byte hash
  83. sha.Hash(Seeds, SeedLength);
  84. sha.Result(digest);
  85. memcpy(RandomCache, digest, SHADigestBytes);
  86. RandomCacheEntries=(SHADigestBytes / sizeof(unsigned int));
  87. unsigned int *int_seeds=(unsigned int *)Seeds;
  88. int_seeds[0]^=Counter; // remove the last counter (double xor)
  89. int_seeds[0]^=(Counter+1); // put the new counter in place
  90. int_seeds[(SeedLength/sizeof(int))-1]^=Counter; // remove the last counter (double xor)
  91. int_seeds[(SeedLength/sizeof(int))-1]^=(Counter+1); // put the new counter in place
  92. Counter++; // increment counter
  93. }
  94. unsigned long retval=RandomCache[--RandomCacheEntries];
  95. // SHA doesn't have the best distribution properties in the world
  96. // We'll XOR the result with the output of another random number
  97. unsigned long helperval=RandomHelper();
  98. retval^=helperval;
  99. return(retval);
  100. }
  101. /////////////////////////////// Private Methods ///////////////////////////////////////
  102. //
  103. // Seed the random number generator.
  104. // The seed is what makes each run of random numbers unique. If an observer
  105. // can guess your seed they can predict your random numbers.
  106. //
  107. // Note the use of XORs everywhere. The XOR of a good random number and a bad random
  108. // number is still a good random number.
  109. //
  110. // Caution: Under windows this isn't nearly as safe as under UNIX!
  111. //
  112. void SecureRandomClass::Generate_Seed(void)
  113. {
  114. int i;
  115. // Start with some garbage values
  116. memset(Seeds, 0xAA, SeedLength);
  117. unsigned int *int_seeds=(unsigned int *)Seeds;
  118. int int_seed_length=SeedLength/sizeof(unsigned int);
  119. #ifdef _USE_DEV_RANDOM
  120. //
  121. // On UNIX we've already got a great random number souce.
  122. // This should be used only for a seed since it's slow.
  123. //
  124. FILE *in=fopen("/dev/random","r");
  125. if (in)
  126. {
  127. for (i=0; i<SeedLength; i++)
  128. Seeds[i]^=fgetc(in);
  129. fclose(in);
  130. }
  131. else
  132. assert(0);
  133. #elif defined(_UNIX)
  134. // UNIX without /dev/random (or it's too slow)
  135. int_seeds[0]^=getuid();
  136. struct sysinfo info;
  137. sysinfo(&info);
  138. int_seeds[1 % int_seed_length]^=info.loads[0];
  139. int_seeds[2 % int_seed_length]^=info.loads[1];
  140. int_seeds[3 % int_seed_length]^=info.loads[2];
  141. int_seeds[4 % int_seed_length]^=info.freeram;
  142. int_seeds[5 % int_seed_length]^=info.freeswap;
  143. int_seeds[6 % int_seed_length]^=info.procs;
  144. int_seeds[7 % int_seed_length]^=info.bufferram;
  145. #else
  146. //
  147. // Get free drive space
  148. //
  149. DWORD spc, bps, nfc, tnc; // various drive attributes (we don't care what they mean)
  150. GetDiskFreeSpace(NULL, &spc, &bps, &nfc, &tnc);
  151. int_seeds[0]^=spc;
  152. int_seeds[1 % int_seed_length]^=bps;
  153. int_seeds[2 % int_seed_length]^=nfc;
  154. int_seeds[3 % int_seed_length]^=tnc;
  155. //
  156. // Get computer & user name
  157. //
  158. char comp_name[128];
  159. char user_name[128];
  160. DWORD comp_len=128;
  161. DWORD name_len=128;
  162. GetComputerName(comp_name, &comp_len);
  163. GetUserName(user_name, &name_len);
  164. for (i=0; i<128; i++)
  165. {
  166. // Offset in case user_name == comp_name
  167. Seeds[(i+0) % SeedLength]^=comp_name[i];
  168. Seeds[(i+2) % SeedLength]^=user_name[i];
  169. }
  170. #endif
  171. for (i=0; i<int_seed_length; i++)
  172. {
  173. if ((i % 4) == 0)
  174. int_seeds[i]^=time(NULL);
  175. else if ((i % 4) == 1)
  176. int_seeds[i]^=getpid();
  177. else if ((i % 4) == 2)
  178. int_seeds[i]^=GetTickCount();
  179. else if ((i % 4) == 3)
  180. int_seeds[i]^=i;
  181. }
  182. }