Mitigating RsaCryptoServiceProvider Security Issues on a Web Server

I have an instance of X509Certificate2 and get its PrivateKey property, which is RsaCryptoServiceProvider . MSDN that this RsaCryptoServiceProvider class RsaCryptoServiceProvider not thread safe. Therefore, if you are given some kind of X.509 evidence, I need to perform asymmetric encryption on multiple threads (typically on a web server), what is the best way to create multiple instances of RsaCryptoServiceProvider ?

The X509Certificate2 private key X509Certificate2 not marked as exportable, so I can’t just export the parameters on the source RsaCryptoServiceProvider and re-import them into another instance to bypass thread safety issues.

I got the original through the X509Store , but this seems to be a collection of X509Certificate2 instances, so if I want a new RsaCryptoServiceProvider instance, I need to create a new X509Store to find the new X509Certificate2 to get the new RsaCryptoServiceProvider . It just seems awfully hard to just force .NET to clone an instance of RsaCryptoServiceProvider .

Are there any better ways?

+3
source share
1 answer

It would seem that RsaCryptoServiceProvider , although its MSDN documentation is not thread safe, is thread safe enough to encrypt / decrypt multiple streams at once. I wrote the following application for testing high concurrency using this class, and it did not crash or was unable to fully encrypt / decrypt:

 using System; using System.Diagnostics; using System.Linq; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Threading; namespace ConsoleApplication1 { class Program { static bool exit; static void Main(string[] args) { var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); try { store.Open(OpenFlags.OpenExistingOnly); Func<RSACryptoServiceProvider> rsaFactory = null; X509Certificate2 winningCert = null; exit = true; foreach (X509Certificate2 cert in store.Certificates) { try { var result = store.Certificates.Find(X509FindType.FindByThumbprint, cert.Thumbprint, false).Cast<X509Certificate2>().FirstOrDefault(); rsaFactory = () => (RSACryptoServiceProvider)result.PrivateKey; UseRsa(rsaFactory()); winningCert = cert; break; } catch (CryptographicException) { Console.WriteLine("Cert {0} failed", cert.Thumbprint); } } exit = false; Console.WriteLine("Winning cert: {0}", winningCert.Thumbprint); RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)winningCert.PrivateKey; rsaFactory = () => rsa; Thread[] threads = new Thread[16]; for (int i = 0; i < threads.Length; i++) { threads[i] = new Thread(state => UseRsa(rsaFactory())); threads[i].Start(); } Thread.Sleep(10000); exit = true; for (int i = 0; i < threads.Length; i++) { threads[i].Join(); } Console.WriteLine("Success."); } finally { store.Close(); } } static void UseRsa(RSACryptoServiceProvider rsa) { var rng = RandomNumberGenerator.Create(); var buffer = new byte[64]; do { rng.GetBytes(buffer); var cipher = rsa.Encrypt(buffer, true); var plaintext = rsa.Decrypt(cipher, true); for (int i = 0; i < buffer.Length; i++) { if (buffer[i] != plaintext[i]) { Debugger.Break(); } } } while (!exit); } } } 
+1
source

Source: https://habr.com/ru/post/1480467/


All Articles