Подтвердить что ты не робот

Безопасность потоков .NET классов шифрования?

У меня есть цель высокого уровня создания класса static, который инкапсулирует шифрование для моего .NET-приложения. Внутри я хотел бы свести к минимуму создание объектов, которые не нужны.

Мой вопрос: Какова безопасность потоков для классов, которые реализуют симметричное шифрование в .NET Framework? В частности, создаются типы System.Security.Cryptography.RijndaelManaged и ICryptoTransform.

Например, в моем конструкторе классов я могу просто сделать что-то в следующих строках?

static MyUtility()
{
    using (RijndaelManaged rm = new RijndaelManaged())
    {
        MyUtility.EncryptorTransform = rm.CreateEncryptor(MyUtility.MyKey, MyUtility.MyIV);
        MyUtility.DecryptorTransform = rm.CreateDecryptor(MyUtility.MyKey, MyUtility.MyIV);
    }
}

Пошаговое решение проблемы заключается в том, что безопасно иметь ключ и IV в этом классе, этот блок примеров вызывает ряд других вопросов:

  • Можно ли повторно использовать EncryptorTransform и DecryptorTransform снова и снова? Свойства *.CanReuseTransform и *.CanTransformMultipleBlocks подразумевают "да", но есть ли какие-либо оговорки, о которых я должен знать?

  • Так как RijndaelManaged реализует IDisposable, мой наклон заключается в том, чтобы поместить его в блок using, особенно потому, что он, вероятно, связан с внешними lib файлами на уровне ОС. Есть ли какие-либо оговорки в этом, поскольку я поддерживаю объекты ICryptoTransform?

  • Потенциально самый важный вопрос в многопотоковой среде я столкнулся с проблемами при совместном использовании объектов ICryptoTransform между потоками?

  • Если ответ на №3 заключается в том, что он не является потокобезопасным, будет ли я испытывать серьезную деградацию производительности от блокировки, когда я использую объекты ICryptoTransform? (Зависит от нагрузки, я полагаю.)

  • Было бы более сложно просто создавать новые RijndaelManaged каждый раз? Или сохранить один RijndaelManaged и генерировать new RijndaelManaged().CreateEncryptor(...) каждый раз?

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

Спасибо!

4b9b3361

Ответ 1

1) Да.

2) Вы избавляетесь от него, вы не можете его использовать. До этого момента вы можете использовать/использовать его (но см. Ниже).

3-4) Из MSDN:

"Любые публичные статические (Shared in Visual Basic) члены этого типа являются потокобезопасными. Любые члены экземпляра не гарантируют безопасность потоков."

Если вы хотите сохранить это и поделиться им между потоками, вам нужно будет реализовать блокировку и рассматривать ее как заблокированный ресурс. В противном случае я бы рекомендовал просто делать отдельные версии по мере необходимости и избавляться от них, когда вы закончите.

5) Я бы рекомендовал создать их по мере необходимости, а затем попытаться оптимизировать его, если позже вы обнаружите, что у вас есть проблемы с производительностью. Не беспокойтесь о влиянии производительности на создание новой версии, пока не увидите, что ее проблема после профилирования.

Ответ 2

Можно решить проблему concurrency просто с кешем на основе параллельного стека:

static ConcurrentStack<ICryptoTransform> decryptors = new ConcurrentStack<ICryptoTransform>();

void Encrypt()
{
   // Pop decryptor from cache...
   ICryptoTransform decryptor;
   if (!decryptors.TryPop(out decryptor))
   {
       // ... or create a new one since cache is depleted
       AesManaged aes = new AesManaged();
       aes.Key = key;
       aes.IV = iv;
       decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
    }

    try
    {
       //// use decryptor
    }
    finally
    {
       decryptors.Push(decryptor);
    }
 }