From a1730c10632b9e1e800db5e280eea576bc9052ec Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Tue, 15 May 2018 00:55:02 +0200 Subject: [PATCH] Add Windows support for getentropy() and arc4random() Import from OpenBSD. --- COPYING | 2 ++ src/Makefile.am | 2 ++ src/arc4random.h | 2 ++ src/arc4random_win.h | 78 ++++++++++++++++++++++++++++++++++++++++++++ src/getentropy.c | 2 ++ src/getentropy_win.c | 59 +++++++++++++++++++++++++++++++++ 6 files changed, 145 insertions(+) create mode 100644 src/arc4random_win.h create mode 100644 src/getentropy_win.c diff --git a/COPYING b/COPYING index e197193..26df85f 100644 --- a/COPYING +++ b/COPYING @@ -449,6 +449,7 @@ Files: src/arc4random_openbsd.h src/arc4random_uniform.c src/arc4random_unix.h + src/arc4random_win.h src/closefrom.c src/getentropy_aix.c src/getentropy_bsd.c @@ -457,6 +458,7 @@ Files: src/getentropy_linux.c src/getentropy_osx.c src/getentropy_solaris.c + src/getentropy_win.c src/readpassphrase.c src/reallocarray.c src/strlcat.c diff --git a/src/Makefile.am b/src/Makefile.am index d85dc69..f3cc0fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ libbsd_la_included_sources = \ getentropy_linux.c \ getentropy_osx.c \ getentropy_solaris.c \ + getentropy_win.c \ $(nil) EXTRA_DIST = \ @@ -64,6 +65,7 @@ libbsd_la_SOURCES = \ arc4random_openbsd.h \ arc4random_uniform.c \ arc4random_unix.h \ + arc4random_win.h \ bsd_getopt.c \ chacha_private.h \ closefrom.c \ diff --git a/src/arc4random.h b/src/arc4random.h index 803ef86..812188b 100644 --- a/src/arc4random.h +++ b/src/arc4random.h @@ -36,6 +36,8 @@ getentropy(void *buf, size_t len); #include "arc4random_openbsd.h" #elif defined(__linux__) #include "arc4random_linux.h" +#elif defined(_WIN32) +#include "arc4random_win.h" #else #include "arc4random_unix.h" #endif diff --git a/src/arc4random_win.h b/src/arc4random_win.h new file mode 100644 index 0000000..deec8a1 --- /dev/null +++ b/src/arc4random_win.h @@ -0,0 +1,78 @@ +/* $OpenBSD: arc4random_win.h,v 1.6 2016/06/30 12:17:29 bcook Exp $ */ + +/* + * Copyright (c) 1996, David Mazieres + * Copyright (c) 2008, Damien Miller + * Copyright (c) 2013, Markus Friedl + * Copyright (c) 2014, Theo de Raadt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Stub functions for portability. + */ + +#include + +static volatile HANDLE arc4random_mtx = NULL; + +/* + * Initialize the mutex on the first lock attempt. On collision, each thread + * will attempt to allocate a mutex and compare-and-swap it into place as the + * global mutex. On failure to swap in the global mutex, the mutex is closed. + */ +#define _ARC4_LOCK() { \ + if (!arc4random_mtx) { \ + HANDLE p = CreateMutex(NULL, FALSE, NULL); \ + if (InterlockedCompareExchangePointer((void **)&arc4random_mtx, (void *)p, NULL)) \ + CloseHandle(p); \ + } \ + WaitForSingleObject(arc4random_mtx, INFINITE); \ +} \ + +#define _ARC4_UNLOCK() ReleaseMutex(arc4random_mtx) + +static inline void +_getentropy_fail(void) +{ + TerminateProcess(GetCurrentProcess(), 0); +} + +static inline int +_rs_allocate(struct _rs **rsp, struct _rsx **rsxp) +{ + *rsp = VirtualAlloc(NULL, sizeof(**rsp), + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (*rsp == NULL) + return (-1); + + *rsxp = VirtualAlloc(NULL, sizeof(**rsxp), + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (*rsxp == NULL) { + VirtualFree(*rsp, 0, MEM_RELEASE); + *rsp = NULL; + return (-1); + } + return (0); +} + +static inline void +_rs_forkhandler(void) +{ +} + +static inline void +_rs_forkdetect(void) +{ +} diff --git a/src/getentropy.c b/src/getentropy.c index 3f11a1e..b4b3fe3 100644 --- a/src/getentropy.c +++ b/src/getentropy.c @@ -40,6 +40,8 @@ #include "getentropy_aix.c" #elif defined(__hpux) #include "getentropy_hpux.c" +#elif defined(_WIN32) +#include "getentropy_win.c" #else #error "No getentropy hooks defined for this platform." #endif diff --git a/src/getentropy_win.c b/src/getentropy_win.c new file mode 100644 index 0000000..bc548e6 --- /dev/null +++ b/src/getentropy_win.c @@ -0,0 +1,59 @@ +/* $OpenBSD: getentropy_win.c,v 1.5 2016/08/07 03:27:21 tb Exp $ */ + +/* + * Copyright (c) 2014, Theo de Raadt + * Copyright (c) 2014, Bob Beck + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 + */ + +#include +#include +#include +#include +#include +#include + +int getentropy(void *buf, size_t len); + +/* + * On Windows, CryptGenRandom is supposed to be a well-seeded + * cryptographically strong random number generator. + */ +int +getentropy(void *buf, size_t len) +{ + HCRYPTPROV provider; + + if (len > 256) { + errno = EIO; + return (-1); + } + + if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT) == 0) + goto fail; + if (CryptGenRandom(provider, len, buf) == 0) { + CryptReleaseContext(provider, 0); + goto fail; + } + CryptReleaseContext(provider, 0); + return (0); + +fail: + errno = EIO; + return (-1); +}