📄 globrand.cpp
字号:
// globrand.cc// code for globrand.h// copyright SafeTP Development Group, Inc., 2000 Terms of use are as specified in license.txt#include "globrand.h" // this module#include "keyutils.h" // LoadKey, SaveKey#include "entropy.h" // a source of entropy#include "exc.h" // xBase#include "ssha.h" // SHA#include "warn.h" // warning#include "nonport.h" // LOCKER, portable{Lock,Unlock}// ------------------ HashedRandomPool -----------------enum { SEED_LENGTH = 384, // use the same value mentioned in randpool.h POOL_MDC_KEY_LENGTH = 64, // MD5's block size TOTAL_SEED_LENGTH = SEED_LENGTH + POOL_MDC_KEY_LENGTH};HashedRandomPool::HashedRandomPool() : basePool(SEED_LENGTH), notSeeded(true){ forceRehash();}void HashedRandomPool::forceRehash(){ outPtr = BUFSIZE;}byte HashedRandomPool::GetByte(){ if (notSeeded) { warning((WarnLevel)(WARN_SECURITY | WARN_DEBUG), "Random pool has not been seeded."); // even though the condition is really still true, // it's pointless to continue to spew warnings notSeeded = false; } // test to see if we have to refill the output buffer if (outPtr >= BUFSIZE) { xassert(outPtr == BUFSIZE); // shouldn't go beyond // grab bytes directly from the pool basePool.GetBlock(outBuffer, BUFSIZE); // hash them in-place xassert((int)BUFSIZE == (int)SHA::DIGESTSIZE); SHA sha; sha.CalculateDigest(outBuffer, outBuffer, BUFSIZE); // reset output ptr to begin at the beginning outPtr = 0; } // return next byte return outBuffer[outPtr++];}DataBlock HashedRandomPool::getSeed(){ // pull out (without hashing) a number of bytes // sufficient to get the pool bytes *plus* the // (internal to basePool) MDC key bytes DataBlock ret(TOTAL_SEED_LENGTH); basePool.GetBlock(ret.getData(), TOTAL_SEED_LENGTH); ret.setDataLen(TOTAL_SEED_LENGTH); return ret;}void HashedRandomPool::seed(DataBlock const &seed){ // just shove the bytes into the base pool and // assume it will properly distribute entropy // (a reasonable assumption, I believe) basePool.Put(seed.getDataC(), seed.getDataLen()); // calling forceRehash would not accomplish much // (I think..), so I don't notSeeded = false;}void HashedRandomPool::Put(byte const *bytes, int length){ basePool.Put(bytes, length); notSeeded = false;}// --------------- functions ----------------------// just some name..// thread safety: I think it's a good idea to protect accesses// to this file toochar const seedKeyName[] = "randomSeed";// thread safety: *requires* all access to be protected by the lock;// static declaration prevents even the linker from find it!// USE INSTEAD: GlobalRandomPool, pool() method (see e.g. cryputil.cpp)static HashedRandomPool globalRandomPool;// read seed from persistent statevoid readRandomSeed(bool complain){ { // scope this to avoid nested locking in addEntropy LOCKER // read it DataBlock seed; string temp(seedKeyName); if (LoadKey(temp, seed)) { // stuff it into the pool globalRandomPool.seed(seed); } else { if (complain) { // this is going to happen the first time, but should // *only* happen the first time warning(WARN_SECURITY, "The random seed file is missing. Creating a new one now."); } } } // on the presumption that calling this fn is done at the start of // the program, there may be entropy in there (this, at very least, // also prevents the seed from being *totally* predictable if the // seed key file is missing) addEntropy(); // SM: There appears to be a bad interaction with loading and then // saving immediately. It's possible that this effect is not // specific to our PRNG. //SaveKey(temp, seed);}bool isRandomSeedThere(){ LOCKER return sm_testKey(seedKeyName);}// save seed to persistent statevoid saveRandomSeed(){ string temp(seedKeyName); DataBlock oldseed; // SM: I've decided there is some risk in this policy, and since // losing entropy from multiple processes is much less important // than losing all/most entropy due to another effect I think // is present# if 0 // we first seed our pool with what is on disk, so that additional // entropy added by other instances of this process is not lost; we // rely on basePool's ability to fold-in new bytes *without* evicting // entropy already in the system (it can; it XORs the new with the old) if (LoadKey(temp, oldseed)) { // stuff it into the pool globalRandomPool.seed(oldseed); }# endif //0 addEntropy(); // get in some more entropy // protect file access LOCKER // retrieve the seed DataBlock seed = globalRandomPool.getSeed(); // write it out if (!SaveKey(temp, seed)) { THROW(xBase("failed to save random seed")); }}// add a specific value that may be entropicvoid addEntropy(long value){ // let's use the locking method external clients are expected // to use, in part to test it GlobalRandomPool grp; // in the unlikely chance an adversary can choose 'value', which // could (conceivably) be used to attack the random pool, // we'll go to the trouble of hashing it now SHA sha; byte digest[SHA::DIGESTSIZE]; // hash the bytes sha.CalculateDigest(digest, (byte*)&value, sizeof(value)); // fold in the hashed bytes grp.pool().Put(digest, SHA::DIGESTSIZE);}// add entropyvoid addEntropy(){ // read things like time of day, current mouse position, etc. long e = getEntropy(); addEntropy(e);}// alternate interfaceDataBlock getRandomBytes(int bytes){ GlobalRandomPool grp; DataBlock ret(bytes); grp.pool().GetBlock(ret.getData(), bytes); ret.setDataLen(bytes); return ret;}// ----------------- the global random pool ----------------GlobalRandomPool::GlobalRandomPool(){ portableLock();}GlobalRandomPool::~GlobalRandomPool(){ portableUnlock();}HashedRandomPool &GlobalRandomPool::pool(){ return globalRandomPool;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -