diff -r 000000000000 -r 6474c204b198 security/manager/boot/src/nsEntropyCollector.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/security/manager/boot/src/nsEntropyCollector.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "prlog.h" +#include "nsEntropyCollector.h" +#include "nsAlgorithm.h" +#include + +nsEntropyCollector::nsEntropyCollector() +:mBytesCollected(0), mWritePointer(mEntropyCache) +{ + // We could use the uninitialized memory in mEntropyCache as initial + // random data, but that means (if any entropy is collected before NSS + // initialization and then forwarded) that we'll get warnings from + // tools like valgrind for every later operation that depends on the + // entropy. + memset(mEntropyCache, 0, sizeof(mEntropyCache)); +} + +nsEntropyCollector::~nsEntropyCollector() +{ +} + +NS_IMPL_ISUPPORTS(nsEntropyCollector, + nsIEntropyCollector, + nsIBufEntropyCollector) + +NS_IMETHODIMP +nsEntropyCollector::RandomUpdate(void *new_entropy, int32_t bufLen) +{ + if (bufLen > 0) { + if (mForwardTarget) { + return mForwardTarget->RandomUpdate(new_entropy, bufLen); + } + else { + const unsigned char *InputPointer = (const unsigned char *)new_entropy; + const unsigned char *PastEndPointer = mEntropyCache + entropy_buffer_size; + + // if the input is large, we only take as much as we can store + int32_t bytes_wanted = std::min(bufLen, int32_t(entropy_buffer_size)); + + // remember the number of bytes we will have after storing new_entropy + mBytesCollected = std::min(int32_t(entropy_buffer_size), + mBytesCollected + bytes_wanted); + + // as the above statements limit bytes_wanted to the entropy_buffer_size, + // this loop will iterate at most twice. + while (bytes_wanted > 0) { + + // how many bytes to end of cyclic buffer? + const int32_t space_to_end = PastEndPointer - mWritePointer; + + // how many bytes can we copy, not reaching the end of the buffer? + const int32_t this_time = std::min(space_to_end, bytes_wanted); + + // copy at most to the end of the cyclic buffer + for (int32_t i = 0; i < this_time; ++i) { + + unsigned int old = *mWritePointer; + + // combine new and old value already stored in buffer + // this logic comes from PSM 1 + *mWritePointer++ = ((old << 1) | (old >> 7)) ^ *InputPointer++; + } + + PR_ASSERT(mWritePointer <= PastEndPointer); + PR_ASSERT(mWritePointer >= mEntropyCache); + + // have we arrived at the end of the buffer? + if (PastEndPointer == mWritePointer) { + // reset write pointer back to begining of our buffer + mWritePointer = mEntropyCache; + } + + // subtract the number of bytes we have already copied + bytes_wanted -= this_time; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsEntropyCollector::ForwardTo(nsIEntropyCollector *aCollector) +{ + NS_PRECONDITION(!mForwardTarget, "|ForwardTo| should only be called once."); + + mForwardTarget = aCollector; + mForwardTarget->RandomUpdate(mEntropyCache, mBytesCollected); + mBytesCollected = 0; + + return NS_OK; +} + +NS_IMETHODIMP +nsEntropyCollector::DontForward() +{ + mForwardTarget = nullptr; + return NS_OK; +}