4

I need many cryptographically secure numbers, so I was thinking about extracting randomness from /dev/urandom and then "converting" it into (say) unsigned long long int. I guess it should be very efficient and it seems it is cryptographically secure, but I will investigate this aspect more in the future.
Now the question is: how can I do so?

I found this code:

char * block;
short size = 1;
ifstream urandom("/dev/urandom", ios::in|ios::binary);
urandom.read(block,size);
urandom.close();

Does it make sense? And how do I convert what I get to the type I desire?

EDIT - Using random interface of C++11

Following a suggestion from the comments, I tried using a uniform distribution over the integers and a random_device initialized as /dev/urandom. Here is the code:

std::uniform_int_distribution<unsigned int> dist(0, modulus-1);
std::random_device urandom("/dev/urandom");
for(unsigned int i = start ; i < end ; ++i)
{
    vector[i] = dist(urandom);
}

The problem is that this code is approximately 1000 times slower than before (I was using a xorshift128+ generator): 5 milliseconds vs. almost 5 seconds. Is this normal? Honestly, I thought that streaming bytes in from /dev/urandom and converting them to unsigned int would have been way faster... Am I missing something?

Community
  • 1
  • 1
minomic
  • 645
  • 1
  • 9
  • 22
  • If you really want secure numbers you shouldn't use `/dev/urandom`... – Simon Kraemer Mar 01 '16 at 15:10
  • @SimonKraemer I see your point but the common belief is that `/dev/urandom` is more than acceptably secure, at least based on the research I made on the internet. Anyway, I will investigate this point later. For the moment I would just like to make it work... – minomic Mar 01 '16 at 15:14
  • 1
    Any reason you don't trust the random number generators that are [already available](http://en.cppreference.com/w/cpp/numeric/random)? – Simon Kraemer Mar 01 '16 at 15:15
  • @SimonKraemer For example `Mersenne Twister` is known not to be cryptographically secure. As for the others, I admit I don't know – minomic Mar 01 '16 at 15:16
  • 3
    why not use the C++11 `random` interface? http://en.cppreference.com/w/cpp/numeric/random/random_device/random_device – manatttta Mar 01 '16 at 15:25
  • [Use a well-established library specifically for this?](https://www.openssl.org/docs/manmaster/crypto/rand.html) – BoBTFish Mar 01 '16 at 15:25
  • @manatttta I didn't know that using that interface is exactly the same thing as using `/dev/urandom`. Maybe because I always used it with a generator like `Mersenne Twister`... Anyway I will definitely take a look at it – minomic Mar 01 '16 at 15:27
  • I don't know if it's the same. I know you can force it to use /dev/urandom, if your system supports so – manatttta Mar 01 '16 at 15:38
  • @manatttta I edited the question. The problem is now the execution time, and actually I am quite surprised that the code is so slow... – minomic Mar 01 '16 at 15:46
  • @minomic You shouldn't mix question. One question per question. Also changing your question invalidates answers which might be confusing for others searching for a solution. – Simon Kraemer Mar 01 '16 at 16:07
  • Generating cryptographically secure random numbers takes some processing time. It's common to get one use /dev/urandom, or its equivalent, to seed a different generator. And, in C++11, `random_device` is meant to be the interface to /dev/urandom or its equivalent. – Max Lybbert Mar 01 '16 at 16:24
  • 1
    Do you have [`arc4random()`](http://arc4random.com) available? it will return a `uint32_t` and you can combine the results from two calls or for bytes: `arc4random_buf()`. – zaph Mar 01 '16 at 16:37
  • @zaph I will take a look at this too but it seems (from `man urandom`) that one of the problems of `random/urandom` is exactly speed. So I guess I can't expect to have a stream of random bytes as I wanted... – minomic Mar 02 '16 at 07:31
  • Try arc4random() it is different in that it is an encryption method that is continuously seeded from device events. – zaph yesterday – zaph Mar 03 '16 at 16:11

1 Answers1

10

So first of your example is incorrect and would cause undefined behaviour.

The char* block isn't pointing to any allocated data, so the ifstream::read would actually write into unallocated memory.

Apart from this the type of size is signed short while it should be size_t.

In order to read a unsigned long long int you could use `ifstream' like this:

#include <iostream>
#include <fstream>

int main()
{
    using namespace std;
    unsigned long long int random_value = 0; //Declare value to store data into
    size_t size = sizeof(random_value); //Declare size of data
    ifstream urandom("/dev/urandom", ios::in|ios::binary); //Open stream
    if(urandom) //Check if stream is open
    {
        urandom.read(reinterpret_cast<char*>(&random_value), size); //Read from urandom
        if(urandom) //Check if stream is ok, read succeeded
        {
            std::cout << "Read random value: " << random_value << std::endl;
        }
        else //Read failed
        {
            std::cerr << "Failed to read from /dev/urandom" << std::endl;
        }
        urandom.close(); //close stream
    }
    else //Open failed
    {
        std::cerr << "Failed to open /dev/urandom" << std::endl;
    }
    return 0;
}

The interesting part would be where this actually reads with urandom.read(reinterpret_cast<char*>(&random_value), size);

The size should be clear. By using sizeof we get the actual size in bytes of the data we want to store the random value into. This is useful as this value might be different on different architectures (e.g. 32-bit and 64-bit).
Be careful if the data type you pass here is a pointer. sizeof will only return the size of the pointer and not the size of the data it is pointing to.

random_value is of type unsigned long long int. So &random_value is the type of the appropriate pointer unsigned long long int*. But we want to read bytes (char) and therefore need to change/cast the value from unsigned long long int* to char* (reinterpret_cast<char*>(&random_value)).

Simon Kraemer
  • 5,700
  • 1
  • 19
  • 49