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