From d988055a49a8f91b47cf5ecbcce655155c4bde75 Mon Sep 17 00:00:00 2001 From: Stefan Date: Sat, 26 Sep 2015 20:54:36 -0400 Subject: [PATCH] added crypto-random-bytes --- .../scribblings/reference/numbers.scrbl | 28 +++++++++++++++++-- racket/collects/racket/private/unix-rand.rkt | 15 ++++++++++ .../collects/racket/private/windows-rand.rkt | 22 +++++++++++++++ racket/collects/racket/random.rkt | 14 ++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 racket/collects/racket/private/unix-rand.rkt create mode 100644 racket/collects/racket/private/windows-rand.rkt create mode 100644 racket/collects/racket/random.rkt diff --git a/pkgs/racket-doc/scribblings/reference/numbers.scrbl b/pkgs/racket-doc/scribblings/reference/numbers.scrbl index 1d4ed6745f..ee9771adbe 100644 --- a/pkgs/racket-doc/scribblings/reference/numbers.scrbl +++ b/pkgs/racket-doc/scribblings/reference/numbers.scrbl @@ -4,7 +4,8 @@ racket/flonum racket/fixnum racket/unsafe/ops - racket/require)) + racket/require + racket/random)) @(define math-eval (make-base-eval)) @(interaction-eval #:eval math-eval (require racket/math)) @@ -835,6 +836,8 @@ both in binary and as integers. @; ------------------------------------------------------------------------ @subsection{Random Numbers} +@margin-note{When security is a concern, use @racket[crypto-random-bytes] instead of @racket[random].} + @defproc*[([(random [k (integer-in 1 4294967087)] [rand-gen pseudo-random-generator? (current-pseudo-random-generator)]) @@ -855,7 +858,6 @@ internal state for generating numbers. The random number generator uses a 54-bit version of L'Ecuyer's MRG32k3a algorithm @cite["L'Ecuyer02"].} - @defproc[(random-seed [k (integer-in 1 (sub1 (expt 2 31)))]) void?]{ @@ -923,6 +925,28 @@ range @racket[0] to @racket[4294944442], inclusive; at least one of the first three integers is non-zero; and at least one of the last three integers is non-zero. Otherwise, the result is @racket[#f].} +@; ------------------------------------------------------------------------ + +@subsection{System-Provided Randomness} + +@defmodule[racket/random]{The @racketmodname[racket/random] module +provides an interface to randomness from the underlying operating +system. Use @racket[crypto-random-bytes] +instead of @racket[random] wherever security is a concern.} + +@defproc[(crypto-random-bytes [n exact-positive-integer?]) + bytes?]{ + +Returns @racket[n] random bytes. On Unix systems, the bytes are +obtained from @filepath{/dev/urandom}, while Windows uses +the @tt{RtlGenRand} system function. + +@examples[ + (eval:alts (crypto-random-bytes 14) #"\0\1\1\2\3\5\b\r\25\"7Y\220\351") +] + +@history[#:added "6.2.900.17"]} + @; ------------------------------------------------------------------------ @subsection{Number--String Conversions} diff --git a/racket/collects/racket/private/unix-rand.rkt b/racket/collects/racket/private/unix-rand.rkt new file mode 100644 index 0000000000..d2c6a3d0cd --- /dev/null +++ b/racket/collects/racket/private/unix-rand.rkt @@ -0,0 +1,15 @@ +#lang racket/base +(provide crypto-random-unix-bytes) + +(define (check-urandom-exists) + (unless (file-exists? "/dev/urandom") + (raise (make-exn:fail:filesystem + "crypto-random-bytes: \"/dev/urandom\" does not exist" + (current-continuation-marks))))) + +; (: crypto-random-unix-bytes (-> Positive-Integer Bytes)) +(define (crypto-random-unix-bytes n) + (check-urandom-exists) + (call-with-input-file* "/dev/urandom" + (lambda (port) + (read-bytes n port)))) diff --git a/racket/collects/racket/private/windows-rand.rkt b/racket/collects/racket/private/windows-rand.rkt new file mode 100644 index 0000000000..ad4067de31 --- /dev/null +++ b/racket/collects/racket/private/windows-rand.rkt @@ -0,0 +1,22 @@ +#lang racket/base +(provide crypto-random-windows-bytes) + +(require ffi/unsafe + ffi/unsafe/define) + +(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 _pointer _ulong -> _bool)) + +; (: crypto-random-windows-bytes (-> Positive-Integer Bytes)) +(define (crypto-random-windows-bytes n) + (define rand-bytes-buf (make-bytes n)) + (if (SystemFunction036 rand-bytes-buf n) + rand-bytes-buf + (raise (make-exn:fail + "crypto-random-windows: SystemFunction036 failed to generate bytes" + (current-continuation-marks))))) diff --git a/racket/collects/racket/random.rkt b/racket/collects/racket/random.rkt new file mode 100644 index 0000000000..2978444c9b --- /dev/null +++ b/racket/collects/racket/random.rkt @@ -0,0 +1,14 @@ +#lang racket/base + +(require "private/unix-rand.rkt" "private/windows-rand.rkt" racket/contract/base) +(provide (contract-out [crypto-random-bytes (-> exact-nonnegative-integer? bytes?)])) + +; (: 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 + "not supported on the current platform" + (current-continuation-marks)))]))