summaryrefslogtreecommitdiff
path: root/src/KM_prng.cpp
diff options
context:
space:
mode:
authorjhurst <jhurst@cinecert.com>2006-04-05 23:03:55 +0000
committerjhurst <>2006-04-05 23:03:55 +0000
commitbfedf725dac9d13f3a02fe69f45c302ab29d2b1e (patch)
tree4a746f759dcb62ebeb6309373e7579d6048f4af6 /src/KM_prng.cpp
parentfdf31e0105bf8272a6b7fa9c4039941dff37a271 (diff)
ginormo merge-back with Kumu, SMPTE MIC key and MPEG parser fix
Diffstat (limited to 'src/KM_prng.cpp')
-rwxr-xr-xsrc/KM_prng.cpp214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/KM_prng.cpp b/src/KM_prng.cpp
new file mode 100755
index 0000000..5e3dd48
--- /dev/null
+++ b/src/KM_prng.cpp
@@ -0,0 +1,214 @@
+/*
+Copyright (c) 2006, John Hurst
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+ /*! \file KM_prng.cpp
+ \version $Id$
+ \brief Fortuna pseudo-random number generator
+ */
+
+#include <KM_prng.h>
+#include <KM_log.h>
+#include <KM_mutex.h>
+#include <string.h>
+#include <assert.h>
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+
+using namespace Kumu;
+
+
+#ifdef KM_WIN32
+
+// make up a byte by sampling the perf counter LSB
+static byte_t get_perf_byte()
+{
+ LARGE_INTEGER ticks;
+ byte_t retval;
+
+ for ( int i = 0; i < 8; i++ )
+ {
+ QueryPerformanceCounter(&ticks);
+ retval |= (ticks.LowPart & 0x00000001) << i;
+ }
+
+ return retval;
+}
+
+#else // KM_WIN32
+
+#include <KM_fileio.h>
+const char* DEV_URANDOM = "/dev/urandom";
+
+#endif // KM_WIN32
+
+
+const ui32_t RNG_KEY_SIZE = 512UL;
+const ui32_t RNG_KEY_SIZE_BITS = 256UL;
+const ui32_t RNG_BLOCK_SIZE = 16UL;
+const ui32_t MAX_SEQUENCE_LEN = 0x00040000UL;
+
+
+// internal implementation class
+class h__RNG
+{
+ KM_NO_COPY_CONSTRUCT(h__RNG);
+
+public:
+ AES_KEY m_Context;
+ byte_t m_ctr_buf[RNG_BLOCK_SIZE];
+ Mutex m_Lock;
+
+ h__RNG()
+ {
+ memset(m_ctr_buf, 0, RNG_BLOCK_SIZE);
+ byte_t rng_key[RNG_KEY_SIZE];
+
+ { // this block scopes the following AutoMutex so that it will be
+ // released before the call to set_key() below.
+ AutoMutex Lock(m_Lock);
+
+#ifdef KM_WIN32
+ for ( ui32_t i = 0; i < RNG_KEY_SIZE; i++ )
+ rng_key[i] = get_perf_byte();
+
+#else // KM_WIN32
+ // on POSIX systems we simply read some seed from /dev/urandom
+ FileReader URandom;
+
+ Result_t result = URandom.OpenRead(DEV_URANDOM);
+
+ if ( KM_SUCCESS(result) )
+ {
+ ui32_t read_count;
+ result = URandom.Read(rng_key, RNG_KEY_SIZE, &read_count);
+ }
+
+ if ( KM_FAILURE(result) )
+ DefaultLogSink().Error("Error opening random device: %s\n", DEV_URANDOM);
+
+#endif // KM_WIN32
+ } // end AutoMutex context
+
+ set_key(rng_key);
+ }
+
+ //
+ void
+ set_key(const byte_t* key_fodder)
+ {
+ assert(key_fodder);
+ byte_t sha_buf[20];
+ SHA_CTX SHA;
+ SHA1_Init(&SHA);
+
+ SHA1_Update(&SHA, (byte_t*)&m_Context, sizeof(m_Context));
+ SHA1_Update(&SHA, key_fodder, RNG_KEY_SIZE);
+ SHA1_Final(sha_buf, &SHA);
+
+ AutoMutex Lock(m_Lock);
+ AES_set_encrypt_key(sha_buf, RNG_KEY_SIZE_BITS, &m_Context);
+ *(ui32_t*)(m_ctr_buf + 12) = 1;
+ }
+
+ //
+ void
+ fill_rand(byte_t* buf, ui32_t len)
+ {
+ assert(len <= MAX_SEQUENCE_LEN);
+ ui32_t gen_count = 0;
+ AutoMutex Lock(m_Lock);
+
+ while ( gen_count + RNG_BLOCK_SIZE <= len )
+ {
+ AES_encrypt(m_ctr_buf, buf + gen_count, &m_Context);
+ *(ui32_t*)(m_ctr_buf + 12) += 1;
+ gen_count += RNG_BLOCK_SIZE;
+ }
+
+ if ( len != gen_count ) // partial count needed?
+ {
+ byte_t tmp[RNG_BLOCK_SIZE];
+ AES_encrypt(m_ctr_buf, tmp, &m_Context);
+ *(ui32_t*)(m_ctr_buf + 12) += 1;
+ memcpy(buf, tmp, len - gen_count);
+ }
+ }
+};
+
+
+static h__RNG* s_RNG = 0;
+
+
+//------------------------------------------------------------------------------------------
+//
+// public interface
+
+Kumu::FortunaRNG::FortunaRNG()
+{
+ if ( s_RNG == 0 )
+ s_RNG = new h__RNG;
+}
+
+Kumu::FortunaRNG::~FortunaRNG() {}
+
+//
+const byte_t*
+Kumu::FortunaRNG::FillRandom(byte_t* buf, ui32_t len)
+{
+ assert(buf);
+ assert(s_RNG);
+
+ while ( len )
+ {
+ // 2^20 bytes max per seeding, use 2^19 to save
+ // room for generating reseed values
+ ui32_t gen_size = xmin(len, MAX_SEQUENCE_LEN);
+ s_RNG->fill_rand(buf, gen_size);
+ buf += gen_size;
+ len -= gen_size;
+
+ // re-seed the generator
+ byte_t rng_key[RNG_KEY_SIZE];
+ s_RNG->fill_rand(rng_key, RNG_KEY_SIZE);
+ s_RNG->set_key(rng_key);
+ }
+
+ return buf;
+}
+
+//
+const byte_t*
+Kumu::FortunaRNG::FillRandom(Kumu::ByteString& Buffer)
+{
+ FillRandom(Buffer.Data(), Buffer.Capacity());
+ Buffer.Length(Buffer.Capacity());
+ return Buffer.Data();
+}
+
+
+//
+// end KM_prng.cpp
+//