Skip to content

fix FIPS enabled context header creation in ManagedAuthenticatedEncryptor#65186

Merged
DeagleGross merged 5 commits intodotnet:mainfrom
DeagleGross:dmkorolev/fips-ubuntu-dataprotection-fix
Jan 28, 2026
Merged

fix FIPS enabled context header creation in ManagedAuthenticatedEncryptor#65186
DeagleGross merged 5 commits intodotnet:mainfrom
DeagleGross:dmkorolev/fips-ubuntu-dataprotection-fix

Conversation

@DeagleGross
Copy link
Copy Markdown
Member

When initializing ManagedAuthenticatedEncryptor we are calling CreateContextHeader() in the constructor, and during that call we invoke ManagedSP800_108_CTR_HMACSHA512.DeriveKeys(kdk: EMPTY_ARRAY, ...) with the kdk of empty array value.

In #59424 we improved the allocations in NET10 on this path by eventually calling

var success = HMACSHA512.TryHashData(kdk, prfInput, prfOutput, out var bytesWritten);

Unfortunately, for FIPS environment, HMACSHA512.TryHashData fails when kdk provided is less than 14 bytes. Current fix ensures, that if kdk is less than 14 bytes, then we will go with using prf and allocating the buffer. It is not on a hotpath, and for most cases kdk is bigger than 14 bytes (its 64 bytes), so it will not impact performance nearly anyhow.

here is the sample app to prove that 14 bytes is the minimum for FIPS environment:

using System.Security.Cryptography;

Console.WriteLine($"FIPS Enabled: {File.ReadAllText("/proc/sys/crypto/fips_enabled").Trim()}");

Span<byte> data = stackalloc byte[64];
Span<byte> output = stackalloc byte[64];

for (int keyLength = 0; keyLength <= 20; keyLength++)
{
    byte[] key = new byte[keyLength];
    try
    {
        bool success = HMACSHA512.TryHashData(key, data, output, out int bytesWritten);
        Console.WriteLine($"Key length {keyLength,2} bytes: Success");
    }
    catch (CryptographicException ex1)
    {
        // Try the instance-based approach as fallback
        try
        {
            using var hmac = new HMACSHA512(key);
            hmac.ComputeHash(data.ToArray());
            Console.WriteLine($"Key length {keyLength,2} bytes: Static failed, Instance works - \"{ex1.Message}\"");
        }
        catch (Exception ex2)
        {
            Console.WriteLine($"Key length {keyLength,2} bytes: Both failed - Static: \"{ex1.Message}\", Instance: \"{ex2.Message}\"");
        }
    }
}

and i can see the change of results happening specifically around 14 bytes length. Also documented in this NIST SP 800-131A Rev 2.:

Keys less than 112 bits in length are disallowed for HMAC generation.
The use of key lengths ≥ 112 bits is acceptable for HMAC generation.

Fixes #64597

@DeagleGross DeagleGross self-assigned this Jan 22, 2026
Copilot AI review requested due to automatic review settings January 22, 2026 14:34
@github-actions github-actions bot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Jan 22, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a FIPS compliance issue in ASP.NET Core 10's Data Protection APIs. The problem was introduced by performance optimizations in PR #59424, which started using HMACSHA512.TryHashData static method. This static method fails in FIPS mode when the key is less than 14 bytes (112 bits), as required by NIST SP 800-131A Rev. 2.

Changes:

  • Added FIPS-compliant key length validation in ManagedSP800_108_CTR_HMACSHA512.DeriveKeys
  • Falls back to instance-based HMAC for keys < 14 bytes to maintain FIPS compatibility
  • Added regression tests for empty KDK scenario that triggered the original issue

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/DataProtection/DataProtection/src/SP800_108/ManagedSP800_108_CTR_HMACSHA512.cs Implements FIPS-compliant key length check and fallback logic for short keys, along with conditional code path in the private DeriveKeys method
src/DataProtection/DataProtection/test/Microsoft.AspNetCore.DataProtection.Tests/SP800_108/SP800_108Tests.cs Adds regression test covering the empty key scenario used by CreateContextHeader()

Copy link
Copy Markdown
Member

@adityamandaleeka adityamandaleeka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo my comment and Copilot's

@DeagleGross
Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

@DeagleGross DeagleGross added area-dataprotection Includes: DataProtection and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Jan 28, 2026
@DeagleGross DeagleGross merged commit 8d90964 into dotnet:main Jan 28, 2026
25 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the 11.0-preview1 milestone Jan 28, 2026
@DeagleGross DeagleGross deleted the dmkorolev/fips-ubuntu-dataprotection-fix branch January 28, 2026 19:28
@DeagleGross
Copy link
Copy Markdown
Member Author

/backport to release/10.0

@github-actions
Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

@github-actions
Copy link
Copy Markdown
Contributor

@DeagleGross backporting to release/10.0 failed, the patch most likely resulted in conflicts. Please backport manually!

git am output
$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Patch format detection failed.
Error: The process '/usr/bin/git' failed with exit code 128

Link to workflow output

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-dataprotection Includes: DataProtection

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ASP.NET Core 10 Data Protection has cryptographic errors on Ubuntu 22.04 with FIPS enabled

4 participants