Как правильно реализовать шифрование AES с помощью .net core 2? - PullRequest
0 голосов
/ 16 октября 2019

По какой-то причине меня попросили внедрить некоторое базовое шифрование для защиты определенного значения, передаваемого клиенту (в зависимости от клиента).

Контекст такой: мы являемся теми, кто генерирует зашифрованныеключ, мы передаем этот зашифрованный ключ клиенту, и клиенту никогда не придется расшифровывать его (но нам придется это делать в бэкэнде)

Example => мы даем зашифрованный ключ "123ABCDE =="клиент. Клиент вызывает наш API, передавая данные + этот зашифрованный ключ, например:

{
"encKey": "123ABCDE==",
"payload": "somedatahere"
}

Затем мы расшифровываем ключ, если он соответствует определенному значению в БД (опять же, в зависимости от клиента), мы продолжаем с некоторыми другимиопераций.

Итак, я решил пойти с шифрованием AES. Вот то, что у меня есть на данный момент.

определение ключевой информации:

 public class KeyInfo
{
    public byte[] Key { get; }
    public byte[] Iv { get; }

    public KeyInfo()
    {
        using (var myAes = Aes.Create())
        {
            Key = myAes.Key;
            Iv = myAes.IV;
        }
    }

    public KeyInfo(string key, string iv)
    {
        Key = Convert.FromBase64String(key);
        Iv = Convert.FromBase64String(iv);
    }
}

метод шифрования

 private static byte[] Encrypt_AES(string plainText, byte[] key, byte[] iv)
        {
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException(nameof(plainText));
            if (key == null || key.Length <= 0)
                throw new ArgumentNullException(nameof(key));
            if (iv == null || iv.Length <= 0)
                throw new ArgumentNullException(nameof(iv));
            byte[] encrypted;

            using (var aesAlgo = Aes.Create())
            {
                aesAlgo.Key = key;
                aesAlgo.IV = iv;

                var encryptor = aesAlgo.CreateEncryptor(aesAlgo.Key, aesAlgo.IV);
                using (var msEncrypt = new MemoryStream())
                {
                    using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(plainText);
                        }

                        encrypted = msEncrypt.ToArray();
                    }
                }

            }

            return encrypted;
        }

метод дешифрования:

private static string Decrypt_AES(byte[] cipherText, byte[] key, byte[] iv)
        {
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException(nameof(cipherText));
            if (key == null || key.Length <= 0)
                throw new ArgumentNullException(nameof(key));
            if (iv == null || iv.Length <= 0)
                throw new ArgumentNullException(nameof(iv));

            string plaintext;
            using (var aesAlgo = Aes.Create())
            {
                aesAlgo.Key = key;
                aesAlgo.IV = iv;

                var decryptor = aesAlgo.CreateDecryptor(aesAlgo.Key, aesAlgo.IV);
                using (var msDecrypt = new MemoryStream(cipherText))
                {
                    using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (var srDecrypt = new StreamReader(csDecrypt))
                        {
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }

            return plaintext;
        }
    }

ключ и IV хранятся в appsettings.json:

"EncryptionKey": "myEncryptionKeyHere",
"EncryptionInitialVector": "myInitialVectorHere",

регистрация в Satrtup.cs

services.AddTransient(ec => new EncryptionService(new KeyInfo(appSettings.EncryptionKey, appSettings.EncryptionInitialVector)));

У меня есть несколько вопросов обо всем этом.

  • Является ли AES rh правильным выбором для моих нужд?
  • правильно ли это реализовано здесь?
  • где я должен хранить ключ и IV? (не уверен, что appsettings.json в порядке)
  • как мне сгенерировать ключ и IV? Есть ли инструменты для этого?

Спасибо за чтение!

РЕДАКТИРОВАТЬ:

Вы говорите: «Мы - тот, кто генерирует зашифрованный ключ, мыпередать этот зашифрованный ключ клиенту "- как это происходит безопасно?

-> Клиент должен будет подключиться к своей учетной записи, где он может получить доступ к этому encKey.

Таким образом, читая ответ @vcsjones, AES, возможно, не подходит для реализации здесь. Поскольку я не хочу хранить IV в базе данных, если клиент потеряет его, это означает, что ему придется сгенерировать другой ключ с другим IV и изменить encKey во всех приложениях.

БудетАсимметричное шифрование будет лучше? Если я правильно понял, это означало бы зашифровать значение с помощью закрытого ключа, передать это зашифрованное значение клиенту + открытый ключ (который будет одинаковым для каждого клиента?)

1 Ответ

1 голос
/ 16 октября 2019

Является ли AES правильным выбором для моих нужд?

Само по себе, нет, это не так. AES - это криптографический примитив - строительный блок, и такие строительные блоки обычно сами по себе бесполезны. Например, с AES-CBC (режим, который вы используете), он в настоящее время уязвим к атаке оракула padding и не имеет аутентификации. AES может быть правильным выбором в сочетании с другими примитивами, которые обеспечивают аутентификацию, такими как HMAC.

лучший способ решить эту проблему - это обработать примитивы для чегоони - примитивы, которых недостаточно для самостоятельного использования. Есть и другие библиотеки, такие как libsodium, которые представляют собой более абстрактные концепции криптографии и предоставляют простые API, которые «делают правильные вещи».

Вы говорите: «Мы - тот, кто генерирует зашифрованный ключ, мы передаем этозашифрованный ключ к клиенту "- как это происходит безопасно?

Если не использовать что-то вроде libsodium, необходимо решить некоторые проблемы.

  1. Нет проверки подлинностизашифрованный текст («аутентификация» в криптографии имеет свое собственное значение, не похожее на аутентификацию при входе в систему).

  2. Вектор инициализации никогда не должен использоваться более одного раза с одним и тем же ключом. Вы, кажется, используете фиксированный IV. Каждая вещь, которую вы шифруете, должна использовать свою собственную случайную IV. IV не секрет. Однако он должен быть аутентифицирован вместе с зашифрованным текстом согласно пункту 1.

где хранить ключ и IV?

IV, поскольку их должно быть 1: 1, каждый текст шифра (зашифрованный вывод) должен храниться вместе с текстом шифра. Когда пришло время расшифровывать, вызывающему абоненту нужно будет снова предоставить IV.

Ключ - настоящий секрет. Надежное их хранение важно. Если вы сохраните его в appsettings.json, то безопасность вашего ключа будет такой же, как и безопасность этого файла JSON. Более распространенным подходом в облачной среде является использование управляемого сервиса. В Azure есть хранилище ключей Azure, в AWS - KMS и Secret Manager.

как мне создать ключ и IV? Есть ли инструменты для этого?

Они должны быть созданы с CSPRNG. Например, чтобы сделать это программно:

byte[] iv = new byte[128 / 8];
RandomNumberGenerator.Fill(iv);
//iv now contains random bytes

Вы можете сделать то же самое для генерации ключа.

...