diff options
Diffstat (limited to 'Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp')
-rw-r--r-- | Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp b/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp new file mode 100644 index 0000000..4c49873 --- /dev/null +++ b/Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1996, David Mazieres <dm@uun.org> + * Copyright (c) 2008, Damien Miller <djm@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Arc4 random number generator for OpenBSD. + * + * This code is derived from section 17.1 of Applied Cryptography, + * second edition, which describes a stream cipher allegedly + * compatible with RSA Labs "RC4" cipher (the actual description of + * which is a trade secret). The same algorithm is used as a stream + * cipher called "arcfour" in Tatu Ylonen's ssh package. + * + * RC4 is a registered trademark of RSA Laboratories. + */ + +#include "config.h" +#include "CryptographicallyRandomNumber.h" + +#include "MainThread.h" +#include "OSRandomSource.h" +#include "StdLibExtras.h" +#include "ThreadingPrimitives.h" + +namespace WTF { + +#if USE(OS_RANDOMNESS) + +namespace { + +class ARC4Stream { +public: + ARC4Stream(); + + uint8_t i; + uint8_t j; + uint8_t s[256]; +}; + +class ARC4RandomNumberGenerator { +public: + ARC4RandomNumberGenerator(); + + uint32_t randomNumber(); + void randomValues(void* buffer, size_t length); + +private: + inline void addRandomData(unsigned char *data, int length); + void stir(); + void stirIfNeeded(); + inline uint8_t getByte(); + inline uint32_t getWord(); + + ARC4Stream m_stream; + int m_count; +#if ENABLE(JSC_MULTIPLE_THREADS) + Mutex m_mutex; +#endif +}; + +ARC4Stream::ARC4Stream() +{ + for (int n = 0; n < 256; n++) + s[n] = n; + i = 0; + j = 0; +} + +ARC4RandomNumberGenerator::ARC4RandomNumberGenerator() + : m_count(0) +{ +} + +void ARC4RandomNumberGenerator::addRandomData(unsigned char* data, int length) +{ + m_stream.i--; + for (int n = 0; n < 256; n++) { + m_stream.i++; + uint8_t si = m_stream.s[m_stream.i]; + m_stream.j += si + data[n % length]; + m_stream.s[m_stream.i] = m_stream.s[m_stream.j]; + m_stream.s[m_stream.j] = si; + } + m_stream.j = m_stream.i; +} + +void ARC4RandomNumberGenerator::stir() +{ + unsigned char randomness[128]; + size_t length = sizeof(randomness); + cryptographicallyRandomValuesFromOS(randomness, length); + addRandomData(randomness, length); + + // Discard early keystream, as per recommendations in: + // http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps + for (int i = 0; i < 256; i++) + getByte(); + m_count = 1600000; +} + +void ARC4RandomNumberGenerator::stirIfNeeded() +{ + if (m_count <= 0) + stir(); +} + +uint8_t ARC4RandomNumberGenerator::getByte() +{ + m_stream.i++; + uint8_t si = m_stream.s[m_stream.i]; + m_stream.j += si; + uint8_t sj = m_stream.s[m_stream.j]; + m_stream.s[m_stream.i] = sj; + m_stream.s[m_stream.j] = si; + return (m_stream.s[(si + sj) & 0xff]); +} + +uint32_t ARC4RandomNumberGenerator::getWord() +{ + uint32_t val; + val = getByte() << 24; + val |= getByte() << 16; + val |= getByte() << 8; + val |= getByte(); + return val; +} + +uint32_t ARC4RandomNumberGenerator::randomNumber() +{ +#if ENABLE(JSC_MULTIPLE_THREADS) + MutexLocker locker(m_mutex); +#else + ASSERT(isMainThread()); +#endif + + m_count -= 4; + stirIfNeeded(); + return getWord(); +} + +void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length) +{ +#if ENABLE(JSC_MULTIPLE_THREADS) + MutexLocker locker(m_mutex); +#else + ASSERT(isMainThread()); +#endif + + unsigned char* result = reinterpret_cast<unsigned char*>(buffer); + stirIfNeeded(); + while (length--) { + m_count--; + stirIfNeeded(); + result[length] = getByte(); + } +} + +ARC4RandomNumberGenerator& sharedRandomNumberGenerator() +{ + DEFINE_STATIC_LOCAL(ARC4RandomNumberGenerator, randomNumberGenerator, ()); + return randomNumberGenerator; +} + +} + +uint32_t cryptographicallyRandomNumber() +{ + return sharedRandomNumberGenerator().randomNumber(); +} + +void cryptographicallyRandomValues(void* buffer, size_t length) +{ + sharedRandomNumberGenerator().randomValues(buffer, length); +} + +#endif + +} |