【问题标题】:Symmetric encryption in C# from byte-array to byte-array without streamsC#中从字节数组到字节数组的对称加密,没有流
【发布时间】:2019-12-25 12:34:43
【问题描述】:

有没有什么方法可以使用来自 .Net 的体面的对称加密(也许我遗漏了一些东西)来实现将源字节数组加密到目标字节数组(都预先分配)?还是我必须查看或编写自定义 AES 加密系统?

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

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

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

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

【问题讨论】:

  • 不清楚为什么不能使用(和池化)MemoryStreams? RijndaelManagedTransform 还将CanReuseTransform 设置为true
  • 可以,但是 ICryptoTransform.TransformFinalBlock 每次都会返回一个新的字节数组。

标签: c# aes encryption-symmetric


【解决方案1】:

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

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

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

除此之外 - 当然 - 优化软件实现本身。诸如 C# 或 Java(它当然主要基于)之类的托管语言在实现许多循环/移位等方面并不是很快,而这种密码基本上是为了在真正的 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 具有不同的目标受众,TLS 是一个相当复杂的协议。使用 DTLS 实现或为嵌入式设备创建的协议可能会更好。但是,如果您朝着这个方向前进,请为陡峭的学习曲线和大量工作做好准备。

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

【讨论】:

  • 感谢文档回复。我的问题不在于 TLS 的速度,而在于它是如何在 .Net 中实现的。这同样适用于 AES 和 Rinjdael 加密类。它的编写方式通常不会重用字节数组和资源,而是会导致大量垃圾收集,这会在每秒来自不同客户端的大量请求的重型生产环境中造成严重问题。
  • 即使在托管环境中也有一些方法可以避免这种情况。然而,我真的很惊讶 TLS 连接会使您的服务器陷入困境。 TLS 连接使用的内存量应该相对较小,而且我觉得奇怪的是,与您之后执行的应用程序级别的东西相比,它甚至会注册。也就是说,如果您想要快速操作,那么使用所谓的 connectors i>.
  • 问题不在于 TLS 本身,而是在加密/解密过程中创建和丢弃的许多小字节数组导致 GC 决定唤醒时冻结。对于普通应用程序(如网站服务等),这应该是不明显的,我们谈论的是少量毫秒。对于实时数据,这会导致大问题:)
【解决方案2】:

经过广泛的研究,我改变了服务器处理请求的方式(基本上放弃了 .net 中的 SSL/TLS 支持),我们在 .net 服务器之前尝试了一个 TLS 终止代理,它将处理所有繁重的 tls 内容。

【讨论】:

    猜你喜欢
    • 2019-05-08
    • 1970-01-01
    • 1970-01-01
    • 2014-11-10
    • 2020-06-22
    • 1970-01-01
    • 2021-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多