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