X-Git-Url: https://git.saurik.com/apple/securityd.git/blobdiff_plain/569135f537d6bd5118fa29c2fb4b6d4d436e066e..4cd1cad0dea00daa03e1b54fdf2797a02373ad5b:/src/entropy.cpp diff --git a/src/entropy.cpp b/src/entropy.cpp index 3f961b2..c936d8f 100644 --- a/src/entropy.cpp +++ b/src/entropy.cpp @@ -39,10 +39,12 @@ #include "dtrace.h" #include #include +#include #include #include #include #include +#include /* when true, action() called every 15 seconds */ #define ENTROPY_QUICK_UPDATE 0 @@ -87,6 +89,48 @@ void EntropyManager::action() } +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. @@ -94,36 +138,66 @@ void EntropyManager::action() // 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() { SECURITYD_ENTROPY_COLLECT(); + int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_KDEBUG; mib[2] = KERN_KDGETENTROPY; mib[3] = 1; // milliseconds maximum delay - mach_timespec_t timings[timingsToCollect]; - size_t size = sizeof(timings); - if (sysctl(mib, 4, timings, &size, NULL, 0)) { - Syslog::alert("entropy collection failed (errno=%d)", errno); - return; + + 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; + } + + SECURITYD_ENTROPY_SEED((void *)nonEnt, (unsigned int) sizeof(nonEnt)); + 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); } - size /= sizeof(mach_timespec_t); // convert to element count - if (size > timingsToCollect) - size = timingsToCollect; // pure paranoia - char buffer[timingsToCollect]; - size /= sizeof(mach_timespec_t); // convert to element count - if (size > timingsToCollect) - size = timingsToCollect; // pure paranoia - for (unsigned n = 0; n < size; n++) - buffer[n] = timings[n].tv_nsec; // truncating to LSB - secdebug("entropy", "Entropy size %d: %02x %02x %02x %02x %02x %02x %02x %02x...", - (int)size, - (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2], - (unsigned char)buffer[3], (unsigned char)buffer[4], (unsigned char)buffer[5], - (unsigned char)buffer[6], (unsigned char)buffer[7]); - SECURITYD_ENTROPY_SEED((void *)buffer, size); - addEntropy(buffer, size); }