diff options
-rw-r--r-- | BUILD.gn | 1 | ||||
-rw-r--r-- | core/fxcrt/fx_random.cpp | 101 | ||||
-rw-r--r-- | core/fxcrt/fx_random_unittest.cpp | 24 |
3 files changed, 71 insertions, 55 deletions
@@ -1932,6 +1932,7 @@ test("pdfium_unittests") { "core/fxcrt/fx_coordinates_unittest.cpp", "core/fxcrt/fx_extension_unittest.cpp", "core/fxcrt/fx_memory_unittest.cpp", + "core/fxcrt/fx_random_unittest.cpp", "core/fxcrt/fx_string_unittest.cpp", "core/fxcrt/fx_system_unittest.cpp", "core/fxge/dib/cstretchengine_unittest.cpp", diff --git a/core/fxcrt/fx_random.cpp b/core/fxcrt/fx_random.cpp index 866a7a97ef..483a56bbf4 100644 --- a/core/fxcrt/fx_random.cpp +++ b/core/fxcrt/fx_random.cpp @@ -19,86 +19,85 @@ #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ #include <wincrypt.h> #else // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ -#include <ctime> +#include <sys/time.h> +#include <unistd.h> #endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ namespace { struct MTContext { - MTContext() { - mti = MT_N + 1; - bHaveSeed = false; - } - uint32_t mti; - bool bHaveSeed; uint32_t mt[MT_N]; }; +bool g_bHaveGlobalSeed = false; +uint32_t g_nGlobalSeed = 0; + #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ -bool GenerateCryptoRandom(uint32_t* pBuffer, int32_t iCount) { +bool GenerateSeedFromCryptoRandom(uint32_t* pSeed) { HCRYPTPROV hCP = 0; if (!::CryptAcquireContext(&hCP, nullptr, nullptr, PROV_RSA_FULL, 0) || !hCP) { return false; } - ::CryptGenRandom(hCP, iCount * sizeof(uint32_t), - reinterpret_cast<uint8_t*>(pBuffer)); + ::CryptGenRandom(hCP, sizeof(uint32_t), reinterpret_cast<uint8_t*>(pSeed)); ::CryptReleaseContext(hCP, 0); return true; } #endif -void Random_GenerateBase(uint32_t* pBuffer, int32_t iCount) { +uint32_t GenerateSeedFromEnvironment() { + char c; + uintptr_t p = reinterpret_cast<uintptr_t>(&c); + uint32_t seed = ~static_cast<uint32_t>(p >> 3); #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ - SYSTEMTIME st1, st2; - ::GetSystemTime(&st1); - do { - ::GetSystemTime(&st2); - } while (memcmp(&st1, &st2, sizeof(SYSTEMTIME)) == 0); - uint32_t dwHash1 = - FX_HashCode_GetA(CFX_ByteStringC((uint8_t*)&st1, sizeof(st1)), true); - uint32_t dwHash2 = - FX_HashCode_GetA(CFX_ByteStringC((uint8_t*)&st2, sizeof(st2)), true); - ::srand((dwHash1 << 16) | (uint32_t)dwHash2); -#else - time_t tmLast = time(nullptr); - time_t tmCur; - while ((tmCur = time(nullptr)) == tmLast) - continue; - - ::srand((tmCur << 16) | (tmLast & 0xFFFF)); -#endif - while (iCount-- > 0) - *pBuffer++ = static_cast<uint32_t>((::rand() << 16) | (::rand() & 0xFFFF)); + SYSTEMTIME st; + GetSystemTime(&st); + seed ^= static_cast<uint32_t>(st.wSecond) * 1000000; + seed ^= static_cast<uint32_t>(st.wMilliseconds) * 1000; + seed ^= GetCurrentProcessId(); +#else // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + struct timeval tv; + gettimeofday(&tv, 0); + seed ^= static_cast<uint32_t>(tv.tv_sec) * 1000000; + seed ^= static_cast<uint32_t>(tv.tv_usec); + seed ^= static_cast<uint32_t>(getpid()); +#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + return seed; +} + +void* ContextFromNextGlobalSeed() { + if (!g_bHaveGlobalSeed) { +#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + if (!GenerateSeedFromCryptoRandom(&g_nGlobalSeed)) + g_nGlobalSeed = GenerateSeedFromEnvironment(); +#else // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + g_nGlobalSeed = GenerateSeedFromEnvironment(); +#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ + g_bHaveGlobalSeed = true; + } + return FX_Random_MT_Start(++g_nGlobalSeed); } } // namespace void* FX_Random_MT_Start(uint32_t dwSeed) { MTContext* pContext = FX_Alloc(MTContext, 1); - pContext->mt[0] = dwSeed; - uint32_t& i = pContext->mti; uint32_t* pBuf = pContext->mt; - for (i = 1; i < MT_N; i++) + pBuf[0] = dwSeed; + for (uint32_t i = 1; i < MT_N; i++) pBuf[i] = (1812433253UL * (pBuf[i - 1] ^ (pBuf[i - 1] >> 30)) + i); - pContext->bHaveSeed = true; + pContext->mti = MT_N; return pContext; } uint32_t FX_Random_MT_Generate(void* pContext) { - ASSERT(pContext); - MTContext* pMTC = static_cast<MTContext*>(pContext); - uint32_t v; - static uint32_t mag[2] = {0, MT_Matrix_A}; - uint32_t& mti = pMTC->mti; uint32_t* pBuf = pMTC->mt; - if ((int)mti < 0 || mti >= MT_N) { - if (mti > MT_N && !pMTC->bHaveSeed) - return 0; - + uint32_t v; + if (pMTC->mti >= MT_N) { + static const uint32_t mag[2] = {0, MT_Matrix_A}; uint32_t kk; for (kk = 0; kk < MT_N - MT_M; kk++) { v = (pBuf[kk] & MT_Upper_Mask) | (pBuf[kk + 1] & MT_Lower_Mask); @@ -110,9 +109,9 @@ uint32_t FX_Random_MT_Generate(void* pContext) { } v = (pBuf[MT_N - 1] & MT_Upper_Mask) | (pBuf[0] & MT_Lower_Mask); pBuf[MT_N - 1] = pBuf[MT_M - 1] ^ (v >> 1) ^ mag[v & 1]; - mti = 0; + pMTC->mti = 0; } - v = pBuf[mti++]; + v = pBuf[pMTC->mti++]; v ^= (v >> 11); v ^= (v << 7) & 0x9d2c5680UL; v ^= (v << 15) & 0xefc60000UL; @@ -121,19 +120,11 @@ uint32_t FX_Random_MT_Generate(void* pContext) { } void FX_Random_MT_Close(void* pContext) { - ASSERT(pContext); FX_Free(pContext); } void FX_Random_GenerateMT(uint32_t* pBuffer, int32_t iCount) { - uint32_t dwSeed; -#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ - if (!GenerateCryptoRandom(&dwSeed, 1)) - Random_GenerateBase(&dwSeed, 1); -#else - Random_GenerateBase(&dwSeed, 1); -#endif - void* pContext = FX_Random_MT_Start(dwSeed); + void* pContext = ContextFromNextGlobalSeed(); while (iCount-- > 0) *pBuffer++ = FX_Random_MT_Generate(pContext); diff --git a/core/fxcrt/fx_random_unittest.cpp b/core/fxcrt/fx_random_unittest.cpp new file mode 100644 index 0000000000..607f1409b7 --- /dev/null +++ b/core/fxcrt/fx_random_unittest.cpp @@ -0,0 +1,24 @@ +// Copyright 2017 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fxcrt/fx_random.h" + +#include <array> +#include <set> + +#include "testing/gtest/include/gtest/gtest.h" + +TEST(FX_Random, GenerateMT3600times) { + // Prove this doesn't spin wait for a second each time. + // Since our global seeds are sequential, they wont't collide once + // seeded until 2^32 calls, and if the PNRG is any good, we won't + // get the same sequence from different seeds, esp. with this few + // iterations. + std::set<std::array<uint32_t, 16>> seen; + std::array<uint32_t, 16> current; + for (int i = 0; i < 3600; ++i) { + FX_Random_GenerateMT(current.data(), 16); + EXPECT_TRUE(seen.insert(current).second); + } +} |