Home | History | Annotate | Download | only in wtf
      1 /*
      2  * Copyright (c) 1996, David Mazieres <dm (at) uun.org>
      3  * Copyright (c) 2008, Damien Miller <djm (at) openbsd.org>
      4  *
      5  * Permission to use, copy, modify, and distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  */
     17 
     18 /*
     19  * Arc4 random number generator for OpenBSD.
     20  *
     21  * This code is derived from section 17.1 of Applied Cryptography,
     22  * second edition, which describes a stream cipher allegedly
     23  * compatible with RSA Labs "RC4" cipher (the actual description of
     24  * which is a trade secret).  The same algorithm is used as a stream
     25  * cipher called "arcfour" in Tatu Ylonen's ssh package.
     26  *
     27  * RC4 is a registered trademark of RSA Laboratories.
     28  */
     29 
     30 #include "config.h"
     31 #include "CryptographicallyRandomNumber.h"
     32 
     33 #include "StdLibExtras.h"
     34 #include "ThreadingPrimitives.h"
     35 
     36 namespace WTF {
     37 
     38 static RandomNumberSource sourceFunction;
     39 
     40 void setRandomSource(RandomNumberSource source)
     41 {
     42     sourceFunction = source;
     43 }
     44 
     45 namespace {
     46 
     47 class ARC4Stream {
     48 public:
     49     ARC4Stream();
     50 
     51     uint8_t i;
     52     uint8_t j;
     53     uint8_t s[256];
     54 };
     55 
     56 class ARC4RandomNumberGenerator {
     57     WTF_MAKE_FAST_ALLOCATED;
     58 public:
     59     ARC4RandomNumberGenerator();
     60 
     61     uint32_t randomNumber();
     62     void randomValues(void* buffer, size_t length);
     63 
     64 private:
     65     inline void addRandomData(unsigned char *data, int length);
     66     void stir();
     67     void stirIfNeeded();
     68     inline uint8_t getByte();
     69     inline uint32_t getWord();
     70 
     71     ARC4Stream m_stream;
     72     int m_count;
     73     Mutex m_mutex;
     74 };
     75 
     76 ARC4Stream::ARC4Stream()
     77 {
     78     for (int n = 0; n < 256; n++)
     79         s[n] = n;
     80     i = 0;
     81     j = 0;
     82 }
     83 
     84 ARC4RandomNumberGenerator::ARC4RandomNumberGenerator()
     85     : m_count(0)
     86 {
     87 }
     88 
     89 void ARC4RandomNumberGenerator::addRandomData(unsigned char* data, int length)
     90 {
     91     m_stream.i--;
     92     for (int n = 0; n < 256; n++) {
     93         m_stream.i++;
     94         uint8_t si = m_stream.s[m_stream.i];
     95         m_stream.j += si + data[n % length];
     96         m_stream.s[m_stream.i] = m_stream.s[m_stream.j];
     97         m_stream.s[m_stream.j] = si;
     98     }
     99     m_stream.j = m_stream.i;
    100 }
    101 
    102 void ARC4RandomNumberGenerator::stir()
    103 {
    104     unsigned char randomness[128];
    105     size_t length = sizeof(randomness);
    106     (*sourceFunction)(randomness, length);
    107     addRandomData(randomness, length);
    108 
    109     // Discard early keystream, as per recommendations in:
    110     // http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
    111     for (int i = 0; i < 256; i++)
    112         getByte();
    113     m_count = 1600000;
    114 }
    115 
    116 void ARC4RandomNumberGenerator::stirIfNeeded()
    117 {
    118     if (m_count <= 0)
    119         stir();
    120 }
    121 
    122 uint8_t ARC4RandomNumberGenerator::getByte()
    123 {
    124     m_stream.i++;
    125     uint8_t si = m_stream.s[m_stream.i];
    126     m_stream.j += si;
    127     uint8_t sj = m_stream.s[m_stream.j];
    128     m_stream.s[m_stream.i] = sj;
    129     m_stream.s[m_stream.j] = si;
    130     return (m_stream.s[(si + sj) & 0xff]);
    131 }
    132 
    133 uint32_t ARC4RandomNumberGenerator::getWord()
    134 {
    135     uint32_t val;
    136     val = getByte() << 24;
    137     val |= getByte() << 16;
    138     val |= getByte() << 8;
    139     val |= getByte();
    140     return val;
    141 }
    142 
    143 uint32_t ARC4RandomNumberGenerator::randomNumber()
    144 {
    145     MutexLocker locker(m_mutex);
    146 
    147     m_count -= 4;
    148     stirIfNeeded();
    149     return getWord();
    150 }
    151 
    152 void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length)
    153 {
    154     MutexLocker locker(m_mutex);
    155 
    156     unsigned char* result = reinterpret_cast<unsigned char*>(buffer);
    157     stirIfNeeded();
    158     while (length--) {
    159         m_count--;
    160         stirIfNeeded();
    161         result[length] = getByte();
    162     }
    163 }
    164 
    165 ARC4RandomNumberGenerator& sharedRandomNumberGenerator()
    166 {
    167     DEFINE_STATIC_LOCAL(ARC4RandomNumberGenerator, randomNumberGenerator, ());
    168     return randomNumberGenerator;
    169 }
    170 
    171 }
    172 
    173 
    174 uint32_t cryptographicallyRandomNumber()
    175 {
    176     return sharedRandomNumberGenerator().randomNumber();
    177 }
    178 
    179 void cryptographicallyRandomValues(void* buffer, size_t length)
    180 {
    181     sharedRandomNumberGenerator().randomValues(buffer, length);
    182 }
    183 
    184 }
    185