Seeding boost::mt19937 with bytes from CryptoGenRandom
I have a C++ program that uses /dev/urandom on Unix systems to seed
boost::mt19937. I'm porting the program to Windows. I can get good, random
seed data on Windows similar to random seed data produced from /dev/urandom
on Unix systems like so:
HCRYPTPROV hProvider = 0;
BYTE randomBytes[8];
CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
CryptGenRandom(hProvider, sizeof(randomBytes), randomBytes);
CryptReleaseContext(hProvider, 0);
However, I'm running into trouble attempting to pass these randomBytes to
boost::mt19937. On Unix I do something similar to this:
uint64_t GetSeed()
{
uint64_t seed;
std::ifstream urandom;
urandom.open("/dev/urandom");
urandom.read(reinterpret_cast
AMDG e m wrote:
I have a C++ program that uses /dev/urandom on Unix systems to seed boost::mt19937. I'm porting the program to Windows. I can get good, random seed data on Windows similar to random seed data produced from /dev/urandom on Unix systems like so:
HCRYPTPROV hProvider = 0; BYTE randomBytes[8]; CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); CryptGenRandom(hProvider, sizeof(randomBytes), randomBytes); CryptReleaseContext(hProvider, 0);
However, I'm running into trouble attempting to pass these randomBytes to boost::mt19937. On Unix I do something similar to this:
uint64_t GetSeed() { uint64_t seed; std::ifstream urandom; urandom.open("/dev/urandom"); urandom.read(reinterpret_cast
(&seed), sizeof(seed)); urandom.close(); return seed; } boost::mt19937 rng(GetSeed());
That works OK on Unix I think. Could anyone suggest how to get the random data from the Windows CryptoAPI passed to boost::mt19937 as seed data? I don't normally program Windows systems, so this has been a bit of a challenge for me.
Try uint64_t seed; memcpy(&seed, &randomBytes[0], sizeof(seed)); In Christ, Steven Watanabe
Steven,
at first this solution seemed to me pretty cool. As far as I understand seed
will contain some value from stack. The only question is how probable is it,
that seed is always initialized with a different value?
Thanks,
Ovanes
On Thu, Feb 11, 2010 at 5:58 AM, Steven Watanabe
AMDG
uint64_t seed; memcpy(&seed, &randomBytes[0], sizeof(seed));
AMDG Ovanes Markarian wrote:
On Thu, Feb 11, 2010 at 5:58 AM, Steven Watanabe
wrote: uint64_t seed; memcpy(&seed, &randomBytes[0], sizeof(seed));
at first this solution seemed to me pretty cool. As far as I understand seed will contain some value from stack. The only question is how probable is it, that seed is always initialized with a different value?
I was assuming that the code I wrote was prefixed with HCRYPTPROV hProvider = 0; BYTE randomBytes[8]; CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); CryptGenRandom(hProvider, sizeof(randomBytes), randomBytes); CryptReleaseContext(hProvider, 0); The memcpy should copy from randomBytes into seed. (Assuming I haven't forgotten the signature of memcpy.) In Christ, Steven Watanabe
The memcpy should copy from randomBytes into seed. (Assuming I haven't forgotten the signature of memcpy.)
Seems, like I forgot the signature... Another way to transfer the bytes would be: union bytes2seed { uint64_t seed_; char bytes_[sizeof(uint64_t)]; }; bytes2seed converter; Now one can pass &converter.bytes_[0] to CryptGenRandom. This does not require an additional memcpy call. Ovanes.
AMDG Ovanes Markarian wrote:
The memcpy should copy from randomBytes into seed. (Assuming I haven't forgotten the signature of memcpy.)
Seems, like I forgot the signature... Another way to transfer the bytes would be:
union bytes2seed { uint64_t seed_; char bytes_[sizeof(uint64_t)]; };
bytes2seed converter;
Now one can pass &converter.bytes_[0] to CryptGenRandom. This does not require an additional memcpy call.
Casting through a union is undefined behavior. :(. In Christ, Steven Watanabe
Steven, I know at least 2 books which describe this possibility and there is nothing stated about undefined behavior. I just double checked the ISO 2003 C++ Standards and did not find anything which disallows the presented approach. Can you point me to the paragraph in the Standard? Thanks, Ovanes
Seems, like I forgot the signature... Another way to transfer the bytes would be:
union bytes2seed { uint64_t seed_; char bytes_[sizeof(uint64_t)]; };
bytes2seed converter;
Now one can pass &converter.bytes_[0] to CryptGenRandom. This does not require an additional memcpy call.
Casting through a union is undefined behavior. :(.
AMDG Ovanes Markarian wrote:
I know at least 2 books which describe this possibility and there is nothing stated about undefined behavior.
Unfortunately this is a very common mistake even among those who ought to know better.
I just double checked the ISO 2003 C++ Standards and did not find anything which disallows the presented approach. Can you point me to the paragraph in the Standard?
The usual aliasing rules apply with only one exception (listed in 9.5): [Note: one special guarantee is made in order to simplify the use of unions: If a POD-union contains several POD-structs that share a common initial sequence (9.2), and if an object of this POD-union type contains one of the POD-structs, it is permitted to inspect the common initial sequence of any of POD-struct members; see 9.2. ] In Christ, Steven Watanabe
On Thu, Feb 11, 2010 at 7:39 PM, Steven Watanabe
The usual aliasing rules apply with only one exception (listed in 9.5):
[Note: one special guarantee is made in order to simplify the use of unions: If a POD-union contains several POD-structs that share a common initial sequence (9.2), and if an object of this POD-union type contains one of the POD-structs, it is permitted to inspect the common initial sequence of any of POD-struct members; see 9.2. ]
Yes I read the paragraph as well. But as far as I understand my use case is legal (assumed uint64_t is POD), which I think it is. Or am I mistaken? This is what 9.2 Clause 16 states (you have a snippet from 9.5 which just refers to that one): "If a POD-union contains two or more POD-structs that share a common initial sequence, and if the PODunion object currently contains one of these POD-structs, it is permitted to inspect the common initial part of any of them. Two POD-structs share a common initial sequence if corresponding members have layoutcompatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members." I understand that that it is allowed to use union for byte conversions of POD types. Regards, Ovanes
AMDG Ovanes Markarian wrote:
Yes I read the paragraph as well. But as far as I understand my use case is legal (assumed uint64_t is POD), which I think it is. Or am I mistaken?
It's legal for char or unsigned char to alias any type, so it would probably actually be okay in this specific case.
This is what 9.2 Clause 16 states (you have a snippet from 9.5 which just refers to that one): "If a POD-union contains two or more POD-structs that share a common initial sequence, and if the PODunion object currently contains one of these POD-structs, it is permitted to inspect the common initial part of any of them. Two POD-structs share a common initial sequence if corresponding members have layoutcompatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members."
I understand that that it is allowed to use union for byte conversions of POD types.
"Common initial sequence" means something like struct { int x; double y; }; struct { int x; float y; }; int x is common to the two structs. You can't use a union to convert between arbitrary PODs. In Christ, Steven Watanabe
Thank you Steven. While I do not have boost installed on this computer, the
code below compiles and runs as I would expect. Upon each execution, the
value of seed changes. I expect boost::mt19937 rng(seed); will work. And now
I have a very good random seed thanks to your advice.
Your friend,
Ed
#include <iostream>
#include
AMDG
e m wrote:
I have a C++ program that uses /dev/urandom on Unix systems to seed boost::mt19937. I'm porting the program to Windows. I can get good, random seed data on Windows similar to random seed data produced from /dev/urandom on Unix systems like so:
HCRYPTPROV hProvider = 0; BYTE randomBytes[8]; CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); CryptGenRandom(hProvider, sizeof(randomBytes), randomBytes); CryptReleaseContext(hProvider, 0);
However, I'm running into trouble attempting to pass these randomBytes to boost::mt19937. On Unix I do something similar to this:
uint64_t GetSeed() { uint64_t seed; std::ifstream urandom; urandom.open("/dev/urandom"); urandom.read(reinterpret_cast
(&seed), sizeof(seed)); urandom.close(); return seed; } boost::mt19937 rng(GetSeed());
That works OK on Unix I think. Could anyone suggest how to get the random data from the Windows CryptoAPI passed to boost::mt19937 as seed data? I don't normally program Windows systems, so this has been a bit of a challenge for me.
Try
uint64_t seed; memcpy(&seed, &randomBytes[0], sizeof(seed));
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (3)
-
e m
-
Ovanes Markarian
-
Steven Watanabe