Смягчение проблем безопасности потоков RsaCryptoServiceProvider на веб-сервере - PullRequest
4 голосов
/ 26 мая 2011

У меня есть экземпляр X509Certificate2, и я получаю его свойство PrivateKey, которое является RsaCryptoServiceProvider. MSDN документирует, что этот класс RsaCryptoServiceProvider является не поточно-ориентированным. Поэтому, если мне предоставлен сертификат X.509, мне нужно выполнить асимметричное шифрование в нескольких потоках (обычно на веб-сервере), каков наилучший способ создания нескольких экземпляров RsaCryptoServiceProvider?

Закрытый ключ на X509Certificate2 не помечен как экспортируемый, поэтому я не могу просто экспортировать параметры на исходном RsaCryptoServiceProvider и повторно импортировать их в другой экземпляр, чтобы обойти проблемы безопасности потока.

Я получил оригинал через X509Store, но, похоже, это набор X509Certificate2 экземпляров, таких, что, если я хочу новый экземпляр RsaCryptoServiceProvider, мне нужно создать экземпляр new X509Store чтобы найти новый X509Certificate2, чтобы получить новый RsaCryptoServiceProvider. Просто кажется очень тяжеловесным просто заставить .NET клонировать экземпляр RsaCryptoServiceProvider.

Есть ли лучшие способы?

1 Ответ

2 голосов
/ 27 мая 2011

Может показаться, что 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);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...