1/* 2 * Copyright (c) 1996, David Mazieres <dm@uun.org> 3 * Copyright (c) 2008, Damien Miller <djm@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 38namespace WTF { 39 40#if USE(OS_RANDOMNESS) 41 42namespace { 43 44class ARC4Stream { 45public: 46 ARC4Stream(); 47 48 uint8_t i; 49 uint8_t j; 50 uint8_t s[256]; 51}; 52 53class ARC4RandomNumberGenerator { 54public: 55 ARC4RandomNumberGenerator(); 56 57 uint32_t randomNumber(); 58 void randomValues(void* buffer, size_t length); 59 60private: 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 74ARC4Stream::ARC4Stream() 75{ 76 for (int n = 0; n < 256; n++) 77 s[n] = n; 78 i = 0; 79 j = 0; 80} 81 82ARC4RandomNumberGenerator::ARC4RandomNumberGenerator() 83 : m_count(0) 84{ 85} 86 87void 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 100void 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 114void ARC4RandomNumberGenerator::stirIfNeeded() 115{ 116 if (m_count <= 0) 117 stir(); 118} 119 120uint8_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 131uint32_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 141uint32_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 152void 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 167ARC4RandomNumberGenerator& sharedRandomNumberGenerator() 168{ 169 DEFINE_STATIC_LOCAL(ARC4RandomNumberGenerator, randomNumberGenerator, ()); 170 return randomNumberGenerator; 171} 172 173} 174 175uint32_t cryptographicallyRandomNumber() 176{ 177 return sharedRandomNumberGenerator().randomNumber(); 178} 179 180void cryptographicallyRandomValues(void* buffer, size_t length) 181{ 182 sharedRandomNumberGenerator().randomValues(buffer, length); 183} 184 185#endif 186 187} 188