srandom.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. ** Command & Conquer Renegade(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. #else
  28. #include "win.h"
  29. #include <process.h>
  30. #endif
  31. #include <time.h>
  32. #include <assert.h>
  33. #include "sha.h"
  34. // Static class variables
  35. unsigned char SecureRandomClass::Seeds[SecureRandomClass::SeedLength];
  36. bool SecureRandomClass::Initialized=false;
  37. unsigned int SecureRandomClass::RandomCache[SecureRandomClass::SHADigestBytes / sizeof(unsigned int)];
  38. int SecureRandomClass::RandomCacheEntries=0;
  39. unsigned int SecureRandomClass::Counter=0;
  40. Random3Class SecureRandomClass::RandomHelper;
  41. SecureRandomClass::SecureRandomClass()
  42. {
  43. if (Initialized == false)
  44. {
  45. Generate_Seed();
  46. Initialized=true;
  47. }
  48. }
  49. SecureRandomClass::~SecureRandomClass()
  50. {
  51. }
  52. //
  53. // Add seed values to our pool of randomness
  54. //
  55. void SecureRandomClass::Add_Seeds(unsigned char *values, int length)
  56. {
  57. for (int i=0; i<length; i++)
  58. {
  59. Seeds[0]^=values[i];
  60. // Rotate the seeds to the left
  61. unsigned char uctemp=Seeds[SeedLength-1];
  62. for (int j=SeedLength-1; j>=1; j--)
  63. Seeds[j]=Seeds[j-1];
  64. Seeds[0]=uctemp;
  65. }
  66. // We have a better seed pool now so trigger new random values
  67. RandomCacheEntries=0;
  68. }
  69. //
  70. // Get a 32bit random value
  71. //
  72. unsigned long SecureRandomClass::Randval(void)
  73. {
  74. if (RandomCacheEntries == 0)
  75. {
  76. SHAEngine sha;
  77. char digest[SHADigestBytes]; // SHA produces a 20 byte hash
  78. sha.Hash(Seeds, SeedLength);
  79. sha.Result(digest);
  80. memcpy(RandomCache, digest, SHADigestBytes);
  81. RandomCacheEntries=(SHADigestBytes / sizeof(unsigned int));
  82. unsigned int *int_seeds=(unsigned int *)Seeds;
  83. int_seeds[0]^=Counter; // remove the last counter (double xor)
  84. int_seeds[0]^=(Counter+1); // put the new counter in place
  85. int_seeds[(SeedLength/sizeof(int))-1]^=Counter; // remove the last counter (double xor)
  86. int_seeds[(SeedLength/sizeof(int))-1]^=(Counter+1); // put the new counter in place
  87. Counter++; // increment counter
  88. }
  89. unsigned long retval=RandomCache[--RandomCacheEntries];
  90. // SHA doesn't have the best distribution properties in the world
  91. // We'll XOR the result with the output of another random number
  92. unsigned long helperval=RandomHelper();
  93. retval^=helperval;
  94. return(retval);
  95. }
  96. /////////////////////////////// Private Methods ///////////////////////////////////////
  97. //
  98. // Seed the random number generator.
  99. // The seed is what makes each run of random numbers unique. If an observer
  100. // can guess your seed they can predict your random numbers.
  101. //
  102. // Note the use of XORs everywhere. The XOR of a good random number and a bad random
  103. // number is still a good random number.
  104. //
  105. // Caution: Under windows this isn't nearly as safe as under UNIX!
  106. //
  107. void SecureRandomClass::Generate_Seed(void)
  108. {
  109. int i;
  110. // Start with some garbage values
  111. memset(Seeds, 0xAA, SeedLength);
  112. unsigned int *int_seeds=(unsigned int *)Seeds;
  113. int int_seed_length=SeedLength/sizeof(unsigned int);
  114. #ifdef _UNIX
  115. //
  116. // On UNIX we've already got a great random number souce.
  117. // This should be used only for a seed since it's slow.
  118. //
  119. FILE *in=fopen("/dev/random","r");
  120. if (in)
  121. {
  122. for (i=0; i<SeedLength; i++)
  123. Seeds[i]^=fgetc(in);
  124. fclose(in);
  125. }
  126. else
  127. assert(0);
  128. #else
  129. //
  130. // Get free drive space
  131. //
  132. DWORD spc, bps, nfc, tnc; // various drive attributes (we don't care what they mean)
  133. GetDiskFreeSpace(NULL, &spc, &bps, &nfc, &tnc);
  134. int_seeds[0]^=spc;
  135. int_seeds[1 % int_seed_length]^=bps;
  136. int_seeds[2 % int_seed_length]^=nfc;
  137. int_seeds[3 % int_seed_length]^=tnc;
  138. //
  139. // Get computer & user name
  140. //
  141. char comp_name[128];
  142. char user_name[128];
  143. DWORD comp_len=128;
  144. DWORD name_len=128;
  145. GetComputerName(comp_name, &comp_len);
  146. GetUserName(user_name, &name_len);
  147. for (i=0; i<128; i++)
  148. {
  149. // Offset in case user_name == comp_name
  150. Seeds[(i+0) % SeedLength]^=comp_name[i];
  151. Seeds[(i+2) % SeedLength]^=user_name[i];
  152. }
  153. #endif
  154. for (i=0; i<int_seed_length; i++)
  155. {
  156. if ((i % 4) == 0)
  157. int_seeds[i]^=time(NULL);
  158. else if ((i % 4) == 1)
  159. int_seeds[i]^=getpid();
  160. else if ((i % 4) == 2)
  161. int_seeds[i]^=GetTickCount();
  162. else if ((i % 4) == 3)
  163. int_seeds[i]^=i;
  164. }
  165. }