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