// PureNoise CryptoLib (c) 1997-2004, PureNoise Ltd Vaduz // Ruptor's Chaos (Six-In-One) Package Version 0.9 (strongly recommended over any HASH or PRNG or linear block chaining) in pure C #include "chaos.h" #define CHAOS_FIXED_WORDS 127 static unsigned long chaos_fixed[CHAOS_FIXED_WORDS] = { 0x7D318A62U, 0x9B5F40ECU, 0xC143D50AU, 0x27B698FDU, 0x4847ED02U, 0xA26F263BU, 0x54671E0EU, 0x446D4CA1U, 0x8530D752U, 0x96BF14EAU, 0x590C2A47U, 0x3FD8E6B1U }; // we only need at least 4 constants here initially to kick off the RNG, but more will do better static chaos_prng chaos_rng = {chaos_fixed, CHAOS_FIXED_WORDS, 0, 2, 1, -1}; /// block cipher encryption function for blocks of data of any size /// can be also used as a hash function with data being the constant-initialized hash and key being the input /// can be also used as a MAC function with data being the key-initialized hash and key being the keyed input /// the total number of rounds is max (3*data_words, 3*key_words, 17)|1 #ifndef __max #define __max(x,y) (((x)>=(y))?(x):(y)) #endif void chaos_block (unsigned long *data, const unsigned long data_words, const unsigned long *key, const unsigned long key_words) { unsigned long r = __max ((__max (data_words, key_words) * 3) | 1, 17), j = 0, k = 1; unsigned long x = (data_words-1) % data_words, y = 0, z = 1 % data_words; while (r--) { if (++x >= data_words) x -= data_words; if (++y >= data_words) y -= data_words; if (++z >= data_words) z -= data_words; if (++j >= key_words) { j -= key_words; k += 22; } data[y] = attach32 (data[x], data[y], data[z], _lrotl (lsf32 (key[j]), k)); // a cipher round, feed forward and feed back in one operation; non-linear block chaining } } /// block cipher decryption function void order_block (unsigned long *data, const unsigned long data_words, const unsigned long *key, const unsigned long key_words) { unsigned long r = __max ((__max (data_words, key_words) * 3) | 1, 17), j = r % key_words, k = 1 + 22 * (r / key_words); unsigned long x = ((data_words-1) + r) % data_words, y = r % data_words, z = (1 + r) % data_words; unsigned long kw; while (r--) { kw = lsf32 (key[j]); data[y] = detach32 (data[x], data[y], data[z], _lrotl (kw, k)); // a cipher round, feed forward and feed back in one operation; non-linear block chaining if (--x >= data_words) x += data_words; if (--y >= data_words) y += data_words; if (--z >= data_words) z += data_words; if (--j >= key_words) { j += key_words; k -= 22; } } } /// Stirring the entire internal state at least 3 times before starting static void pseudo_chaos_stir (chaos_prng *prng, const unsigned long *key, const unsigned long key_words) { unsigned long i; prng->X = 0, prng->Y = 2, prng->Z = 1; prng->K = 3; i = __max (prng->state_words, key_words) * 3 + chaos_rand32 (prng, key, key_words) % prng->state_words; while (i--) chaos_rand32 (prng, key, key_words); } /// Either a Random Number Generator with data being its internal entropy pool /// or a Stream Cipher with data being its key-generated internal state unsigned long chaos_rand32 (chaos_prng *prng, const unsigned long *key, const unsigned long key_words) { OCTET n; unsigned long x = prng->X, y = prng->Y, z = prng->Z; if (prng->state == chaos_fixed) { n.Q[0] = clock_counter (); // to use as PRNG set the key, otherwise entropy is used n.D[0] = attach32 (n.D[1], n.D[0], n.D[1], n.D[0]); if (chaos_rng.K == -1) { // this will be executed automatically only once; // any subsequent reseedings have to be done manually, preferably in a separate thread pseudo_chaos_init (prng, key, key_words, prng->state_words); // reseed, rehash, reseed, incremental } } else { if (chaos_rng.K == -1) { // this will be executed automatically only once; // any subsequent reseedings have to be done manually, preferably in a separate thread pseudo_chaos_init (prng, key, key_words, 0); // initializing the PRNG with a value derived from the key } if (++prng->K >= prng->state_words) prng->K %= prng->state_words; // replace "%" with "-" to improve speed if safe n.D[0] = prng->state[prng->K]; // using the internal state itself as the encryption key } if ((x += 3) >= prng->state_words) x %= prng->state_words; prng->X = x; // replace "%" with "-" to improve speed if safe if ((y += 5) >= prng->state_words) y %= prng->state_words; prng->Y = y; // replace "%" with "-" to improve speed if safe if ((z += 7) >= prng->state_words) z %= prng->state_words; prng->Z = z; // replace "%" with "-" to improve speed if safe prng->state[y] = attach32 (prng->state[x], prng->state[y], prng->state[z], n.D[0]); // both feed forward and feed back in one operation return prng->state[x] ^ prng->state[y] ^ prng->state[z] ^ n.D[0]; // I hope we are not leaking too much here ;) } /// a hassle-free 32-bit RNG function unsigned long rand32 (void) { return chaos_rand32 (&chaos_rng, chaos_fixed, CHAOS_FIXED_WORDS/2+1); } /// Stream Cipher (PRNG) Initialization (called automatically by rand32) void pseudo_chaos_init (chaos_prng *prng, const unsigned long *key, const unsigned long key_words, const unsigned long incremental) { unsigned long i = incremental, m = __max ((__max (prng->state_words, key_words) * 3) | 1, 17); unsigned long n[3] = { 0x524BC31DU, 0xF690A7EU, 0x8A257D41U }; for (; i < m; i++) { n[0] = attach32 (n[2], n[0], n[1], key[(i+0) % key_words]); n[1] = attach32 (n[0], n[1], n[2], key[(i+1) % key_words]); n[2] = attach32 (n[1], n[2], n[0], key[(i+2) % key_words]); if (i < prng->state_words) // initial { prng->state[i] = n[0] ^ n[1] ^ n[2]; } else // incremental { prng->state[i % prng->state_words] += n[0] ^ n[1] ^ n[2]; } } pseudo_chaos_stir (prng, key, key_words); // reseed chaos_block (prng->state, prng->state_words, key, key_words); // rehash pseudo_chaos_stir (prng, key, key_words); // reseed } void big_rand (unsigned long *x, const unsigned long n) { unsigned long t; // completely reseeding the generator with entropy and rehashing its entire internal state pseudo_chaos_init (&chaos_rng, chaos_fixed, CHAOS_FIXED_WORDS/2+1, CHAOS_FIXED_WORDS); // don't you love the +='s? ;) for (t = n; t; t--) x[t] += rand32(); x[0] = n; while (x[n] == 0) x[n] += rand32(); }