1 module tagion.crypto.random.random; 2 3 import std.format; 4 import std.system : os; 5 import std.traits; 6 import tagion.basic.Version; 7 8 static if (ver.iOS || ver.OSX || ver.BSD || ver.Android) { 9 enum is_getrandom = false; 10 extern (C) void arc4random_buf(void* buf, size_t buflen) nothrow; 11 } 12 else static if (ver.linux) { 13 enum is_getrandom = true; 14 extern (C) ptrdiff_t getrandom(void* buf, size_t buflen, uint flags) nothrow; 15 } 16 else { 17 static assert(0, format("Random function not support for %s", os)); 18 } 19 20 bool isGetRandomAvailable() nothrow { 21 import core.stdc.errno; 22 23 static if (is_getrandom) { 24 enum GRND_NONBLOCK = 0x0001; 25 const res = getrandom(null, 0, GRND_NONBLOCK); 26 if (res < 0) { 27 switch (errno) { 28 case ENOSYS: 29 case EPERM: 30 return false; 31 default: 32 return true; 33 } 34 } 35 else { 36 return true; 37 } 38 } 39 else { 40 return true; 41 } 42 } 43 44 unittest { 45 assert(isGetRandomAvailable, "hardware random function is not available in this environment"); 46 } 47 48 /++ 49 + getRandom - runs platform specific random function. 50 +/ 51 @trusted 52 void getRandom(ref scope ubyte[] buf) nothrow 53 in (buf.length <= 256) 54 do { 55 if (buf.length == 0) { 56 return; 57 } 58 static if (is_getrandom) { 59 enum sikkenogetskidt = "Problem with random generation"; 60 // GRND_NONBLOCK = 0x0001. Don't block and return EAGAIN instead 61 enum GRND_RANDOM = 0x0002; // No effect 62 // GRND_INSECURE = 0x0004. Return non-cryptographic random bytes 63 const size = getrandom(&buf[0], buf.length, GRND_RANDOM); 64 assert(size == buf.length, sikkenogetskidt); 65 } 66 else { 67 arc4random_buf(&buf[0], buf.length); 68 } 69 } 70 71 @trusted 72 T getRandom(T)() nothrow if (isBasicType!T) { 73 T result; 74 auto buf = (cast(ubyte*)&result)[0 .. T.sizeof]; 75 getRandom(buf); 76 return result; 77 78 }