По какой-то причине меня попросили внедрить некоторое базовое шифрование для защиты определенного значения, передаваемого клиенту (в зависимости от клиента).
Контекст такой: мы являемся теми, кто генерирует зашифрованныеключ, мы передаем этот зашифрованный ключ клиенту, и клиенту никогда не придется расшифровывать его (но нам придется это делать в бэкэнде)
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
во всех приложениях.
БудетАсимметричное шифрование будет лучше? Если я правильно понял, это означало бы зашифровать значение с помощью закрытого ключа, передать это зашифрованное значение клиенту + открытый ключ (который будет одинаковым для каждого клиента?)