Signed-off-by: Paul Gofman pgofman@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 )