【问题标题】:Mitigating RsaCryptoServiceProvider thread safety issues on a web server缓解 Web 服务器上的 RsaCryptoServiceProvider 线程安全问题
【发布时间】:2011-05-27 09:30:20
【问题描述】:

我有一个X509Certificate2 实例,并获取它的PrivateKey 属性,即RsaCryptoServiceProvider。 MSDN 记录了这个 RsaCryptoServiceProvider 类是 not 线程安全的。因此,如果给定一些 X.509 证书,我需要在多个线程上执行非对称加密(通常在 Web 服务器上),创建RsaCryptoServiceProvider 的多个实例的最佳方法是什么?

X509Certificate2 上的私钥未标记为可导出,因此我不能简单地导出原始 RsaCryptoServiceProvider 上的参数并将它们重新导入另一个实例以解决线程安全问题。

我通过X509Store 获得了原始文件,但这似乎是X509Certificate2 实例的集合,因此如果我想要RsaCryptoServiceProvider 的新实例,我必须实例化一个new X509Store 找到一个 X509Certificate2,获得一个 RsaCryptoServiceProvider。让 .NET 克隆 RsaCryptoServiceProvider 实例似乎非常重要。

有没有更好的方法?

【问题讨论】:

    标签: asp.net security azure thread-safety x509certificate2


    【解决方案1】:

    看起来RsaCryptoServiceProvider,尽管它的 MSDN 文档声明它不是线程安全的,但它的线程安全性足以同时在多个线程上加密/解密。我使用这个类编写了以下应用程序来测试高并发,它根本没有崩溃或无法正确加密/解密:

    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);
            }
        }
    }
    

    【讨论】:

    • 我认为它起作用的原因是 X509Certificate2.PrivateKey 和 X509Certificate2.PublicKey.Key 在每次调用时都会创建新的 RSACryptoServiceProvider 实例。
    猜你喜欢
    • 1970-01-01
    • 2012-03-13
    • 2011-03-24
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多