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 ## # 18AF7C8586141A47EAAD416C2B356431D001FAFF3B8C98C80AA108DC971B230D
## # 18AF7C8586141A47EAAD416C2B356431D001FAFF3B8C98C80AA108DC971B230D ## # 18AF7C8586141A47EAAD416C2B356431D001FAFF3B8C98C80AA108DC971B230D
import hash, utils import utils
import sha, sha2, ripemd, keccak, blake2, hash import sha, sha2, ripemd, keccak, blake2, hash
export sha, sha2, ripemd, keccak, blake2, hash export sha, sha2, ripemd, keccak, blake2, hash

View File

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