C#加密场景下MemoryStream与CryptoStream的使用疑问
AES加密两种实现方式的疑问
我常看到如下AES加密代码(key和plain为字节数组):
byte[] cipher; using (Aes algo= Aes.Create()) { algo.Mode = CipherMode.ECB; algo.Key = key; algo.KeySize = key.Length * 8; algo.Padding = PaddingMode.None; // Create an encryptor to perform the stream transform. ICryptoTransform encryptor = algo.CreateEncryptor(algo.Key, null); // Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { // Sometimes another using StreamWriter/StreamReader if supplying // string instead of byte[] csEncrypt.Write(plain); csEncrypt.FlushFinalBlock(); } cipher = msEncrypt.ToArray(); } }
我疑惑为何要使用MemoryStream和CryptoStream,而非如下实现:
byte[] cipher; using (Aes algo= Aes.Create()) { algo.Mode = CipherMode.ECB; algo.Key = Key; algo.KeySize = key.Length * 8; algo.Padding = PaddingMode.None; // Create an encryptor to perform the stream transform. ICryptoTransform encryptor = algo.CreateEncryptor(key, null); cipher = encryptor.TransformFinalBlock(plain, 0, plain.Length); }
我猜测TransformFinalBlock内部可能使用MemoryStream和CryptoStream,因此更高效;或者CryptoStream内部调用TransformFinalBlock,导致更低效。我尝试计时测试,但即使运行100000次,Stopwatch结果仍波动极大。
注:这只是简单示例,无需讨论ECB模式的弊端。
微软官网C#示例采用MemoryStream+CryptoStream方式,因此我有两个问题:
- 这种方式是否更高效?
- 仅仅是为了演示CryptoStream的用法?
解答
1. 关于效率
TransformFinalBlock的实现更高效。原因如下:
CryptoStream+MemoryStream的组合会产生额外的对象创建开销(两个流实例),还会涉及多次内存拷贝(写入流、最终调用ToArray()提取数据);而TransformFinalBlock直接在输入字节数组上完成转换,输出结果数组,中间没有多余的流包装开销。- 你测试时结果波动大,是因为这类加密操作本身耗时极短,系统线程调度、GC临时回收等外部因素会对计时结果产生显著影响。如果要做更准确的性能测试,建议:
- 先跑几轮预热JIT,不计入最终时间
- 使用更大的明文数据(比如几MB级)
- 多次测试取平均值
实际上,CryptoStream内部就是通过调用TransformBlock和TransformFinalBlock来处理数据的,它本质是一个流包装器,额外开销是必然存在的。
2. 微软示例用流的原因
主要是为了演示CryptoStream的通用用法。现实开发中的加密场景不全是处理现成的字节数组:
- 可能是来自文件流、网络流的大块数据,无法一次性加载到内存
- 可能需要边读取边加密,避免占用过多内存
- 示例需要展示加密操作如何与.NET的流体系结合,这是更通用的编程模式,能覆盖更多实际需求
直接用TransformFinalBlock虽然简洁,但只适用于一次性处理全部数据的场景,而流的方式是通用解决方案,适用性更广。
内容的提问来源于stack exchange,提问作者cup
相关产品推荐
相关产品推荐

