围绕AesManaged的这个包装好吗?

时间:2015-03-25 09:22:26

标签: c# .net encryption aes encryption-symmetric

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

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

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

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

问题:

  1. 将IV与加密数据一起存储是否可以?
  2. 是否有其他方法可以在不使用相同的盐的情况下每次创建密钥(基于给定的密码)?
  3. 使用AES128或AES256进行加密吗?
  4. IV是否总是16个字节,还是可以改变?

  5.     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);
        }
    

3 个答案:

答案 0 :(得分:7)

不,这不行。

1)您在不同的地方使用Encoding.Default。不要这样做 - 这意味着你可以随心所欲地登上平台。在大多数情况下,始终使用显式编码,理想情况下为UTF-8。

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

对于您的其他问题:

  • 是的,据我所知,将加密数据存储在IV中是可以的。
  • 您可以对密码使用相同的方法:每次生成不同的盐,并将 与加密文本一起存储。不确定这是否一般是推荐的,我很害怕。
  • 我相信您控制的是密钥大小是128位还是256位,并且呼叫passwordBytes.GetBytes(32) - 这是一个256位密钥,因此它是AES256。< / LI>
  • 我相信AES的IV大小总是16字节(128位)

答案 1 :(得分:1)

通常,salt与密码的加密哈希一起使用以防止字典攻击。要使用AES获得对称加密的相同保护,您应该使用随机初始化向量。因此,当您加密时,创建一个随机IV并将其添加到消息中(以明文形式)。解密时从加密消息中获取IV并使用它来解密消息。然后,用相同密钥加密的相同消息的密文将是不同的。

  • 所以,是的,可以将IV与加密数据一起存储。

  • 你不需要每次都使用不同的盐,因为随机IV的目的与盐使字典攻击哈希的方式类似。

  • AES可以使用128,192或256位的密钥大小,因此要使用AES 256,您需要使用256位密钥(32字节)。

  • AES使用128位块,需要128位IV(或16字节)。

答案 2 :(得分:0)

  

将IV与加密数据一起存储是否可以?

是的,没关系。此外,您在未明确设置AesManaged的情况下使用Mode - 此案例模式为CBC,而在CBC模式下,IV应在cyphertext之前。

  

是否有其他方法可以在不使用相同的盐的情况下每次创建密钥(基于给定的密码)?

Rfc2898DeriveBytes是从文本密码派生密钥的非常标准的方法。没有必要重新发明从密码中导出密钥的方法,只需使用Rfc2898DeriveBytes,就像现在一样。

  

这种加密是使用AES128还是AES256完成的?

AES256,因为您使用的是32字节密码。

  

IV是否总是16byte,或者这可以改变吗?

IV property的大小必须与BlockSize属性除以8相同。对于128位块,它的大小为16.