You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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方式,因此我有两个问题:

  1. 这种方式是否更高效?
  2. 仅仅是为了演示CryptoStream的用法?

解答

1. 关于效率

TransformFinalBlock的实现更高效。原因如下:

  • CryptoStream + MemoryStream的组合会产生额外的对象创建开销(两个流实例),还会涉及多次内存拷贝(写入流、最终调用ToArray()提取数据);而TransformFinalBlock直接在输入字节数组上完成转换,输出结果数组,中间没有多余的流包装开销。
  • 你测试时结果波动大,是因为这类加密操作本身耗时极短,系统线程调度、GC临时回收等外部因素会对计时结果产生显著影响。如果要做更准确的性能测试,建议:
    • 先跑几轮预热JIT,不计入最终时间
    • 使用更大的明文数据(比如几MB级)
    • 多次测试取平均值

实际上,CryptoStream内部就是通过调用TransformBlock和TransformFinalBlock来处理数据的,它本质是一个流包装器,额外开销是必然存在的。

2. 微软示例用流的原因

主要是为了演示CryptoStream的通用用法。现实开发中的加密场景不全是处理现成的字节数组:

  • 可能是来自文件流、网络流的大块数据,无法一次性加载到内存
  • 可能需要边读取边加密,避免占用过多内存
  • 示例需要展示加密操作如何与.NET的流体系结合,这是更通用的编程模式,能覆盖更多实际需求

直接用TransformFinalBlock虽然简洁,但只适用于一次性处理全部数据的场景,而流的方式是通用解决方案,适用性更广。

内容的提问来源于stack exchange,提问作者cup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 08:31:10