Skip to content

[API Proposal]: SLH-DSA #116282

Closed
@PranavSenthilnathan

Description

@PranavSenthilnathan

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

Metadata

Metadata

Labels

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions