C# 中的对称加密,从字节数组到没有流的字节数组

Symmetric encryption in C# from byte-array to byte-array without streams

有没有什么方法可以使用 .Net 中的适当对称加密(也许我漏掉了什么)来实现源字节数组到目标字节数组(均预先分配)的加密?或者我必须查看或编写自定义 AES 加密系统?

我需要字节数组到字节数组的原因解释如下:

我正在为现有的基于 C# 套接字的服务器添加加密。服务器使用 Socket.Select 来处理非常大量的非阻塞客户端套接字,这些套接字有时会在很少的线程上发送相对较小的数据块。该服务器还高度优化了速度和内存分配。服务器是围绕发送和接收最大 16k 字节的数据块的想法构建的(通常只有几百个实际交换,很少有 1-2k)。所有这些块都被重新使用以避免分配。

我试过使用 .Net 的 SslStream,但我找不到没有它的方法 许多线程或 .Net async/begin-end 机制 - 似乎在大约 100 多个客户端时阻塞(取决于 os 和机器功率)。使用 SslStream 我能够使用服务器分配的内存块,但由于涉及流(tcp 和 ssl),我无法以安全的方式使用 Socket.Select。

我的下一步是尝试手动实现 SSL 套接字。我可以将服务器的 public 密钥传输到客户端,在那里我使用 RijndaelManaged 生成一个新的对称密钥,然后我使用服务器的 public 密钥对其进行加密并将其发送回服务器。一切都很好,但是如果没有 ICryptoTransform,我找不到使用 RijndaelManaged 加密的方法,它有两个问题:我必须使用 CreateEncryptor 创建很多 ICryptoTransform(导致内存混乱)并且它还会生成一个新的字节数组每次加密后都会导致 GC 进行更多工作。

握手后 TLS 执行的实际加密操作 包括明文的对称加密和身份验证标记的验证。现在,这正是您必须实施的操作才能获得足够的安全性。

当然有办法加快这些操作。基本上有两种方式:

  1. 对所用算法的硬件支持,例如使用使用 AES-NI 和其他硬件指令的 TLS 提供程序
  2. 在软件中速度很快的算法。

此外 - 当然 - 优化软件实施本身。托管语言,如 C# 或 Java(当然主要基于它)在实现许多循环/移位等方面并不是很快。在基本上已经创建为 [=55= 的密码中] 真正的快 CPU。使用 RijndaelManaged 可能不是最好的方法(你知道有一个 AES.Create 函数吗?)。


但让我们关注列出的两个方法。

TLS 提供商可能已经在使用硬件指令,但您可以确保您的提供商和平台确实是为支持它们而编写的。

另一种加快加密/解密速度的方法是切换到软件算法,例如 Salsa20 / Poly1305,这是一种经过身份验证的加密方案,从 1.2 开始引入 TLS,得到 Google 的支持。


在撰写本文时,最新版本的 TLS 协议是 TLS 1.3。 TLS 1.3 有很多方法可以提高握手的性能。实际上,如果建立了先前的秘密,它可能会完全跳过它。如果如果建立了很多连接而不是传输了很多数据,这可能真的有帮助。因此,如果您想拥有一流的安全性,您可能需要 TLS 1.3 并为此进行优化。


如果你这样做了但失败了,那么你总是可以在你的机器前面放一个 TLS 端点,比如一个真正的 TLS 加速器,然后简单地使用它。 Java 架构通常 运行 在 Apache Tomcat 上或派生的应用程序服务器,其前面配置有 Apache 网络服务器(配置为代理)。当连接到应用程序服务器时,中间的连接器甚至会发送有关 TLS 连接的信息。还有提供这种服务的单独硬件产品,如果您准备好花费 $$$ 和时间来正确配置它们(密钥/证书),它们将支持比您永远需要的更多的 TLS 流管理)。


这里肯定有与 TLS 不同的目标受众的协议,这是一个相当复杂的协议。使用 DTLS 实现或为嵌入式设备创建的协议可能会更好。但是,如果您朝那个方向前进,请准备好接受陡峭的学习曲线和大量的工作。

所以总而言之,我不会去寻找 TLS 的快速替代方案,因为任何替代方案基本上 都必须执行相同的操作 。加速 TLS 可能是更好的选择。您当然不应该做的是创建自己的协议,并且只有在您对该主题有足够的经验时才应该自己执行 TLS - 创建传输协议实现时存在太多陷阱。

经过广泛的研究,我改变了服务器处理请求的方式(基本上放弃了 .net 中的 SSL/TLS 支持),我们正在尝试在 .net 服务器之前使用 TLS 终止代理来处理所有繁重的任务tls 东西。