1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/boot/src/nsEntropyCollector.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,103 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "prlog.h" 1.10 +#include "nsEntropyCollector.h" 1.11 +#include "nsAlgorithm.h" 1.12 +#include <algorithm> 1.13 + 1.14 +nsEntropyCollector::nsEntropyCollector() 1.15 +:mBytesCollected(0), mWritePointer(mEntropyCache) 1.16 +{ 1.17 + // We could use the uninitialized memory in mEntropyCache as initial 1.18 + // random data, but that means (if any entropy is collected before NSS 1.19 + // initialization and then forwarded) that we'll get warnings from 1.20 + // tools like valgrind for every later operation that depends on the 1.21 + // entropy. 1.22 + memset(mEntropyCache, 0, sizeof(mEntropyCache)); 1.23 +} 1.24 + 1.25 +nsEntropyCollector::~nsEntropyCollector() 1.26 +{ 1.27 +} 1.28 + 1.29 +NS_IMPL_ISUPPORTS(nsEntropyCollector, 1.30 + nsIEntropyCollector, 1.31 + nsIBufEntropyCollector) 1.32 + 1.33 +NS_IMETHODIMP 1.34 +nsEntropyCollector::RandomUpdate(void *new_entropy, int32_t bufLen) 1.35 +{ 1.36 + if (bufLen > 0) { 1.37 + if (mForwardTarget) { 1.38 + return mForwardTarget->RandomUpdate(new_entropy, bufLen); 1.39 + } 1.40 + else { 1.41 + const unsigned char *InputPointer = (const unsigned char *)new_entropy; 1.42 + const unsigned char *PastEndPointer = mEntropyCache + entropy_buffer_size; 1.43 + 1.44 + // if the input is large, we only take as much as we can store 1.45 + int32_t bytes_wanted = std::min(bufLen, int32_t(entropy_buffer_size)); 1.46 + 1.47 + // remember the number of bytes we will have after storing new_entropy 1.48 + mBytesCollected = std::min(int32_t(entropy_buffer_size), 1.49 + mBytesCollected + bytes_wanted); 1.50 + 1.51 + // as the above statements limit bytes_wanted to the entropy_buffer_size, 1.52 + // this loop will iterate at most twice. 1.53 + while (bytes_wanted > 0) { 1.54 + 1.55 + // how many bytes to end of cyclic buffer? 1.56 + const int32_t space_to_end = PastEndPointer - mWritePointer; 1.57 + 1.58 + // how many bytes can we copy, not reaching the end of the buffer? 1.59 + const int32_t this_time = std::min(space_to_end, bytes_wanted); 1.60 + 1.61 + // copy at most to the end of the cyclic buffer 1.62 + for (int32_t i = 0; i < this_time; ++i) { 1.63 + 1.64 + unsigned int old = *mWritePointer; 1.65 + 1.66 + // combine new and old value already stored in buffer 1.67 + // this logic comes from PSM 1 1.68 + *mWritePointer++ = ((old << 1) | (old >> 7)) ^ *InputPointer++; 1.69 + } 1.70 + 1.71 + PR_ASSERT(mWritePointer <= PastEndPointer); 1.72 + PR_ASSERT(mWritePointer >= mEntropyCache); 1.73 + 1.74 + // have we arrived at the end of the buffer? 1.75 + if (PastEndPointer == mWritePointer) { 1.76 + // reset write pointer back to begining of our buffer 1.77 + mWritePointer = mEntropyCache; 1.78 + } 1.79 + 1.80 + // subtract the number of bytes we have already copied 1.81 + bytes_wanted -= this_time; 1.82 + } 1.83 + } 1.84 + } 1.85 + 1.86 + return NS_OK; 1.87 +} 1.88 + 1.89 +NS_IMETHODIMP 1.90 +nsEntropyCollector::ForwardTo(nsIEntropyCollector *aCollector) 1.91 +{ 1.92 + NS_PRECONDITION(!mForwardTarget, "|ForwardTo| should only be called once."); 1.93 + 1.94 + mForwardTarget = aCollector; 1.95 + mForwardTarget->RandomUpdate(mEntropyCache, mBytesCollected); 1.96 + mBytesCollected = 0; 1.97 + 1.98 + return NS_OK; 1.99 +} 1.100 + 1.101 +NS_IMETHODIMP 1.102 +nsEntropyCollector::DontForward() 1.103 +{ 1.104 + mForwardTarget = nullptr; 1.105 + return NS_OK; 1.106 +}