Skip to content

Instantly share code, notes, and snippets.

@eu90h
Last active September 17, 2015 02:07
Show Gist options
  • Save eu90h/5dfd65a3aa1b276be49c to your computer and use it in GitHub Desktop.
Save eu90h/5dfd65a3aa1b276be49c to your computer and use it in GitHub Desktop.
OS-based rng access
#lang racket/base
(require racket/contract/base "unix_rand.rkt" "windows_rand.rkt" (only-in file/sha1 bytes->hex-string))
(provide (contract-out [crypto-random-bytes (-> exact-positive-integer? (or/c bytes? string?))]
[crypto-random (-> exact-positive-integer? exact-positive-integer?)]))
(define bytes->number (compose (lambda (s) (string->number s 16)) bytes->hex-string))
; (: crypto-random-bytes (-> Positive-Integer Bytes))
; returns n random bytes from the os.
(define (crypto-random-bytes n)
(case (system-type 'os)
[(unix macosx) (crypto-random-unix-bytes n)]
[(windows) (crypto-random-windows-bytes n)]
[else (raise (make-exn:fail:unsupported
"Only UNIX, OS X, and Windows XP or greater are currently supported"
(current-continuation-marks)))]))
; (: crypto-random (-> Positive-Integer Nonnegative-Integer))
; returns a random n byte nonnegative-integer
(define (crypto-random n)
(bytes->number (crypto-random-bytes n)))
#lang racket/base
(provide crypto-random-unix-bytes)
(define (check-urandom-exists)
(unless (file-exists? "/dev/urandom")
(raise (make-exn:fail:filesystem
"/dev/urandom does not exist"
(current-continuation-marks)))))
; (: crypto-random-unix-bytes (-> Positive-Integer Bytes))
(define (crypto-random-unix-bytes n)
(check-urandom-exists)
(define urandom (open-input-file "/dev/urandom"))
(read-bytes n urandom))
#lang racket/base
(provide crypto-random-windows-bytes)
(require ffi/com
ffi/unsafe
ffi/unsafe/define
ffi/winapi)
(define-ffi-definer define-advapi (and (eq? (system-type) 'windows) (ffi-lib "Advapi32.dll"))
#:default-make-fail make-not-available)
; supposed to be the same csprng as CryptGenRand, but with less overhead
; see Microsoft security dev Michael Howard: http://blogs.msdn.com/b/michael_howard/archive/2005/01/14/353379.aspx
; this is for Windows XP and later only, but I doubt that's a problem
(define-advapi SystemFunction036
(_fun #:abi winapi _pointer _ulong -> _bool))
(define (check-SystemFunction036-exists)
(unless SystemFunction036
(raise (make-exn:fail:unsupported
"Unable to load RtlGenRandom (SystemFunction036) from Advapi32.dll"
(current-continuation-marks)))))
; (: crypto-random-windows-bytes (-> Positive-Integer Bytes))
(define (crypto-random-windows-bytes n)
(check-SystemFunction036-exists)
(define rand-bytes-buf (make-bytes n))
(if (SystemFunction036 rand-bytes-buf n)
rand-bytes-buf
(raise (make-exn:fail
"SystemFunction036 failed to generate bytes"
(current-continuation-marks)))))
@eu90h
Copy link
Author

eu90h commented Sep 16, 2015

I decided to remove the hex string option. bytes->hex-string makes it trivial for someone to convert the output of crypto-random-bytes into a hex string if they need it, so it doesn't warrant the added complexity.

a bytes->number would definitely be a useful addition to the bytes pkg.

your point about crypto-random's interface is spot-on. I'll have to think of how best to do this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment