Color scheme: Dark
You are here: start » en » Documentation » Post-Quantum Cryptography » WKL.System.Security.Cryptography overview » Concepts » Crypto modes and call binding

Crypto modes and call binding

graph TD
    CALL["Method call, for example CreateSelfSigned"]
    FW[".NET method, unchanged"]
    EXT["Library extension"]
    DEF["PostQuantumConfig.DefaultMode"]
    C["Classic: result of the .NET method"]
    H["Hybrid: classical plus ML-DSA"]
    P["PostQuantum: ML-DSA or ML-KEM only"]
    CALL -- "without a CryptoMode argument" --> FW
    CALL -- "with a CryptoMode argument" --> EXT
    EXT -- "value null" --> DEF
    EXT --> C
    EXT --> H
    EXT --> P
    DEF --> C
    DEF --> H
    DEF --> P

Figure: The compiler alone decides whether a call reaches the library, based on the CryptoMode argument. Only inside the library does the argument's value select the mode.

The library has three modes. You choose the mode at the call site. There's no global switch that silently changes the behavior of existing code.

Key features

  • Three modes in the CryptoMode enumeration: Classic, Hybrid, and PostQuantum.
  • Binding by the compiler: A call without CryptoMode always reaches the .NET method.
  • A default for the value null: PostQuantumConfig.DefaultMode determines what a call with mode: null creates.
  • No silent fallback: A requested PQ mode delivers PQ or fails.
  • PostQuantum only after an opt-in: Under the BSI TR-02102-1 defaults, PQ algorithms on their own are allowed only after your app permits them.

Core concepts

The three modes

ModeResultWho can verify it
Classicexactly the result of the .NET methodany software
Hybridthe classical result (RSA or ECDSA) plus an ML-DSA or ML-KEM partany software verifies the classical part; software that uses this library verifies both parts
PostQuantumML-DSA or ML-KEM onlyonly software that supports ML-DSA or ML-KEM

Hybrid is the mode for the transition. Peers that don't know about PQ keep working unchanged, and the PQ part protects the data once the classical algorithms can be broken. BSI TR-02102-1 recommends PQ algorithms only in this combination with a classical algorithm.

PostQuantum requires every party to handle ML-DSA or ML-KEM. Because the policy doesn't recommend a PQ algorithm on its own, every operation in this mode throws a CryptographicException until your app sets PostQuantumExemptions.PurePostQuantum in PostQuantumConfig.Exemptions. That applies to verification, too. For details, see Post-quantum algorithm policy.

Binding by the compiler

Each extension has the same name and parameters as the .NET method and appends an optional parameter, CryptoMode? mode. When both an instance method and an extension method fit, the C# compiler always prefers the instance method. As a result:

// Binds to CertificateRequest.CreateSelfSigned in .NET.
using var classic = request.CreateSelfSigned(notBefore, notAfter);
 
// Binds to the library's extension.
using var hybrid = request.CreateSelfSigned(notBefore, notAfter, CryptoMode.Hybrid);

A call without the argument therefore behaves exactly as before, including its errors. For example, for a request with an ML-DSA key, CreateSelfSigned without the argument throws the .NET InvalidOperationException, because .NET doesn't know that key. Only the call with CryptoMode.PostQuantum issues the certificate.

The value null and DefaultMode

When you pass mode: null, the extension applies PostQuantumConfig.DefaultMode. The default is Classic. PostQuantumConfig.EnablePostQuantum(mode) loads OpenSSL and sets DefaultMode to mode only after that succeeds. This lets you set the mode in one place in your app, while every call site still shows through its argument that it uses the library:

PostQuantumConfig.EnablePostQuantum(CryptoMode.Hybrid);
 
// DefaultMode is now Hybrid, so this call creates a hybrid certificate.
using var certificate = request.CreateSelfSigned(notBefore, notAfter, mode: null);

No silent fallback

If a call requests Hybrid or PostQuantum and the library can't create the PQ part, the call fails with a CryptographicException. That happens when OpenSSL is missing or doesn't provide the algorithm, when a required ML-DSA key isn't in the process, and when the key doesn't match the mode. Such a call never returns a result that carries only the classical part.

EnablePostQuantum follows the same rule. If OpenSSL fails to load or doesn't provide ML-DSA-65 or ML-KEM-768, the method throws, and DefaultMode keeps its previous value. EnablePostQuantum(CryptoMode.PostQuantum) throws without the PurePostQuantum exemption before it even loads OpenSSL.

Limitations

  • No argument, no PQ. DefaultMode only affects calls that pass the CryptoMode argument. Existing code without that argument doesn't gain a PQ part from EnablePostQuantum.
  • Pass null by name only. A positional null can bind to a different .NET overload. For example, request.CreateSigningRequest(null) calls the .NET overload that takes an X509SignatureGenerator. Write mode: null instead.
  • The mode and the key must match. PostQuantum needs an ML-DSA or ML-KEM key, and Hybrid needs an RSA or ECDSA key. The library generates the accompanying ML-DSA key or takes it from the caller.
  • Process-wide defaults. DefaultMode and OpenSslPath apply to the whole process. Set both once when your app starts, before the first cryptographic operation runs.
en/wiki/pqcrypt/lib/concepts/crypto-modes.txt · Last modified: by Wolfgang van der Stille