security/manager/boot/src/nsEntropyCollector.cpp

changeset 0
6474c204b198
     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 +}

mercurial