C# Aes byte[] 加密/解密:不是一个完整的块
Posted
技术标签:
【中文标题】C# Aes byte[] 加密/解密:不是一个完整的块【英文标题】:C# Aes byte[] Encrypt/Decrypt : not a complete block 【发布时间】:2018-05-13 11:52:14 【问题描述】:我得到错误“输入数据不是一个完整的块”,我不知道我的代码是错误的还是缺少什么。我尝试用相同的长度加密/解密字节。
=byte[] plain => MyEnc(plain) => byte[] encrypted => MyDec(encrypt) => byte[] plain
明文和加密的长度相同。
这是我的加密代码:
public static byte[] MyEnc(byte[] Input)
byte[] inputencdec = Input;
byte[] encrypted;
using (MemoryStream mstream = new MemoryStream())
using (AesCryptoServiceProvider encdec = new AesCryptoServiceProvider())
encdec.BlockSize = 128;
encdec.KeySize = 256;
encdec.Key = ASCIIEncoding.ASCII.GetBytes(Key);
encdec.IV = ASCIIEncoding.ASCII.GetBytes(IV);
ICryptoTransform icrypt = encdec.CreateEncryptor(encdec.Key, encdec.IV);
using (CryptoStream cryptoStream = new CryptoStream(mstream,
icrypt, CryptoStreamMode.Write))
cryptoStream.Write(inputencdec, 0, inputencdec.Length);
encrypted = mstream.ToArray();
return encrypted;
这是我的解密代码:
public static byte[] MyDec(byte[] Input)
byte[] inputencdec = Input;
byte[] buffer = new byte[Input.Length];
int totalRead = 0;
byte[] plain;
MemoryStream plainStream = new MemoryStream();
using (MemoryStream mStream = new MemoryStream(inputencdec))
using (AesCryptoServiceProvider encdec = new AesCryptoServiceProvider())
encdec.BlockSize = 128;
encdec.KeySize = 256;
encdec.Key = ASCIIEncoding.ASCII.GetBytes(Key);
encdec.IV = ASCIIEncoding.ASCII.GetBytes(IV);
ICryptoTransform icrypt = encdec.CreateDecryptor(encdec.Key, encdec.IV);
using (CryptoStream cryptoStream = new CryptoStream(mStream, icrypt, CryptoStreamMode.Read))
while (true)
int read = cryptoStream.Read(buffer, 0, inputencdec.Length);
if (read == 0)
break;
else
plainStream.Write(buffer, totalRead, read);
totalRead += read;
plain = plainStream.ToArray();
return plain;
【问题讨论】:
最好(甚至策略)使用 C# 作为标签而不是标题。它将提高您问题的曝光率,并自动突出显示您的代码。请始终提供错误的完整堆栈跟踪以及发生异常的代码中的提示,因为我们没有行号。int read = cryptoStream.Read(buffer, 0, inputencdec.Length);
处的错误代码如果明文和密码的长度不同。所以我不能让两者的长度相同?或使用另一种密码模式?我想尝试什么,例如,如果我有 50k 字节并且我解析 20k-40k 的字节。并且只需加密/解密解析字节并再次添加到该文件。
您可以使用流式操作模式,例如计数器模式。这是最常见的流媒体模式,但由于某些脑死亡的原因,它不适用于 .NET(很多 Mickeysoft 加密 API 以这种方式脑死亡,我猜他们缺少与开发人员、开发人员、开发人员的联系......但是有 CFB 模式,这是一种不需要填充的旧模式。但我现在可以看到缓冲区与密文的大小相同;这意味着您的密文大小错误;这意味着密文的生成很可能搞砸了。
所以 CFB 模式会使plain 和 cipher 具有相同的字节长度?
是的,如果您可以导出 IV 或更改每条消息的密钥。例如,IV 可以兼作消息编号以避免重放攻击。请注意,CBC 和 CFB 都不提供真实性/完整性;你需要例如GCM 为此,但它在密文中添加了一个身份验证标签。
【参考方案1】:
对于您正在使用的 CBC 模式加密,普通和加密的长度不同。明文在加密前需要填充,所以密文大小总是大于CBC的明文消息(这是解密器使用的默认模式)。
流模式不需要扩展密文,因为它们不需要填充。不幸的是,Microsoft 选择不在 .NET 中包含计数器模式。你可以使用CFB模式。
如果您需要并行加密(在问题下方的 cmets 中),您也可以决定使用 ECB实现计数器模式。通常,如今 AES 是如此之快,以至于不需要并行性。与创建多线程代码相比,实现静态大小的计数器和 CTR 缓冲区应该相形见绌。
这是不正确的,可能会导致问题:
int read = cryptoStream.Read(buffer, 0, inputencdec.Length);
你当然应该输入buffer.length
,而不是inputencdec.length
。缓冲区的用途是将数据存储在缓冲区中,每次循环迭代最多读取buffer.length
个字节。
这也是不正确的:
plainStream.Write(buffer, totalRead, read);
问题在于totalRead
应该是buffer
中的偏移量,而不是流中的偏移量。您正在读取缓冲区的偏移量 0,因此您也应该从偏移量 0 开始写入。
您还可以为明文创建MemoryStream
,使用解密器将其包装为CryptoStream
,然后一次性编写密文。据我所知,加密/解密不需要使用不同的方案。无论如何,您似乎将所有明文/密文都保留在内存中。
注意事项:
对于 CBC 模式,IV 应该是随机的;它通常作为密文的前缀并被解密器删除和使用; 密钥和IV应该由随机字节组成;它们应该不是字符串。【讨论】:
以上是关于C# Aes byte[] 加密/解密:不是一个完整的块的主要内容,如果未能解决你的问题,请参考以下文章