Модель шифрования .NET

.NET предоставляет реализации многих стандартных алгоритмов шифрования.

Наследование объектов

Система шифрования .NET реализует расширяемый шаблон наследования производного класса. Иерархия имеет представленный ниже вид.

  • Класс типа алгоритма, например SymmetricAlgorithm, AsymmetricAlgorithmили HashAlgorithm. Этот уровень является абстрактным.

  • Класс алгоритма, наследующий от класса типа алгоритма, например, AesRSAили ECDiffieHellman. Этот уровень является абстрактным.

  • Реализация класса алгоритма, наследуемого от класса алгоритма, например, AesManagedRC2CryptoServiceProviderили ECDiffieHellmanCng. Этот уровень полностью реализован.

Этот шаблон производных классов позволяет добавить новый алгоритм или новую реализацию существующего алгоритма. Например, чтобы создать новый алгоритм открытого ключа, можно наследовать от класса AsymmetricAlgorithm. Чтобы создать новую реализацию определенного алгоритма, можно создать неабстрактный производный класс этого алгоритма.

В будущем эта модель наследования не используется для новых типов примитивов, таких как AesGcm или Shake128. Эти алгоритмы являются sealed. Если вам нужен шаблон расширяемости или абстракция по этим типам, реализация абстракции является ответственностью разработчика.

Интерфейсы API с одним выстрелом

Начиная с .NET 5, более простые API были представлены для хэширования и HMAC. Хотя немного менее гибкие, эти однозастрелные API:

  • Проще использовать (и менее подвержены неправильному использованию)
  • Сокращение выделения или свободное выделение
  • Являются потокобезопасны
  • Использование оптимальной реализации для платформы

Хэширование и примитивы HMAC предоставляют однократный API через статический HashData метод типа, например SHA256.HashData. Статические API не предлагают встроенный механизм расширяемости. Если вы реализуете собственные алгоритмы, рекомендуется также предложить аналогичные статические API алгоритма.

Класс RandomNumberGenerator также предлагает статические методы для создания или заполнения буферов с криптографическими случайными данными. Эти методы всегда используют криптографически безопасный генератор чисел псевдорандома (CSPRNG).

Как реализованы алгоритмы в .NET

В качестве примера различных реализаций, доступных для алгоритма, рассмотрим симметричные алгоритмы. Основой для всех симметричного алгоритма является SymmetricAlgorithm, который наследуется Aes, TripleDESи другие, которые больше не рекомендуется.

Aesнаследуется , AesCryptoServiceProviderAesCngи AesManaged.

В платформа .NET Framework в Windows:

  • *CryptoServiceProvider Классы алгоритмов, например AesCryptoServiceProvider, являются оболочками вокруг реализации API шифрования Windows (CAPI) алгоритма.
  • *Cng классы алгоритмов, такие как ECDiffieHellmanCngоболочки вокруг реализации Windows Cryptography Next Generation (CNG).
  • *Managed классы, такие как AesManaged, полностью написаны в управляемом коде. *Managedреализации не сертифицированы федеральными стандартами обработки информации (FIPS) и могут быть медленнее, чем *CryptoServiceProvider классы-оболочки.*Cng

В .NET Core и .NET 5 и более поздних версиях все классы реализации (*CryptoServiceProvider, *Managedи *Cng) являются оболочками для алгоритмов операционной системы (ОС). Если алгоритмы ОС сертифицированы по протоколу FIPS, то .NET использует сертифицированные по FIPS алгоритмы. Дополнительные сведения см. в разделе "Кроссплатформенная криптография".

В большинстве случаев вам не нужно напрямую ссылаться на класс реализации алгоритма, например AesCryptoServiceProvider. Методы и свойства, которые обычно требуются, находятся в базовом классе алгоритма, например Aes. Создайте экземпляр класса реализации по умолчанию с помощью метода фабрики в базовом классе алгоритма и обратитесь к базовому классу алгоритма. Например, см. выделенную строку кода в следующем примере:

using System.Security.Cryptography;

try
{
    using (FileStream fileStream = new("TestData.txt", FileMode.OpenOrCreate))
    {
        using (Aes aes = Aes.Create())
        {
            byte[] key =
            {
                0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
                0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16
            };
            aes.Key = key;

            byte[] iv = aes.IV;
            fileStream.Write(iv, 0, iv.Length);

            using (CryptoStream cryptoStream = new(
                fileStream,
                aes.CreateEncryptor(),
                CryptoStreamMode.Write))
            {
                // By default, the StreamWriter uses UTF-8 encoding.
                // To change the text encoding, pass the desired encoding as the second parameter.
                // For example, new StreamWriter(cryptoStream, Encoding.Unicode).
                using (StreamWriter encryptWriter = new(cryptoStream))
                {
                    encryptWriter.WriteLine("Hello World!");
                }
            }
        }
    }

    Console.WriteLine("The file was encrypted.");
}
catch (Exception ex)
{
    Console.WriteLine($"The encryption failed. {ex}");
}
Imports System
Imports System.IO
Imports System.Security.Cryptography

Module Module1
    Sub Main()
        Try
            ' Create a file stream
            Using fileStream As New FileStream("TestData.txt", FileMode.OpenOrCreate)

                ' Create a new instance of the default Aes implementation class  
                ' and configure encryption key.
                Using aes As Aes = Aes.Create()
                    'Encryption key used to encrypt the stream.
                    'The same value must be used to encrypt and decrypt the stream.
                    Dim key As Byte() = {
                        &H1, &H2, &H3, &H4, &H5, &H6, &H7, &H8,
                        &H9, &H10, &H11, &H12, &H13, &H14, &H15, &H16
                    }

                    aes.Key = key

                    ' Stores IV at the beginning of the file.
                    ' This information will be used for decryption.
                    Dim iv As Byte() = aes.IV
                    fileStream.Write(iv, 0, iv.Length)

                    ' Create a CryptoStream, pass it the FileStream, and encrypt
                    ' it with the Aes class.
                    Using cryptoStream As New CryptoStream(fileStream, aes.CreateEncryptor(), CryptoStreamMode.Write)

                        ' By default, the StreamWriter uses UTF-8 encoding.
                        ' To change the text encoding, pass the desired encoding as the second parameter.
                        ' For example, New StreamWriter(cryptoStream, Encoding.Unicode).
                        Using sWriter As New StreamWriter(cryptoStream)

                            'Write to the stream.
                            sWriter.WriteLine("Hello World!")
                        End Using
                    End Using
                End Using
            End Using

            'Inform the user that the message was written  
            'to the stream.  
            Console.WriteLine("The text was encrypted.")
        Catch
            'Inform the user that an exception was raised.  
            Console.WriteLine("The encryption failed.")
            Throw
        End Try
    End Sub
End Module

Выбор алгоритма

Алгоритм можно выбирать, исходя из различных причин, например для обеспечения целостности данных, для обеспечения конфиденциальности данных или для создания ключа. Симметричные и хэш-алгоритмы предназначены для защиты данных от нарушения целостности (защита от изменения) или конфиденциальности (защита от просмотра). Хэш-алгоритмы используются в основном для обеспечения целостности данных.

Ниже приведен список рекомендуемых алгоритмов в зависимости от приложения.

См. также