Description
Based on the initial API outlined in #113506.
The PKCS#8 and SPKI APIs for SLH-DSA were approved in #114453 for ML-KEM. They are repeated here just for completeness.
API Proposal
namespace System.Security.Cryptogrpahy
{
// System.Security.Cryptography and Microsoft.Bcl.Cryptography
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public abstract class SlhDsa : IDisposable
{
public static bool IsSupported { get; }
protected SlhDsa(SlhDsaAlgorithm algorithm);
public SlhDsaAlgorithm Algorithm { get; }
// Sign/Verify
public byte[] SignData(byte[] data, byte[]? context = null);
public void SignData(ReadOnlySpan<byte> data, Span<byte> destination, ReadOnlySpan<byte> context = default);
protected abstract void SignDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte> context, Span<byte> destination);
public bool VerifyData(byte[] data, byte[] signature, byte[]? context = null);
public bool VerifyData(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, ReadOnlySpan<byte> context = default);
protected abstract bool VerifyDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte> context, ReadOnlySpan<byte> signature);
public byte[] SignPreHash(byte[] hash, string hashAlgorithmOid, byte[]? context = null);
public void SignPreHash(ReadOnlySpan<byte> hash, Span<byte> destination, string hashAlgorithmOid, ReadOnlySpan<byte> context = default);
protected abstract void SignPreHashCore(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> context, string hashAlgorithmOid, Span<byte> destination);
public bool VerifyPreHash(byte[] hash, byte[] signature, string hashAlgorithmOid, byte[]? context = null);
public bool VerifyPreHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature, string hashAlgorithmOid, ReadOnlySpan<byte> context = default);
protected abstract bool VerifyPreHashCore(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> context, string hashAlgorithmOid, ReadOnlySpan<byte> signature);
// Create/Import/Export
public static SlhDsa GenerateKey(SlhDsaAlgorithm algorithm);
public static SlhDsa ImportSlhDsaPublicKey(SlhDsaAlgorithm algorithm, byte[] source);
public static SlhDsa ImportSlhDsaPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source);
public static SlhDsa ImportSlhDsaSecretKey(SlhDsaAlgorithm algorithm, byte[] source);
public static SlhDsa ImportSlhDsaSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source);
public byte[] ExportSlhDsaPublicKey();
public void ExportSlhDsaPublicKey(Span<byte> destination);
protected abstract void ExportSlhDsaPublicKeyCore(Span<byte> destination);
public byte[] ExportSlhDsaSecretKey();
public void ExportSlhDsaSecretKey(Span<byte> destination);
protected abstract void ExportSlhDsaSecretKeyCore(Span<byte> destination);
// SPKI / PKCS#8
public static SlhDsa ImportSubjectPublicKeyInfo(byte[] source);
public static SlhDsa ImportSubjectPublicKeyInfo(ReadOnlySpan<byte> source);
public static SlhDsa ImportPkcs8PrivateKey(byte[] source);
public static SlhDsa ImportPkcs8PrivateKey(ReadOnlySpan<byte> source);
public static SlhDsa ImportFromPem(ReadOnlySpan<char> source);
public static SlhDsa ImportFromPem(string source);
public static SlhDsa ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, ReadOnlySpan<byte> source);
public static SlhDsa ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source);
public static SlhDsa ImportEncryptedPkcs8PrivateKey(string password, byte[] source);
public static SlhDsa ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<byte> passwordBytes);
public static SlhDsa ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<char> password);
public static SlhDsa ImportFromEncryptedPem(string source, byte[] passwordBytes);
public static SlhDsa ImportFromEncryptedPem(string source, string password);
public byte[] ExportSubjectPublicKeyInfo();
public bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out int bytesWritten);
public string ExportSubjectPublicKeyInfoPem();
public byte[] ExportPkcs8PrivateKey();
public bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritten);
protected virtual bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out int bytesWritten);
public string ExportPkcs8PrivateKeyPem();
public byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
public byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters pbeParameters);
public byte[] ExportEncryptedPkcs8PrivateKey(string password, PbeParameters pbeParameters);
public bool TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters, Span<byte> destination, out int bytesWritten);
public bool TryExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters pbeParameters, Span<byte> destination, out int bytesWritten);
public bool TryExportEncryptedPkcs8PrivateKey(string password, PbeParameters pbeParameters, Span<byte> destination, out int bytesWritten);
public string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
public string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<char> password, PbeParameters pbeParameters);
public string ExportEncryptedPkcs8PrivateKeyPem(string password, PbeParameters pbeParameters);
public void Dispose();
protected virtual void Dispose(bool disposing);
}
// System.Security.Cryptography and Microsoft.Bcl.Cryptography
[DebuggerDisplay("{Name,nq}")]
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public sealed class SlhDsaAlgorithm : IEquatable<SlhDsaAlgorithm>
{
internal SlhDsaAlgorithm();
public string Name { get; }
public int PublicKeySizeInBytes { get; }
public int SecretKeySizeInBytes { get; }
public int SignatureSizeInBytes { get; }
public static SlhDsaAlgorithm SlhDsaSha2_128f { get; }
public static SlhDsaAlgorithm SlhDsaSha2_128s { get; }
public static SlhDsaAlgorithm SlhDsaSha2_192f { get; }
public static SlhDsaAlgorithm SlhDsaSha2_192s { get; }
public static SlhDsaAlgorithm SlhDsaSha2_256f { get; }
public static SlhDsaAlgorithm SlhDsaSha2_256s { get; }
public static SlhDsaAlgorithm SlhDsaShake128f { get; }
public static SlhDsaAlgorithm SlhDsaShake128s { get; }
public static SlhDsaAlgorithm SlhDsaShake192f { get; }
public static SlhDsaAlgorithm SlhDsaShake192s { get; }
public static SlhDsaAlgorithm SlhDsaShake256f { get; }
public static SlhDsaAlgorithm SlhDsaShake256s { get; }
public bool Equals(SlhDsaAlgorithm? other);
public static bool operator ==(SlhDsaAlgorithm? left, SlhDsaAlgorithm? right);
public static bool operator !=(SlhDsaAlgorithm? left, SlhDsaAlgorithm? right);
}
// System.Security.Cryptography only
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public sealed class SlhDsaOpenSsl : SlhDsa
{
[UnsupportedOSPlatformAttribute("android")]
[UnsupportedOSPlatformAttribute("browser")]
[UnsupportedOSPlatformAttribute("ios")]
[UnsupportedOSPlatformAttribute("osx")]
[UnsupportedOSPlatformAttribute("tvos")]
[UnsupportedOSPlatformAttribute("windows")]
public SlhDsaOpenSsl(SafeEvpPKeyHandle pkeyHandle);
public SafeEvpPKeyHandle DuplicateKeyHandle();
}
}
namespace System.Security.Cryptography.X509Certificates
{
// System.Security.Cryptography only
public sealed partial class CertificateRequest
{
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public CertificateRequest(X500DistinguishedName subjectName, SlhDsa key);
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public CertificateRequest(string subjectName, SlhDsa key);
}
// System.Security.Cryptography only
public sealed partial class PublicKey
{
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public PublicKey(SlhDsa key);
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
[UnsupportedOSPlatformAttribute("browser")]
public SlhDsa? GetSlhDsaPublicKey();
}
// System.Security.Cryptography only
public partial class X509Certificate2
{
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public X509Certificate2 CopyWithPrivateKey(SlhDsa privateKey);
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public SlhDsa? GetSlhDsaPrivateKey();
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public SlhDsa? GetSlhDsaPublicKey();
}
// System.Security.Cryptography only
public abstract partial class X509SignatureGenerator
{
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public static X509SignatureGenerator CreateForSlhDsa(SlhDsa key);
}
// Microsoft.Bcl.Cryptography only
public static partial class X509CertificateKeyAccessors
{
[Experimental("SYSLIB5006", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public static SlhDsa? GetSlhDsaPublicKey(this X509Certificate2 certificate);
[Experimental("SYSLIB5006", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public static SlhDsa? GetSlhDsaPrivateKey(this X509Certificate2 certificate);
[Experimental("SYSLIB5006", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public static X509Certificate2 CopyWithPrivateKey(this X509Certificate2 certificate, SlhDsa privateKey)
}
}
#if NET
namespace System.Security.Cryptography.Pkcs
{
public sealed partial class CmsSigner
{
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public CmsSigner(SubjectIdentifierType signerIdentifierType, X509Certificate2? certificate, SlhDsa? privateKey);
public bool HasPrivateKey { get; }
}
}
#endif