1 /**
2  * Interface to the OS CSPRNG.
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.sys.osrng;
15 
16 import std.conv : to;
17 
18 version (CRuntime_Bionic)
19 	version = SecureARC4Random; // ChaCha20
20 version (OSX)
21 	version = SecureARC4Random; // AES
22 version (OpenBSD)
23 	version = SecureARC4Random; // ChaCha20
24 version (NetBSD)
25 	version = SecureARC4Random; // ChaCha20
26 
27 // Not SecureARC4Random:
28 // CRuntime_UClibc (ARC4)
29 // FreeBSD (ARC4)
30 // DragonFlyBSD (ARC4)
31 
32 version (Windows)
33 {
34 	import ae.sys.windows;
35 
36 	import ae.sys.windows.imports;
37 	mixin(importWin32!q{wincrypt});
38 	mixin(importWin32!q{windef});
39 
40 	/// Fill `buf` with random data.
41 	void genRandom(ubyte[] buf)
42 	{
43 		HCRYPTPROV hCryptProv;
44 		wenforce(CryptAcquireContext(&hCryptProv, null, null, PROV_RSA_FULL, 0), "CryptAcquireContext");
45 		scope(exit) wenforce(CryptReleaseContext(hCryptProv, 0), "CryptReleaseContext");
46 		wenforce(CryptGenRandom(hCryptProv, buf.length.to!DWORD, buf.ptr), "CryptGenRandom");
47 	}
48 }
49 else
50 version (SecureARC4Random)
51 {
52 	extern(C) private @nogc nothrow
53 	{
54 		void arc4random_buf(scope void* buf, size_t nbytes) @system;
55 	}
56 
57 	/// Fill `buf` with random data.
58 	void genRandom(ubyte[] buf)
59 	{
60 		arc4random_buf(buf.ptr, buf.length);
61 	}
62 }
63 else
64 version (Posix)
65 {
66 	import std.stdio;
67 	import std.exception;
68 
69 	/// Fill `buf` with random data.
70 	void genRandom(ubyte[] buf)
71 	{
72 		auto f = File("/dev/urandom");
73 		auto result = f.rawRead(buf);
74 		enforce(result.length == buf.length, "Couldn't read enough random bytes");
75 	}
76 }