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 "wtf/CryptographicallyRandomNumber.h"
     32 
     33 #include "wtf/StdLibExtras.h"
     34 #include "wtf/Threading.h"
     35 #include "wtf/ThreadingPrimitives.h"
     36 
     37 namespace WTF {
     38 
     39 static RandomNumberSource sourceFunction;
     40 
     41 void setRandomSource(RandomNumberSource source)
     42 {
     43     sourceFunction = source;
     44 }
     45 
     46 namespace {
     47 
     48 class ARC4Stream {
     49 public:
     50     ARC4Stream();
     51 
     52     uint8_t i;
     53     uint8_t j;
     54     uint8_t s[256];
     55 };
     56 
     57 class ARC4RandomNumberGenerator {
     58     WTF_MAKE_FAST_ALLOCATED;
     59 public:
     60     ARC4RandomNumberGenerator();
     61 
     62     uint32_t randomNumber();
     63     void randomValues(void* buffer, size_t length);
     64 
     65 private:
     66     inline void addRandomData(unsigned char *data, int length);
     67     void stir();
     68     void stirIfNeeded();
     69     inline uint8_t getByte();
     70     inline uint32_t getWord();
     71 
     72     ARC4Stream m_stream;
     73     int m_count;
     74     Mutex m_mutex;
     75 };
     76 
     77 ARC4Stream::ARC4Stream()
     78 {
     79     for (int n = 0; n < 256; n++)
     80         s[n] = n;
     81     i = 0;
     82     j = 0;
     83 }
     84 
     85 ARC4RandomNumberGenerator::ARC4RandomNumberGenerator()
     86     : m_count(0)
     87 {
     88 }
     89 
     90 void ARC4RandomNumberGenerator::addRandomData(unsigned char* data, int length)
     91 {
     92     m_stream.i--;
     93     for (int n = 0; n < 256; n++) {
     94         m_stream.i++;
     95         uint8_t si = m_stream.s[m_stream.i];
     96         m_stream.j += si + data[n % length];
     97         m_stream.s[m_stream.i] = m_stream.s[m_stream.j];
     98         m_stream.s[m_stream.j] = si;
     99     }
    100     m_stream.j = m_stream.i;
    101 }
    102 
    103 void ARC4RandomNumberGenerator::stir()
    104 {
    105     unsigned char randomness[128];
    106     size_t length = sizeof(randomness);
    107     (*sourceFunction)(randomness, length);
    108     addRandomData(randomness, length);
    109 
    110     // Discard early keystream, as per recommendations in:
    111     // http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
    112     for (int i = 0; i < 256; i++)
    113         getByte();
    114     m_count = 1600000;
    115 }
    116 
    117 void ARC4RandomNumberGenerator::stirIfNeeded()
    118 {
    119     if (m_count <= 0)
    120         stir();
    121 }
    122 
    123 uint8_t ARC4RandomNumberGenerator::getByte()
    124 {
    125     m_stream.i++;
    126     uint8_t si = m_stream.s[m_stream.i];
    127     m_stream.j += si;
    128     uint8_t sj = m_stream.s[m_stream.j];
    129     m_stream.s[m_stream.i] = sj;
    130     m_stream.s[m_stream.j] = si;
    131     return (m_stream.s[(si + sj) & 0xff]);
    132 }
    133 
    134 uint32_t ARC4RandomNumberGenerator::getWord()
    135 {
    136     uint32_t val;
    137     val = getByte() << 24;
    138     val |= getByte() << 16;
    139     val |= getByte() << 8;
    140     val |= getByte();
    141     return val;
    142 }
    143 
    144 uint32_t ARC4RandomNumberGenerator::randomNumber()
    145 {
    146     MutexLocker locker(m_mutex);
    147 
    148     m_count -= 4;
    149     stirIfNeeded();
    150     return getWord();
    151 }
    152 
    153 void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length)
    154 {
    155     MutexLocker locker(m_mutex);
    156 
    157     unsigned char* result = reinterpret_cast<unsigned char*>(buffer);
    158     stirIfNeeded();
    159     while (length--) {
    160         m_count--;
    161         stirIfNeeded();
    162         result[length] = getByte();
    163     }
    164 }
    165 
    166 ARC4RandomNumberGenerator& sharedRandomNumberGenerator()
    167 {
    168     AtomicallyInitializedStatic(ARC4RandomNumberGenerator*, randomNumberGenerator = new ARC4RandomNumberGenerator);
    169     return *randomNumberGenerator;
    170 }
    171 
    172 }
    173 
    174 
    175 uint32_t cryptographicallyRandomNumber()
    176 {
    177     return sharedRandomNumberGenerator().randomNumber();
    178 }
    179 
    180 void cryptographicallyRandomValues(void* buffer, size_t length)
    181 {
    182     sharedRandomNumberGenerator().randomValues(buffer, length);
    183 }
    184 
    185 }
    186