使用AesCryptoServiceProvider的正确方式

3

我正在尝试编写一些简单的加密程序。以下是我基于网络搜索得到的结果。

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;
}

有两个问题:

  • 首先,我发现大多数的例子都是硬编码 KeyIV。我的做法是把它们写入加密后的字节流中。这将使我的加密数据变得更大。有更好的方法吗?
  • 另外,我没有使用任何密码。是否需要使用密码来生成自定义的 Key?如果需要,如何确定该密钥需要多长?
1个回答

4
首先,我发现大多数例子都是硬编码了密钥和IV。因此,我的做法是将其写入加密字节中。这将使我的加密数据变得更大。有更好的方法吗?
显然,您不应该将密钥写入未受保护的流中,因为密钥需要事先共享或建立并保持机密性。可以通过许多方式来执行密钥共享,从密钥协商到密钥派生、梯度递增等等。
此外,我没有使用任何密码。有人会使用密码生成自定义密钥吗?如果是这样,我如何知道该密钥需要多长?
这是一个可能性。然而,要记住密码通常并不强大,因此,如果可以避免基于密码的加密(PBE),那么这可能是一个好主意。
如果您从密码中派生密钥,您应该使用基于密码的密钥派生函数(有时也称为密码哈希)。在C#中,有一个名为Rfc2898DeriveBytes的PBKDF2实现(质量差)。但是,如果您设置足够高的迭代次数,它应该就足够了。当您从人类记忆的密码中派生密钥时,128位就足够了。几乎没有比用于派生它的密码更容易找到密钥的方法。

谢谢。我将研究如何对密码进行哈希。至于“IV”,怎么做才能确保在解密时拥有正确的“IV”数据呢? - Jonathan Wood
1
哦,抱歉。如果IV是随机的,您可以简单地添加前缀,然后像您已经做的那样读回来。对于CBC模式(默认模式),IV需要对攻击者不可预测,但不需要保密。如果您正在使用CBC模式,则绕过IV和填充开销会很棘手。 - Maarten Bodewes
我需要为模式或填充做些什么,还是我已经可以了? - Jonathan Wood
1
不使用默认值也可以。通常我会建议使用CTR模式,但是由于某些奇怪的原因,在.NET中它不是默认包含的。使用CTR,您可以将一个随机数作为“IV”,而CTR模式不需要任何填充。我认为CFB在其中,但是CFB和OFB几乎不再使用。 - Maarten Bodewes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接