Правильное использование AesCryptoServiceProvider - PullRequest
2 голосов
/ 03 июля 2019

Я пытаюсь написать несколько простых процедур шифрования.Вот то, что я смог придумать, основываясь на поиске в Интернете.

public string Encrypt(string plainText)
{
    byte[] encrypted;

    // Create an AesCryptoServiceProvider object
    // with the specified key and IV.
    using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
    {
        // Create an encryptor to perform the stream transform.
        ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

        // Create the streams used for encryption.
        using (MemoryStream msEncrypt = new MemoryStream())
        {
            msEncrypt.WriteByte((byte)aesAlg.Key.Length);
            msEncrypt.Write(aesAlg.Key, 0, aesAlg.Key.Length);
            msEncrypt.WriteByte((byte)aesAlg.IV.Length);
            msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);

            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                {
                    //Write all data to the stream.
                    swEncrypt.Write(plainText);
                }
                encrypted = msEncrypt.ToArray();
            }
        }
    }
    return Convert.ToBase64String(encrypted);
}

public string Decrypt(string cipherText)
{
    string plaintext = null;

    using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
    {
        // Create the streams used for decryption.
        using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
        {
            int l = msDecrypt.ReadByte();
            byte[] key = new byte[l];
            msDecrypt.Read(key, 0, l);
            l = msDecrypt.ReadByte();
            byte[] IV = new byte[l];
            msDecrypt.Read(IV, 0, l);

            // Create a decryptor to perform the stream transform.
            ICryptoTransform decryptor = aesAlg.CreateDecryptor(key, IV);

            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
            {

                // Read the decrypted bytes from the decrypting stream
                // and place them in a string.
                plaintext = srDecrypt.ReadToEnd();
            }
        }
    }
    return plaintext;
}

Два вопроса:

  • Во-первых, большинство примеров, которые я нашел, жестко закодировано Key и IV.Итак, что я делаю, это записываю его в зашифрованные байты.Это сделает мои зашифрованные данные больше.Есть ли лучший способ?
  • Кроме того, я не использую пароль.Можно ли использовать пароль для создания пользовательского Key?И если да, то как я узнаю, как долго должен быть этот ключ?

1 Ответ

4 голосов
/ 03 июля 2019

Во-первых, большинство примеров, которые я нашел, жестко закодированы ключом и IV. Итак, что я делаю, это записываю его в зашифрованные байты. Это сделает мои зашифрованные данные больше. Есть ли лучший способ?

Очевидно, что вы не должны записывать ключ в незащищенный поток, так как ключ должен быть передан или установлен заранее и должен оставаться в секрете. Это совместное использование секретного ключа может быть выполнено многими способами, начиная от согласования ключа до получения ключа, прерывания и т. Д. И т. Д.

Кроме того, я не использую пароль. Можно ли использовать пароль для создания пользовательского ключа? И если да, то как я узнаю, как долго должен быть этот ключ?

Это возможно. Однако помните, что пароли часто не так надежны, поэтому, если можно избежать шифрования на основе паролей (PBE), это может быть хорошей идеей.

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

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

...