Есть ли способ улучшить мой код шифрования AES в C #? - PullRequest
0 голосов
/ 30 декабря 2010

У меня есть этот код для шифрования AES, кто-нибудь может проверить, что этот код хорош, а не неправильн? Работает нормально, но меня больше беспокоит реализация алгоритма.

// Plaintext value to be encrypted.

//Passphrase from which a pseudo-random password will be derived.
//The derived password will be used to generate the encryption key.

//Password can be any string. In this example we assume that this passphrase is an ASCII string.

//Salt value used along with passphrase to generate password.
//Salt can be any string. In this example we assume that salt is an ASCII string.

//HashAlgorithm used to generate password. Allowed values are: "MD5" and "SHA1".
//SHA1 hashes are a bit slower, but more secure than MD5 hashes.

//PasswordIterations used to generate password. One or two iterations should be enough.

//InitialVector (or IV). This value is required to encrypt the first block of plaintext data.
//For RijndaelManaged class IV must be exactly 16 ASCII characters long.

//KeySize. Allowed values are: 128, 192, and 256.
//Longer keys are more secure than shorter keys.

//Encrypted value formatted as a base64-encoded string.


public static string Encrypt(string PlainText, string Password, string Salt, string HashAlgorithm, int PasswordIterations, string InitialVector, int KeySize)
{
    byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
    byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
    byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
    PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
    byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
    RijndaelManaged SymmetricKey = new RijndaelManaged();
    SymmetricKey.Mode = CipherMode.CBC;
    ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
    MemoryStream MemStream = new MemoryStream();
    CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
    CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
    CryptoStream.FlushFinalBlock();
    byte[] CipherTextBytes = MemStream.ToArray();
    MemStream.Close();
    CryptoStream.Close();
    return Convert.ToBase64String(CipherTextBytes);
}

public static string Decrypt(string CipherText, string Password, string Salt, string HashAlgorithm, int PasswordIterations, string InitialVector, int KeySize)
{
    byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
    byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
    byte[] CipherTextBytes = Convert.FromBase64String(CipherText);
    PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
    byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
    RijndaelManaged SymmetricKey = new RijndaelManaged();
    SymmetricKey.Mode = CipherMode.CBC;
    ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes);
    MemoryStream MemStream = new MemoryStream(CipherTextBytes);
    CryptoStream cryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read);
    byte[] PlainTextBytes = new byte[CipherTextBytes.Length];
    int ByteCount = cryptoStream.Read(PlainTextBytes, 0, PlainTextBytes.Length);
    MemStream.Close();
    cryptoStream.Close();
    return Encoding.UTF8.GetString(PlainTextBytes, 0, ByteCount);
}

Я не профессионал в области безопасности и не программист, я начинаю учиться и люблю это понимать

В мои планы входит создание функций шифрования AES, требующих минимального ввода и следующих стандартов, поэтому будет легко создавать эквивалентные функции на других языках, таких как PHP и JavaScript!

Спасибо

Ответы [ 2 ]

3 голосов
/ 30 декабря 2010

Некоторые общие комментарии.Первый около IV.В общем, вы хотите, чтобы IV был случайным.Ограничивая его (отображаемым) ASCII, вы несколько ограничиваете возможные значения.В общем, вам лучше было бы: а) использовать метод GenerateIV () и б) добавить значение IV к зашифрованному тексту, так что в) вам не нужно передавать его в качестве параметра для любой функции.

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

Вы также можете добавить множество решений в свои конфигурационные файлы.Например, вы можете создать имя для своего крипто провайдера (например, MyAppSymmetricCrypto), который сопоставляется с RijndaelManaged сегодня, но позже может быть изменен на тот, который тогда подходит.

2 голосов
/ 30 декабря 2010

В дополнение к ответу @Damien_The_Unbeliever

MS рекомендует использовать Rfc2898DeriveBytes вместо PasswordDeriveBytes. (а затем вы можете удалить HashAlgorithm из параметров вашего метода).

Вы можете рассчитать IV по вашему паролю:

var bytes = new Rfc2898DeriveBytes(password, salt, iterations);
var key = bytes.GetBytes(keySize);
var iv = bytes.GetBytes(ivSize);

Вы должны проверить свои входные значения на предмет недопустимых значений / диапазонов.

Оберните классы MemoryStream & CryptoStream в using операторы.

...