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