123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- module secured.random;
- import secured.util;
- version(CRuntime_Bionic)
- version = SecureARC4Random;//ChaCha20
- else version(OSX)
- version = SecureARC4Random;//AES
- else version(OpenBSD)
- version = SecureARC4Random;//ChaCha20
- else version(NetBSD)
- version = SecureARC4Random;//ChaCha20
- // Can uncomment following two lines if Solaris versions prior to 11.3 are unsupported:
- //else version (Solaris)
- // version = SecureARC4Random;
- version(SecureARC4Random)
- extern(C) @nogc nothrow private @system
- {
- void arc4random_buf(scope void* buf, size_t nbytes);
- }
- @trusted public ubyte[] random(uint bytes)
- {
- if (bytes == 0) {
- throw new CryptographicException("The number of requested bytes must be greater than zero.");
- }
- ubyte[] buffer = new ubyte[bytes];
- version(SecureARC4Random)
- {
- arc4random_buf(buffer.ptr, bytes);
- }
- else version(Posix)
- {
- import std.exception;
- import std.format;
- import std.stdio;
- try {
- //Initialize the system random file buffer
- File urandom = File("/dev/urandom", "rb");
- urandom.setvbuf(null, _IONBF);
- scope(exit) urandom.close();
- //Read into the buffer
- try {
- buffer = urandom.rawRead(buffer);
- }
- catch(ErrnoException ex) {
- throw new CryptographicException(format("Cannot get the next random bytes. Error ID: %d, Message: %s", ex.errno, ex.msg));
- }
- catch(Exception ex) {
- throw new CryptographicException(format("Cannot get the next random bytes. Message: %s", ex.msg));
- }
- }
- catch(ErrnoException ex) {
- throw new CryptographicException(format("Cannot initialize the system RNG. Error ID: %d, Message: %s", ex.errno, ex.msg));
- }
- catch(Exception ex) {
- throw new CryptographicException(format("Cannot initialize the system RNG. Message: %s", ex.msg));
- }
- }
- else version(Windows)
- {
- import core.sys.windows.windows;
- import core.sys.windows.wincrypt;
- import std.format;
-
- HCRYPTPROV hCryptProv;
- //Get the cryptographic context from Windows
- if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
- throw new CryptographicException("Unable to acquire Cryptographic Context.");
- }
- //Release the context when finished
- scope(exit) CryptReleaseContext(hCryptProv, 0);
- //Generate the random bytes
- if (!CryptGenRandom(hCryptProv, cast(DWORD)buffer.length, buffer.ptr)) {
- throw new CryptographicException(format("Cannot get the next random bytes. Error ID: %d", GetLastError()));
- }
- }
- else
- {
- static assert(0, "SecureD does not support this OS.");
- }
- return buffer;
- }
- unittest
- {
- import std.digest;
- import std.stdio;
- writeln("Testing Random Number Generator with 32/64/512/2048 bytes:");
- //Test 32 bytes
- ubyte[] rnd1 = random(32);
- writeln("32 Bytes:");
- writeln(toHexString!(LetterCase.lower)(rnd1));
- assert(rnd1.length == 32);
- //Test 128 bytes
- ubyte[] rnd2 = random(128);
- writeln("128 Bytes:");
- writeln(toHexString!(LetterCase.lower)(rnd2));
- assert(rnd2.length == 128);
- //Test 512 bytes
- ubyte[] rnd3 = random(512);
- writeln("512 Bytes:");
- writeln(toHexString!(LetterCase.lower)(rnd3));
- assert(rnd3.length == 512);
- //Test 2048 bytes
- ubyte[] rnd4 = random(2048);
- writeln("2048 Bytes:");
- writeln(toHexString!(LetterCase.lower)(rnd4));
- assert(rnd4.length == 2048);
- }
- unittest
- {
- import std.digest;
- import std.stdio;
- writeln("Testing Random Number Generator for Equality:");
- //Test 32 bytes
- ubyte[] rnd1 = random(32);
- ubyte[] rnd2 = random(32);
- writeln("Testing with 32 Bytes");
- assert(!constantTimeEquality(rnd1, rnd2));
- //Test 128 bytes
- rnd1 = random(128);
- rnd2 = random(128);
- writeln("Testing with 128 Bytes");
- assert(!constantTimeEquality(rnd1, rnd2));
- //Test 512 bytes
- rnd1 = random(512);
- rnd2 = random(512);
- writeln("Testing with 512 Bytes");
- assert(!constantTimeEquality(rnd1, rnd2));
- //Test 2048 bytes
- rnd1 = random(2048);
- rnd2 = random(2048);
- writeln("Testing with 2048 Bytes");
- assert(!constantTimeEquality(rnd1, rnd2));
- }
|