3
3
4
4
using System ;
5
5
using System . Diagnostics ;
6
+ using System . Threading ;
6
7
using Microsoft . Win32 . SafeHandles ;
7
8
using BCryptCreateHashFlags = Interop . BCrypt . BCryptCreateHashFlags ;
8
9
using BCryptOpenAlgorithmProviderFlags = Interop . BCrypt . BCryptOpenAlgorithmProviderFlags ;
@@ -63,47 +64,57 @@ internal HashProviderCng(string hashAlgId, ReadOnlySpan<byte> key, bool isHmac)
63
64
public sealed override unsafe void AppendHashData ( ReadOnlySpan < byte > source )
64
65
{
65
66
Debug . Assert ( _hHash != null ) ;
66
- NTSTATUS ntStatus = Interop . BCrypt . BCryptHashData ( _hHash , source , source . Length , 0 ) ;
67
- if ( ntStatus != NTSTATUS . STATUS_SUCCESS )
67
+
68
+ using ( ConcurrencyBlock . Enter ( ref _block ) )
68
69
{
69
- throw Interop . BCrypt . CreateCryptographicException ( ntStatus ) ;
70
- }
70
+ NTSTATUS ntStatus = Interop . BCrypt . BCryptHashData ( _hHash , source , source . Length , 0 ) ;
71
+ if ( ntStatus != NTSTATUS . STATUS_SUCCESS )
72
+ {
73
+ throw Interop . BCrypt . CreateCryptographicException ( ntStatus ) ;
74
+ }
71
75
72
- _running = true ;
76
+ _running = true ;
77
+ }
73
78
}
74
79
75
80
public override int FinalizeHashAndReset ( Span < byte > destination )
76
81
{
77
82
Debug . Assert ( destination . Length >= _hashSize ) ;
78
-
79
83
Debug . Assert ( _hHash != null ) ;
80
- NTSTATUS ntStatus = Interop . BCrypt . BCryptFinishHash ( _hHash , destination , _hashSize , 0 ) ;
81
- if ( ntStatus != NTSTATUS . STATUS_SUCCESS )
84
+
85
+ using ( ConcurrencyBlock . Enter ( ref _block ) )
82
86
{
83
- throw Interop . BCrypt . CreateCryptographicException ( ntStatus ) ;
84
- }
87
+ NTSTATUS ntStatus = Interop . BCrypt . BCryptFinishHash ( _hHash , destination , _hashSize , 0 ) ;
88
+
89
+ if ( ntStatus != NTSTATUS . STATUS_SUCCESS )
90
+ {
91
+ throw Interop . BCrypt . CreateCryptographicException ( ntStatus ) ;
92
+ }
85
93
86
- _running = false ;
87
- Reset ( ) ;
88
- return _hashSize ;
94
+ _running = false ;
95
+ Reset ( ) ;
96
+ return _hashSize ;
97
+ }
89
98
}
90
99
91
100
public override int GetCurrentHash ( Span < byte > destination )
92
101
{
93
102
Debug . Assert ( destination . Length >= _hashSize ) ;
94
-
95
103
Debug . Assert ( _hHash != null ) ;
96
104
97
- using ( SafeBCryptHashHandle tmpHash = Interop . BCrypt . BCryptDuplicateHash ( _hHash ) )
105
+ using ( ConcurrencyBlock . Enter ( ref _block ) )
98
106
{
99
- NTSTATUS ntStatus = Interop . BCrypt . BCryptFinishHash ( tmpHash , destination , _hashSize , 0 ) ;
100
-
101
- if ( ntStatus != NTSTATUS . STATUS_SUCCESS )
107
+ using ( SafeBCryptHashHandle tmpHash = Interop . BCrypt . BCryptDuplicateHash ( _hHash ) )
102
108
{
103
- throw Interop . BCrypt . CreateCryptographicException ( ntStatus ) ;
104
- }
109
+ NTSTATUS ntStatus = Interop . BCrypt . BCryptFinishHash ( tmpHash , destination , _hashSize , 0 ) ;
105
110
106
- return _hashSize ;
111
+ if ( ntStatus != NTSTATUS . STATUS_SUCCESS )
112
+ {
113
+ throw Interop . BCrypt . CreateCryptographicException ( ntStatus ) ;
114
+ }
115
+
116
+ return _hashSize ;
117
+ }
107
118
}
108
119
}
109
120
@@ -125,21 +136,27 @@ public sealed override void Dispose(bool disposing)
125
136
126
137
public override void Reset ( )
127
138
{
139
+ // Reset does not need to use ConcurrencyBlock. It either no-ops, or creates an entirely new handle, exchanges
140
+ // them, and disposes of the old handle. We don't need to block concurrency on the Dispose because SafeHandle
141
+ // does that.
128
142
if ( _reusable && ! _running )
129
143
return ;
130
144
131
- DestroyHash ( ) ;
132
-
133
145
BCryptCreateHashFlags flags = _reusable ?
134
146
BCryptCreateHashFlags . BCRYPT_HASH_REUSABLE_FLAG :
135
147
BCryptCreateHashFlags . None ;
136
148
137
149
SafeBCryptHashHandle hHash ;
138
150
NTSTATUS ntStatus = Interop . BCrypt . BCryptCreateHash ( _hAlgorithm , out hHash , IntPtr . Zero , 0 , _key , _key == null ? 0 : _key . Length , flags ) ;
151
+
139
152
if ( ntStatus != NTSTATUS . STATUS_SUCCESS )
153
+ {
154
+ hHash . Dispose ( ) ;
140
155
throw Interop . BCrypt . CreateCryptographicException ( ntStatus ) ;
156
+ }
141
157
142
- _hHash = hHash ;
158
+ SafeBCryptHashHandle ? previousHash = Interlocked . Exchange ( ref _hHash , hHash ) ;
159
+ previousHash ? . Dispose ( ) ;
143
160
}
144
161
145
162
private void DestroyHash ( )
@@ -161,5 +178,6 @@ private void DestroyHash()
161
178
162
179
private readonly int _hashSize ;
163
180
private bool _running ;
181
+ private ConcurrencyBlock _block ;
164
182
}
165
183
}
0 commit comments