Skip to content

Commit 3152361

Browse files
committed
Initial code review
Simplify CreateRSACngProvider. Use static CngProvider instances for well-known providers where possible.
1 parent 127960b commit 3152361

File tree

1 file changed

+33
-16
lines changed

1 file changed

+33
-16
lines changed

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlColumnEncryptionCngProvider.Windows.cs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -144,36 +144,32 @@ private static void ValidateNonEmptyKeyPath([NotNull] string? masterKeyPath, boo
144144
private static RSACng CreateRSACngProvider(string keyPath, bool isSystemOp)
145145
{
146146
// 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);
151148

152149
try
153150
{
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);
155155
}
156156
catch (CryptographicException)
157157
{
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);
164159
}
165160
}
166161

167162
/// <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.
169164
/// </summary>
170165
/// <param name="keyPath">Key path in the format [CNG provider name]/[key name].</param>
171166
/// <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>
173168
/// <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)
175170
{
176-
int indexOfSlash = keyPath.IndexOf('/');
171+
ReadOnlySpan<char> keyPathSpan = keyPath.AsSpan();
172+
int indexOfSlash = keyPathSpan.IndexOf('/');
177173

178174
if (indexOfSlash == -1)
179175
{
@@ -188,7 +184,28 @@ private static void GetCngProviderAndKeyId(string keyPath, bool isSystemOp, out
188184
throw SQL.EmptyCngKeyId(keyPath, isSystemOp);
189185
}
190186

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+
192209
keyIdentifier = keyPath.Substring(indexOfSlash + 1);
193210
}
194211
}

0 commit comments

Comments
 (0)