uuids/src/urandom.nim
Ruslan Mustakov 3951521a16 First version
2016-09-15 20:35:01 +07:00

65 lines
2 KiB
Nim

# Source: https://github.com/BlaXpirit/nim-random/blob/master/src/random/urandom.nim
when defined(windows):
import winlean
type ULONG_PTR = int
type HCRYPTPROV = ULONG_PTR
var PROV_RSA_FULL {.importc, header: "<windows.h>".}: DWORD
var CRYPT_VERIFYCONTEXT {.importc, header: "<windows.h>".}: DWORD
{.push, stdcall, dynlib: "Advapi32.dll".}
when useWinUnicode:
proc CryptAcquireContext(
phProv: ptr HCRYPTPROV, pszContainer: WideCString,
pszProvider: WideCString, dwProvType: DWORD, dwFlags: DWORD
): WinBool {.importc: "CryptAcquireContextW".}
else:
proc CryptAcquireContext(
phProv: ptr HCRYPTPROV, pszContainer: cstring, pszProvider: cstring,
dwProvType: DWORD, dwFlags: DWORD
): WinBool {.importc: "CryptAcquireContextA".}
proc CryptGenRandom(
hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: pointer
): WinBool {.importc: "CryptGenRandom".}
{.pop.}
var cryptProv: HCRYPTPROV = 0
proc urandomInit() =
let success = CryptAcquireContext(
addr cryptProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT
)
if success == 0:
raise newException(OSError, "Call to CryptAcquireContext failed")
template urandomImpl() =
when defined(windows):
if cryptProv == 0:
urandomInit()
let success = CryptGenRandom(cryptProv, DWORD(size), addr result[0])
if success == 0:
raise newException(OSError, "Call to CryptGenRandom failed")
else:
var file: File
if not file.open("/dev/urandom"):
raise newException(OSError, "/dev/urandom is not available")
try:
var index = 0
while index < size:
let bytesRead = file.readBuffer(addr result[index], size-index)
if bytesRead <= 0:
raise newException(OSError, "Can't read enough bytes from /dev/urandom")
index += bytesRead
finally:
file.close()
proc urandom*(size: static[Natural]): array[size, uint8] =
## Returns an ``array`` of random integers ``0 <= n < 256`` provided by
## the operating system's cryptographic source.
urandomImpl()