C# 使用字节数组管理的AES

C# 使用字节数组管理的AES,c#,memorystream,cryptostream,C#,Memorystream,Cryptostream,我正在尝试实现内存中的AES管理加密/解密。此处的代码基于以下内容: 加密部分似乎可以工作,也就是说,没有例外。但是解密部分抛出“索引超出数组边界”错误 在前面的代码中,转换是这样初始化的: aes = new AesManaged(); aes.BlockSize = aes.LegalBlockSizes[0].MaxSize; aes.KeySize = aes.LegalKeySizes[0].MaxSize; Rfc2898DeriveBytes ke

我正在尝试实现内存中的AES管理加密/解密。此处的代码基于以下内容:

加密部分似乎可以工作,也就是说,没有例外。但是解密部分抛出“索引超出数组边界”错误

在前面的代码中,转换是这样初始化的:

 aes = new AesManaged();
 aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
 aes.KeySize = aes.LegalKeySizes[0].MaxSize;            
 Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(Key, salt, 1);
 aes.Key = key.GetBytes(aes.KeySize / 8);
 aes.IV = key.GetBytes(aes.BlockSize / 8);
 aes.Mode = CipherMode.CBC;
 transform = aes.CreateDecryptor(aes.Key, aes.IV);


void AESDecrypt(ref byte[] inB)
{
    using (MemoryStream destination = new MemoryStream(inB, 0, inB.Length))
    {
        using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
            {
                try
                {
                    using (MemoryStream source = new MemoryStream(inB, 0, inB.Length))
                    {
                        if (source.CanWrite==true)
                        {
                            source.Write(inB, 0, inB.Length);
                            source.Flush(); //<<inB is unchanged by the write
                        }
                    }
                }
                catch (CryptographicException exception)
                {
                    if (exception.Message == "Padding is invalid and cannot be removed.")
                        throw new ApplicationException("Universal Microsoft Cryptographic Exception (Not to be believed!)", exception);
                    else
                        throw;
                }
            }
        } <====At this point I get an IndexOutofBounds exception.
    }
}
aes=新的aes管理();
aes.BlockSize=aes.LegalBlockSize[0].MaxSize;
aes.KeySize=aes.LegalKeySizes[0].MaxSize;
Rfc2898DeriveBytes键=新的Rfc2898DeriveBytes(键,salt,1);
aes.Key=Key.GetBytes(aes.KeySize/8);
aes.IV=key.GetBytes(aes.BlockSize/8);
aes.Mode=CipherMode.CBC;
transform=aes.CreateDecryptor(aes.Key,aes.IV);
无效AES解密(参考字节[]inB)
{
使用(MemoryStream destination=新的MemoryStream(inB,0,inB.Length))
{
使用(CryptoStream CryptoStream=新的CryptoStream(目标、转换、CryptoStreamMode.Write))
{
尝试
{
使用(内存流源=新内存流(inB,0,inB.Length))
{
if(source.CanWrite==true)
{
源写入(inB,0,inB.Length);

source.Flush();//您没有向加密流提供任何数据,它需要一些数据,因为它正在尝试删除填充。尝试注释掉源代码的整个Try/catch块,您将得到相同的错误

加密流为空,但您要求它读取填充。在“new()之后第行,添加以下内容:
aes.Padding=PaddingMode.None
。现在您的代码可以工作了,尽管它不会解密任何内容。因为您不向CryptoStream提供任何内容,也不要求它读取任何填充内容,所以它不再抱怨。它什么也不做。您有一个错误,即您没有向CryptoStream提供密文

请尝试此操作,而不是源的MemoryStream:

using (BinaryWriter source = new BinaryWriter(cryptoStream))
{
    source.Write(inB, 0, inB.Length);
}
现在涉及到加密流,它将接收inB进行解密

处理填充可能有问题。在编写代码时(修复大括号打字错误),您要求解密程序去除填充,但不修剪输出数组(ref byte[]inB)那么,您如何知道返回了多少数据呢?它将始终返回与输入相同的长度,但只是覆盖了解密的数据量

以下是一些示例数据:

尝试使用32个零字节的密钥和16个零字节的IV:

aes.Key = new byte[32];
aes.IV = new byte[16];
并将此密文解密为inB:

byte[] inB = { 0xf9, 0x14, 0x32, 0x2a, 0x7a, 0x35, 0xf9, 0xef, 0x27, 0x98, 0x1a, 0x86, 0xe2, 0x80, 0x5e, 0x9b };
如果不设置Padding.None,则您将看到我的原始纯文本“Hello”仅覆盖inB的前五个字节。剩余的11个字节不变。填充已被删除(默认设置),并且未写入目标流

现在设置Padding.None并重试。由于我填充了数据,您将看到destination现在包含“Hello”,后跟11个字节的值11——填充。由于这次没有删除填充,您将看到它写入了输出


此外,正如usr所评论的,每次使用密钥加密时,IV都应该是唯一的。每次都会得到相同的IV和密钥。如果此密钥只使用一次,那就好了。如果同一密钥多次使用,这是一个错误。IV应该是唯一的。它可以清晰地发送——不需要保密。

还有什么你试过?比如调试你自己的代码?是的,不确定你得到了什么。
if(source.CanWrite==true)
。如果CanWrite为false怎么办?那么你什么也不写?如果你不处理这个问题,最好让它失败。关于你的实际问题,你发送的数据是错误的。可能是错误的密钥、IV或字节。所以也要显示加密。顺便说一句,任何人都可以修改你的加密数据,而不必注意解密。你应该ld使用经过身份验证的加密(AES-GCM非常安全)。此外,每种加密的IV都应该是唯一的。使用CBC您很幸运,但对于其他模式,不同数据的相同IV会100%破坏安全性。