From 762b374db0b226b2aefaf65bc2776061a3f8e854 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Fri, 16 Oct 2026 14:47:34 +0900 Subject: [PATCH] Windows: handle extended processor state save failures Use per-context software SHA-256/SHA-512 after a failed state save without changing global dispatch. Return an error and clear Argon2's output before its accelerated core can run. --- src/Common/Pkcs5.c | 64 +++++++++++++++++++++++++++++++++++++--------- src/Crypto/Sha2.c | 58 +++++++++++++++++++++++++++++++++++------ src/Crypto/Sha2.h | 16 ++++++++++-- 3 files changed, 116 insertions(+), 22 deletions(-) diff --git a/src/Common/Pkcs5.c b/src/Common/Pkcs5.c index 944b3acf..40b1f31f 100644 --- a/src/Common/Pkcs5.c +++ b/src/Common/Pkcs5.c @@ -44,6 +44,15 @@ #include "Pkcs5.h" #include "Crypto.h" +/* Driver calls can select a software initializer without changing global dispatch. */ +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) +#define SHA256_HMAC_BEGIN sha256Begin +#define SHA512_HMAC_BEGIN sha512Begin +#else +#define SHA256_HMAC_BEGIN sha256_begin +#define SHA512_HMAC_BEGIN sha512_begin +#endif + #if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_SHA2) typedef struct hmac_sha256_ctx_struct @@ -96,10 +105,15 @@ void hmac_sha256 int b; unsigned char key[SHA256_DIGESTSIZE]; #if defined (DEVICE_DRIVER) && !defined(_M_ARM64) + void (*sha256Begin)(sha256_ctx*) = sha256_begin; NTSTATUS saveStatus = STATUS_INVALID_PARAMETER; XSTATE_SAVE SaveState; if (IsCpuIntel() && HasSAVX()) + { saveStatus = KeSaveExtendedProcessorState(XSTATE_MASK_GSSE, &SaveState); + if (!NT_SUCCESS(saveStatus)) + sha256Begin = sha256_begin_software; + } #endif /* If the key is longer than the hash algorithm block size, let key = sha256(key), as per HMAC specifications. */ @@ -107,7 +121,7 @@ void hmac_sha256 { sha256_ctx tctx; - sha256_begin (&tctx); + SHA256_HMAC_BEGIN (&tctx); sha256_hash (k, lk, &tctx); sha256_end (key, &tctx); @@ -120,7 +134,7 @@ void hmac_sha256 /**** Precompute HMAC Inner Digest ****/ ctx = &(hmac.inner_digest_ctx); - sha256_begin (ctx); + SHA256_HMAC_BEGIN (ctx); /* Pad the key for inner digest */ for (b = 0; b < lk; ++b) @@ -132,7 +146,7 @@ void hmac_sha256 /**** Precompute HMAC Outer Digest ****/ ctx = &(hmac.outer_digest_ctx); - sha256_begin (ctx); + SHA256_HMAC_BEGIN (ctx); for (b = 0; b < lk; ++b) buf[b] = (unsigned char) (k[b] ^ 0x5C); @@ -226,10 +240,15 @@ void derive_key_sha256 (const unsigned char *pwd, int pwd_len, const unsigned ch #ifndef TC_WINDOWS_BOOT unsigned char key[SHA256_DIGESTSIZE]; #if defined (DEVICE_DRIVER) && !defined(_M_ARM64) + void (*sha256Begin)(sha256_ctx*) = sha256_begin; NTSTATUS saveStatus = STATUS_INVALID_PARAMETER; XSTATE_SAVE SaveState; if (IsCpuIntel() && HasSAVX()) + { saveStatus = KeSaveExtendedProcessorState(XSTATE_MASK_GSSE, &SaveState); + if (!NT_SUCCESS(saveStatus)) + sha256Begin = sha256_begin_software; + } #endif /* If the password is longer than the hash algorithm block size, let pwd = sha256(pwd), as per HMAC specifications. */ @@ -237,7 +256,7 @@ void derive_key_sha256 (const unsigned char *pwd, int pwd_len, const unsigned ch { sha256_ctx tctx; - sha256_begin (&tctx); + SHA256_HMAC_BEGIN (&tctx); sha256_hash (pwd, pwd_len, &tctx); sha256_end (key, &tctx); @@ -262,7 +281,7 @@ void derive_key_sha256 (const unsigned char *pwd, int pwd_len, const unsigned ch /**** Precompute HMAC Inner Digest ****/ ctx = &(hmac.inner_digest_ctx); - sha256_begin (ctx); + SHA256_HMAC_BEGIN (ctx); /* Pad the key for inner digest */ for (b = 0; b < pwd_len; ++b) @@ -274,7 +293,7 @@ void derive_key_sha256 (const unsigned char *pwd, int pwd_len, const unsigned ch /**** Precompute HMAC Outer Digest ****/ ctx = &(hmac.outer_digest_ctx); - sha256_begin (ctx); + SHA256_HMAC_BEGIN (ctx); for (b = 0; b < pwd_len; ++b) buf[b] = (unsigned char) (pwd[b] ^ 0x5C); @@ -375,10 +394,15 @@ void hmac_sha512 int b; unsigned char key[SHA512_DIGESTSIZE]; #if defined (DEVICE_DRIVER) && !defined(_M_ARM64) + void (*sha512Begin)(sha512_ctx*) = sha512_begin; NTSTATUS saveStatus = STATUS_INVALID_PARAMETER; XSTATE_SAVE SaveState; if (IsCpuIntel() && HasSAVX()) + { saveStatus = KeSaveExtendedProcessorState(XSTATE_MASK_GSSE, &SaveState); + if (!NT_SUCCESS(saveStatus)) + sha512Begin = sha512_begin_software; + } #endif /* If the key is longer than the hash algorithm block size, @@ -387,7 +411,7 @@ void hmac_sha512 { sha512_ctx tctx; - sha512_begin (&tctx); + SHA512_HMAC_BEGIN (&tctx); sha512_hash (k, lk, &tctx); sha512_end (key, &tctx); @@ -400,7 +424,7 @@ void hmac_sha512 /**** Precompute HMAC Inner Digest ****/ ctx = &(hmac.inner_digest_ctx); - sha512_begin (ctx); + SHA512_HMAC_BEGIN (ctx); /* Pad the key for inner digest */ for (b = 0; b < lk; ++b) @@ -412,7 +436,7 @@ void hmac_sha512 /**** Precompute HMAC Outer Digest ****/ ctx = &(hmac.outer_digest_ctx); - sha512_begin (ctx); + SHA512_HMAC_BEGIN (ctx); for (b = 0; b < lk; ++b) buf[b] = (unsigned char) (k[b] ^ 0x5C); @@ -470,10 +494,15 @@ void derive_key_sha512 (const unsigned char *pwd, int pwd_len, const unsigned ch int b, l, r; unsigned char key[SHA512_DIGESTSIZE]; #if defined (DEVICE_DRIVER) && !defined(_M_ARM64) + void (*sha512Begin)(sha512_ctx*) = sha512_begin; NTSTATUS saveStatus = STATUS_INVALID_PARAMETER; XSTATE_SAVE SaveState; if (IsCpuIntel() && HasSAVX()) + { saveStatus = KeSaveExtendedProcessorState(XSTATE_MASK_GSSE, &SaveState); + if (!NT_SUCCESS(saveStatus)) + sha512Begin = sha512_begin_software; + } #endif /* If the password is longer than the hash algorithm block size, @@ -482,7 +511,7 @@ void derive_key_sha512 (const unsigned char *pwd, int pwd_len, const unsigned ch { sha512_ctx tctx; - sha512_begin (&tctx); + SHA512_HMAC_BEGIN (&tctx); sha512_hash (pwd, pwd_len, &tctx); sha512_end (key, &tctx); @@ -506,7 +535,7 @@ void derive_key_sha512 (const unsigned char *pwd, int pwd_len, const unsigned ch /**** Precompute HMAC Inner Digest ****/ ctx = &(hmac.inner_digest_ctx); - sha512_begin (ctx); + SHA512_HMAC_BEGIN (ctx); /* Pad the key for inner digest */ for (b = 0; b < pwd_len; ++b) @@ -518,7 +547,7 @@ void derive_key_sha512 (const unsigned char *pwd, int pwd_len, const unsigned ch /**** Precompute HMAC Outer Digest ****/ ctx = &(hmac.outer_digest_ctx); - sha512_begin (ctx); + SHA512_HMAC_BEGIN (ctx); for (b = 0; b < pwd_len; ++b) buf[b] = (unsigned char) (pwd[b] ^ 0x5C); @@ -1331,7 +1360,15 @@ int derive_key_argon2(const unsigned char *pwd, int pwd_len, const unsigned char NTSTATUS saveStatus = STATUS_INVALID_PARAMETER; XSTATE_SAVE SaveState; if (HasSAVX2()) + { saveStatus = KeSaveExtendedProcessorState(XSTATE_MASK_GSSE, &SaveState); + if (!NT_SUCCESS(saveStatus)) + { + result = (saveStatus == STATUS_INSUFFICIENT_RESOURCES) + ? ARGON2_MEMORY_ALLOCATION_ERROR : ARGON2_INCORRECT_PARAMETER; + goto err; + } + } #endif result = argon2id_hash_raw( iterations, // number of iterations @@ -1342,6 +1379,9 @@ int derive_key_argon2(const unsigned char *pwd, int pwd_len, const unsigned char dk, dklen,// derived key and its length pAbortKeyDerivation ); +#if defined (DEVICE_DRIVER) && !defined(_M_ARM64) +err: +#endif if (0 != result) { // If the Argon2 derivation fails, ensure unchecked legacy callers cannot use stale data. diff --git a/src/Crypto/Sha2.c b/src/Crypto/Sha2.c index db06a617..7d157acf 100644 --- a/src/Crypto/Sha2.c +++ b/src/Crypto/Sha2.c @@ -251,24 +251,40 @@ void sha512_begin(sha512_ctx* ctx) #endif transfunc = StdTransform; } +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) + ctx->transform = transfunc; +#endif } +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) +void sha512_begin_software(sha512_ctx* ctx) +{ + sha512_begin(ctx); + ctx->transform = StdTransform; +} +#endif + void sha512_end(unsigned char * result, sha512_ctx* ctx) { int i; uint_64t mlen, pos = ctx->count[0]; uint_8t* m = (uint_8t*) ctx->wbuf; +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) + transformFn transform = ctx->transform; +#else + transformFn transform = transfunc; +#endif m[pos++] = 0x80; if (pos > 112) { memset(m + pos, 0, (size_t) (128 - pos)); - transfunc(ctx, m, 1); + transform(ctx, m, 1); pos = 0; } memset(m + pos, 0, (size_t) (128 - pos)); mlen = SHA2_BE64(ctx->count[1]); memcpy(m + (128 - 8), &mlen, 64 / 8); - transfunc(ctx, m, 1); + transform(ctx, m, 1); for (i = 0; i < 8; i++) { ctx->hash[i] = SHA2_BE64(ctx->hash[i]); @@ -281,10 +297,15 @@ void sha512_hash(const unsigned char * data, uint_64t len, sha512_ctx *ctx) uint_64t pos = ctx->count[0]; uint_64t total = ctx->count[1]; uint_8t* m = (uint_8t*) ctx->wbuf; +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) + transformFn transform = ctx->transform; +#else + transformFn transform = transfunc; +#endif if (pos && pos + len >= 128) { memcpy(m + pos, data, (size_t) (128 - pos)); - transfunc(ctx, m, 1); + transform(ctx, m, 1); len -= 128 - pos; total += (128 - pos) * 8; data += 128 - pos; @@ -294,7 +315,7 @@ void sha512_hash(const unsigned char * data, uint_64t len, sha512_ctx *ctx) { uint_64t blocks = len / 128; uint_64t bytes = blocks * 128; - transfunc(ctx, (void*)data, blocks); + transform(ctx, (void*)data, blocks); len -= bytes; total += (bytes)* 8; data += bytes; @@ -853,24 +874,40 @@ void sha256_begin(sha256_ctx* ctx) sha256transfunc = StdSha256Transform; #endif } +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) + ctx->transform = sha256transfunc; +#endif } +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) +void sha256_begin_software(sha256_ctx* ctx) +{ + sha256_begin(ctx); + ctx->transform = StdSha256Transform; +} +#endif + void sha256_end(unsigned char * result, sha256_ctx* ctx) { int i; uint_64t mlen, pos = ctx->count[0]; uint_8t* m = (uint_8t*) ctx->wbuf; +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) + sha256transformFn transform = ctx->transform; +#else + sha256transformFn transform = sha256transfunc; +#endif m[pos++] = 0x80; if (pos > 56) { memset(m + pos, 0, (size_t) (64 - pos)); - sha256transfunc(ctx, m, 1); + transform(ctx, m, 1); pos = 0; } memset(m + pos, 0, (size_t) (56 - pos)); mlen = SHA2_BE64((uint_64t) ctx->count[1]); memcpy(m + (64 - 8), &mlen, 64 / 8); - sha256transfunc(ctx, m, 1); + transform(ctx, m, 1); for (i = 0; i < 8; i++) { ctx->hash[i] = SHA2_BE32(ctx->hash[i]); @@ -883,10 +920,15 @@ void sha256_hash(const unsigned char * data, uint_32t len, sha256_ctx *ctx) uint_32t pos = ctx->count[0]; uint_32t total = ctx->count[1]; uint_8t* m = (uint_8t*) ctx->wbuf; +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) + sha256transformFn transform = ctx->transform; +#else + sha256transformFn transform = sha256transfunc; +#endif if (pos && pos + len >= 64) { memcpy(m + pos, data, 64 - pos); - sha256transfunc(ctx, m, 1); + transform(ctx, m, 1); len -= 64 - pos; total += (64 - pos) * 8; data += 64 - pos; @@ -896,7 +938,7 @@ void sha256_hash(const unsigned char * data, uint_32t len, sha256_ctx *ctx) { uint_32t blocks = len / 64; uint_32t bytes = blocks * 64; - sha256transfunc(ctx, (void*)data, blocks); + transform(ctx, (void*)data, blocks); len -= bytes; total += (bytes)* 8; data += bytes; diff --git a/src/Crypto/Sha2.h b/src/Crypto/Sha2.h index d1a21d91..6621bce2 100644 --- a/src/Crypto/Sha2.h +++ b/src/Crypto/Sha2.h @@ -39,14 +39,20 @@ extern "C" { typedef struct wc_Sha512 sha512_ctx; typedef struct wc_Sha256 sha256_ctx; #else -typedef struct +typedef struct sha512_ctx { uint_64t count[2]; +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) + void (*transform)(struct sha512_ctx*, void*, uint_64t); +#endif SHA2_ALIGN uint_64t hash[8]; SHA2_ALIGN uint_64t wbuf[16]; } sha512_ctx; -typedef struct +typedef struct sha256_ctx { uint_32t count[2]; +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) + void (*transform)(struct sha256_ctx*, void*, uint_64t); +#endif SHA2_ALIGN uint_32t hash[8]; SHA2_ALIGN uint_32t wbuf[16]; } sha256_ctx; @@ -63,6 +69,12 @@ void sha256_hash(const unsigned char * source, uint_32t sourceLen, sha256_ctx *c void sha256_end(unsigned char * result, sha256_ctx* ctx); void sha256(unsigned char * result, const unsigned char* source, uint_32t sourceLen); +#if defined(DEVICE_DRIVER) && !defined(_M_ARM64) +/* Per-context fallback when the driver cannot save extended processor state. */ +void sha512_begin_software(sha512_ctx* ctx); +void sha256_begin_software(sha256_ctx* ctx); +#endif + #if defined(__cplusplus) } #endif