HKDF.DeriveKey mutates ikm parameter and returns all-zero output in .NET 10
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
## Description
In .NET 10, HKDF.DeriveKey exhibits two critical bugs:
The ikm byte array is mutated after the call — even when using the ReadOnlySpan overload, the underlying array content is overwritten.
The output is always all zeros — regardless of input values, DeriveKey produces zero-filled output.
HKDF.Extract and HKDF.Expand work correctly when called individually. The bug is specific to HKDF.DeriveKey.
## Reproduction
C#
```
using System.Security.Cryptography;
// RFC 5869 Appendix A.1 test vector
byte[] ikm = new byte[] {
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
};
byte[] salt = new byte[] {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c
};
byte[] info = new byte[] {
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9
};
byte[] ikmCopy = new byte[ikm.Length];
Buffer.BlockCopy(ikm, 0, ikmCopy, 0, ikm.Length);
byte[] output = new byte[42];
HKDF.DeriveKey(HashAlgorithmName.SHA256, output, ikmCopy, salt, info);
Console.WriteLine($"ikm mutated: {!ikmCopy.AsSpan().SequenceEqual(ikm)}");
// Output: ikm mutated: True
// ikm changed from: 0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B-0B
// to: E4-F4-90-BD-DC-B7-26-F9-8D-D2-D4-2F-F2-98-80-33-BB-E3-AC-E4-56-61
Console.WriteLine($"output is all zeros: {output.All(b => b == 0)}");
// Output: output is all zeros: True
// Expected OKM (RFC 5869 A.1, 42 bytes):
// 3C-B2-5F-25-FA-AC-D5-7A-90-43-4F-64-D0-36-2F-2A-2D-2D-0A-90-CF-1A-5A-4C-5D-B0-2D-56-EC-C4-C5-BF-34-00-72-08-D5-B8-87-18-58-65
```
The ReadOnlySpan overload exhibits the same behavior:
C#
```
HKDF.DeriveKey(HashAlgorithmName.SHA256, output.AsSpan(), ikmCopy.AsSpan(), salt.AsSpan(), info.AsSpan());
// ikmCopy is still mutated, output is still all zeros
```
## What works correctly
HKDF.Extract(HashAlgorithmName.SHA256, ikm, salt) — produces correct PRK, does not mutate ikm
HKDF.Expand(HashAlgorithmName.SHA256, prk, output, info) — produces correct OKM, does not mutate prk
Combining HKDF.Extract + manual HKDF.Expand (or using HMACSHA256 directly) works correctly as a workaround.
## Affected parameters
The bug reproduces with all ikm lengths tested (16, 22, 32, 64 bytes) and various salt/info sizes. It is not specific to any particular input size.
## Configuration
.NET version: 10.0.9
CLR: 10.0.9
OS: Windows 11 (x64)
Runtime: net10.0
Regression
This is a regression from .NET 9 and earlier, where HKDF.DeriveKey worked correctly and matched RFC 5869.
## Impact
This is a cryptographic correctness bug:
Key derivation produces deterministic all-zero output, which is trivially predictable
Anyone relying on HKDF.DeriveKey for key material derivation will get zero keys, completely breaking security
The ikm mutation is a side-channel concern and violates the ReadOnlySpan contract
## Workaround
Use HKDF.Extract + HKDF.Expand separately, or a manual HMAC-SHA256 implementation of RFC 5869.
Contributor guide
Assessment
This issue has not been assessed yet.