Skip to Content
New release 11.7 available 🎉
ObfuscatorFIPS Compliance

FIPS Compliance

Assemblies protected with Babel Obfuscator run on FIPS-enabled hosts. This page explains how the protection features that rely on runtime decryption — Code Encryption (MSIL), String Encryption, Resource Encryption and Value and Array Encryption — behave on such hosts, a startup issue you may encounter in containers, and how to resolve it — either at obfuscation time, by protecting with Babel’s self-contained managed AES, or at the environment level.

Background

Many customers deploy on hosts where the operating system runs in FIPS mode — on Linux this is exposed as /proc/sys/crypto/fips_enabled = 1. In this mode the platform crypto provider (OpenSSL on Linux) is expected to service every cryptographic operation through a certified FIPS module.

A common problem arises when a container inherits the host’s FIPS flag but its base image does not ship a certified OpenSSL FIPS provider. OpenSSL 3 then tries to enter FIPS mode, fails to load the FIPS provider module, and ends up in a broken state where every digest and cipher operation fails — not only the ones FIPS would normally disallow.

This is an environment condition, not a defect in the obfuscated assembly or in Babel Obfuscator. It is documented independently of Babel — see dotnet/dotnet-docker#5849  and dotnet/runtime#87884 . It affects any OpenSSL-backed .NET cryptography in the process, including TLS (HttpClient, gRPC), not just obfuscated code.

How it can surface in obfuscated assemblies

When an assembly is protected with a feature that decrypts content at runtime — most notably Code Encryption and String Encryption — Babel injects a small runtime that uses the platform’s cryptographic provider to decrypt method bodies and strings. On a broken-FIPS host that provider is unusable, so the decryption runs inside a type initializer and the assembly fails to start before any of your code runs:

System.TypeInitializationException: The type initializer for '...' threw an exception. ---> Interop+Crypto+OpenSslCryptographicException: error:0308010C:digital envelope routines::unsupported at System.Security.Cryptography.AesImplementation.CreateTransform(...)

You can prevent this startup failure at obfuscation time by protecting the assembly with Babel’s managed AES algorithm: the injected runtime then decrypts without the platform cryptographic provider — see Starting on a broken-FIPS host with managed AES below. Fixing the OpenSSL environment (also described below) is still recommended when you control the container, because it additionally resolves other OpenSSL-backed operations in the process, such as TLS.

Starting on a broken-FIPS host with managed AES

Babel Obfuscator can carry a self-contained managed AES decryptor inside the protected assembly, so the injected runtime no longer depends on the platform cryptographic provider. Protect the assembly with the encryption=aesmanaged value of the --use switch:

babel MyApp.dll --msilencryption --use encryption=aesmanaged

or, in an MSBuild / .babel project:

<Use>encryption=aesmanaged</Use>

The obfuscator still encrypts with the platform provider on the build host (which is healthy) and produces the same ciphertext; only the decryptor carried inside the protected assembly changes. This lets the assembly start on a broken-FIPS host without any environment change. Assemblies protected with an earlier Babel release must be re-obfuscated to pick up the managed decryptor.

Performance. The managed decryptor runs at roughly 40 MB/s, versus several GB/s for the hardware-accelerated platform AES. For string, resource and the common (cached) code encryption this is a one-time cost at startup and is not noticeable. The exception is Code Encryption on a method marked cache=false, whose body is decrypted on every call: avoid combining cache=false with encryption=aesmanaged on hot-path methods, and keep the method cache enabled (the default) so decryption happens once.

Resolving it in containers

Make OpenSSL usable inside the container. Either option resolves the obfuscation-runtime symptom and every other OpenSSL-backed operation in your process (for example, if the same assembly also uses Babel Licensing or TLS).

Option 1 — Do not auto-enter FIPS in the container

On Ubuntu-based .NET images, OpenSSL honors the OPENSSL_FORCE_FIPS_MODE environment variable. Set it to 0 so OpenSSL does not try to enter FIPS mode with a provider the image does not ship.

In a Dockerfile:

ENV OPENSSL_FORCE_FIPS_MODE=0

or in docker-compose.yml:

environment: OPENSSL_FORCE_FIPS_MODE: 0

Use this when the container itself does not need to be FIPS-validated: the host stays FIPS-enabled and only this container’s OpenSSL opts out of the broken auto-FIPS path.

Option 2 — Use a base image with a certified FIPS provider

If FIPS compliance is required inside the container, run on a base image that ships a validated FIPS provider so the crypto layer initializes correctly instead of failing:

  • Azure Linux 3.0 .NET images (mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0 and similar), which ship Microsoft’s FIPS-certified SymCrypt provider,
  • Red Hat UBI 9 based .NET images (registry.access.redhat.com/ubi9/dotnet-90 and similar), or
  • Ubuntu Pro with the FIPS-certified OpenSSL packages.

Verifying the environment

A quick check from inside the container tells you whether OpenSSL is healthy:

# Fails on a broken-FIPS host, succeeds once fixed echo test | openssl dgst -sha1
  • Failure with error:03000086 (or a message about fips.so not being loadable) — OpenSSL is in the broken state; apply Option 1 or 2.
  • A normal SHA1(stdin)= ... line — OpenSSL is healthy and obfuscated assemblies start normally.

If you cannot change the environment

If you have no control over the base image or environment variables and the target must remain strictly FIPS constrained, protect the assembly with the managed AES algorithm described above (--use encryption=aesmanaged) so the injected decryptor does not need the platform provider. This lets a protected assembly start even on a broken-OpenSSL host without touching the environment, and keeps all the runtime-decryption features — Code Encryption, String Encryption, Resource Encryption and Value and Array Encryption — available. Note that other OpenSSL-backed operations in the same process (such as TLS) will still fail until the environment is fixed. Contact support  if you need guidance for a specific deployment.

Last updated on