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