围绕AesManaged的这个包装好吗?

Man*_*uel 4 .net c# encryption aes encryption-symmetric

我需要加密/解密一些字符串.我根据msdn文档构建了我的包装类,但有一些更改.

由于我想使用给定的字符串/密码来加密/解密数据,因此我不会AesManaged用于创建密钥.(用户应该能够使用他输入的密钥加密/解密,因此我无法使用密钥AesManaged,我无法保存密钥).

我改为通过使用Rfc2898DeriveBytes(PBKDF2)给定盐来创建密钥.使用给定的盐,因为我没有存储密钥,因此我认为盐必须始终相同.

然后我创建一个IV,加密给定的字符串并连接IV和加密的字符串.这将最终保存在文件中.这意味着IV与加密数据一起保存.

问题:

  1. 可以将IV与加密数据一起存储吗?
  2. 有没有其他方法来创建密钥而不是每次都使用相同的盐(基于给定的密码)?
  3. 这种加密是使用AES128还是AES256完成的?
  4. IV总是16个字节,还是可以改变?

    static void Main(string[] args)
    {
        const string stringToEncrypt = "String to be encrypted/decrypted. Encryption is done via AesManaged";
        const string password = "m1Sup3rS3cre!Password";

        string encrypted = EncryptString(stringToEncrypt, password);
        string roundtrip = DecryptStringFromBytes_Aes(encrypted, password);

        Console.WriteLine("Original:   {0}", stringToEncrypt);
        Console.WriteLine("Round Trip: {0}", roundtrip);

        Console.ReadLine();
    }

    static string EncryptString(string plainText, string password)
    {
        string encryptedString;

        using (AesManaged aesAlg = new AesManaged())
        {
            aesAlg.Key = PasswordAsByte(password);
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        swEncrypt.Write(plainText);
                    }
                    var encrypted = msEncrypt.ToArray();

                    encryptedString = Encoding.Default.GetString(aesAlg.IV);
                    encryptedString += Encoding.Default.GetString(encrypted);
                }
            }
        }
        return encryptedString;
    }

    static string DecryptStringFromBytes_Aes(string cipherText, string password)
    {
        using (AesManaged aesAlg = new AesManaged())
        {
            aesAlg.Key = PasswordAsByte(password);

            aesAlg.IV = Encoding.Default.GetBytes(cipherText).Take(16).ToArray();

            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

            var encryptedByteArray = Encoding.Default.GetBytes(cipherText).Skip(16).ToArray();

            using (MemoryStream msDecrypt = new MemoryStream(encryptedByteArray))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {
                        return srDecrypt.ReadToEnd();
                    }
                }
            }
        }
    }

    private static byte[] PasswordAsByte(string password)
    {
        byte[] salt = Encoding.Default.GetBytes("foobar42");
        Rfc2898DeriveBytes passwordBytes = new Rfc2898DeriveBytes(password, salt);

        return passwordBytes.GetBytes(32);
    }
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 7

不,这不行.

1)你Encoding.Default在各个地方使用.不要这样做 - 这意味着你正处于平台的心血来潮之中.在大多数情况下,始终使用显式编码,理想情况下为UTF-8.

2)您正在使用Encoding.GetString/ Encoding.GetBytes任意二进制数据转换为字符串并返回.这几乎必然会丢失数据.(它碰巧在我的机器上取得了成功,但它实际上取决于编码 - 而且从根本上说这是一个坏主意.)Encoding是专为本来就是文本数据的数据而设计的,而你只是以某种方式应用编码.您的加密数据本质上是二进制数据.使用Convert.ToBase64StringConvert.FromBase64String替代.

对于您的其他问题:

  • 是的,据我所知,可以将IV与加密数据一起存储.
  • 您可以对密码使用相同的方法:每次生成不同的盐,并将与加密文本一起存储.我不敢确定是否一般是推荐的.
  • 我相信你正在控制密钥大小是128位还是256位,而你的调用是passwordBytes.GetBytes(32)- 这是一个256位密钥,所以它是AES256.
  • 我相信AES的IV大小总是16字节(128位)