Skip to content

ML-KEM: Windows ephemeral implementation #116440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libraries/Common/src/Interop/Windows/BCrypt/Cng.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ internal static class AlgorithmName
public const string RSA = "RSA"; // BCRYPT_RSA_ALGORITHM
public const string MD5 = "MD5"; // BCRYPT_MD5_ALGORITHM
public const string MLDsa = "ML-DSA"; // BCRYPT_MLDSA_ALGORITHM
public const string MLKem = "ML-KEM"; // BCRYPT_MLKEM_ALGORITHM
public const string Sha1 = "SHA1"; // BCRYPT_SHA1_ALGORITHM
public const string Sha256 = "SHA256"; // BCRYPT_SHA256_ALGORITHM
public const string Sha384 = "SHA384"; // BCRYPT_SHA384_ALGORITHM
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

internal static partial class Interop
{
internal static partial class BCrypt
{
[LibraryImport(Libraries.BCrypt)]
private static unsafe partial NTSTATUS BCryptDecapsulate(
SafeBCryptKeyHandle hKey,
byte* pbCipherText,
uint cbCipherText,
byte* pbSecretKey,
uint cbSecretKey,
out uint pcbSecretKey,
uint dwFlags);

[LibraryImport(Libraries.BCrypt)]
private static unsafe partial NTSTATUS BCryptEncapsulate(
SafeBCryptKeyHandle hKey,
byte* pbSecretKey,
uint cbSecretKey,
out uint pcbSecretKey,
byte* pbCipherText,
uint cbCipherText,
out uint pcbCipherText,
uint dwFlags);

internal static unsafe uint BCryptDecapsulate(
SafeBCryptKeyHandle hKey,
ReadOnlySpan<byte> cipherText,
Span<byte> secretKey,
uint dwFlags)
{
fixed (byte* pCiphertext = cipherText)
fixed (byte* pSecretKey = secretKey)
{
NTSTATUS status = BCryptDecapsulate(
hKey,
pCiphertext,
(uint)cipherText.Length,
pSecretKey,
(uint)secretKey.Length,
out uint pcbSecretKey,
dwFlags);

if (status != NTSTATUS.STATUS_SUCCESS)
{
throw CreateCryptographicException(status);
}

return pcbSecretKey;
}
}

internal static unsafe void BCryptEncapsulate(
SafeBCryptKeyHandle hKey,
Span<byte> secretKey,
Span<byte> cipherText,
out uint pcbSecretKey,
out uint pcbCipherText,
uint dwFlags)
{
fixed (byte* pSecretKey = secretKey)
fixed (byte* pCipherText = cipherText)
{
NTSTATUS status = BCryptEncapsulate(
hKey,
pSecretKey,
(uint)secretKey.Length,
out pcbSecretKey,
pCipherText,
(uint)cipherText.Length,
out pcbCipherText,
dwFlags);

if (status != NTSTATUS.STATUS_SUCCESS)
{
throw CreateCryptographicException(status);
}
}
}
}
}
16 changes: 16 additions & 0 deletions src/libraries/Common/src/Interop/Windows/BCrypt/Interop.Blobs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ internal enum KeyBlobMagicNumber : int
BCRYPT_MLDSA_PRIVATE_MAGIC = 0x4B535344,
BCRYPT_MLDSA_PRIVATE_SEED_MAGIC = 0x53535344,

BCRYPT_MLKEM_PUBLIC_MAGIC = 0x504B4C4D, // MLKP
BCRYPT_MLKEM_PRIVATE_MAGIC = 0x524B4C4D, // MLKR
BCRYPT_MLKEM_PRIVATE_SEED_MAGIC = 0x534B4C4D, // MLKS

BCRYPT_RSAPUBLIC_MAGIC = 0x31415352,
BCRYPT_RSAPRIVATE_MAGIC = 0x32415352,
BCRYPT_RSAFULLPRIVATE_MAGIC = 0x33415352,
Expand Down Expand Up @@ -141,6 +145,10 @@ internal static class KeyBlobType
internal const string BCRYPT_PQDSA_PUBLIC_BLOB = "PQDSAPUBLICBLOB";
internal const string BCRYPT_PQDSA_PRIVATE_BLOB = "PQDSAPRIVATEBLOB";
internal const string BCRYPT_PQDSA_PRIVATE_SEED_BLOB = "PQDSAPRIVATESEEDBLOB";

internal const string BCRYPT_MLKEM_PRIVATE_SEED_BLOB = "MLKEMPRIVATESEEDBLOB";
internal const string BCRYPT_MLKEM_PRIVATE_BLOB = "MLKEMPRIVATEBLOB";
internal const string BCRYPT_MLKEM_PUBLIC_BLOB = "MLKEMPUBLICBLOB";
}

/// <summary>
Expand Down Expand Up @@ -255,6 +263,14 @@ internal struct BCRYPT_PQDSA_KEY_BLOB
// The rest of the buffer contains the data
}

[StructLayout(LayoutKind.Sequential)]
internal struct BCRYPT_MLKEM_KEY_BLOB
{
internal KeyBlobMagicNumber dwMagic;
internal uint cbParameterSet;
internal uint cbKey;
}

/// <summary>
/// NCrypt or BCrypt buffer descriptors
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal static partial MLDsaImplementation GenerateKeyImpl(MLDsaAlgorithm algor
{
Debug.Assert(s_algHandle is not null, $"Check {nameof(SupportsAny)}() before calling.");

string parameterSet = PqcBlobHelpers.GetParameterSet(algorithm);
string parameterSet = PqcBlobHelpers.GetMLDsaParameterSet(algorithm);
SafeBCryptKeyHandle keyHandle = Interop.BCrypt.BCryptGenerateKeyPair(s_algHandle, keyLength: 0);

try
Expand All @@ -66,7 +66,7 @@ internal static partial MLDsaImplementation ImportPublicKey(MLDsaAlgorithm algor

SafeBCryptKeyHandle key =
PqcBlobHelpers.EncodeMLDsaBlob(
PqcBlobHelpers.GetParameterSet(algorithm),
PqcBlobHelpers.GetMLDsaParameterSet(algorithm),
source,
PublicBlobType,
static blob => Interop.BCrypt.BCryptImportKeyPair(s_algHandle, PublicBlobType, blob));
Expand All @@ -82,7 +82,7 @@ internal static partial MLDsaImplementation ImportSecretKey(MLDsaAlgorithm algor

SafeBCryptKeyHandle key =
PqcBlobHelpers.EncodeMLDsaBlob(
PqcBlobHelpers.GetParameterSet(algorithm),
PqcBlobHelpers.GetMLDsaParameterSet(algorithm),
source,
PrivateBlobType,
static blob => Interop.BCrypt.BCryptImportKeyPair(s_algHandle, PrivateBlobType, blob));
Expand All @@ -98,7 +98,7 @@ internal static partial MLDsaImplementation ImportSeed(MLDsaAlgorithm algorithm,

SafeBCryptKeyHandle key =
PqcBlobHelpers.EncodeMLDsaBlob(
PqcBlobHelpers.GetParameterSet(algorithm),
PqcBlobHelpers.GetMLDsaParameterSet(algorithm),
source,
PrivateSeedBlobType,
static blob => Interop.BCrypt.BCryptImportKeyPair(s_algHandle, PrivateSeedBlobType, blob));
Expand Down
Loading
Loading