OpenSSL 还是原生密码学:在 Delphi 中运行时选择

· 组件
OpenSSL 还是原生密码学:在 Delphi 中运行时选择

从 Delphi 应用中去掉 OpenSSL DLL,过去是一个构建期的决定:打开一个编译器 define,重新构建,再给那些机器上不能有 OpenSSL 的客户交付第二个可执行文件。sgcWebSockets 2026.10 把它变成了一个运行时决定:一个全局变量,在启动时设置一次,就能决定应用的密码学运算是跑在 OpenSSL 上,还是跑在库内置的、用 Object Pascal 编写的密码学实现上。

连接这一侧,也就是不依赖 OpenSSL 的 TLS,已经在《不依赖 OpenSSL DLL 的 Delphi TLS 1.3》一文中介绍过。这篇文章讲的是其余的一切:你的应用在 TLS 握手之外所做的签名、哈希、密钥协商和加密。

启动时一行代码

单元 sgcBase_Helpers 声明了类型为 TsgcCryptoBackend 的全局变量 sgcCryptoBackend:

uses
  sgcBase_Helpers;

begin
  sgcCryptoBackend := cbNative;
  sgcCheckNativeCrypto;
  Application.Initialize;
  ...

这个开关是全局的,不是按组件设置的,所以要在创建任何组件之前设置好。sgcCheckNativeCrypto 是可选的:如果原生密码学相关的 unit 没有编译进去,它会在启动时就以一条清晰的提示信息报错,而不是等到你的应用尝试生成第一个签名时才出问题。

三个取值

cbAuto 适合那些两种方式都要部署的产品。有些客户会把 OpenSSL 库装在可执行文件旁边,有些则被禁止这样做,而同一个构建版本对两者都适用,不会再收到关于缺少 DLL 的支持工单。

// same executable, with or without the OpenSSL libraries beside it
sgcCryptoBackend := cbAuto;

这个开关涵盖的内容

这个开关涵盖了组件替你完成的下列密码学操作:

这些都不需要修改代码。昨天还是用 OpenSSL 签名的 JWT,今天就会因为这个变量的设置而改用原生方式签名。

连接是单独的设置

sgcCryptoBackend 不会改变组件的连接方式。一个连接使用的 TLS 是按组件单独选择的:在 TCP、HTTP 和 WebSocket 组件,以及构建在它们之上的一切(比如 MQTT)上,用 IOHandler = iohNativeTLS;在 QUIC 和 HTTP/3 上也是如此;WebRTC 上则是 DTLSOptions:

sgcCryptoBackend := cbNative;                  // application crypto
oClient.TLSOptions.IOHandler := iohNativeTLS;  // this connection

保留 OpenSSL handler 的组件,在连接时仍然会加载 OpenSSL。在 QUIC、HTTP/3 和 DTLS 上使用 iohNativeTLS 时,无论开关怎么设置,都完全不会用到 OpenSSL。想要在任何地方都不用 OpenSSL 的应用需要同时设置两处:为密码学设置这个开关,并为每一个建立安全连接的组件设置 handler。

这个 Define 现在是可选的

在此之前,不使用 OpenSSL 运行就意味着要用 SGC_NATIVE_CRYPTO 这个编译器 define。现在已经不再需要了。不加这个 define,OpenSSL 和原生代码都会被编译进去,由这个变量在运行时决定用哪一个。

这个 define 仍然有一个用处:无论 sgcCryptoBackend 设置成什么,它都会强制使用原生后端,并把 OpenSSL 代码从应用的密码学 unit 中去掉,从而让可执行文件更小。如果你确定某个构建版本永远不会用到 OpenSSL,它仍然是正确的选择。如果你还不确定,就先不加这个 define,留到启动时再决定。

为什么这很重要

升级

在你设置这个变量之前,不会有任何变化,因为 cbOpenSSL 是默认值。要尝试原生后端,把上面那两行加到你的项目文件里,跑一遍测试,再做对比。受这个开关影响的完整列表,以及每个部分要实现运行时零 OpenSSL 各需要哪些设置,都在帮助主题《不使用 OpenSSL 运行》中。

延伸阅读

有问题、反馈,或需要迁移方面的帮助?欢迎联系我们。你会收到编写这些代码的人的回复。