OpenSSL or Native Crypto in Delphi: Choose at Runtime

· Components
OpenSSL or Native Crypto in Delphi: Choose at Runtime

Removing the OpenSSL DLLs from a Delphi application used to be a build decision. You turned on a compiler define, rebuilt, and shipped a second executable to the customers who could not have OpenSSL on their machines. sgcWebSockets 2026.10 turns it into a runtime decision: one global variable, set once at startup, chooses whether the application cryptography runs on OpenSSL or on the cryptography built into the library, written in Object Pascal.

The connection side, TLS without OpenSSL, is covered in Delphi TLS 1.3 Without OpenSSL DLLs. This post is about everything else: the signatures, hashes, key agreement and encryption your application does outside the TLS handshake.

One Line at Startup

The unit sgcBase_Helpers declares the global sgcCryptoBackend, of type TsgcCryptoBackend:

uses
  sgcBase_Helpers;

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

The switch is global, not per component, so set it before any component is created. sgcCheckNativeCrypto is optional: if the native crypto units are not compiled in, it raises at startup with a clear message instead of on the first signature your application tries to make.

Three Values

cbAuto is the one for products that are deployed both ways. Some customers install the OpenSSL libraries next to the executable, some are not allowed to, and the same build works for both without a support ticket about a missing DLL.

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

What Follows the Switch

The switch covers the cryptography the components do on your behalf:

None of these need a code change. A JWT that was signed with OpenSSL yesterday is signed natively today because the variable says so.

The Connections Are a Separate Setting

sgcCryptoBackend does not change how a component connects. The TLS of a connection is chosen per component, with IOHandler = iohNativeTLS, on the TCP, HTTP and WebSocket components and everything built on them, such as MQTT, on QUIC and HTTP/3, and on DTLSOptions for WebRTC:

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

A component that keeps the OpenSSL handler still loads OpenSSL when it connects. With iohNativeTLS on QUIC, HTTP/3 and DTLS, no OpenSSL is used at all, whatever the switch says. An application that wants no OpenSSL anywhere sets both: the switch for its cryptography, and the handler on each component that opens a secure connection.

The Define Is Now Optional

Until now, running without OpenSSL meant the SGC_NATIVE_CRYPTO compiler define. It is no longer needed. Without it, both the OpenSSL and the native code are compiled in and the variable decides at runtime.

The define still has one use. It forces the native backend whatever sgcCryptoBackend says and removes the OpenSSL code from the application crypto units, so the executable is smaller. If you know a build will never use OpenSSL, it is still the right choice. If you do not know yet, leave it off and decide at startup.

Why It Matters

Upgrading

Nothing changes until you set the variable, because cbOpenSSL is the default. To try the native backend, add the two lines above to your project file, run your tests, and compare. The full list of what follows the switch, and which setting each area needs for zero OpenSSL at runtime, is in the help topic Running without OpenSSL.

Questions, feedback or migration help? Get in touch. You will get a reply from the people who wrote the code.