The implementation of random_device in VS2010?
According to a comment left on this question by Hans Passant, random_device
uses advapi32:SystemFunction036
, which according to MSDN is an alias for RtlGenRandom
. This is verified by the runtime library source provided with VC++ 2010:
random_device::operator()()
in <random>
calls the following chain of functions:
_Random_device() // in xrngdev.cpp
rand_s() // in rand_s.c
RtlGenRandom()/SystemFunction036() // in advapi32.dll
According to a comment left by Michael Howard on one of his blog articles, "Cryptographically Secure Random number on Windows without using CryptoAPI", RtlGenRandom
uses the following:
The RNG generates as specified in FIPS 186-2 appendix 3.1 with SHA-1
as the G function. With entropy from:
The current process ID (GetCurrentProcessID).
The current thread ID (GetCurrentThreadID).
The ticks since boot (GetTickCount).
The current time (GetLocalTime).
Various high-precision performance counters (QueryPerformanceCounter).
An MD4 hash of the user's environment block, which includes username, computer name, and search path. MD4 is a hashing algorithm
that creates a 128-bit message digest from input data to verify data
integrity.High-precision internal CPU counters, such as RDTSC, RDMSR, RDPMC
Low-level system information: Idle Process Time, Io Read Transfer Count, I/O Write Transfer Count, I/O Other Transfer Count, I/O Read
Operation Count, I/O Write Operation Count, I/O Other Operation Count,
Available Pages, Committed Pages, Commit Limit, Peak Commitment, Page
Fault Count, Copy On Write Count, Transition Count, Cache Transition
Count, Demand Zero Count, Page Read Count, Page Read I/O Count, Cache
Read Count, Cache I/O Count, Dirty Pages Write Count, Dirty Write I/O
Count, Mapped Pages Write Count, Mapped Write I/O Count, Paged Pool
Pages, Non Paged Pool Pages, Paged Pool Allocated space, Paged Pool
Free space, Non Paged Pool Allocated space, Non Paged Pool Free space,
Free System page table entry, Resident System Code Page, Total System
Driver Pages, Total System Code Pages, Non Paged Pool Lookaside Hits,
Paged Pool Lookaside Hits, Available Paged Pool Pages, Resident System
Cache Page, Resident Paged Pool Page, Resident System Driver Page,
Cache manager Fast Read with No Wait, Cache manager Fast Read with
Wait, Cache manager Fast Read Resource Missed, Cache manager Fast Read
Not Possible, Cache manager Fast Memory Descriptor List Read with No
Wait, Cache manager Fast Memory Descriptor List Read with Wait, Cache
manager Fast Memory Descriptor List Read Resource Missed, Cache
manager Fast Memory Descriptor List Read Not Possible, Cache manager
Map Data with No Wait, Cache manager Map Data with Wait, Cache manager
Map Data with No Wait Miss, Cache manager Map Data Wait Miss, Cache
manager Pin-Mapped Data Count, Cache manager Pin-Read with No Wait,
Cache manager Pin Read with Wait, Cache manager Pin-Read with No Wait
Miss, Cache manager Pin-Read Wait Miss, Cache manager Copy-Read with
No Wait, Cache manager Copy-Read with Wait, Cache manager Copy-Read
with No Wait Miss, Cache manager Copy-Read with Wait Miss, Cache
manager Memory Descriptor List Read with No Wait, Cache manager Memory
Descriptor List Read with Wait, Cache manager Memory Descriptor List
Read with No Wait Miss, Cache manager Memory Descriptor List Read with
Wait Miss, Cache manager Read Ahead IOs, Cache manager Lazy-Write IOs,
Cache manager Lazy-Write Pages, Cache manager Data Flushes, Cache
manager Data Pages, Context Switches, First Level Translation buffer
Fills, Second Level Translation buffer Fills, and System Calls.System exception information consisting of Alignment Fix up Count, Exception Dispatch Count, Floating Emulation Count, and Byte Word
Emulation Count.System lookaside information consisting of Current Depth, Maximum Depth, Total Allocates, Allocate Misses, Total Frees, Free Misses,
Type, Tag, and Size.System interrupt information consisting of context switches, deferred procedure call count, deferred procedure call rate, time
increment, deferred procedure call bypass count, and asynchronous
procedure call bypass count.System process information consisting of Next Entry Offset, Number Of Threads, Create Time, User Time, Kernel Time, Image Name, Base
Priority, Unique Process ID, Inherited from Unique Process ID, Handle
Count, Session ID, Page Directory Base, Peak Virtual Size, Virtual
Size, Page Fault Count, Peak Working Set Size, Working Set Size, Quota
Peak Paged Pool Usage, Quota Paged Pool Usage, Quota Peak Non Paged
Pool Usage, Quota Non Paged Pool Usage, Page file Usage, Peak Page
file Usage, Private Page Count, Read Operation Count, Write Operation
Count, Other Operation Count, Read Transfer Count, Write Transfer
Count, and Other Transfer Count.
There's a full explanation (including diagrams) in Chapter 8 of Writing Secure Code, 2nd Edition.
How do I use boost::random_device to generate a cryptographically secure 64 bit integer?
Analyzing your question is harder than it might seem:
You seed the mersenne twister with rd()
, which returns an unsigned int
, and therefore (on most platforms) contains at most 32 random bits.
Everything that the mersenne twister does from this point on is determined by those 32 bits.
This means that the value
can only take on 2**32 different values, which can be a problem if any attack vector exists that attacks whatever you do with this number by brute force. In fact, the mersenne twister's seeding routine may even reduce the number of possible values for the first result, since it distributes the 32 random bits over its complete state (to ensure that this is not the case you would have to analyse the seed routine boost uses).
The primary weakness of the mersenne twister (its state can be derived after seeing 624 numbers) is not even of interest in this case however, since you generate a sequence that is so short (1 value).
Generating 64 cryptographically secure bits
Assuming that unsigned int
is equivalent to uint32_t
on your platform, you can easily generate 64 cryptographically secure random bits by using boost::random_device
:
boost::random_device rd;
std::uint64_t value = rd();
value = (value << 32) | rd();
This is fairly secure, since the implementations for both linux and windows use the operating system's own cryptographically secure randomness sources.
Generating cryptographically secure values with arbitrary distributions
While the previous works well enough, you may wish for a more flexible solution. This is easy to do by realizing that you can actually use the random distributions boost provides with random_device
as well. A simple example would be to rewrite the previous solution like this:
boost::random_device rd;
boost::random::uniform_int_distribution<std::uint64_t> dis;
std::uint64_t value = dis(rd);
(While this can in theory also provide a more robust solution if the previous one does not actually contain a number in [0, 2**32), this is not a problem in practice.)
Binding distribution to generator
To improve usability you will often find usage of boost::bind
to bind distribution and generator together. Since boost::bind
copies its arguments, and the copy ctor is deleted for boost::random_device
, you need to use a little trick:
boost::random_device rd;
boost::random::uniform_int_distribution<std::uint64_t> dis;
boost::function<std::uint64_t()> gen = boost::bind(dis, boost::ref(rd));
std::uint64_t value = gen();
Using engines for random number generation
Is there a recommended way of generating Random bytes and adding entropy in OpenSSL?
Yes. See the OpenSSL wiki on Random Numbers. It takes you through adding entropy for a seed, and extracting bytes for use in keying and other secret material.
Adding entropy for seeding is covered under Random Numbers and Seeds. Extracting bytes for use in keysing and other secret material is covered at Random Numbers and Generation.
Where can I get other Engine implementations, and how can I swap them in?
OpenSSL comes with a few engines related to random numbers. The default is a software based PRNG engine, md_rand
. You can find its source code at <openssl src>/crypto/rand/md_rand.c
. Another is Intel's RDRAND
engine. You can find the source at <openssl src>/crypto/engine/eng_rdrand.c
.
You can also use hardware based RNGs if you have the hardware. You can even write your own engine that provides a SHA-512 HMAC. Or even one that combines (XORs) an SHA-512 HMAC with with RDRAND
. The Mersenne Twister is popular, and you could even write an engine for it, too.
Here's how you swap in an engine to use for random numbers. Its taken from the OpenSSL wiki, and it swaps-in the Intel RDRAND
engine:
1 unsigned long err = 0;
2 int rc = 0;
3
4 OPENSSL_cpuid_setup();
5 ENGINE_load_rdrand();
6
7 ENGINE* eng = ENGINE_by_id("rdrand");
8 err = ERR_get_error();
9
10 if(NULL == eng) {
11 fprintf(stderr, "ENGINE_load_rdrand failed, err = 0x%lx\n", err);
12 abort(); /* failed */
13 }
14
15 rc = ENGINE_init(eng);
16 err = ERR_get_error();
17
18 if(0 == rc) {
19 fprintf(stderr, "ENGINE_init failed, err = 0x%lx\n", err);
20 abort(); /* failed */
21 }
22
23 rc = ENGINE_set_default(eng, ENGINE_METHOD_RAND);
24 err = ERR_get_error();
25
26 if(0 == rc) {
27 fprintf(stderr, "ENGINE_set_default failed, err = 0x%lx\n", err);
28 abort(); /* failed */
29 }
30
31 /* OK to proceed */
32
33 ...
34 ENGINE_finish(eng);
35 ENGINE_free(eng);
36 ENGINE_cleanup();
... I am trying to use the RAND_bytes API of OpenSSL ...
You never do anything other than use RAND_bytes
, RAND_add
and friends as normal. How you use RAND_bytes
, RAND_add
and friends never changes.
The Mersenne Twister is popular, and you could even write an engine for it, too...
If you do this, then you might consider posting the source code for others to use. I would suggest creating a page on OpenSSL's wiki, explain the Mersenne Twister engine, explain how to use it, and provide a patch for it.
The other choice is to submit it to the RT system (the bug tracker) as a feature/enhancement. But its been my observation that most things wither and die once they enter RT.
Initialization Vector Creation
Use a cryptography PRNG, just like you do for the key.
On windows use CryptGenRandom
/RtlGenRandom
and on Linux/Unix use /dev/urandom
. Those get seeded by the OS, so you don't need to take care of it.
If you really want to create your own PRNG, look into Fortuna. Don't use a Mersenne twister.
Why do I keep getting the same first digit while I've seeded a generator with time?
You are setting initial states into your random-generator that are very similar. Depending on the quality of the generator, this may or may not result in similar outputs. To illustrate, I've augmented your sample to (a) print only the first sequence, since that is what we care about, and (b) print several results of various resolution:
int main(){
auto t = time(0);
cout << "time: " << t << endl;
default_random_engine e(t);
default_random_engine e2(t);
default_random_engine e3(t);
default_random_engine e4(t);
uniform_int_distribution<int> uniform_dist(0, 9);
uniform_int_distribution<int> uniform_dist2(0,999);
uniform_int_distribution<int> uniform_dist3(0,99999);
uniform_int_distribution<int> uniform_dist4(0,9999999);
cout << "sequence: ";
cout << uniform_dist(e) << " " << uniform_dist2(e2) << " " << uniform_dist3(e3) << " " << uniform_dist4(e4);
cout << endl;
return 0;
}
When run:
$ ./a.out
time: 1541162210
sequence: 7 704 70457 7070079
$ ./a.out
time: 1541162211
sequence: 7 704 70457 7070157
$ ./a.out
time: 1541162212
sequence: 7 704 70458 7070236
$ ./a.out
time: 1541162213
sequence: 7 704 70459 7070315
$ ./a.out
time: 1541162214
sequence: 7 704 70460 7070393
$ ./a.out
time: 1541162215
sequence: 7 704 70461 7070472
$ ./a.out
time: 1541162216
sequence: 7 704 70461 7070550
$ ./a.out
time: 1541162217
sequence: 7 704 70462 7070629
$ ./a.out
time: 1541162218
sequence: 7 704 70463 7070707
$ ./a.out
time: 1541162219
sequence: 7 704 70464 7070786
While I do not know exactly what this random-generator implementation is doing, you can easily see that it is performing a very simple transformation of your seed into state, and state into output values. As other comments have suggested, there are better random generators and better seeds. Also note that the quality varies between implementations; Visual Studio 2017 does not exhibit this behavior.
Uniform random number generator in c++
You have to initialize the engine with a seed, otherwise the default seed is going to be used:
eng.seed(static_cast<unsigned int >(time(NULL)));
However, true randomness is something you cannot achieve on a deterministic machine without additional input. Every pseudo-random number generator is periodical in some way, which is something you wouldn't expect from a non-deterministic number. For example std::mt19937
has a period of 219937-1 iterations. True randomness is hard to achieve, as you would have to monitor something that doesn't seem deterministic (user input, atmospheric noise). See Jerry's and Handprint's answer.
If you don't want a time based seed you can use std::random_device
as seen in emsr's answer. You could even use std::random_device
as generator, which is the closest you'll get to true randomness with standard library methods only.
Related Topics
How to Return Array from C++ Function to Python Using Ctypes
Do Static Members of a Class Occupy Memory If No Object of That Class Is Created
C++: How to Get Fprintf Results as a Std::String W/O Sprintf
Lambda Capture and Parameter with Same Name - Who Shadows the Other? (Clang VS Gcc)
Is There Some Ninja Trick to Make a Variable Constant After Its Declaration
Weird Msc 8.0 Error: "The Value of Esp Was Not Properly Saved Across a Function Call..."
How to Use Const in Vectors to Allow Adding Elements, But Not Modifications to the Already Added
C++, Static VS. Namespace VS. Singleton
Deciphering C++ Template Error Messages
Lnk2019: Unresolved External Symbol _Main Referenced in Function _Tmaincrtstartup
Does an R Compiler to C/C++ Exist
Is Make_Shared Really More Efficient Than New