diff --git a/docs/workflow/building/libraries/README.md b/docs/workflow/building/libraries/README.md
index ae017971914b09..c5da32b51c633b 100644
--- a/docs/workflow/building/libraries/README.md
+++ b/docs/workflow/building/libraries/README.md
@@ -128,7 +128,7 @@ The libraries build contains some native code. This includes shims over libc, op
- Building and updating the binplace (for e.g. the testhost), which is needed when iterating on native components
```bash
-dotnet.sh build src/native/libraries/build-native.proj
+dotnet.sh build src/native/libs/build-native.proj
```
- The following example shows how you would do an arm cross-compile build
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.Kem.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.Kem.cs
index 7fec2cd26ea838..c5157bf7bd6268 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.Kem.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.Kem.cs
@@ -11,6 +11,19 @@ internal static partial class Interop
{
internal static partial class Crypto
{
+ ///
+ /// Gets the extra handle associated with the EVP_PKEY. Some tests need to access
+ /// the interop layer and achieve this by adding the relevant classes to the test
+ /// project as links. However, accesses to internal members like
+ /// in the product project will not work in the test project. In this particular case,
+ /// the test project does not need the value of the handle, so it can implement this
+ /// method to return a null pointer.
+ ///
+ ///
+ /// The extra handle associated with the EVP_PKEY.
+ ///
+ /// The extra handle associated with the EVP_PKEY.
+ ///
private static partial IntPtr GetExtraHandle(SafeEvpPKeyHandle handle);
// Must be kept in sync with PalKemId in native shim.
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPKey.MLDsa.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.MLDsa.cs
similarity index 78%
rename from src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPKey.MLDsa.cs
rename to src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.MLDsa.cs
index 908bf35bd81431..c38270bad490d1 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPKey.MLDsa.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.MLDsa.cs
@@ -64,42 +64,6 @@ internal static SafeEvpPKeyHandle MLDsaGenerateKey(string algorithmName, ReadOnl
return handle;
}
- [LibraryImport(Libraries.CryptoNative, StringMarshalling = StringMarshalling.Utf8)]
- private static partial SafeEvpPKeyHandle CryptoNative_MLDsaImportSecretKey(string keyType, ReadOnlySpan sk, int skLength);
-
- internal static SafeEvpPKeyHandle MLDsaImportSecretKey(string algorithmName, ReadOnlySpan sk)
- {
- SafeEvpPKeyHandle? handle = CryptoNative_MLDsaImportSecretKey(algorithmName, sk, sk.Length);
- Debug.Assert(handle != null, "handle != null");
-
- if (handle.IsInvalid)
- {
- Exception ex = Interop.Crypto.CreateOpenSslCryptographicException();
- handle.Dispose();
- throw ex;
- }
-
- return handle;
- }
-
- [LibraryImport(Libraries.CryptoNative, StringMarshalling = StringMarshalling.Utf8)]
- private static partial SafeEvpPKeyHandle CryptoNative_MLDsaImportPublicKey(string keyType, ReadOnlySpan pk, int pkLength);
-
- internal static SafeEvpPKeyHandle MLDsaImportPublicKey(string algorithmName, ReadOnlySpan pk)
- {
- SafeEvpPKeyHandle handle = CryptoNative_MLDsaImportPublicKey(algorithmName, pk, pk.Length);
- Debug.Assert(handle != null, "handle != null");
-
- if (handle.IsInvalid)
- {
- Exception ex = Interop.Crypto.CreateOpenSslCryptographicException();
- handle.Dispose();
- throw ex;
- }
-
- return handle;
- }
-
[LibraryImport(Libraries.CryptoNative)]
private static partial int CryptoNative_MLDsaSignPure(
SafeEvpPKeyHandle pkey, IntPtr extraHandle,
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPKey.MLDsaAlgs.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.MLDsaAlgs.cs
similarity index 100%
rename from src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPKey.MLDsaAlgs.cs
rename to src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.MLDsaAlgs.cs
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.SlhDsa.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.SlhDsa.cs
new file mode 100644
index 00000000000000..3049426151834e
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.SlhDsa.cs
@@ -0,0 +1,146 @@
+// 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.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using Microsoft.Win32.SafeHandles;
+
+internal static partial class Interop
+{
+ internal static partial class Crypto
+ {
+ [LibraryImport(Libraries.CryptoNative, StringMarshalling = StringMarshalling.Utf8)]
+ private static partial SafeEvpPKeyHandle CryptoNative_SlhDsaGenerateKey(string keyType);
+
+ internal static SafeEvpPKeyHandle SlhDsaGenerateKey(string algorithmName)
+ {
+ SafeEvpPKeyHandle handle = CryptoNative_SlhDsaGenerateKey(algorithmName);
+ Debug.Assert(handle != null, "handle != null");
+
+ if (handle.IsInvalid)
+ {
+ Exception ex = Interop.Crypto.CreateOpenSslCryptographicException();
+ handle.Dispose();
+ throw ex;
+ }
+
+ return handle;
+ }
+
+ // Must be kept in sync with PalSlhDsaId in native shim.
+ internal enum PalSlhDsaAlgorithmId
+ {
+ Unknown = 0,
+ SlhDsaSha2_128s = 1,
+ SlhDsaShake128s = 2,
+ SlhDsaSha2_128f = 3,
+ SlhDsaShake128f = 4,
+ SlhDsaSha2_192s = 5,
+ SlhDsaShake192s = 6,
+ SlhDsaSha2_192f = 7,
+ SlhDsaShake192f = 8,
+ SlhDsaSha2_256s = 9,
+ SlhDsaShake256s = 10,
+ SlhDsaSha2_256f = 11,
+ SlhDsaShake256f = 12,
+ }
+
+ [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SlhDsaGetPalId")]
+ private static partial int CryptoNative_SlhDsaGetPalId(
+ SafeEvpPKeyHandle slhDsa,
+ out PalSlhDsaAlgorithmId slhDsaId);
+
+ internal static PalSlhDsaAlgorithmId GetSlhDsaAlgorithmId(SafeEvpPKeyHandle key)
+ {
+ const int Success = 1;
+ const int Fail = 0;
+ int result = CryptoNative_SlhDsaGetPalId(key, out PalSlhDsaAlgorithmId slhDsaId);
+
+ return result switch
+ {
+ Success => slhDsaId,
+ Fail => throw CreateOpenSslCryptographicException(),
+ int other => throw FailThrow(other),
+ };
+
+ static Exception FailThrow(int result)
+ {
+ Debug.Fail($"Unexpected return value {result} from {nameof(CryptoNative_SlhDsaGetPalId)}.");
+ return new CryptographicException();
+ }
+ }
+
+ [LibraryImport(Libraries.CryptoNative)]
+ private static partial int CryptoNative_SlhDsaSignPure(
+ SafeEvpPKeyHandle pkey, IntPtr extraHandle,
+ ReadOnlySpan msg, int msgLength,
+ ReadOnlySpan context, int contextLength,
+ Span destination, int destinationLength);
+
+ internal static void SlhDsaSignPure(
+ SafeEvpPKeyHandle pkey,
+ ReadOnlySpan msg,
+ ReadOnlySpan context,
+ Span destination)
+ {
+ int ret = CryptoNative_SlhDsaSignPure(
+ pkey, GetExtraHandle(pkey),
+ msg, msg.Length,
+ context, context.Length,
+ destination, destination.Length);
+
+ if (ret != 1)
+ {
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+ }
+
+ [LibraryImport(Libraries.CryptoNative)]
+ private static partial int CryptoNative_SlhDsaVerifyPure(
+ SafeEvpPKeyHandle pkey, IntPtr extraHandle,
+ ReadOnlySpan msg, int msgLength,
+ ReadOnlySpan context, int contextLength,
+ ReadOnlySpan signature, int signatureLength);
+
+ internal static bool SlhDsaVerifyPure(
+ SafeEvpPKeyHandle pkey,
+ ReadOnlySpan msg,
+ ReadOnlySpan context,
+ ReadOnlySpan signature)
+ {
+ int ret = CryptoNative_SlhDsaVerifyPure(
+ pkey, GetExtraHandle(pkey),
+ msg, msg.Length,
+ context, context.Length,
+ signature, signature.Length);
+
+ if (ret == 1)
+ {
+ return true;
+ }
+ else if (ret == 0)
+ {
+ return false;
+ }
+ else
+ {
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+ }
+
+ [LibraryImport(Libraries.CryptoNative)]
+ private static partial int CryptoNative_SlhDsaExportSecretKey(SafeEvpPKeyHandle pkey, Span destination, int destinationLength);
+
+ [LibraryImport(Libraries.CryptoNative)]
+ private static partial int CryptoNative_SlhDsaExportPublicKey(SafeEvpPKeyHandle pkey, Span destination, int destinationLength);
+
+ internal static void SlhDsaExportSecretKey(SafeEvpPKeyHandle key, Span destination) =>
+ Interop.Crypto.ExportKeyContents(key, destination, CryptoNative_SlhDsaExportSecretKey);
+
+ internal static void SlhDsaExportPublicKey(SafeEvpPKeyHandle key, Span destination) =>
+ Interop.Crypto.ExportKeyContents(key, destination, CryptoNative_SlhDsaExportPublicKey);
+ }
+}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.SlhDsaAlgs.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.SlhDsaAlgs.cs
new file mode 100644
index 00000000000000..43f5f032aadeb6
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.SlhDsaAlgs.cs
@@ -0,0 +1,52 @@
+// 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.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using Microsoft.Win32.SafeHandles;
+
+internal static partial class Interop
+{
+ internal static partial class Crypto
+ {
+ internal static partial class EvpPKeySlhDsaAlgs
+ {
+ internal static string? SlhDsaSha2_128s { get; }
+ internal static string? SlhDsaShake128s { get; }
+ internal static string? SlhDsaSha2_128f { get; }
+ internal static string? SlhDsaShake128f { get; }
+ internal static string? SlhDsaSha2_192s { get; }
+ internal static string? SlhDsaShake192s { get; }
+ internal static string? SlhDsaSha2_192f { get; }
+ internal static string? SlhDsaShake192f { get; }
+ internal static string? SlhDsaSha2_256s { get; }
+ internal static string? SlhDsaShake256s { get; }
+ internal static string? SlhDsaSha2_256f { get; }
+ internal static string? SlhDsaShake256f { get; }
+
+ static EvpPKeySlhDsaAlgs()
+ {
+ CryptoInitializer.Initialize();
+
+ // Do not use property initializers for these because we need to ensure CryptoInitializer.Initialize
+ // is called first. Property initializers happen before cctors, so instead set the property after the
+ // initializer is run.
+ SlhDsaSha2_128s = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaSha2_128s.Name);
+ SlhDsaShake128s = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaShake128s.Name);
+ SlhDsaSha2_128f = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaSha2_128f.Name);
+ SlhDsaShake128f = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaShake128f.Name);
+ SlhDsaSha2_192s = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaSha2_192s.Name);
+ SlhDsaShake192s = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaShake192s.Name);
+ SlhDsaSha2_192f = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaSha2_192f.Name);
+ SlhDsaShake192f = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaShake192f.Name);
+ SlhDsaSha2_256s = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaSha2_256s.Name);
+ SlhDsaShake256s = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaShake256s.Name);
+ SlhDsaSha2_256f = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaSha2_256f.Name);
+ SlhDsaShake256f = IsSignatureAlgorithmAvailable(SlhDsaAlgorithm.SlhDsaShake256f.Name);
+ }
+ }
+ }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
index 4f0a89829213ba..c70c5effb3fe3d 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
@@ -285,9 +285,9 @@ public byte[] ExportPkcs8PrivateKey()
ThrowIfDisposed();
// TODO: When defining this, provide a virtual method whose base implementation is to
- // call ExportPrivateSeed and/or ExportSecretKey, and then assemble the result,
- // but allow the derived class to override it in case they need to implement those
- // others in terms of the PKCS8 export from the underlying provider.
+ // call ExportSecretKey, and then assemble the result, but allow the derived class to
+ // override it in case they need to implement those others in terms of the PKCS8 export
+ // from the underlying provider.
throw new NotImplementedException("The PKCS#8 format is still under debate");
}
@@ -342,7 +342,6 @@ public string ExportPkcs8PrivateKeyPem()
throw new NotImplementedException("The PKCS#8 format is still under debate");
}
-#if !NETSTANDARD2_0_OR_GREATER && !NETFRAMEWORK // Remove once PbeParameters is outboxed
///
/// Exports the current key in the PKCS#8 EncryptedPrivateKeyInfo format with a char-based password.
///
@@ -620,7 +619,6 @@ public string ExportEncryptedPkcs8PrivateKeyPem(
writer.Reset();
}
}
-#endif
///
/// Exports the public-key portion of the current key in the FIPS 205 public key format.
@@ -679,36 +677,6 @@ public int ExportSlhDsaSecretKey(Span destination)
return secretKeySizeInBytes;
}
- ///
- /// Exports the private seed of the current key.
- ///
- ///
- /// The buffer to receive the private seed.
- ///
- ///
- /// The number of bytes written to .
- ///
- ///
- /// is too small to hold the private seed.
- ///
- ///
- /// An error occurred while exporting the private seed.
- ///
- public int ExportSlhDsaPrivateSeed(Span destination)
- {
- int privateSeedSizeInBytes = Algorithm.PrivateSeedSizeInBytes;
-
- if (destination.Length < privateSeedSizeInBytes)
- {
- throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
- }
-
- ThrowIfDisposed();
-
- ExportSlhDsaPrivateSeedCore(destination.Slice(0, privateSeedSizeInBytes));
- return privateSeedSizeInBytes;
- }
-
///
/// Generates a new SLH-DSA key for the specified algorithm.
///
@@ -1031,7 +999,7 @@ public static SlhDsa ImportSlhDsaPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySp
if (source.Length != algorithm.PublicKeySizeInBytes)
{
- throw new ArgumentException(SR.Argument_PublicKeyWrongSizeForAlgorithm);
+ throw new ArgumentException(SR.Argument_PublicKeyWrongSizeForAlgorithm, nameof(source));
}
ThrowIfNotSupported();
@@ -1070,7 +1038,7 @@ public static SlhDsa ImportSlhDsaSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySp
if (source.Length != algorithm.SecretKeySizeInBytes)
{
- throw new ArgumentException(SR.Argument_SecretKeyWrongSizeForAlgorithm);
+ throw new ArgumentException(SR.Argument_SecretKeyWrongSizeForAlgorithm, nameof(source));
}
ThrowIfNotSupported();
@@ -1078,45 +1046,6 @@ public static SlhDsa ImportSlhDsaSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySp
return SlhDsaImplementation.ImportSecretKey(algorithm, source);
}
- ///
- /// Imports an SLH-DSA private key from its private seed value.
- ///
- ///
- /// The specific SLH-DSA algorithm for this key.
- ///
- ///
- /// The bytes the key seed.
- ///
- ///
- /// The imported key.
- ///
- ///
- ///
- /// is not a valid SLH-DSA algorithm identifier.
- ///
- /// -or-
- ///
- /// is not the correct size for the specified algorithm.
- ///
- /// -or-
- ///
- /// An error occurred while importing the key.
- ///
- ///
- public static SlhDsa ImportSlhDsaPrivateSeed(SlhDsaAlgorithm algorithm, ReadOnlySpan source)
- {
- ThrowIfNull(algorithm);
-
- if (source.Length != algorithm.PrivateSeedSizeInBytes)
- {
- throw new ArgumentException(SR.Argument_PrivateSeedWrongSizeForAlgorithm);
- }
-
- ThrowIfNotSupported();
-
- return SlhDsaImplementation.ImportSeed(algorithm, source);
- }
-
///
/// Called by the Dispose() and Finalize() methods to release the managed and unmanaged
/// resources used by the current instance of the class.
@@ -1183,14 +1112,6 @@ protected virtual void Dispose(bool disposing)
///
protected abstract void ExportSlhDsaSecretKeyCore(Span destination);
- ///
- /// When overridden in a derived class, exports the private seed to the specified buffer.
- ///
- ///
- /// The buffer to receive the private seed.
- ///
- protected abstract void ExportSlhDsaPrivateSeedCore(Span destination);
-
private AsnWriter ExportSubjectPublicKeyInfoCore()
{
byte[] rented = CryptoPool.Rent(Algorithm.PublicKeySizeInBytes);
diff --git a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaAlgorithm.cs b/src/libraries/Common/src/System/Security/Cryptography/SlhDsaAlgorithm.cs
index bbaaa5e61538ce..e807190365e990 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaAlgorithm.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/SlhDsaAlgorithm.cs
@@ -45,14 +45,6 @@ public sealed class SlhDsaAlgorithm
///
public int SignatureSizeInBytes { get; }
- ///
- /// Gets the size of the private seed in bytes for this algorithm.
- ///
- ///
- /// The size of the private seed in bytes for this algorithm.
- ///
- public int PrivateSeedSizeInBytes { get; }
-
///
/// Gets the Object Identifier (OID) for this algorithm.
///
@@ -80,9 +72,8 @@ private SlhDsaAlgorithm(string name, int n, int signatureSizeInBytes, string oid
{
Name = name;
- // The seed, secret key and public key sizes are shown to be 3n, 4n and 2n respectively in
+ // The secret key and public key sizes are shown to be 4n and 2n respectively in
// section 9.1 "Key Generation", particularly figure 15 and 16.
- PrivateSeedSizeInBytes = 3 * n;
SecretKeySizeInBytes = 4 * n;
PublicKeySizeInBytes = 2 * n;
SignatureSizeInBytes = signatureSizeInBytes;
diff --git a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.NotSupported.cs b/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.NotSupported.cs
index 4200bb0ee443f3..9873e76235c8cc 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.NotSupported.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.NotSupported.cs
@@ -29,9 +29,6 @@ protected override void ExportSlhDsaPublicKeyCore(Span destination) =>
protected override void ExportSlhDsaSecretKeyCore(Span destination) =>
throw new PlatformNotSupportedException();
- protected override void ExportSlhDsaPrivateSeedCore(Span destination) =>
- throw new PlatformNotSupportedException();
-
internal static partial SlhDsa ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
throw new PlatformNotSupportedException();
@@ -40,8 +37,5 @@ internal static partial SlhDsa ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algori
internal static partial SlhDsa ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
throw new PlatformNotSupportedException();
-
- internal static partial SlhDsa ImportSeed(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
- throw new PlatformNotSupportedException();
}
}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.OpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.OpenSsl.cs
deleted file mode 100644
index 93567712bc637b..00000000000000
--- a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.OpenSsl.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Buffers;
-using System.Diagnostics.CodeAnalysis;
-
-namespace System.Security.Cryptography
-{
- internal sealed partial class SlhDsaImplementation : SlhDsa
- {
- internal static partial bool SupportsAny() => false;
-
- // TODO: Define this in terms of OpenSSL
- private SlhDsaImplementation(/* SafeEvpPKeyHandle handle, */ SlhDsaAlgorithm algorithm) : base(algorithm) =>
- throw new PlatformNotSupportedException();
-
- internal static partial SlhDsa GenerateKeyCore(SlhDsaAlgorithm algorithm) =>
- throw new PlatformNotSupportedException();
-
- protected override void SignDataCore(ReadOnlySpan data, ReadOnlySpan context, Span destination) =>
- throw new PlatformNotSupportedException();
-
- protected override bool VerifyDataCore(ReadOnlySpan data, ReadOnlySpan context, ReadOnlySpan signature) =>
- throw new PlatformNotSupportedException();
-
- protected override void ExportSlhDsaPublicKeyCore(Span destination) =>
- throw new PlatformNotSupportedException();
-
- protected override void ExportSlhDsaSecretKeyCore(Span destination) =>
- throw new PlatformNotSupportedException();
-
- protected override void ExportSlhDsaPrivateSeedCore(Span destination) =>
- throw new PlatformNotSupportedException();
-
- internal static partial SlhDsa ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
- throw new PlatformNotSupportedException();
-
- internal static partial SlhDsa ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
- throw new PlatformNotSupportedException();
-
- internal static partial SlhDsa ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
- throw new PlatformNotSupportedException();
-
- internal static partial SlhDsa ImportSeed(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
- throw new PlatformNotSupportedException();
- }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.Windows.cs b/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.Windows.cs
index 7509782430f566..67afac26e8ea7d 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.Windows.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.Windows.cs
@@ -29,9 +29,6 @@ protected override void ExportSlhDsaPublicKeyCore(Span destination) =>
protected override void ExportSlhDsaSecretKeyCore(Span destination) =>
throw new PlatformNotSupportedException();
- protected override void ExportSlhDsaPrivateSeedCore(Span destination) =>
- throw new PlatformNotSupportedException();
-
internal static partial SlhDsa ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
throw new PlatformNotSupportedException();
@@ -40,8 +37,5 @@ internal static partial SlhDsa ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algori
internal static partial SlhDsa ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
throw new PlatformNotSupportedException();
-
- internal static partial SlhDsa ImportSeed(SlhDsaAlgorithm algorithm, ReadOnlySpan source) =>
- throw new PlatformNotSupportedException();
}
}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.cs b/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.cs
index dc6b390c319dbb..79da5d43d0cfbe 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.cs
@@ -15,6 +15,5 @@ internal sealed partial class SlhDsaImplementation : SlhDsa
internal static partial SlhDsa ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source);
internal static partial SlhDsa ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source);
internal static partial SlhDsa ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source);
- internal static partial SlhDsa ImportSeed(SlhDsaAlgorithm algorithm, ReadOnlySpan source);
}
}
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTests.cs
index e73498072eaa16..5cb78e93dcb98e 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTests.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTests.cs
@@ -32,8 +32,7 @@ public static void IsSupported_AgreesWithPlatform()
Assert.Equal(PlatformSupportsMLDsa(), MLDsa.IsSupported);
}
- private static bool PlatformSupportsMLDsa()
- => PlatformDetection.IsOpenSslSupported && PlatformDetection.OpenSslVersion >= new Version(3, 5);
+ private static bool PlatformSupportsMLDsa() => PlatformDetection.IsOpenSsl3_5;
[Fact]
public static void DisposeIsCalledOnImplementation()
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTestsBase.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTestsBase.cs
index 2e85f2de199fe6..39bdb8d91c33a3 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTestsBase.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTestsBase.cs
@@ -49,6 +49,29 @@ public void GenerateSignVerifyWithContext(MLDsaAlgorithm algorithm)
ExerciseSuccessfulVerify(mldsa, data, signature, context);
}
+ [Theory]
+ [MemberData(nameof(MLDsaTestsData.AllMLDsaAlgorithms), MemberType = typeof(MLDsaTestsData))]
+ public void GenerateSignVerifyEmptyMessageNoContext(MLDsaAlgorithm algorithm)
+ {
+ using MLDsa mldsa = GenerateKey(algorithm);
+ byte[] signature = new byte[mldsa.Algorithm.SignatureSizeInBytes];
+ Assert.Equal(signature.Length, mldsa.SignData([], signature));
+
+ ExerciseSuccessfulVerify(mldsa, [], signature, []);
+ }
+
+ [Theory]
+ [MemberData(nameof(MLDsaTestsData.AllMLDsaAlgorithms), MemberType = typeof(MLDsaTestsData))]
+ public void GenerateSignVerifyEmptyMessageWithContext(MLDsaAlgorithm algorithm)
+ {
+ using MLDsa mldsa = GenerateKey(algorithm);
+ byte[] context = [1, 1, 3, 5, 6];
+ byte[] signature = new byte[mldsa.Algorithm.SignatureSizeInBytes];
+ Assert.Equal(signature.Length, mldsa.SignData([], signature, context));
+
+ ExerciseSuccessfulVerify(mldsa, [], signature, context);
+ }
+
[Theory]
[MemberData(nameof(MLDsaTestsData.AllMLDsaAlgorithms), MemberType = typeof(MLDsaTestsData))]
public void GenerateSignExportPublicVerifyWithPublicOnly(MLDsaAlgorithm algorithm)
@@ -200,9 +223,24 @@ public void NistImportSecretKeyVerifyExportsAndSignature(MLDsaNistTestCase testC
protected static void ExerciseSuccessfulVerify(MLDsa mldsa, byte[] data, byte[] signature, byte[] context)
{
AssertExtensions.TrueExpression(mldsa.VerifyData(data, signature, context));
- data[0] ^= 1;
- AssertExtensions.FalseExpression(mldsa.VerifyData(data, signature, context));
- data[0] ^= 1;
+
+ if (data.Length > 0)
+ {
+ AssertExtensions.FalseExpression(mldsa.VerifyData([], signature, context));
+ AssertExtensions.FalseExpression(mldsa.VerifyData(ReadOnlySpan.Empty, signature, context));
+
+ data[0] ^= 1;
+ AssertExtensions.FalseExpression(mldsa.VerifyData(data, signature, context));
+ data[0] ^= 1;
+ }
+ else
+ {
+ AssertExtensions.TrueExpression(mldsa.VerifyData([], signature, context));
+ AssertExtensions.TrueExpression(mldsa.VerifyData(ReadOnlySpan.Empty, signature, context));
+
+ AssertExtensions.FalseExpression(mldsa.VerifyData([0], signature, context));
+ AssertExtensions.FalseExpression(mldsa.VerifyData([1, 2, 3], signature, context));
+ }
signature[0] ^= 1;
AssertExtensions.FalseExpression(mldsa.VerifyData(data, signature, context));
@@ -211,6 +249,7 @@ protected static void ExerciseSuccessfulVerify(MLDsa mldsa, byte[] data, byte[]
if (context.Length > 0)
{
AssertExtensions.FalseExpression(mldsa.VerifyData(data, signature, []));
+ AssertExtensions.FalseExpression(mldsa.VerifyData(data, signature, ReadOnlySpan.Empty));
context[0] ^= 1;
AssertExtensions.FalseExpression(mldsa.VerifyData(data, signature, context));
@@ -218,6 +257,9 @@ protected static void ExerciseSuccessfulVerify(MLDsa mldsa, byte[] data, byte[]
}
else
{
+ AssertExtensions.TrueExpression(mldsa.VerifyData(data, signature, []));
+ AssertExtensions.TrueExpression(mldsa.VerifyData(data, signature, ReadOnlySpan.Empty));
+
AssertExtensions.FalseExpression(mldsa.VerifyData(data, signature, [0]));
AssertExtensions.FalseExpression(mldsa.VerifyData(data, signature, [1, 2, 3]));
}
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaAlgorithmTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaAlgorithmTests.cs
index 4d400e6866d570..93684d19b324f5 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaAlgorithmTests.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaAlgorithmTests.cs
@@ -16,84 +16,72 @@ public static void AlgorithmsHaveExpectedParameters()
Assert.Equal("SLH-DSA-SHA2-128s", algorithm.Name);
Assert.Equal(32, algorithm.PublicKeySizeInBytes);
Assert.Equal(64, algorithm.SecretKeySizeInBytes);
- Assert.Equal(48, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(7856, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaShake128s;
Assert.Equal("SLH-DSA-SHAKE-128s", algorithm.Name);
Assert.Equal(32, algorithm.PublicKeySizeInBytes);
Assert.Equal(64, algorithm.SecretKeySizeInBytes);
- Assert.Equal(48, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(7856, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaSha2_128f;
Assert.Equal("SLH-DSA-SHA2-128f", algorithm.Name);
Assert.Equal(32, algorithm.PublicKeySizeInBytes);
Assert.Equal(64, algorithm.SecretKeySizeInBytes);
- Assert.Equal(48, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(17088, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaShake128f;
Assert.Equal("SLH-DSA-SHAKE-128f", algorithm.Name);
Assert.Equal(32, algorithm.PublicKeySizeInBytes);
Assert.Equal(64, algorithm.SecretKeySizeInBytes);
- Assert.Equal(48, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(17088, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaSha2_192s;
Assert.Equal("SLH-DSA-SHA2-192s", algorithm.Name);
Assert.Equal(48, algorithm.PublicKeySizeInBytes);
Assert.Equal(96, algorithm.SecretKeySizeInBytes);
- Assert.Equal(72, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(16224, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaShake192s;
Assert.Equal("SLH-DSA-SHAKE-192s", algorithm.Name);
Assert.Equal(48, algorithm.PublicKeySizeInBytes);
Assert.Equal(96, algorithm.SecretKeySizeInBytes);
- Assert.Equal(72, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(16224, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaSha2_192f;
Assert.Equal("SLH-DSA-SHA2-192f", algorithm.Name);
Assert.Equal(48, algorithm.PublicKeySizeInBytes);
Assert.Equal(96, algorithm.SecretKeySizeInBytes);
- Assert.Equal(72, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(35664, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaShake192f;
Assert.Equal("SLH-DSA-SHAKE-192f", algorithm.Name);
Assert.Equal(48, algorithm.PublicKeySizeInBytes);
Assert.Equal(96, algorithm.SecretKeySizeInBytes);
- Assert.Equal(72, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(35664, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaSha2_256s;
Assert.Equal("SLH-DSA-SHA2-256s", algorithm.Name);
Assert.Equal(64, algorithm.PublicKeySizeInBytes);
Assert.Equal(128, algorithm.SecretKeySizeInBytes);
- Assert.Equal(96, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(29792, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaShake256s;
Assert.Equal("SLH-DSA-SHAKE-256s", algorithm.Name);
Assert.Equal(64, algorithm.PublicKeySizeInBytes);
Assert.Equal(128, algorithm.SecretKeySizeInBytes);
- Assert.Equal(96, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(29792, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaSha2_256f;
Assert.Equal("SLH-DSA-SHA2-256f", algorithm.Name);
Assert.Equal(64, algorithm.PublicKeySizeInBytes);
Assert.Equal(128, algorithm.SecretKeySizeInBytes);
- Assert.Equal(96, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(49856, algorithm.SignatureSizeInBytes);
algorithm = SlhDsaAlgorithm.SlhDsaShake256f;
Assert.Equal("SLH-DSA-SHAKE-256f", algorithm.Name);
Assert.Equal(64, algorithm.PublicKeySizeInBytes);
Assert.Equal(128, algorithm.SecretKeySizeInBytes);
- Assert.Equal(96, algorithm.PrivateSeedSizeInBytes);
Assert.Equal(49856, algorithm.SignatureSizeInBytes);
}
}
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaApiTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaApiTests.cs
new file mode 100644
index 00000000000000..f944a015dae3fd
--- /dev/null
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaApiTests.cs
@@ -0,0 +1,171 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Reflection.Emit;
+using Xunit;
+using Xunit.Sdk;
+
+namespace System.Security.Cryptography.SLHDsa.Tests
+{
+ public sealed class SlhDsaApiTests : SlhDsaInstanceTestsBase
+ {
+ public static IEnumerable