You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

onetimepad.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // onetimepad.cpp
  2. //
  3. // Copyright (C) 2006-2020 MicroNeil Research Corporation.
  4. //
  5. // This software is released under the MIT license. See LICENSE.TXT.
  6. #include "onetimepad.hpp"
  7. #include "timing.hpp"
  8. /*
  9. class OneTimePad { // One Time Pad generator.
  10. private:
  11. MANGLER PagGenerator; // MANGLER as a PRNG.
  12. PadBuffer Entropy(int Length = 1024); // System entropy source.
  13. public:
  14. ** OneTimePad(); // Constructor initializes w/ Entropy.
  15. ** PadBuffer Pad(int Length); // Get a pad of Length.
  16. ** void addEntropy(); // Add entropy from the system source.
  17. ** void addEntropy(PadBuffer Entropy); // Add entropy from this source.
  18. };
  19. */
  20. ////////////////////////////////////////////////////////////////////////////////
  21. // Platform specific strong entropy sourcing.
  22. #ifdef WIN32
  23. //// WIN32 Strong Entropy Source == CryptGenRandom() ///////////////////////////
  24. #include <windows.h>
  25. #include <wincrypt.h>
  26. namespace codedweller {
  27. PadBuffer OneTimePad::Entropy(int Length) { // Get a PadBuffer full of randomness.
  28. PadBuffer Buffer(Length, 0); // Start by initializing the buffer.
  29. HCRYPTPROV provider = 0; // We will need a handle for the source.
  30. if( // Try a two different sources.
  31. !CryptAcquireContext( // If we can get a hardware source
  32. &provider, NULL, NULL, PROV_INTEL_SEC, CRYPT_VERIFYCONTEXT)) { // from an intel CPU then use that first.
  33. if( // If we can't use get that
  34. !CryptAcquireContext( // entropy source for some reason then
  35. &provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { // try to use the RSA source. That should
  36. // always work, but if it doesn't we need
  37. provider = 0; // to know about it so we'll have a zero
  38. } // handle.
  39. }
  40. if(0 != provider) { // If we did get a good source then
  41. CryptGenRandom (provider, Length, (BYTE*)&Buffer[0]); // grab the random bit required and
  42. CryptReleaseContext(provider,0); // then let the provider go.
  43. StrongEntropyFlag = true; // We DID get strong entropy.
  44. }
  45. else { // If we did not get a good source
  46. StrongEntropyFlag = false; // then we are not strong.
  47. }
  48. return Buffer; // Return the data we got.
  49. }
  50. } // End namespace codddweller
  51. #else
  52. //// *NIX Strong Entropy Source == /dev/urandom ////////////////////////////////
  53. #include <fstream>
  54. namespace codedweller {
  55. PadBuffer OneTimePad::Entropy(int Length) { // Get Length bytes of strong entropy.
  56. PadBuffer Buffer(Length, 0); // Initialize a buffer to hold them.
  57. try { // Handle this in a try block.
  58. std::ifstream Source("/dev/urandom", std::ios::binary); // Open /dev/urandom if possible.
  59. Source.read(reinterpret_cast<char*>(&Buffer[0]), Length); // Read data into the buffer.
  60. if(!Source.bad() && Source.gcount() == Length) { // If we got what we came for then
  61. StrongEntropyFlag = true; // we have strong cryptography.
  62. } else { // If we didn't then we are not
  63. StrongEntropyFlag = false; // strong, and don't have things
  64. } // to make us go.
  65. Source.close(); // We're done, so close the stream.
  66. }
  67. catch(...) { // If we had an exception then we
  68. StrongEntropyFlag = false; // did not get strong entropy.
  69. }
  70. return Buffer; // Return the buffer.
  71. }
  72. } // End namespace codedweller
  73. #endif
  74. // End Platform Specific Bits
  75. ////////////////////////////////////////////////////////////////////////////////
  76. namespace codedweller {
  77. // Lightweight entropy is built from a combination of the time in ms UTC that
  78. // the application was started, the number of milliseconds since that time in
  79. // milliseconds, the number and times of calls to addLightweightEntropy(), and
  80. // the state of the MANGLER engine at each call -- that state is effected by
  81. // the combined previous use of the MANGLER and any other entropy that was
  82. // added including the timing of those events (since they all trigger the
  83. // addLightweightEntropy() function.
  84. Timer OneTimePadRunTimer; // Millisecond entropy source.
  85. msclock LightweightEntropyBuffer; // Lightweight entropy bucket.
  86. void OneTimePad::addLightweightEntropy() { // Add entropy based on the
  87. msclock StartFill = OneTimePadRunTimer.getStartClock(); // initial start time of the app
  88. msclock ElapsedFill = OneTimePadRunTimer.getElapsedTime(); // and the number of millisecs since.
  89. msclock CombinedFill = StartFill ^ ElapsedFill; // XOR the two together to combine.
  90. CombinedFill = CombinedFill ^ LightweightEntropyBuffer; // Pick up some previous state entropy.
  91. unsigned char* PrimerBuffer = (unsigned char*) &CombinedFill; // Treat the value as a bunch of bytes.
  92. unsigned char* EntropyBuffer = (unsigned char*) &LightweightEntropyBuffer; // Likewise with the entropy buffer.
  93. for(size_t i = 0; i < sizeof(msclock); i++) { // Fold bytes into the mangler one
  94. EntropyBuffer[i] += // byte at a time, capturing the
  95. PadGenerator.Encrypt( // the results and using one extra
  96. PadGenerator.Encrypt(PrimerBuffer[i])); // round per byte to increase the
  97. } // amount of guessing an attacker
  98. } // needs to do.
  99. void OneTimePad::addEntropy() { // Add strong entropy if available.
  100. PadBuffer Fill = Entropy(); // Grab the entropy bits to add.
  101. for(size_t i = 0; i < Fill.size(); i++) { // Pump them in one byte at a
  102. PadGenerator.Encrypt( // time and then run an extra
  103. PadGenerator.Encrypt(Fill.at(i))); // round per byte to increase the
  104. } // amount of guessing an attacker
  105. } // needs to do.
  106. void OneTimePad::addEntropy(PadBuffer Entropy) { // Add entropy from a given source.
  107. addLightweightEntropy(); // Start with some lightweight entropy.
  108. for(size_t i = 0; i < Entropy.size(); i++) { // Then loop through the provided
  109. PadGenerator.Encrypt( // entropy and mix it in with one
  110. PadGenerator.Encrypt(Entropy.at(i))); // extra round per byte to increase
  111. } // the amount of guessing an attacker
  112. } // needs to do.
  113. PadBuffer OneTimePad::Pad(int Length) { // Grab a pad of a specific length.
  114. addLightweightEntropy(); // Add some lightweight entropy.
  115. PadBuffer Output; Output.reserve(Length); // Create a buffer the right size.
  116. unsigned char x; // Starting with an uninitialized
  117. for(int i = 0; i < Length; i++) // char, fill the buffer with
  118. Output.push_back(x = PadGenerator.Encrypt(x)); // random bytes from the mangler.
  119. return Output; // Return the new pad.
  120. }
  121. void* OneTimePad::fill(void* Object, int Size) { // Fill *Object with random bytes.
  122. PadBuffer FillData = Pad(Size); // Get a Pad of the correct size.
  123. unsigned char* Ptr = reinterpret_cast<unsigned char*>(Object); // Reinterpret the pointer type.
  124. for(int i = 0; i < Size; i++) Ptr[i] = FillData.at(i); // Fill the object with the Pad.
  125. return Object; // Return the object.
  126. }
  127. bool OneTimePad::isStrong() { return StrongEntropyFlag; } // Tell them if I'm strong!
  128. OneTimePad::OneTimePad() { // Initialize the one time pad.
  129. addLightweightEntropy(); // Add lightweight entropy.
  130. addEntropy(); // Add cryptographic entropy.
  131. unsigned char x; // Starting with an uninitialized
  132. for(int i = 0; i < 1024; i++) { // character, run 1024 rounds to
  133. x = PadGenerator.Encrypt(x); // reduce the predictability of the
  134. } // initial Mangler state.
  135. } // The OneTimePad object is ready.
  136. } // End namespace codedweller