RFC: Improve std.random.unpredictableSeed#5230
Conversation
582727d to
d424605
Compare
That's what it's for. For Linux >= 3.17 Also you might be very interested in my related work at mir.random which also exposes a |
std/random.d
Outdated
| { | ||
| bool ret = CryptAcquireContext(&hProv, null, null, PROV_RSA_FULL, 0); | ||
| if (!ret) | ||
| throw new Exception("CryptAcquireContext"); |
There was a problem hiding this comment.
it's possible to recover from this:
if (GetLastError() == NTE_BAD_KEYSET)
{
// Attempt to create default container
if (!CryptAcquireContextA(&hProvider, null, null, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_SILENT))
return 1;
std/random.d
Outdated
| uint rand; | ||
| if (!initialized) | ||
| { | ||
| bool ret = CryptAcquireContext(&hProv, null, null, PROV_RSA_FULL, 0); |
There was a problem hiding this comment.
CryptAcquireContextW(&hProv, null, null, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))-> https://msdn.microsoft.com/en-us/library/windows/desktop/aa379942(v=vs.85).aspx
|
It took me a very long time (and many runs on AppVeyor) to figure out that the Wincrypt headers in druntime aren't correct for x64. Hence I highly recommend to have use the overrides I use in Mir - it's tested ;-) // the wincrypt headers in druntime are broken for x64!
private alias ULONG_PTR = size_t; // uint in druntime
private alias BOOL = bool;
private alias DWORD = size_t; // uint in druntime
private alias LPCWSTR = wchar*;
private alias PBYTE = ubyte*;
private alias HCRYPTPROV = ULONG_PTR;
private alias LPCSTR = const(char)*;
private extern(Windows) BOOL CryptGenRandom(HCRYPTPROV, DWORD, PBYTE) @nogc @safe nothrow;
private extern(Windows) BOOL CryptAcquireContextA(HCRYPTPROV*, LPCSTR, LPCSTR, DWORD, DWORD) @nogc nothrow;
private extern(Windows) BOOL CryptAcquireContextW(HCRYPTPROV*, LPCWSTR, LPCWSTR, DWORD, DWORD) @nogc nothrow;
private extern(Windows) BOOL CryptReleaseContext(HCRYPTPROV, ULONG_PTR) @nogc nothrow;
private __gshared ULONG_PTR hProvider; |
|
@wilzbach What's the correct way to detect Linux version in D? |
|
@wilzbach Maybe you should push changes to druntime? |
There's no "correct" way, but the system call -> Another friendly redirect to my work: https://github.com/libmir/mir-random/pull/13/files import core.sys.posix.sys.utsname : utsname;
// druntime's version isn't annotated with attributes
private extern(C) int uname(utsname* __name) @nogc nothrow;
private bool hasGetRandom() @nogc @trusted nothrow
{
import core.stdc.string : strtok;
import core.stdc.stdlib : atoi;
utsname uts;
uname(&uts);
char* p = uts.release.ptr;
// poor man's version check
auto token = strtok(p, ".");
int major = atoi(token);
if (major > 3)
return true;
if (major == 3)
{
token = strtok(p, ".");
if (atoi(token) >= 17)
return true;
}
return false;
}(this is done without the D standard library, s.t. it can be used in
I haven't used Windows for the last five years, so I don't know much about the Windows bindings in druntime. |
| else version(NetBSD) | ||
| { | ||
| version = ARC4_RANDOM; | ||
| } |
There was a problem hiding this comment.
macOS also has the arc4random function. Not sure what's best to use.
There was a problem hiding this comment.
In recent version of OpenBSD/NetBSD, arc4random is supported by ChaCha20. On macOS it's ARC4.
OTH macOS's /dev/random uses Yarrow, so I guess that's a better choice?
| return rand; | ||
| } | ||
| } | ||
| else |
There was a problem hiding this comment.
Do we even support any non-windows and non-posix OS's?
std/random.d
Outdated
| static bool seeded; | ||
| static MinstdRand0 rand; | ||
| if (!seeded) | ||
| version(Windows) |
There was a problem hiding this comment.
space between version and (
| @@ -1281,17 +1294,79 @@ A single unsigned integer seed value, different on each successive call | |||
| */ | |||
| @property uint unpredictableSeed() @trusted | |||
There was a problem hiding this comment.
this should be a template with trusted escapes so the attributes can be inferred
std/random.d
Outdated
|
|
||
| version(ARC4_RANDOM) | ||
| { | ||
| extern(C) uint arc4random(); |
6414960 to
2d2e2af
Compare
Implemented according to suggestions from Cédric Picard.
| { | ||
| version = ARC4_RANDOM; | ||
| } | ||
|
|
There was a problem hiding this comment.
I suggest also setting version = ARC4_RANDOM for version (FreeBSD) and version (OSX).
|
On my machine I profiled all of the implementations except the one using CryptGenRandom:
I think the last two have the wrong speed/unpredictability tradeoff for a non-cryptographic API. |
|
Going to close this in a week if @yshui doesn't respond. |
|
@JackStouffer I'm not sure where this pull request is going... |
Also, @wilzbach you seem to know about this area, any other comments on the implementation? |
OSX has arc4random with AES instead of ChaCha20. FreeBSD has an arc4random that still uses RC4 and has the problem that forked processes see the same sequences when the PID wraps. It shouldn't be used anywhere a cryptographically secure PRNG is required, but for non-cryptographic uses it would still be a significant improvement over the current |
|
Ping @yshui |
|
One general comment / question: reading the articles posted at the two given links in the original PR description, I come away with the understanding that what the article was advocating for was not to try to make In that context, this PR seems a little misplaced. What's the value of going through all of this trouble to use |
|
@quickfur I agree. I have the impression that this issue has already been solved when the disclaimer is add to the std.random document. I will close this PR. |
Implemented according to suggestions from Cédric Picard (see 1 2)
I only have linux machine to test with, so I opened this pull request to abuse the build bot.
Shoot if you spot any problems.