使用 RijndaelManaged 在 C# 中加密/解密流
Posted
技术标签:
【中文标题】使用 RijndaelManaged 在 C# 中加密/解密流【英文标题】:Encrypt/Decrypt Stream in C# using RijndaelManaged 【发布时间】:2016-06-07 20:57:45 【问题描述】:我正在尝试在 C# 中加密通用流。程序虽然没有问题,但是加解密转换成字符串时返回空白。任何帮助表示赞赏。
public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
byte[] encryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] 1, 2, 3, 4, 5, 6, 7, 8 ;
using (MemoryStream ms = new MemoryStream())
using (RijndaelManaged AES = new RijndaelManaged())
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 10000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
encryptedBytes = ms.ToArray();
return encryptedBytes;
public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
byte[] decryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] 1, 2, 3, 4, 5, 6, 7, 8 ;
using (MemoryStream ms = new MemoryStream())
using (RijndaelManaged AES = new RijndaelManaged())
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 10000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
decryptedBytes = ms.ToArray();
return decryptedBytes;
private void Encrypt(Stream input, Stream output, String password)
input.Position = 0;
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
using (var stream = new MemoryStream())
byte[] buffer = new byte[2048]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
stream.Write(buffer, 0, bytesRead);
var tmp = AES_Encrypt(buffer, passwordBytes);
output.Write(tmp, 0, tmp.Length);
private void Decrypt(Stream input, Stream output, String password)
input.Position = 0;
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
using (var stream = new MemoryStream())
byte[] buffer = new byte[2048]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
stream.Write(buffer, 0, bytesRead);
var tmp = AES_Decrypt(buffer, passwordBytes);
output.Write(tmp, 0, tmp.Length);
static void Main(string[] args)
Program obj = new Program();
var message = new MemoryStream();
var cipher = new MemoryStream();
string tmp = "This is a test if the encryption is working!";
StreamWriter sw = new StreamWriter(message);
sw.Write(tmp);
obj.Encrypt(message, cipher, "password");
cipher.Position = 0;
message = new MemoryStream();
obj.Decrypt(cipher, message, "password");
using (var memoryStream = new MemoryStream())
message.CopyTo(memoryStream);
var bytesdecrypt = memoryStream.ToArray();
string result = Encoding.UTF8.GetString(bytesdecrypt);
Console.WriteLine(result);
Console.ReadLine();
问题可能出在我在流中读写时。
【问题讨论】:
看看这个:***.com/questions/202011/encrypt-and-decrypt-a-string/… “空白”是什么意思?你如何检查那里是否有东西? Johnny D. 以下是针对您的特定问题的更相关链接:***.com/questions/22145836/… 解密后,我得到一个空字符串。 所以加密是非空白的,对吧? 【参考方案1】:这段代码有很多问题。
什么都没有解密的原因是你在做message.CopyTo(memoryStream)
之前忘记重置message
流,因为CopyTo
从当前位置开始工作,解密后你没有改变位置。
你可以重置它
message.Position = 0;
如果对任意数据进行加密,使用 CBC 等某种操作模式的 AES 是不够的。我们通常需要某种填充方案。在 C# 中,默认方案是 PKCS#7 填充。即使明文已经是块大小的倍数,也总是添加明确的填充。在这些情况下,会添加一个完整的填充块。
现在的问题是您在加密和解密期间读取 2048 字节的块,但加密会产生 2064 字节的密文块,在解密期间必须照此读取。这是一个简单的解决方法,但最好一直使用流而不是加密这些单独的块。
您正在为每个 2048 字节的块调用 Rfc2898DeriveBytes
,但它永远不会改变。要么引入随机性,但实际上使用随机盐和随机 IV,或者缓存密钥。 (随机盐和随机IV仍然是实现语义安全所必需的)
【讨论】:
谢谢@Artjom B.! 使用 PKCS#7 填充的示例将不胜感激。很高兴批评,但没有提供代码来显示概念证明,它不是很有帮助。如何随机化盐的示例也会很有用。以上是关于使用 RijndaelManaged 在 C# 中加密/解密流的主要内容,如果未能解决你的问题,请参考以下文章
使用 CryptDecrypt 解密 RijndaelManaged 加密字符串
AesManaged 与 RijndaelManaged [关闭]