@@ -144,36 +144,32 @@ private static void ValidateNonEmptyKeyPath([NotNull] string? masterKeyPath, boo
144
144
private static RSACng CreateRSACngProvider ( string keyPath , bool isSystemOp )
145
145
{
146
146
// Get CNGProvider and the KeyID
147
- GetCngProviderAndKeyId ( keyPath , isSystemOp , out string cngProviderName , out string keyIdentifier ) ;
148
-
149
- CngProvider cngProvider = new ( cngProviderName ) ;
150
- CngKey cngKey ;
147
+ GetCngProviderAndKeyId ( keyPath , isSystemOp , out CngProvider cngProvider , out string keyIdentifier ) ;
151
148
152
149
try
153
150
{
154
- cngKey = CngKey . Open ( keyIdentifier , cngProvider ) ;
151
+ using CngKey cngKey = CngKey . Open ( keyIdentifier , cngProvider ) ;
152
+
153
+ // The RSACng constructor copies the input CngKey, so it is safe to dispose the original.
154
+ return new RSACng ( cngKey ) ;
155
155
}
156
156
catch ( CryptographicException )
157
157
{
158
- throw SQL . InvalidCngKey ( keyPath , cngProviderName , keyIdentifier , isSystemOp ) ;
159
- }
160
-
161
- using ( cngKey )
162
- {
163
- return new RSACng ( cngKey ) ;
158
+ throw SQL . InvalidCngKey ( keyPath , cngProvider . Provider , keyIdentifier , isSystemOp ) ;
164
159
}
165
160
}
166
161
167
162
/// <summary>
168
- /// Extracts the CNG provider name and key name from the given key path.
163
+ /// Extracts the CNG provider and key name from the given key path.
169
164
/// </summary>
170
165
/// <param name="keyPath">Key path in the format [CNG provider name]/[key name].</param>
171
166
/// <param name="isSystemOp">Indicates if ADO.NET calls or the customer calls the API.</param>
172
- /// <param name="cngProvider">CNG provider name .</param>
167
+ /// <param name="cngProvider">CNG provider.</param>
173
168
/// <param name="keyIdentifier">Key name inside the CNG provider.</param>
174
- private static void GetCngProviderAndKeyId ( string keyPath , bool isSystemOp , out string cngProvider , out string keyIdentifier )
169
+ private static void GetCngProviderAndKeyId ( string keyPath , bool isSystemOp , out CngProvider cngProvider , out string keyIdentifier )
175
170
{
176
- int indexOfSlash = keyPath . IndexOf ( '/' ) ;
171
+ ReadOnlySpan < char > keyPathSpan = keyPath . AsSpan ( ) ;
172
+ int indexOfSlash = keyPathSpan . IndexOf ( '/' ) ;
177
173
178
174
if ( indexOfSlash == - 1 )
179
175
{
@@ -188,7 +184,28 @@ private static void GetCngProviderAndKeyId(string keyPath, bool isSystemOp, out
188
184
throw SQL . EmptyCngKeyId ( keyPath , isSystemOp ) ;
189
185
}
190
186
191
- cngProvider = keyPath . Substring ( 0 , indexOfSlash ) ;
187
+ ReadOnlySpan < char > cngProviderName = keyPathSpan . Slice ( 0 , indexOfSlash ) ;
188
+
189
+ // If the provider is one of the well-known providers, use the static instance instead of allocating a new string and CngProvider.
190
+ if ( cngProviderName . Equals ( CngProvider . MicrosoftSoftwareKeyStorageProvider . Provider . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) )
191
+ {
192
+ cngProvider = CngProvider . MicrosoftSoftwareKeyStorageProvider ;
193
+ }
194
+ else if ( cngProviderName . Equals ( CngProvider . MicrosoftSmartCardKeyStorageProvider . Provider . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) )
195
+ {
196
+ cngProvider = CngProvider . MicrosoftSmartCardKeyStorageProvider ;
197
+ }
198
+ #if NET
199
+ else if ( cngProviderName . Equals ( CngProvider . MicrosoftPlatformCryptoProvider . Provider . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) )
200
+ {
201
+ cngProvider = CngProvider . MicrosoftPlatformCryptoProvider ;
202
+ }
203
+ #endif
204
+ else
205
+ {
206
+ cngProvider = new ( cngProviderName . ToString ( ) ) ;
207
+ }
208
+
192
209
keyIdentifier = keyPath . Substring ( indexOfSlash + 1 ) ;
193
210
}
194
211
}
0 commit comments