From 288b9bb5acd0575fcd544fa5e339cf156157e22a Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 10 Dec 2024 19:34:35 +0100 Subject: [PATCH 1/7] Add support for MSVC in zw_endianness.m4 MSVC doesn't define any endianness macros, but for x64 (and ARM64EC) as well as x86 processors MSVC uses little-endian order. We define that accordingly. --- build-aux/m4/zw_endianness.m4 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build-aux/m4/zw_endianness.m4 b/build-aux/m4/zw_endianness.m4 index 95132161..00c3fdde 100644 --- a/build-aux/m4/zw_endianness.m4 +++ b/build-aux/m4/zw_endianness.m4 @@ -101,6 +101,10 @@ m4_define([zw_C_ENDIANNESS_options], [ [ [_MIPSEB and _MIPSEL], [(defined _MIPSEB) != (defined _MIPSEL)], [defined _MIPSEB], [defined _MIPSEL], [0], +], +[ [_MSC_VER and _M_X64 or _M_IX86], + [defined _MSC_VER && (defined _M_X64 || defined _M_IX86)], + [0], [1], [0], ] ]) From 2f19228c690a39b38b352d4a91d16d8d61c9e67c Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 10 Dec 2024 19:35:26 +0100 Subject: [PATCH 2/7] Define NO_INLINE for MSVC --- lib/crypt-port.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/crypt-port.h b/lib/crypt-port.h index a7079396..21b362a5 100644 --- a/lib/crypt-port.h +++ b/lib/crypt-port.h @@ -83,6 +83,8 @@ /* Functions that should not be inlined. */ #if defined __GNUC__ && __GNUC__ >= 3 # define NO_INLINE __attribute__ ((__noinline__)) +#elif defined(_MSC_VER) +# define NO_INLINE __declspec(noinline) #else # error "Don't know how to prevent function inlining" #endif From 7d92528b21a5d98ffd70d14e6a72c72609cf8b88 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 10 Dec 2024 19:40:34 +0100 Subject: [PATCH 3/7] Define STATIC_RESTRICT to work around MSVC limitations --- lib/alg-sha256.c | 24 ++++++++++++------------ lib/crypt-port.h | 7 +++++++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/alg-sha256.c b/lib/alg-sha256.c index 7298fa31..3fad12ba 100644 --- a/lib/alg-sha256.c +++ b/lib/alg-sha256.c @@ -101,9 +101,9 @@ static const uint32_t Krnd[64] = { * the 512-bit input block to produce a new state. */ static void -SHA256_Transform(uint32_t state[static restrict 8], - const uint8_t block[static restrict 64], - uint32_t W[static restrict 64], uint32_t S[static restrict 8]) +SHA256_Transform(uint32_t state[STATIC_RESTRICT 8], + const uint8_t block[STATIC_RESTRICT 64], + uint32_t W[STATIC_RESTRICT 64], uint32_t S[STATIC_RESTRICT 8]) { int i; @@ -174,7 +174,7 @@ static const uint8_t PAD[64] = { /* Add padding and terminating bit-count. */ static void -SHA256_Pad(SHA256_CTX * ctx, uint32_t tmp32[static restrict 72]) +SHA256_Pad(SHA256_CTX * ctx, uint32_t tmp32[STATIC_RESTRICT 72]) { size_t r; @@ -228,7 +228,7 @@ SHA256_Init(SHA256_CTX * ctx) */ static void _SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len, - uint32_t tmp32[static restrict 72]) + uint32_t tmp32[STATIC_RESTRICT 72]) { uint32_t r; const uint8_t * src = in; @@ -286,7 +286,7 @@ SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len) */ static void _SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx, - uint32_t tmp32[static restrict 72]) + uint32_t tmp32[STATIC_RESTRICT 72]) { /* Add padding. */ @@ -342,8 +342,8 @@ SHA256_Buf(const void * in, size_t len, uint8_t digest[32]) */ static void _HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen, - uint32_t tmp32[static restrict 72], uint8_t pad[static restrict 64], - uint8_t khash[static restrict 32]) + uint32_t tmp32[STATIC_RESTRICT 72], uint8_t pad[STATIC_RESTRICT 64], + uint8_t khash[STATIC_RESTRICT 32]) { const uint8_t * K = _K; size_t i; @@ -395,7 +395,7 @@ HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) */ static void _HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len, - uint32_t tmp32[static restrict 72]) + uint32_t tmp32[STATIC_RESTRICT 72]) { /* Feed data to the inner SHA256 operation. */ @@ -422,7 +422,7 @@ HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len) */ static void _HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx, - uint32_t tmp32[static restrict 72], uint8_t ihash[static restrict 32]) + uint32_t tmp32[STATIC_RESTRICT 72], uint8_t ihash[STATIC_RESTRICT 32]) { /* Finish the inner SHA256 operation. */ @@ -478,8 +478,8 @@ HMAC_SHA256_Buf(const void * K, size_t Klen, const void * in, size_t len, /* Add padding and terminating bit-count, but don't invoke Transform yet. */ static int -SHA256_Pad_Almost(SHA256_CTX * ctx, uint8_t len[static restrict 8], - uint32_t tmp32[static restrict 72]) +SHA256_Pad_Almost(SHA256_CTX * ctx, uint8_t len[STATIC_RESTRICT 8], + uint32_t tmp32[STATIC_RESTRICT 72]) { uint32_t r; diff --git a/lib/crypt-port.h b/lib/crypt-port.h index 21b362a5..0e59cd54 100644 --- a/lib/crypt-port.h +++ b/lib/crypt-port.h @@ -101,6 +101,13 @@ #define MIN_SIZE(x) (x) #endif +/* MSVC does not support static restrict array declarations. */ +#ifdef _MSC_VER +#define STATIC_RESTRICT +#else +#define STATIC_RESTRICT static restrict +#endif + /* Detect system endianness. */ #if ENDIANNESS_IS_BIG # define XCRYPT_USE_BIGENDIAN 1 From f34133655a9da0fab95d95bbb16d25c5b6589671 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 10 Dec 2024 19:42:20 +0100 Subject: [PATCH 4/7] Define symver_nop() for compatibility with MSVC MSVC does not support any inline assembly (let alone symversioning). --- lib/crypt-port.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/crypt-port.h b/lib/crypt-port.h index 0e59cd54..a81e5f97 100644 --- a/lib/crypt-port.h +++ b/lib/crypt-port.h @@ -249,7 +249,11 @@ extern size_t strcpy_or_abort (void *dst, size_t d_size, const void *src); /* A construct with the same syntactic role as the expansion of symver_set, but which does nothing. */ +#ifdef _MSC_VER +#define symver_nop() +#else #define symver_nop() __asm__ ("") +#endif /* The macros for versioned symbols work differently in this library than they do in glibc. They are mostly auto-generated From 09ece669c20f41939636dc377af58210846c4d39 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 10 Dec 2024 19:44:50 +0100 Subject: [PATCH 5/7] typedef ssize_t for MSVC `ssize_t` is not supported, but `SSIZE_T` with the same meaning. --- lib/crypt-port.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/crypt-port.h b/lib/crypt-port.h index a81e5f97..841899c2 100644 --- a/lib/crypt-port.h +++ b/lib/crypt-port.h @@ -49,6 +49,9 @@ #ifdef HAVE_SYS_PARAM_H #include #endif +#ifdef _MSC_VER +#include +#endif /* unistd.h may contain declarations of crypt, crypt_r, crypt_data, encrypt, and setkey; if present, they may be incompatible with our @@ -148,6 +151,10 @@ typedef union } max_align_t; #endif +#ifdef _MSC_VER +typedef SSIZE_T ssize_t; +#endif + /* Several files expect the traditional definitions of these macros. (We don't trust sys/param.h to define them correctly.) */ #undef MIN From 7fcc3e87098b91aa2926edfa691feb766b2d81a1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 10 Dec 2024 19:47:26 +0100 Subject: [PATCH 6/7] Use SecureZeroMemory() as explicit_bzero() for MSVC MSVC doesn't support `explicit_memset()` nor `memset_s()`, but has `SecureZeroMemory()`, which appears to be more appropriate than falling back on an own function definition. --- lib/crypt-port.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/crypt-port.h b/lib/crypt-port.h index 841899c2..f389c463 100644 --- a/lib/crypt-port.h +++ b/lib/crypt-port.h @@ -182,6 +182,8 @@ typedef SSIZE_T ssize_t; #define explicit_bzero(s, len) explicit_memset(s, 0, len) #elif defined HAVE_MEMSET_S #define explicit_bzero(s, len) memset_s(s, len, 0, len) +#elif defined _MSC_VER +#define explicit_bzero(s, len) SecureZeroMemory(s, len) #else /* activate our fallback implementation */ #undef INCLUDE_explicit_bzero From dfab9d3c0842e197e6808b971d6647d690e3f844 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 10 Dec 2024 19:59:16 +0100 Subject: [PATCH 7/7] Implement get_random_bytes() for MSVC --- lib/util-get-random-bytes.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/util-get-random-bytes.c b/lib/util-get-random-bytes.c index 79816db3..b59cd8fd 100644 --- a/lib/util-get-random-bytes.c +++ b/lib/util-get-random-bytes.c @@ -31,6 +31,9 @@ #ifdef HAVE_SYS_STAT_H #include #endif +#ifdef _MSC_VER +#include +#endif /* If we have O_CLOEXEC, we use it, but if we don't, we don't worry about it. */ @@ -52,7 +55,10 @@ getentropy() and enforced regardless of the actual back-end in use). If we fall all the way back to /dev/urandom, we open and close it on - each call. */ + each call. + + With MSVC we fall back to BCryptGenRandom(), and open and close the + provider on each call. */ bool get_random_bytes(void *buf, size_t buflen) @@ -146,6 +152,27 @@ get_random_bytes(void *buf, size_t buflen) } } #endif + +#ifdef _MSC_VER + static bool bcrypt_doesnt_work; + if (!bcrypt_doesnt_work) + { + BCRYPT_ALG_HANDLE algo; + NTSTATUS res; + res = BCryptOpenAlgorithmProvider(&algo, BCRYPT_RNG_ALGORITHM, NULL, 0); + if (!BCRYPT_SUCCESS(res)) + bcrypt_doesnt_work = true; + else + { + res = BCryptGenRandom(algo, buf, (ULONG) buflen, 0); + if (!BCRYPT_SUCCESS(res)) + bcrypt_doesnt_work = true; + + BCryptCloseAlgorithmProvider(algo, 0); + return !bcrypt_doesnt_work; + } + } +#endif #endif /* no arc4random_buf */ /* if we get here, we're just completely hosed */