|
|
|
|
|
|
|
|
|
|
|
// onetimepad.cpp |
|
|
|
|
|
// Copyright (C) 2006-2007 MicroNeil Research Corporation |
|
|
|
|
|
|
|
|
|
|
|
#include "onetimepad.hpp" |
|
|
|
|
|
#include "timing.hpp" |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
class OneTimePad { // One Time Pad generator. |
|
|
|
|
|
private: |
|
|
|
|
|
MANGLER PagGenerator; // MANGLER as a PRNG. |
|
|
|
|
|
PadBuffer Entropy(int Length = 1024); // System entropy source. |
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
** OneTimePad(); // Constructor initializes w/ Entropy. |
|
|
|
|
|
** PadBuffer Pad(int Length); // Get a pad of Length. |
|
|
|
|
|
** void addEntropy(); // Add entropy from the system source. |
|
|
|
|
|
** void addEntropy(PadBuffer Entropy); // Add entropy from this source. |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Platform specific strong entropy sourcing. |
|
|
|
|
|
|
|
|
|
|
|
#ifdef WIN32 |
|
|
|
|
|
|
|
|
|
|
|
//// WIN32 Strong Entropy Source == CryptGenRandom() /////////////////////////// |
|
|
|
|
|
|
|
|
|
|
|
#include <windows.h> |
|
|
|
|
|
#include <wincrypt.h> |
|
|
|
|
|
|
|
|
|
|
|
PadBuffer OneTimePad::Entropy(int Length) { // Get a PadBuffer full of randomness. |
|
|
|
|
|
PadBuffer Buffer(Length, 0); // Start by initializing the buffer. |
|
|
|
|
|
HCRYPTPROV provider = 0; // We will need a handle for the source. |
|
|
|
|
|
|
|
|
|
|
|
if( // Try a two different sources. |
|
|
|
|
|
!CryptAcquireContext( // If we can get a hardware source |
|
|
|
|
|
&provider, NULL, NULL, PROV_INTEL_SEC, CRYPT_VERIFYCONTEXT)) { // from an intel CPU then use that first. |
|
|
|
|
|
|
|
|
|
|
|
if( // If we can't use get that |
|
|
|
|
|
!CryptAcquireContext( // entropy source for some reason then |
|
|
|
|
|
&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { // try to use the RSA source. That should |
|
|
|
|
|
// always work, but if it doesn't we need |
|
|
|
|
|
provider = 0; // to know about it so we'll have a zero |
|
|
|
|
|
} // handle. |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(0 != provider) { // If we did get a good source then |
|
|
|
|
|
CryptGenRandom (provider, Length, (BYTE*)&Buffer[0]); // grab the random bit required and |
|
|
|
|
|
CryptReleaseContext(provider,0); // then let the provider go. |
|
|
|
|
|
StrongEntropyFlag = true; // We DID get strong entropy. |
|
|
|
|
|
} |
|
|
|
|
|
else { // If we did not get a good source |
|
|
|
|
|
StrongEntropyFlag = false; // then we are not strong. |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return Buffer; // Return the data we got. |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
|
|
|
|
//// *NIX Strong Entropy Source == /dev/urandom //////////////////////////////// |
|
|
|
|
|
|
|
|
|
|
|
#include <fstream> |
|
|
|
|
|
|
|
|
|
|
|
PadBuffer OneTimePad::Entropy(int Length) { // Get Length bytes of strong entropy. |
|
|
|
|
|
PadBuffer Buffer(Length, 0); // Initialize a buffer to hold them. |
|
|
|
|
|
try { // Handle this in a try block. |
|
|
|
|
|
ifstream Source("/dev/urandom", ios::binary); // Open /dev/urandom if possible. |
|
|
|
|
|
Source.read(reinterpret_cast<char*>(&Buffer[0]), Length); // Read data into the buffer. |
|
|
|
|
|
if(!Source.bad() && Source.gcount() == Length) { // If we got what we came for then |
|
|
|
|
|
StrongEntropyFlag = true; // we have strong cryptography. |
|
|
|
|
|
} else { // If we didn't then we are not |
|
|
|
|
|
StrongEntropyFlag = false; // strong, and don't have things |
|
|
|
|
|
} // to make us go. |
|
|
|
|
|
Source.close(); // We're done, so close the stream. |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
catch(...) { // If we had an exception then we |
|
|
|
|
|
StrongEntropyFlag = false; // did not get strong entropy. |
|
|
|
|
|
} |
|
|
|
|
|
return Buffer; // Return the buffer. |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
// End Platform Specific Bits |
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
|
|
|
|
|
|
// Lightweight entropy is built from a combination of the time in ms UTC that |
|
|
|
|
|
// the application was started, the number of milliseconds since that time in |
|
|
|
|
|
// milliseconds, the number and times of calls to addLightweightEntropy(), and |
|
|
|
|
|
// the state of the MANGLER engine at each call -- that state is effected by |
|
|
|
|
|
// the combined previous use of the MANGLER and any other entropy that was |
|
|
|
|
|
// added including the timing of those events (since they all trigger the |
|
|
|
|
|
// addLightweightEntropy() function. |
|
|
|
|
|
|
|
|
|
|
|
Timer OneTimePadRunTimer; // Millisecond entropy source. |
|
|
|
|
|
msclock LightweightEntropyBuffer; // Lightweight entropy bucket. |
|
|
|
|
|
|
|
|
|
|
|
void OneTimePad::addLightweightEntropy() { // Add entropy based on the |
|
|
|
|
|
msclock StartFill = OneTimePadRunTimer.getStartClock(); // initial start time of the app |
|
|
|
|
|
msclock ElapsedFill = OneTimePadRunTimer.getElapsedTime(); // and the number of millisecs since. |
|
|
|
|
|
msclock CombinedFill = StartFill ^ ElapsedFill; // XOR the two together to combine. |
|
|
|
|
|
CombinedFill = CombinedFill ^ LightweightEntropyBuffer; // Pick up some previous state entropy. |
|
|
|
|
|
unsigned char* PrimerBuffer = (unsigned char*) &CombinedFill; // Treat the value as a bunch of bytes. |
|
|
|
|
|
unsigned char* EntropyBuffer = (unsigned char*) &LightweightEntropyBuffer; // Likewise with the entropy buffer. |
|
|
|
|
|
for(int i = 0; i < sizeof(msclock); i++) { // Fold bytes into the mangler one |
|
|
|
|
|
EntropyBuffer[i] += // byte at a time, capturing the |
|
|
|
|
|
PadGenerator.Encrypt( // the results and using one extra |
|
|
|
|
|
PadGenerator.Encrypt(PrimerBuffer[i])); // round per byte to increase the |
|
|
|
|
|
} // amount of guessing an attacker |
|
|
|
|
|
} // needs to do. |
|
|
|
|
|
|
|
|
|
|
|
void OneTimePad::addEntropy() { // Add strong entropy if available. |
|
|
|
|
|
PadBuffer Fill = Entropy(); // Grab the entropy bits to add. |
|
|
|
|
|
for(int i = 0; i < Fill.size(); i++) { // Pump them in one byte at a |
|
|
|
|
|
PadGenerator.Encrypt( // time and then run an extra |
|
|
|
|
|
PadGenerator.Encrypt(Fill.at(i))); // round per byte to increase the |
|
|
|
|
|
} // amount of guessing an attacker |
|
|
|
|
|
} // needs to do. |
|
|
|
|
|
|
|
|
|
|
|
void OneTimePad::addEntropy(PadBuffer Entropy) { // Add entropy from a given source. |
|
|
|
|
|
addLightweightEntropy(); // Start with some lightweight entropy. |
|
|
|
|
|
for(int i = 0; i < Entropy.size(); i++) { // Then loop through the provided |
|
|
|
|
|
PadGenerator.Encrypt( // entropy and mix it in with one |
|
|
|
|
|
PadGenerator.Encrypt(Entropy.at(i))); // extra round per byte to increase |
|
|
|
|
|
} // the amount of guessing an attacker |
|
|
|
|
|
} // needs to do. |
|
|
|
|
|
|
|
|
|
|
|
PadBuffer OneTimePad::Pad(int Length) { // Grab a pad of a specific length. |
|
|
|
|
|
addLightweightEntropy(); // Add some lightweight entropy. |
|
|
|
|
|
PadBuffer Output; Output.reserve(Length); // Create a buffer the right size. |
|
|
|
|
|
unsigned char x; // Starting with an uninitialized |
|
|
|
|
|
for(int i = 0; i < Length; i++) // char, fill the buffer with |
|
|
|
|
|
Output.push_back(x = PadGenerator.Encrypt(x)); // random bytes from the mangler. |
|
|
|
|
|
return Output; // Return the new pad. |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void* OneTimePad::fill(void* Object, int Size) { // Fill *Object with random bytes. |
|
|
|
|
|
PadBuffer FillData = Pad(Size); // Get a Pad of the correct size. |
|
|
|
|
|
unsigned char* Ptr = reinterpret_cast<unsigned char*>(Object); // Reinterpret the pointer type. |
|
|
|
|
|
for(int i = 0; i < Size; i++) Ptr[i] = FillData.at(i); // Fill the object with the Pad. |
|
|
|
|
|
return Object; // Return the object. |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool OneTimePad::isStrong() { return StrongEntropyFlag; } // Tell them if I'm strong! |
|
|
|
|
|
|
|
|
|
|
|
OneTimePad::OneTimePad() { // Initialize the one time pad. |
|
|
|
|
|
addLightweightEntropy(); // Add lightweight entropy. |
|
|
|
|
|
addEntropy(); // Add cryptographic entropy. |
|
|
|
|
|
unsigned char x; // Starting with an uninitialized |
|
|
|
|
|
for(int i = 0; i < 1024; i++) { // character, run 1024 rounds to |
|
|
|
|
|
x = PadGenerator.Encrypt(x); // reduce the predictability of the |
|
|
|
|
|
} // initial Mangler state. |
|
|
|
|
|
} // The OneTimePad object is ready. |
|
|
|
|
|
|