Refactor sysrand to remove `result` usage and fix style check issues. (#57)

* Refactor sysrand to remove `result` usage and fix style check issues.

* Fix duplicated imports.
This commit is contained in:
Eugene Kabanov 2022-07-05 15:33:37 +03:00 committed by GitHub
parent 4a0633dc0b
commit b41129f955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 112 additions and 104 deletions

View File

@ -55,7 +55,7 @@
## # 18AF7C8586141A47EAAD416C2B356431D001FAFF3B8C98C80AA108DC971B230D
## # 18AF7C8586141A47EAAD416C2B356431D001FAFF3B8C98C80AA108DC971B230D
## # 18AF7C8586141A47EAAD416C2B356431D001FAFF3B8C98C80AA108DC971B230D
import hash, utils
import utils
import sha, sha2, ripemd, keccak, blake2, hash
export sha, sha2, ripemd, keccak, blake2, hash

View File

@ -13,8 +13,8 @@
## ``Windows`` using BCryptGenRandom (if available),
## CryptGenRandom(PROV_INTEL_SEC) (if available), RtlGenRandom.
##
## RtlGenRandom (available from Windows XP)
## BCryptGenRandom (available from Windows Vista SP1)
## RtlGenRandom (available since Windows XP)
## BCryptGenRandom (available since Windows Vista SP1)
## CryptGenRandom(PROV_INTEL_SEC) (only when Intel SandyBridge
## CPU is available).
##
@ -25,60 +25,63 @@
## ``NetBSD``, ``FreeBSD``, ``MacOS``, ``Solaris`` using `/dev/urandom`.
{.deadCodeElim:on.}
{.push raises: [].}
when defined(posix):
import os, posix
proc urandomRead(pbytes: pointer, nbytes: int): int =
result = -1
var st: Stat
let fd = posix.open("/dev/urandom", posix.O_RDONLY)
if fd != -1:
if posix.fstat(fd, st) != -1 and S_ISCHR(st.st_mode):
result = 0
while result < nbytes:
var p = cast[pointer](cast[uint]((pbytes)) + uint(result))
var res = posix.read(fd, p, nbytes - result)
if res > 0:
result += res
elif res == 0:
break
else:
if osLastError().int32 != EINTR:
result = -1
break
if fd == -1:
return -1
if posix.fstat(fd, st) == -1 or not(S_ISCHR(st.st_mode)):
discard posix.close(fd)
return -1
var res = 0
while res < nbytes:
var p = cast[pointer](cast[uint]((pbytes)) + uint(res))
var bytesRead = posix.read(fd, p, nbytes - res)
if bytesRead > 0:
res += bytesRead
elif bytesRead == 0:
break
else:
if osLastError() != OSErrorCode(EINTR):
break
discard posix.close(fd)
res
when defined(openbsd):
import posix, os
proc getentropy(pBytes: pointer, nBytes: int): cint
proc getentropy(pbytes: pointer, nbytes: int): cint
{.importc: "getentropy", header: "<unistd.h>".}
proc randomBytes*(pbytes: pointer, nbytes: int): int =
var p: pointer
while result < nbytes:
p = cast[pointer](cast[uint](pbytes) + uint(result))
let res = getentropy(p, nbytes - result)
if res > 0:
result += res
elif res == 0:
var res = 0
while res < nbytes:
p = cast[pointer](cast[uint](pbytes) + uint(res))
let bytesRead = getentropy(p, nbytes - res)
if bytesRead > 0:
res += bytesRead
elif bytesRead == 0:
break
else:
if osLastError().int32 != EINTR:
result = -1
if osLastError() != OSErrorCode(EINTR):
break
if result == -1:
result = urandomRead(pbytes, nbytes)
elif result < nbytes:
p = cast[pointer](cast[uint](pbytes) + uint(result))
let res = urandomRead(p, nbytes - result)
if res != -1:
result += res
if res <= 0:
res = urandomRead(pbytes, nbytes)
elif res < nbytes:
p = cast[pointer](cast[uint](pbytes) + uint(res))
let bytesRead = urandomRead(p, nbytes - res)
if bytesRead != -1:
res += bytesRead
res
elif defined(linux):
import posix, os
when defined(i386):
const SYS_getrandom = 355
elif defined(powerpc64) or defined(powerpc64el) or defined(powerpc):
@ -109,47 +112,50 @@ elif defined(linux):
var gSystemRng {.threadvar.}: SystemRng ## System thread global RNG
proc newSystemRNG(): SystemRng =
result = SystemRng()
proc newSystemRng(): SystemRng =
var rng = SystemRng()
if SYS_getrandom != 0:
var data: int
result.getRandomPresent = true
rng.getRandomPresent = true
let res = syscall(SYS_getrandom, addr data, 1, GRND_NONBLOCK)
if res == -1:
let err = osLastError().int32
if err == ENOSYS or err == EPERM:
result.getRandomPresent = false
let err = osLastError()
if err == OSErrorCode(ENOSYS) or err == OSErrorCode(EPERM):
rng.getRandomPresent = false
rng
proc getSystemRNG(): SystemRng =
if gSystemRng.isNil: gSystemRng = newSystemRng()
result = gSystemRng
proc getSystemRng(): SystemRng =
if isNil(gSystemRng):
gSystemRng = newSystemRng()
gSystemRng
proc randomBytes*(pbytes: pointer, nbytes: int): int =
var p: pointer
let srng = getSystemRNG()
let srng = getSystemRng()
if srng.getRandomPresent:
while result < nbytes:
p = cast[pointer](cast[uint](pbytes) + uint(result))
let res = syscall(SYS_getrandom, pBytes, nBytes - result, 0)
if res > 0:
result += res
elif res == 0:
var res = 0
while res < nbytes:
p = cast[pointer](cast[uint](pbytes) + uint(res))
let bytesRead = syscall(SYS_getrandom, pbytes, nbytes - res, 0)
if bytesRead > 0:
res += bytesRead
elif bytesRead == 0:
break
else:
if osLastError().int32 != EINTR:
result = -1
break
if result == -1:
result = urandomRead(pbytes, nbytes)
elif result < nbytes:
p = cast[pointer](cast[uint](pbytes) + uint(result))
let res = urandomRead(p, nbytes - result)
if res != -1:
result += res
if res <= 0:
res = urandomRead(pbytes, nbytes)
elif res < nbytes:
p = cast[pointer](cast[uint](pbytes) + uint(res))
let bytesRead = urandomRead(p, nbytes - res)
if bytesRead != -1:
res += bytesRead
res
else:
result = urandomRead(pbytes, nbytes)
urandomRead(pbytes, nbytes)
elif defined(windows):
import os, winlean, dynlib
@ -219,71 +225,73 @@ elif defined(windows):
proc isEqualOrHigher(major: int, minor: int, servicePack: int): bool =
var mask = 0'u64
var ov = OSVERSIONINFOEXW()
ov.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW).DWORD
ov.dwMajorVersion = major.DWORD
ov.dwMinorVersion = minor.DWORD
ov.wServicePackMajor = servicePack.uint16
ov.wServicePackMinor = 0
var typeMask = (VER_MAJORVERSION or VER_MINORVERSION or
VER_SERVICEPACKMAJOR or VER_SERVICEPACKMINOR).DWORD
var ov = OSVERSIONINFOEXW(
dwOSVersionInfoSize: DWORD(sizeof(OSVERSIONINFOEXW)),
dwMajorVersion: DWORD(major),
dwMinorVersion: DWORD(minor),
wServicePackMajor: uint16(servicePack),
wServicePackMinor: 0
)
let typeMask =
DWORD(VER_MAJORVERSION or VER_MINORVERSION or
VER_SERVICEPACKMAJOR or VER_SERVICEPACKMINOR)
mask = verSetConditionMask(mask, VER_MAJORVERSION, VER_GREATER_EQUAL)
mask = verSetConditionMask(mask, VER_MINORVERSION, VER_GREATER_EQUAL)
mask = verSetConditionMask(mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL)
mask = verSetConditionMask(mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL)
return (verifyVersionInfo(addr ov, typeMask, mask) == 1)
verifyVersionInfo(addr ov, typeMask, mask) == 1
proc newSystemRNG(): SystemRng =
result = SystemRng()
proc newSystemRng(): SystemRng =
var rng = SystemRng()
if isEqualOrHigher(6, 0, 0):
if isEqualOrHigher(6, 0, 1):
let lib = loadLib("bcrypt.dll")
if lib != nil:
var lProc = cast[BCGRMPROC](symAddr(lib, "BCryptGenRandom"))
if not isNil(lProc):
result.bCryptGenRandom = lProc
rng.bCryptGenRandom = lProc
var hp: HCRYPTPROV = 0
let intelDef = newWideCString(INTEL_DEF_PROV)
let res1 = cryptAcquireContext(addr hp, nil, intelDef, PROV_INTEL_SEC,
CRYPT_VERIFYCONTEXT or CRYPT_SILENT).bool
if res1:
result.hIntel = hp
let res = cryptAcquireContext(addr hp, nil, intelDef, PROV_INTEL_SEC,
CRYPT_VERIFYCONTEXT or CRYPT_SILENT).bool
if res:
rng.hIntel = hp
rng
proc getSystemRNG(): SystemRng =
if gSystemRng.isNil: gSystemRng = newSystemRng()
result = gSystemRng
proc getSystemRng(): SystemRng =
if isNil(gSystemRng):
gSystemRng = newSystemRng()
gSystemRng
proc randomBytes*(pbytes: pointer, nbytes: int): int =
let srng = getSystemRNG()
result = -1
let srng = getSystemRng()
if not isNil(srng.bCryptGenRandom):
if srng.bCryptGenRandom(nil, pbytes, nbytes.ULONG,
if srng.bCryptGenRandom(nil, pbytes, ULONG(nbytes),
BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0:
result = nbytes
if srng.hIntel != 0 and result == -1:
if cryptGenRandom(srng.hIntel, nbytes.DWORD, pbytes) != 0:
result = nbytes
if result == -1:
if rtlGenRandom(pBytes, nbytes.ULONG) != 0:
result = nbytes
return nbytes
if srng.hIntel != 0:
if cryptGenRandom(srng.hIntel, DWORD(nbytes), pbytes) != 0:
return nbytes
if rtlGenRandom(pbytes, ULONG(nbytes)) != 0:
return nbytes
-1
proc randomClose*() =
let srng = getSystemRNG()
let srng = getSystemRng()
if srng.hIntel != 0:
if cryptReleaseContext(srng.hIntel, 0) == 0:
raiseOsError(osLastError())
else:
import posix
discard cryptReleaseContext(srng.hIntel, 0)
else:
proc randomBytes*(pbytes: pointer, nbytes: int): int =
result = urandomRead(pbytes, nbytes)
urandomRead(pbytes, nbytes)
proc randomBytes*[T](bytes: var openArray[T]): int =
let length = len(bytes) * sizeof(T)
if length > 0:
result = randomBytes(addr bytes[0], length)
if result != -1:
result = result div sizeof(T)
if length == 0:
return 0
let res = randomBytes(addr bytes[0], length)
if res != -1:
res div sizeof(T)
else:
res