Does ARM (or whatever CPU the current iOS devices use) have an analog of RDRAND? If it does - it would be silly not to use it. If it doesn’t - I’m not aware of a comparably good randomness source short of a purpose-built hardware. On Mar 14, 2015, at 21:39 , Jeffrey Walton <[email protected]> wrote:
> > > On Saturday, March 14, 2015 at 10:36:28 AM UTC-4, Jean-Pierre Münch wrote: > Hey everyone, > > as you may or may not know I'm currently modernizing Crypto++ to some extent. > During some of my other research I noticed that the LibreSSL team decided to > drop their (OpenSSL's) PRNG. > They stated that it's not the job of the TLS library to provide users with > randomness but rather the OS's job. > > I disagree. > > Dropping PRNG code effectively violates sound security engineering > principals. There's a lot to security engineering, but one of the foundations > is: it must be easy to use correctly and hard to use incorrectly. Forcing > users to re-invent it means its *not* easy to use correctly. And allowing > each developer to "roll their own" makes its easy to use incorrectly. > > Also, if RTFM was going to work, then it would have happened in the last 50 > years or so. > > So here comes my question: > > How far do we trust the PRNGs of Windows (CryptGenRandom()) and UNIX > (/dev/random?)? > > This has already been studied and answered. See, for example: > > * Cryptanalysis of the Random Number Generator of the > Windows Operating System, https://eprint.iacr.org/2007/419.pdf. > > * Analysis of the Linux Random Number Generator, > https://eprint.iacr.org/2006/086.pdf. > > Is it necessary to find any source of potential entropy we can get or do we > just sit there and use the entropy the OS provides to us? > > OS entropy should be one input to the generator. You should add other entropy > if you have it available. > > For example, I have an entropy gatherer that collects entropy from sensors on > mobile devices (see the code below I am using for iOS and Crypto++). As > another example, if I am on a desktop with dev/urandom, > /proc/sys/kernel/random/boot_id, /proc/sys/kernel/random/uuid and RDRAND, > then I sample them and add to my generator's state (see the code below I am > using for Linux and OpenSSL). > > I actually avoid /dev/random because (1) I don't want to block, and (2) I > think /dev/random and /dev/urandom are mostly equivalent. From the network > attacker's perspective, they are equivalent. > > You also have /dev/hw_rand and virtio on virtual machines. If available, you > should sample them, too. > > Also see Peter Gutmann's comments at > http://lists.randombit.net/pipermail/cryptography/2013-July/004746.html. I > tend to agree with Gutmann: add any entropy you can get your hands on, even > the less than perfect ones. That's why I am happy to add the high resolution > time stamp, the pid, boot_id and uuid. > > Depending on your answers I'll adapt my Fortuna implementation (if we trust > in the OS, the OS will feed the pools, if not I have to do it). > > I think it depends on your threat model and security goals for Fortuna. > Either the built-in Crypto++ stuff meets your requirements, or they don't and > you have to address the gaps. > > Now the master question: DO we even CAN get GOOD entropy in USERLAND? (-> > Crypto++'s main usage) > > I believe so, as long as process isolation is working as expected. But it > depends on your threat model and security goals. > > Note: nearly all threat models I have seen related to PRNGs presume an > attacker cannot determine the generator's internal state (either view it or > predict it). This is usually fine for network based attackers and other > userland processes. Obviously, the underlying OS can see your generator's > state, so you can't defend against the OS or its compromise. > > Jeff > > ********** > > static CryptoPP::RandomPool& GetRandomPool() > { > static CryptoPP::RandomPool pool; > static dispatch_once_t once = 0; > > dispatch_once(&once, ^{ > CryptoPP::SecByteBlock seed(32); > CryptoPP::OS_GenerateRandomBlock(false, seed.data(), seed.size()); > pool.IncorporateEntropy(seed.data(), seed.size()); > }); > > // First, send in all the uninitialized data. Then: > // sesnors[0,1,2] uses accelerometer, if available > // sesnors[3,4,5] uses gyroscope, if available > // sesnors[6,7,8] uses magnetometer, if available > CryptoPP::SecBlock<double> sensors(3 * 3); > pool.IncorporateEntropy(sensors.BytePtr(), sensors.SizeInBytes()); > > // See Event Handling Guide for iOS, Event Motions > // > https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/motion_event_basics/motion_event_basics.html > CMMotionManager* mgr = [[CMMotionManager alloc] init]; > if(mgr == nil) { return pool; } > > // Start motion services > if([mgr isAccelerometerAvailable] != NO) > [mgr startAccelerometerUpdates]; > if([mgr isGyroAvailable] != NO) > [mgr startGyroUpdates]; > if([mgr isMagnetometerAvailable] != NO) > [mgr startMagnetometerUpdates]; > > // The components starts slowly... A pause less than about 0.150s > // will cause individual sensor data to return nil. > [NSThread sleepForTimeInterval:0.150f]; > > if([mgr isAccelerometerAvailable] != NO) { > CMAccelerometerData* accelData = [mgr accelerometerData]; > if(accelData) { > sensors[0] = [accelData acceleration].x; > sensors[1] = [accelData acceleration].y; > sensors[2] = [accelData acceleration].z; > } > [mgr stopAccelerometerUpdates]; > } > > if([mgr isGyroAvailable] != NO) { > CMGyroData* gyroData = [mgr gyroData]; > if(gyroData) { > sensors[3] = [gyroData rotationRate].x; > sensors[4] = [gyroData rotationRate].y; > sensors[5] = [gyroData rotationRate].z; > } > [mgr stopGyroUpdates]; > } > > if([mgr isMagnetometerAvailable] != NO) { > CMMagnetometerData* magnetData = [mgr magnetometerData]; > if(magnetData) { > sensors[6] = [magnetData magneticField].x; > sensors[7] = [magnetData magneticField].y; > sensors[8] = [magnetData magneticField].z; > } > [mgr stopMagnetometerUpdates]; > } > > pool.IncorporateEntropy(sensors.BytePtr(), sensors.SizeInBytes()); > > [mgr release], mgr = nil; > > #if !defined(NDEBUG) > NSLog(@"\n A: %f, %f, %f" \ > @"\n G: %f, %f, %f" \ > @"\n M: %f, %f, %f", > sensors[0], sensors[1], sensors[2], > sensors[3], sensors[4], sensors[5], > sensors[6], sensors[7], sensors[8] ); > #endif > > return pool; > } > > ********** > > int ReseedPrng() > { > int rc = 0; > unsigned long err = 0; > > AcConfig config; > ostringstream oss; > unsigned int seed = 0; > > byte buffer1[RAND_BUFFER_BYTES], buffer2[RAND_BUFFER_BYTES]; > string seedFile = config.GetPrngSeedFile(); > AC_ASSERT(!seedFile.empty()); > > /* Stash away some current bytes */ > rc = RAND_bytes(buffer1, (int) sizeof(buffer1)); > AC_ASSERT(rc == 1); > > rc = RAND_load_file(seedFile.c_str(), -1); > err = ERR_get_error(); > > AC_ASSERT(rc > 0); > if (!(rc > 0)) > { > rc = CreateSeedFile(); > AC_ASSERT(rc == 0); > if (rc != 0) > { > oss << "RAND_load_file failed for seed file, error "; > oss << err << ", " << std::hex << "0x" << err; > LogError(oss); > } > } > > if (rc > 0) > seed += rc; > > if (HasRDRAND()) > { > rc = RDRAND_bytes(buffer2, sizeof(buffer2)); > AC_ASSERT(rc == RAND_BUFFER_BYTES); > > if (!(rc == RAND_BUFFER_BYTES)) > { > oss << "RDRAND_bytes failed, requested " << sizeof(buffer2); > oss << " bytes, received " << rc << " bytes"; > LogError(oss); > } > > if (rc > 0) > seed += rc; > } > > /* Add previous random bytes with RDRAND bytes */ > RAND_seed(buffer1, (int) sizeof(buffer1)); > RAND_seed(buffer2, (int) sizeof(buffer2)); > > /* /dev/urandom */ > rc = RAND_load_file("/dev/urandom", RAND_BUFFER_BYTES); > AC_ASSERT(rc == RAND_BUFFER_BYTES); > > if (!(rc == RAND_BUFFER_BYTES)) > { > oss << "/dev/urandom failed, requested " << RAND_BUFFER_BYTES; > oss << " bytes, received " << rc << " bytes"; > LogError(oss); > } > > if (rc > 0) > seed += rc; > > /* High resolution time stamp */ > uint64_t tsc = rdtsc(); > RAND_seed(&tsc, (int) sizeof(tsc)); > seed += (int) sizeof(tsc); > > /* Process ID */ > pid_t pid = getpid(); > RAND_seed(&pid, (int) sizeof(pid)); > seed += (int) sizeof(pid); > > #if defined(__linux__) || defined(__linux) > /* Boot ID */ > rc = RAND_load_file("/proc/sys/kernel/random/boot_id", -1); > AC_ASSERT(rc > 0); > if (!(rc > 0)) > { > LogError("RAND_load_file failed for RANDOM_BOOT_ID"); > } > > if (rc > 0) > seed += rc; > #endif > > #if defined(__linux__) || defined(__linux) > /* UUID */ > rc = RAND_load_file("/proc/sys/kernel/random/uuid", -1); > AC_ASSERT(rc > 0); > if (!(rc > 0)) > { > LogError("RAND_load_file failed for RANDOM_UUID"); > } > > if (rc > 0) > seed += rc; > #endif > > /* Discard bytes for good measure */ > rc = RAND_bytes(buffer1, (int) sizeof(buffer1)); > AC_ASSERT(rc == 1); > > rc = RAND_bytes(buffer2, (int) sizeof(buffer2)); > AC_ASSERT(rc == 1); > > OPENSSL_cleanse(buffer1, sizeof(buffer1)); > OPENSSL_cleanse(buffer2, sizeof(buffer2)); > > oss << "seeded PRNG with " << seed << " bytes"; > LogRelevant(oss); > > return (seed >= (unsigned int) RAND_BUFFER_BYTES) ? 0 : 1; > } > > /* Shamelessly ripped from somewhere */ > static uint64_t rdtsc(void) > { > unsigned hi, lo; > __asm__ __volatile__ ( > "rdtsc" : "=a"(lo), "=d"(hi) > ); > > return ((((uint64_t) hi) << 32) | (uint64_t) lo); > } > > > -- > -- > You received this message because you are subscribed to the "Crypto++ Users" > Google Group. > To unsubscribe, send an email to [email protected]. > More information about Crypto++ and this group is available at > http://www.cryptopp.com. > --- > You received this message because you are subscribed to the Google Groups > "Crypto++ Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/d/optout. -- -- You received this message because you are subscribed to the "Crypto++ Users" Google Group. To unsubscribe, send an email to [email protected]. More information about Crypto++ and this group is available at http://www.cryptopp.com. --- You received this message because you are subscribed to the Google Groups "Crypto++ Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
