Patch by Anton Kovalenko.
Fixes lp#1102748
* enhancement: by setting SB-EXT:*ON-PACKAGE-VARIANCE* appropriately variant
DEFPACKAGE forms can now signal a full error with restarts provided for
resolving the situation. See manual for details. (lp#891351)
+ * enhancement: make-random-state now uses CryptGenRandom as a seed on Windows.
+ (Thanks to Anton Kovalenko.) (lp#1102748)
* bug fix: secondary CLOS dispatch functions have better debug names.
(lp#503081)
* bug fix: deleting a package removes it from implementation-package
"CLOSE-HANDLE"
"CREATE-FILE"
"CREATE-FILE-MAPPING"
+ "CRYPT-GEN-RANDOM"
"DWORD"
"FD-CLEAR-INPUT"
"FD-LISTEN"
(check-type state (or boolean random-state))
(seed-random-state state))
+(defun fallback-random-seed ()
+ ;; When /dev/urandom is not available, we make do with time and pid
+ ;; Thread ID and/or address of a CONS cell would be even better, but...
+ (/show0 "No /dev/urandom, using randomness from time and pid")
+ (+ (get-internal-real-time)
+ (ash (sb!unix:unix-getpid) 32)))
+
+#!-win32
+(defun os-random-seed ()
+ (or
+ ;; On unices, we try to read from /dev/urandom and pass the results
+ ;; to our (simple-array (unsigned-byte 32) (*)) processor below.
+ ;; More than 256 bits would provide a false sense of security.
+ ;; If you need more bits than that, you probably also need
+ ;; a better algorithm too.
+ (ignore-errors
+ (with-open-file (r "/dev/urandom" :element-type '(unsigned-byte 32)
+ :direction :input :if-does-not-exist :error)
+ (let ((a (make-array '(8) :element-type '(unsigned-byte 32))))
+ (assert (= 8 (read-sequence a r)))
+ a)))
+ (fallback-random-seed)))
+
+#!+win32
+(defun os-random-seed ()
+ (/show0 "Getting randomness from CryptGenRandom")
+ (or (sb!win32:crypt-gen-random 32)
+ (fallback-random-seed)))
+
(defun seed-random-state (&optional state)
#!+sb-doc
"Make a random state object. The optional STATE argument specifies a seed
;; Standard case, less easy: try to randomly initialize a state.
((eql t)
(/show0 "getting randomness from the operating system")
- (seed-random-state
- (or
- ;; On unices, we try to read from /dev/urandom and pass the results
- ;; to our (simple-array (unsigned-byte 32) (*)) processor below.
- ;; More than 256 bits would provide a false sense of security.
- ;; If you need more bits than that, you probably also need
- ;; a better algorithm too.
- #!-win32
- (ignore-errors
- (with-open-file (r "/dev/urandom" :element-type '(unsigned-byte 32)
- :direction :input :if-does-not-exist :error)
- (let ((a (make-array '(8) :element-type '(unsigned-byte 32))))
- (assert (= 8 (read-sequence a r)))
- a)))
- ;; When /dev/urandom is not available, we make do with time and pid
- ;; Thread ID and/or address of a CONS cell would be even better, but...
- (progn
- (/show0 "No /dev/urandom, using randomness from time and pid")
- (+ (get-internal-real-time)
- (ash (sb!unix:unix-getpid) 32))))))
+ (seed-random-state (os-random-seed)))
;; For convenience to users, we accept (simple-array (unsigned-byte 8) (*))
;; We just convert it to (simple-array (unsigned-byte 32) (*)) in a
;; completely straightforward way.
(unwind-protect (funcall thunk fd)
(real-crt-close fd)))
(values nil errno))))
+
+;;; random seeding
+
+(define-alien-routine ("CryptGenRandom" %crypt-gen-random) lispbool
+ (handle handle)
+ (length dword)
+ (buffer (* t)))
+
+(define-alien-routine (#!-sb-unicode "CryptAcquireContextA"
+ #!+sb-unicode "CryptAcquireContextW"
+ %crypt-acquire-context) lispbool
+ (handle handle :out)
+ (container system-string)
+ (provider system-string)
+ (provider-type dword)
+ (flags dword))
+
+(define-alien-routine ("CryptReleaseContext" %crypt-release-context) lispbool
+ (handle handle)
+ (flags dword))
+
+(defun crypt-gen-random (length)
+ (multiple-value-bind (ok context)
+ (%crypt-acquire-context nil nil prov-rsa-full
+ (logior crypt-verifycontext crypt-silent))
+ (unless ok
+ (return-from crypt-gen-random (values nil (get-last-error))))
+ (unwind-protect
+ (let ((data (make-array length :element-type '(unsigned-byte 8))))
+ (with-pinned-objects (data)
+ (if (%crypt-gen-random context length (vector-sap data))
+ data
+ (values nil (get-last-error)))))
+ (unless (%crypt-release-context context 0)
+ (win32-error '%crypt-release-context)))))
LINKFLAGS = -Wl,-export-all-symbols -Wl,mswin64.def -Wl,mswin.def
-OS_LIBS = -l ws2_32
+OS_LIBS = -l ws2_32 -ladvapi32
ifdef LISP_FEATURE_SB_CORE_COMPRESSION
OS_LIBS += -lz
endif
# interface, though.:-| As far as I (WHN 2002-05-19) know, no one is
# working on one and it would be a nice thing to have.)
LINKFLAGS = -Wl,-export-all-symbols -Wl,mswin.def
-OS_LIBS = -l ws2_32
+OS_LIBS = -l ws2_32 -ladvapi32
ifdef LISP_FEATURE_SB_CORE_COMPRESSION
OS_LIBS += -lz
endif
#include "gc.h"
#include "gencgc-internal.h"
#include <winsock2.h>
+#include <wincrypt.h>
#if 0
int linux_sparc_siginfo_bug = 0;
/* a function from shell32.dll */
SHGetFolderPathA(0, 0, 0, 0, 0);
+
+ /* from advapi32.dll */
+ CryptGenRandom(0, 0, 0);
}
char *
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlobj.h>
+ #include <wincrypt.h>
#undef boolean
#else
#include <poll.h>
defconstant("STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE);
defconstant("STD_ERROR_HANDLE", STD_ERROR_HANDLE);
+ printf(";;; WinCrypt\n");
+ defconstant("crypt-verifycontext", CRYPT_VERIFYCONTEXT);
+ defconstant("crypt-silent", CRYPT_SILENT);
+ defconstant("prov-rsa-full", PROV_RSA_FULL);
/* FIXME: SB-UNIX and SB-WIN32 really need to be untangled. */
printf("(in-package \"SB!UNIX\")\n\n");