Как использовать шифрование Rijndael с библиотекой классов .Net Core? (Не .NET Framework)

Как мы используем шифрование Rijndael в библиотеке классов .Net Core? (Не библиотека классов .Net Framework) Нам нужно создать общую библиотеку .Net Core для использования в нескольких проектах и ​​реализовать методы шифрования и дешифрования, которые используют одно и то же шифрование Rijndael для всех проектов.

В настоящее время мы используем:

  • VS Enterprise 2015
  • С#
  • .Net Core Class Library
  • Ссылка .NETStandard, Version = v1.6

Похоже, что реализация Rijndael и AES отсутствует в выпуске .Net Core 1.0... похоже, только включает базовые классы. Как мы можем получить .NET-версию Rijndael или AES-шифрования, добавленную в качестве ссылки на новый проект библиотеки .NET Core Class?

Вот метод шифрования, который работает в .NET Framework 4.5.2:

    public static string Encrypt(string valueToEncrypt, string symmetricKey, string initializationVector)
    {
        string returnValue = valueToEncrypt;

        var aes = new System.Security.Cryptography.RijndaelManaged();
        try
        {
            aes.Key = ASCIIEncoding.ASCII.GetBytes(symmetricKey);
            aes.IV = ASCIIEncoding.ASCII.GetBytes(initializationVector);
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.ISO10126;

            var desEncrypter = aes.CreateEncryptor();
            var buffer = ASCIIEncoding.ASCII.GetBytes(valueToEncrypt);

            returnValue = Convert.ToBase64String(desEncrypter.TransformFinalBlock(buffer, 0, buffer.Length));
        }
        catch (Exception)
        {
            returnValue = string.Empty;
        }

        return returnValue;
    }

Ответ 1

Разница (в .NET) между Rijndael и AES заключается в том, что Rijndael позволяет изменять размер блока, но AES этого не делает. Поскольку размер блока RijndaelManaged по умолчанию совпадает с размером блока AES (128 бит /16 байт), вы фактически используете AES.

Вместо создания экземпляра типа реализации по имени просто используйте factory (Aes.Create()). Это работает как в .NET Core, так и в .NET Framework.

Другие вещи, о которых стоит упомянуть:

  • Все экземпляры SymmetricAlgorithm являются IDisposable, вы должны использовать их в инструкции using.
  • Все экземпляры ICryptoTransform (например, неверно названные desEncryptor) являются IDisposable, вы должны использовать их в инструкции using.
  • Отступ по ISO10126 недоступен в .NET Core 1.0. Если вам нужно быть совместимым с существующими потоками, вы можете применить дополнение и указать PaddingMode.None. В противном случае PKCS7 является более стандартным.
  • Ваш ключ AES не очень случайный, поскольку он исходит из строки ASCII (много значений не будут действительными).
    • Base64 по крайней мере имеет полный диапазон значений
    • PBKDF2 (функция деривации ключа на основе пароля 2) с помощью класса Rfc2898DeriveBytes допускает разделяемую секвенцию, предсказуемый шум.
    • KeyAgreement в целом лучше, но ни ECDH, ни классический DH не доступны в .NET Core 1.0.
  • Обычно шифр должен вычислять случайный IV (вызов aes.GenerateIV() при использовании одного и того же объекта для нескольких операций) и представить его зашифрованным текстом. Таким образом, шифрование принимает ключ и открытый текст и создает шифрованный текст и IV. Decrypt принимает (ключ, IV, зашифрованный текст) и создает открытый текст.

Ответ 2

Если вы просто хотите зашифровать/дешифровать материал, не используйте Rijndael напрямую, так как ядро ​​asp.net имеет гораздо более приятные оболочки, которые намного проще в использовании и, скорее всего, будут правильно защищены по умолчанию. Он известен как DataProtection.

using Microsoft.AspNetCore.DataProtection;

// During startup add DP
serviceCollection.AddDataProtection();

...

// the 'provider' parameter is provided by DI
public MyClass(IDataProtectionProvider provider)
{
    _protector = provider.CreateProtector("Contoso.MyClass.v1");
}

...

// protect the payload
string protectedPayload = _protector.Protect(input);
Console.WriteLine($"Protect returned: {protectedPayload}");

...

// unprotect the payload
string unprotectedPayload = _protector.Unprotect(protectedPayload);
Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

Подробнее см. документы для защиты данных.