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.

Reply via email to