[PATCH 1/2] bcrypt: Synchronize symmetric key access for encrypt and decrypt.
Paul Gofman
pgofman at codeweavers.com
Tue Apr 20 05:48:46 CDT 2021
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
Forza Horizon 4 crashes during entering multiplayer mode due to BCryptEncrypt and
BCryptDecrypt being used from different threads with the same key using MODE_ID_GCM.
Most of the time that is either glinc free() assertion or segfault inside gnutls function.
While bcrypt functions are probably not thread safe in general on Windows, I suppose
the native implementation does not modify any key data in encrypt and decrypt
in this mode.
dlls/bcrypt/bcrypt_internal.h | 1 +
dlls/bcrypt/bcrypt_main.c | 16 ++++++++++++++--
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h
index eb136111509..efa1a463489 100644
--- a/dlls/bcrypt/bcrypt_internal.h
+++ b/dlls/bcrypt/bcrypt_internal.h
@@ -164,6 +164,7 @@ struct key_symmetric
ULONG vector_len;
UCHAR *secret;
ULONG secret_len;
+ CRITICAL_SECTION cs;
};
#define KEY_FLAG_LEGACY_DSA_V2 0x00000001
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index a1423dcd836..2ef26e81291 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -1480,6 +1480,7 @@ NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_
if (!(block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
+ InitializeCriticalSection( &key->u.s.cs );
key->hdr.magic = MAGIC_KEY;
key->alg_id = alg->id;
key->u.s.mode = alg->mode;
@@ -1588,6 +1589,8 @@ static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
key_copy->u.s.block_size = key_orig->u.s.block_size;
key_copy->u.s.secret = buffer;
key_copy->u.s.secret_len = key_orig->u.s.secret_len;
+
+ InitializeCriticalSection( &key_copy->u.s.cs );
}
else
{
@@ -1613,6 +1616,7 @@ static void key_destroy( struct key *key )
key_funcs->key_symmetric_destroy( key );
heap_free( key->u.s.vector );
heap_free( key->u.s.secret );
+ DeleteCriticalSection( &key->u.s.cs );
}
else
{
@@ -1714,6 +1718,7 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags )
{
struct key *key = handle;
+ NTSTATUS ret;
TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len, padding, iv, iv_len, output,
output_len, ret_len, flags );
@@ -1730,13 +1735,17 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
return STATUS_NOT_IMPLEMENTED;
}
- return key_encrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags );
+ EnterCriticalSection( &key->u.s.cs );
+ ret = key_encrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags );
+ LeaveCriticalSection( &key->u.s.cs );
+ return ret;
}
NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv,
ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags )
{
struct key *key = handle;
+ NTSTATUS ret;
TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len, padding, iv, iv_len, output,
output_len, ret_len, flags );
@@ -1753,7 +1762,10 @@ NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
return STATUS_NOT_IMPLEMENTED;
}
- return key_decrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags );
+ EnterCriticalSection( &key->u.s.cs );
+ ret = key_decrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags );
+ LeaveCriticalSection( &key->u.s.cs );
+ return ret;
}
NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
--
2.30.2
More information about the wine-devel
mailing list