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
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,18 @@ private void ExportKey(KeyBlobMagicNumber kind, Span<byte> destination)

int blobHeaderSize = Marshal.SizeOf<BCRYPT_MLKEM_KEY_BLOB>();
int keySize = checked((int)blob->cbKey);

if (keySize != destination.Length)
{
throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
}

int paramSetSize = checked((int)blob->cbParameterSet);
string paramSet = Marshal.PtrToStringUni((nint)(pExportedSpan + blobHeaderSize))!;
string expectedParamSet = PqcBlobHelpers.GetMLKemParameterSet(Algorithm);
ReadOnlySpan<char> paramSetWithNull = new(pExportedSpan + blobHeaderSize, paramSetSize / sizeof(char));
ReadOnlySpan<char> paramSet = paramSetWithNull[0..^1];
ReadOnlySpan<char> expectedParamSet = PqcBlobHelpers.GetMLKemParameterSet(Algorithm);

if (paramSet != expectedParamSet)
if (!paramSet.SequenceEqual(expectedParamSet) || paramSetWithNull[^1] != '\0')
{
throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey);
}
Expand All @@ -253,5 +260,7 @@ private void ExportKey(KeyBlobMagicNumber kind, Span<byte> destination)
CryptoPool.Return(exported);
}
}


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ public void ExportPrivateSeed_OnlyHasDecapsulationKey()
{
using MLKem kem = ImportDecapsulationKey(MLKemAlgorithm.MLKem512, MLKemTestData.MLKem512DecapsulationKey);

Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed());
Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed(
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed());
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed(
new byte[MLKemAlgorithm.MLKem512.PrivateSeedSizeInBytes]));
}

Expand All @@ -58,8 +58,8 @@ public void ExportPrivateSeed_OnlyHasEncapsulationKey()
{
using MLKem kem = ImportEncapsulationKey(MLKemAlgorithm.MLKem512, MLKemTestData.MLKem512EncapsulationKey);

Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed());
Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed(
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed());
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed(
new byte[MLKemAlgorithm.MLKem512.PrivateSeedSizeInBytes]));
}

Expand All @@ -68,8 +68,8 @@ public void ExportDecapsulationKey_OnlyHasEncapsulationKey()
{
using MLKem kem = ImportEncapsulationKey(MLKemAlgorithm.MLKem512, MLKemTestData.MLKem512EncapsulationKey);

Assert.Throws<CryptographicException>(() => kem.ExportDecapsulationKey());
Assert.Throws<CryptographicException>(() => kem.ExportDecapsulationKey(
Assert.ThrowsAny<CryptographicException>(() => kem.ExportDecapsulationKey());
Assert.ThrowsAny<CryptographicException>(() => kem.ExportDecapsulationKey(
new byte[MLKemAlgorithm.MLKem512.DecapsulationKeySizeInBytes]));
}

Expand Down Expand Up @@ -344,7 +344,7 @@ public void ExportPkcs8PrivateKey_DecapsulationKey_Roundtrip()
using MLKem imported = MLKem.ImportPkcs8PrivateKey(pkcs8);
Assert.Equal(MLKemAlgorithm.MLKem512, imported.Algorithm);

Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed());
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed());
AssertExtensions.SequenceEqual(MLKemTestData.MLKem512DecapsulationKey, kem.ExportDecapsulationKey());
});
}
Expand All @@ -370,7 +370,7 @@ public void ExportEncryptedPkcs8PrivateKey_DecapsulationKey_Roundtrip()
AssertExtensions.SequenceEqual(
MLKemTestData.MLKem512DecapsulationKey,
imported.ExportDecapsulationKey());
Assert.Throws<CryptographicException>(() => imported.ExportPrivateSeed());
Assert.ThrowsAny<CryptographicException>(() => imported.ExportPrivateSeed());
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public static void GetMLKemPublicKey_WithoutPrivateKey()
}
}

[ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))]
[ConditionalFact(typeof(PlatformSupport), nameof(PlatformSupport.IsPqcMLKemX509Supported))]
public static void GetMLKemPublicKey_WithPrivateKey()
{
using (X509Certificate2 cert = X509CertificateLoader.LoadPkcs12(
Expand All @@ -179,7 +179,7 @@ public static void GetMLKemPublicKey_WithPrivateKey()
}
}

[ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))]
[ConditionalFact(typeof(PlatformSupport), nameof(PlatformSupport.IsPqcMLKemX509Supported))]
public static void GetMLKemPrivateKey_NoPrivateKey()
{
using (X509Certificate2 cert = MLKemCertTests.LoadCertificateFromPem(MLKemTestData.IetfMlKem512CertificatePem))
Expand Down
Loading