197 lines
4.9 KiB
C++
197 lines
4.9 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// SecureRandomClass - Generate random values
|
||
|
//
|
||
|
|
||
|
#pragma warning(disable : 4514) // unreferenced inline function removed....
|
||
|
|
||
|
#include "srandom.h"
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#ifdef _UNIX
|
||
|
#include "osdep.h"
|
||
|
#else
|
||
|
#include "win.h"
|
||
|
#include <process.h>
|
||
|
#endif
|
||
|
#include <time.h>
|
||
|
#include <assert.h>
|
||
|
#include "sha.h"
|
||
|
|
||
|
// Static class variables
|
||
|
unsigned char SecureRandomClass::Seeds[SecureRandomClass::SeedLength];
|
||
|
bool SecureRandomClass::Initialized=false;
|
||
|
unsigned int SecureRandomClass::RandomCache[SecureRandomClass::SHADigestBytes / sizeof(unsigned int)];
|
||
|
int SecureRandomClass::RandomCacheEntries=0;
|
||
|
unsigned int SecureRandomClass::Counter=0;
|
||
|
Random3Class SecureRandomClass::RandomHelper;
|
||
|
|
||
|
SecureRandomClass::SecureRandomClass()
|
||
|
{
|
||
|
if (Initialized == false)
|
||
|
{
|
||
|
Generate_Seed();
|
||
|
Initialized=true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SecureRandomClass::~SecureRandomClass()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Add seed values to our pool of randomness
|
||
|
//
|
||
|
void SecureRandomClass::Add_Seeds(unsigned char *values, int length)
|
||
|
{
|
||
|
for (int i=0; i<length; i++)
|
||
|
{
|
||
|
Seeds[0]^=values[i];
|
||
|
|
||
|
// Rotate the seeds to the left
|
||
|
unsigned char uctemp=Seeds[SeedLength-1];
|
||
|
for (int j=SeedLength-1; j>=1; j--)
|
||
|
Seeds[j]=Seeds[j-1];
|
||
|
Seeds[0]=uctemp;
|
||
|
}
|
||
|
|
||
|
// We have a better seed pool now so trigger new random values
|
||
|
RandomCacheEntries=0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get a 32bit random value
|
||
|
//
|
||
|
unsigned long SecureRandomClass::Randval(void)
|
||
|
{
|
||
|
if (RandomCacheEntries == 0)
|
||
|
{
|
||
|
SHAEngine sha;
|
||
|
char digest[SHADigestBytes]; // SHA produces a 20 byte hash
|
||
|
|
||
|
sha.Hash(Seeds, SeedLength);
|
||
|
sha.Result(digest);
|
||
|
|
||
|
memcpy(RandomCache, digest, SHADigestBytes);
|
||
|
RandomCacheEntries=(SHADigestBytes / sizeof(unsigned int));
|
||
|
|
||
|
unsigned int *int_seeds=(unsigned int *)Seeds;
|
||
|
int_seeds[0]^=Counter; // remove the last counter (double xor)
|
||
|
int_seeds[0]^=(Counter+1); // put the new counter in place
|
||
|
|
||
|
int_seeds[(SeedLength/sizeof(int))-1]^=Counter; // remove the last counter (double xor)
|
||
|
int_seeds[(SeedLength/sizeof(int))-1]^=(Counter+1); // put the new counter in place
|
||
|
|
||
|
Counter++; // increment counter
|
||
|
}
|
||
|
|
||
|
unsigned long retval=RandomCache[--RandomCacheEntries];
|
||
|
|
||
|
// SHA doesn't have the best distribution properties in the world
|
||
|
// We'll XOR the result with the output of another random number
|
||
|
unsigned long helperval=RandomHelper();
|
||
|
retval^=helperval;
|
||
|
|
||
|
return(retval);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////// Private Methods ///////////////////////////////////////
|
||
|
|
||
|
|
||
|
//
|
||
|
// Seed the random number generator.
|
||
|
// The seed is what makes each run of random numbers unique. If an observer
|
||
|
// can guess your seed they can predict your random numbers.
|
||
|
//
|
||
|
// Note the use of XORs everywhere. The XOR of a good random number and a bad random
|
||
|
// number is still a good random number.
|
||
|
//
|
||
|
// Caution: Under windows this isn't nearly as safe as under UNIX!
|
||
|
//
|
||
|
void SecureRandomClass::Generate_Seed(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
// Start with some garbage values
|
||
|
memset(Seeds, 0xAA, SeedLength);
|
||
|
|
||
|
unsigned int *int_seeds=(unsigned int *)Seeds;
|
||
|
int int_seed_length=SeedLength/sizeof(unsigned int);
|
||
|
|
||
|
#ifdef _UNIX
|
||
|
//
|
||
|
// On UNIX we've already got a great random number souce.
|
||
|
// This should be used only for a seed since it's slow.
|
||
|
//
|
||
|
FILE *in=fopen("/dev/random","r");
|
||
|
if (in)
|
||
|
{
|
||
|
for (i=0; i<SeedLength; i++)
|
||
|
Seeds[i]^=fgetc(in);
|
||
|
fclose(in);
|
||
|
}
|
||
|
else
|
||
|
assert(0);
|
||
|
#else
|
||
|
|
||
|
//
|
||
|
// Get free drive space
|
||
|
//
|
||
|
DWORD spc, bps, nfc, tnc; // various drive attributes (we don't care what they mean)
|
||
|
GetDiskFreeSpace(NULL, &spc, &bps, &nfc, &tnc);
|
||
|
int_seeds[0]^=spc;
|
||
|
int_seeds[1 % int_seed_length]^=bps;
|
||
|
int_seeds[2 % int_seed_length]^=nfc;
|
||
|
int_seeds[3 % int_seed_length]^=tnc;
|
||
|
|
||
|
//
|
||
|
// Get computer & user name
|
||
|
//
|
||
|
char comp_name[128];
|
||
|
char user_name[128];
|
||
|
DWORD comp_len=128;
|
||
|
DWORD name_len=128;
|
||
|
|
||
|
GetComputerName(comp_name, &comp_len);
|
||
|
GetUserName(user_name, &name_len);
|
||
|
for (i=0; i<128; i++)
|
||
|
{
|
||
|
// Offset in case user_name == comp_name
|
||
|
Seeds[(i+0) % SeedLength]^=comp_name[i];
|
||
|
Seeds[(i+2) % SeedLength]^=user_name[i];
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
for (i=0; i<int_seed_length; i++)
|
||
|
{
|
||
|
if ((i % 4) == 0)
|
||
|
int_seeds[i]^=time(NULL);
|
||
|
else if ((i % 4) == 1)
|
||
|
int_seeds[i]^=getpid();
|
||
|
else if ((i % 4) == 2)
|
||
|
int_seeds[i]^=GetTickCount();
|
||
|
else if ((i % 4) == 3)
|
||
|
int_seeds[i]^=i;
|
||
|
}
|
||
|
}
|