X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/b04fe171f0375ecd5d8a24747ca1dff85720a0ca..6b200bc335dc93c5516ccb52f14bd896d8c7fad7:/securityd/src/entropy.cpp diff --git a/securityd/src/entropy.cpp b/securityd/src/entropy.cpp deleted file mode 100644 index 3e962e58..00000000 --- a/securityd/src/entropy.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2000-2004,2007-2008,2010,2012-2013 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -// -// EntropyManager - manage entropy on the system. -// -// Here is our mission: -// (1) On startup, read the entropy file and seed it into the RNG for initial use -// (2) Periodically, collect entropy from the system and seed it into the RNG -// (3) Once in a while, take entropy from the RNG and write it to the entropy file -// for use across reboots. -// -// This class will fail to operate if the process has (and retains) root privileges. -// We re-open the entropy file on each use so that we don't work with a "phantom" -// file that some fool administrator removed yesterday. -// -#include "entropy.h" -#include "dtrace.h" -#include -#include -#include -#include -#include -#include -#include -#include - -/* when true, action() called every 15 seconds */ -#define ENTROPY_QUICK_UPDATE 0 -#if ENTROPY_QUICK_UPDATE -#define COLLECT_INTERVAL 15 -#else -#define COLLECT_INTERVAL collectInterval -#endif //ENTROPY_QUICK_UPDATE - -using namespace UnixPlusPlus; - - -// -// During construction, we perform initial entropy file recovery. -// -EntropyManager::EntropyManager(MachPlusPlus::MachServer &srv, const char *entropyFile) - : DevRandomGenerator(true), server(srv), - mEntropyFilePath(entropyFile), mNextUpdate(Time::now()) -{ - // Read the entropy file and seed the RNG. It is not an error if we can't find one. - try { - AutoFileDesc oldEntropyFile(entropyFile, O_RDONLY); - char buffer[entropyFileSize]; - if (size_t size = oldEntropyFile.read(buffer)) - addEntropy(buffer, size); - } catch (...) { } - - // go through a collect/update/reschedule cycle immediately - action(); -} - - -// -// Timer action -// -void EntropyManager::action() -{ - collectEntropy(); - updateEntropyFile(); - - server.setTimer(this, Time::Interval(COLLECT_INTERVAL)); // drifting reschedule (desired) -} - - -static const double kBytesOfEntropyToCollect = 240; -// that gives us a minimum of 2.16 * 10^609 possible combinations. It's a finite number to be sure... - -static const int kExpectedLoops = 10; - -// Calculate the amount of entropy in the buffer (per Shannon's Entropy Calculation) -static double CalculateEntropy(const void* buffer, size_t bufferSize) -{ - double sizef = bufferSize; - const u_int8_t* charBuffer = (const u_int8_t*) buffer; - - // zero the tabulation array - int counts[256]; - memset(counts, 0, sizeof(counts)); - - // tabulate the occurances of each byte in the array - size_t i; - for (i = 0; i < bufferSize; ++i) - { - counts[charBuffer[i]] += 1; - } - - // calculate the number of bits/byte of entropy - double entropy = 0.0; - - for (i = 0; i < 256; ++i) - { - if (counts[i] > 0) - { - double p = ((double) counts[i]) / sizef; - double term = p * -log2(p); - entropy += term; - } - } - - double entropicBytes = bufferSize * entropy / 8.0; - - return entropicBytes; -} - - - -// -// Collect system timings and seed into the RNG. -// Note that the sysctl will block until the buffer is full or the timeout expires. -// We currently use a 1ms timeout, which almost always fills the buffer and -// does not provide enough of a delay to worry about it. If we ever get worried, -// we could call longTermActivity on the server object to get another thread going. -// - -void EntropyManager::collectEntropy() -{ - secinfo("SS", "Collecting entropy"); - - int mib[4]; - mib[0] = CTL_KERN; - mib[1] = KERN_KDEBUG; - mib[2] = KERN_KDGETENTROPY; - mib[3] = 1; // milliseconds maximum delay - - mach_timespec_t buffer[timingsToCollect]; - - int result; - - double bytesRemaining = kBytesOfEntropyToCollect; - - int loopCount = 0; - - while (bytesRemaining >= 0) - { - size_t size = sizeof(mach_timespec_t) * timingsToCollect; - - result = sysctl(mib,4, buffer, &size, NULL, 0); - if (result == -1) { - Syslog::alert("entropy measurement returned no entropy (errno=%d)", errno); - sleep(1); - } - else if (size == 0) - { - Syslog::alert("entropy measurement returned no entropy."); - sleep(1); - } - - // remove the non-entropic pieces from the buffer - u_int16_t nonEnt[timingsToCollect]; - - // treat the received buffer as an array of u_int16 and only take the first two bytes of each - u_int16_t *rawEnt = (u_int16_t*) buffer; - - int i; - for (i = 0; i < timingsToCollect; ++i) - { - nonEnt[i] = *rawEnt; - rawEnt += 4; - } - - addEntropy(nonEnt, sizeof(nonEnt)); - - double entropyRead = CalculateEntropy(nonEnt, sizeof(nonEnt)); - bytesRemaining -= entropyRead; - - loopCount += 1; - } - - if (loopCount > kExpectedLoops) - { - Syslog::alert("Entropy collection fulfillment took %d loops", loopCount); - } -} - - -// -// (Re)write the entropy file with random data pulled from the RNG -// -void EntropyManager::updateEntropyFile() -{ - if (Time::now() >= mNextUpdate) { - try { - mNextUpdate = Time::now() + Time::Interval(updateInterval); - secinfo("entropy", "updating %s", mEntropyFilePath.c_str()); - char buffer[entropyFileSize]; - random(buffer, entropyFileSize); - AutoFileDesc entropyFile(mEntropyFilePath.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0600); - if (entropyFile.write(buffer) != entropyFileSize) - Syslog::warning("short write on entropy file %s", mEntropyFilePath.c_str()); - } catch (...) { - Syslog::warning("error writing entropy file %s", mEntropyFilePath.c_str()); - } - } -} -