Skip to content

[API Proposal]: MLKem #114453

Closed
Closed

Description

@vcsjones

Background and motivation

This is the proposed API that resulted from the MLKem work in #113508.

API Proposal

namespace System.Security.Cryptogrpahy
{
    // Present in both System.Security.Cryptography and Microsoft.Bcl.Cryptography
    [ExperimentalAttribute("SYSLIB5006")]
    public abstract partial class MLKem : IDisposable
    {
        protected MLKem(MLKemAlgorithm algorithm);

        public static bool IsSupported { get; }

        public MLKemAlgorithm Algorithm { get; }

        public byte[] Decapsulate(byte[] ciphertext);
        public void Decapsulate(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret);
        public void Decapsulate(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret, out int sharedSecretBytesWritten);
        protected abstract void DecapsulateCore(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret);

        public byte[] Encapsulate(out byte[] sharedSecret);
        public byte[] Encapsulate(Span<byte> sharedSecret);
        public void Encapsulate(Span<byte> ciphertext, Span<byte> sharedSecret);
        public void Encapsulate(
            Span<byte> ciphertext,
            Span<byte> sharedSecret,
            out int ciphertextBytesWritten,
            out int sharedSecretBytesWritten);
        protected abstract void EncapsulateCore(Span<byte> ciphertext, Span<byte> sharedSecret);

        public byte[] ExportDecapsulationKey();
        public void ExportDecapsulationKey(Span<byte> destination);
        protected abstract void ExportDecapsulationKeyCore(Span<byte> destination);

        public byte[] ExportEncapsulationKey();
        public void ExportEncapsulationKey(Span<byte> destination);
        protected abstract void ExportEncapsulationKeyCore(Span<byte> destination);

        public byte[] ExportPrivateSeed();
        public void ExportPrivateSeed(Span<byte> destination);
        protected abstract void ExportPrivateSeedCore(Span<byte> destination);

        public static MLKem GenerateKey(MLKemAlgorithm algorithm);

        public static MLKem ImportDecapsulationKey(MLKemAlgorithm algorithm, byte[] source);
        public static MLKem ImportDecapsulationKey(MLKemAlgorithm algorithm, ReadOnlySpan<byte> source);
        public static MLKem ImportEncapsulationKey(MLKemAlgorithm algorithm, byte[] source);
        public static MLKem ImportEncapsulationKey(MLKemAlgorithm algorithm, ReadOnlySpan<byte> source);

        public static MLKem ImportPrivateSeed(MLKemAlgorithm algorithm, byte[] source);
        public static MLKem ImportPrivateSeed(MLKemAlgorithm algorithm, ReadOnlySpan<byte> source);

        protected void ThrowIfDisposed();
        public void Dispose();
        protected virtual void Dispose(bool disposing);

#region SPKI / PKCS8

        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 byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
        public byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters pbeParameters);
        public byte[] ExportEncryptedPkcs8PrivateKey(string password, PbeParameters pbeParameters);
        public string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
        public string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<char> password, PbeParameters pbeParameters);
        public string ExportEncryptedPkcs8PrivateKeyPem(string password, PbeParameters pbeParameters);

        public byte[] ExportPkcs8PrivateKey();
        public string ExportPkcs8PrivateKeyPem();
        public bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritten);
        protected abstract bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out int bytesWritten);

        public byte[] ExportSubjectPublicKeyInfo();
        public bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out int bytesWritten);
        public string ExportSubjectPublicKeyInfoPem();

        public static MLKem ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, ReadOnlySpan<byte> source);
        public static MLKem ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source);
        public static MLKem ImportEncryptedPkcs8PrivateKey(string password, ReadOnlySpan<byte> source);

        public static MLKem ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<byte> passwordBytes);
        public static MLKem ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<char> password);
        public static MLKem ImportFromEncryptedPem(string source, byte[] passwordBytes);
        public static MLKem ImportFromEncryptedPem(string source, string password);

        public static MLKem ImportFromPem(ReadOnlySpan<char> source);
        public static MLKem ImportFromPem(string source);

        public static MLKem ImportPkcs8PrivateKey(byte[] source);
        public static MLKem ImportPkcs8PrivateKey(ReadOnlySpan<byte> source);

        public static MLKem ImportSubjectPublicKeyInfo(byte[] source);
        public static MLKem ImportSubjectPublicKeyInfo(ReadOnlySpan<byte> source);
#endregion
    }

    // Present in both System.Security.Cryptography and Microsoft.Bcl.Cryptography
    [ExperimentalAttribute("SYSLIB5006")]
    public sealed partial class MLKemAlgorithm : IEquatable<MLKemAlgorithm>
    {
        internal MLKemAlgorithm();

        public static MLKemAlgorithm MLKem512 { get; }
        public static MLKemAlgorithm MLKem768 { get; }
        public static MLKemAlgorithm MLKem1024 { get; }

        public string Name { get; }

        public int CiphertextSizeInBytes { get; }
        public int DecapsulationKeySizeInBytes { get; }
        public int EncapsulationKeySizeInBytes { get; }
        public int PrivateSeedSizeInBytes { get; }
        public int SharedSecretSizeInBytes { get; }

        public bool Equals(MLKemAlgorithm? other);

        public static bool operator ==(MLKemAlgorithm? left, MLKemAlgorithm? right);
        public static bool operator !=(MLKemAlgorithm? left, MLKemAlgorithm? right);
    }

    // Present in System.Security.Cryptography only
    [ExperimentalAttribute("SYSLIB5006")]
    public sealed partial class MLKemOpenSsl : MLKem
    {
        [UnsupportedOSPlatform("android")]
        [UnsupportedOSPlatform("browser")]
        [UnsupportedOSPlatform("ios")]
        [UnsupportedOSPlatform("osx")]
        [UnsupportedOSPlatform("tvos")]
        [UnsupportedOSPlatform("windows")]
        public MLKemOpenSsl(SafeEvpPKeyHandle pkeyHandle);

        public SafeEvpPKeyHandle DuplicateKeyHandle();
    }
}

namespace System.Security.Cryptography.X509Certificates
{
    // Existing class
    // Present in System.Security.Cryptography only
    public sealed partial class PublicKey
    {
        [Experimental("SYSLIB5006")]
        public PublicKey(MLKem key);

        [Experimental("SYSLIB5006")]
        [UnsupportedOSPlatform("browser")]
        public MLKem? GetMLKemPublicKey();
    }

    // Existing class
    // Present in System.Security.Cryptography only
    public partial class X509Certificate2
    {
        [ExperimentalAttribute("SYSLIB5006")]
        public MLKem GetMLKemPublicKey();

        [ExperimentalAttribute("SYSLIB5006")]
        public MLKem GetMLKemPrivateKey();

        [ExperimentalAttribute("SYSLIB5006")]
        public X509Certificate2 CopyWithPrivateKey(MLKem privateKey);
    }

    // New class (will also be used for future algorithms)
    // Present in Microsoft.Bcl.Cryptography only
    public static class X509CertificateKeyAccessors
    {
        [ExperimentalAttribute("SYSLIB5006")]
        public static MLKem GetMLKemPublicKey(this X509Certificate2 certificate);

        [ExperimentalAttribute("SYSLIB5006")]
        public static MLKem GetMLKemPrivateKey(this X509Certificate2 certificate);

        [ExperimentalAttribute("SYSLIB5006")]
        public static X509Certificate2 CopyWithPrivateKey(this X509Certificate2 certificate, MLKem key);
    }
}

API Usage

See https://github.com/vcsjones/ml-kem-demo/blob/main/Program.cs for an example of the end-to-end scenarios for MLKem.

Alternative Designs

No response

Risks

No response

Activity

  1. added this to the 10.0.0 milestone on Apr 9, 2025
  2. dotnet-policy-service commented on Apr 9, 2025

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones
    See info in area-owners.md if you want to be subscribed.

  3. added theissue type on Apr 9, 2025
  4. added
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    and removed
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    on Apr 11, 2025
  5. bartonjs commented on Apr 15, 2025

    @bartonjs
    Member

    Video

    • Decapsulate(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret, out int sharedSecretBytesWritten); seems a little weird and unnecessary. If there's demand for it we can add it in the future.
    • By analogy, we cut the out-writing ones for Encapsulate
    • Encapsulate got reshaped to simplify the outs vs returns vs span-writing
    • ThrowIfDisposed seemes unnecessary

    We ran out of time after the instance methods on MLKem, we'll resume in a future session.

    namespace System.Security.Cryptogrpahy
    {
        // Present in both System.Security.Cryptography and Microsoft.Bcl.Cryptography
        [ExperimentalAttribute("SYSLIB5006")]
        public abstract partial class MLKem : IDisposable
        {
            protected MLKem(MLKemAlgorithm algorithm);
    
            public static bool IsSupported { get; }
    
            public MLKemAlgorithm Algorithm { get; }
    
            public byte[] Decapsulate(byte[] ciphertext);
            public void Decapsulate(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret);
            protected abstract void DecapsulateCore(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret);
    
            public void Encapsulate(out byte[] ciphertext, out byte[] sharedSecret);
            public void Encapsulate(Span<byte> ciphertext, Span<byte> sharedSecret);
            protected abstract void EncapsulateCore(Span<byte> ciphertext, Span<byte> sharedSecret);
    
            public byte[] ExportDecapsulationKey();
            public void ExportDecapsulationKey(Span<byte> destination);
            protected abstract void ExportDecapsulationKeyCore(Span<byte> destination);
    
            public byte[] ExportEncapsulationKey();
            public void ExportEncapsulationKey(Span<byte> destination);
            protected abstract void ExportEncapsulationKeyCore(Span<byte> destination);
    
            public byte[] ExportPrivateSeed();
            public void ExportPrivateSeed(Span<byte> destination);
            protected abstract void ExportPrivateSeedCore(Span<byte> destination);
    
    // Continue from here.
            public static MLKem GenerateKey(MLKemAlgorithm algorithm);
    
            public static MLKem ImportDecapsulationKey(MLKemAlgorithm algorithm, byte[] source);
            public static MLKem ImportDecapsulationKey(MLKemAlgorithm algorithm, ReadOnlySpan<byte> source);
            public static MLKem ImportEncapsulationKey(MLKemAlgorithm algorithm, byte[] source);
            public static MLKem ImportEncapsulationKey(MLKemAlgorithm algorithm, ReadOnlySpan<byte> source);
    
            public static MLKem ImportPrivateSeed(MLKemAlgorithm algorithm, byte[] source);
            public static MLKem ImportPrivateSeed(MLKemAlgorithm algorithm, ReadOnlySpan<byte> source);
    
            public void Dispose();
            protected virtual void Dispose(bool disposing);
    
    #region SPKI / PKCS8
    
            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 byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
            public byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters pbeParameters);
            public byte[] ExportEncryptedPkcs8PrivateKey(string password, PbeParameters pbeParameters);
            public string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
            public string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<char> password, PbeParameters pbeParameters);
            public string ExportEncryptedPkcs8PrivateKeyPem(string password, PbeParameters pbeParameters);
    
            public byte[] ExportPkcs8PrivateKey();
            public string ExportPkcs8PrivateKeyPem();
            public bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritten);
            protected abstract bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out int bytesWritten);
    
            public byte[] ExportSubjectPublicKeyInfo();
            public bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out int bytesWritten);
            public string ExportSubjectPublicKeyInfoPem();
    
            public static MLKem ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, ReadOnlySpan<byte> source);
            public static MLKem ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source);
            public static MLKem ImportEncryptedPkcs8PrivateKey(string password, ReadOnlySpan<byte> source);
    
            public static MLKem ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<byte> passwordBytes);
            public static MLKem ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<char> password);
            public static MLKem ImportFromEncryptedPem(string source, byte[] passwordBytes);
            public static MLKem ImportFromEncryptedPem(string source, string password);
    
            public static MLKem ImportFromPem(ReadOnlySpan<char> source);
            public static MLKem ImportFromPem(string source);
    
            public static MLKem ImportPkcs8PrivateKey(byte[] source);
            public static MLKem ImportPkcs8PrivateKey(ReadOnlySpan<byte> source);
    
            public static MLKem ImportSubjectPublicKeyInfo(byte[] source);
            public static MLKem ImportSubjectPublicKeyInfo(ReadOnlySpan<byte> source);
    #endregion
        }
    
        // Present in both System.Security.Cryptography and Microsoft.Bcl.Cryptography
        [ExperimentalAttribute("SYSLIB5006")]
        public sealed partial class MLKemAlgorithm : IEquatable<MLKemAlgorithm>
        {
            internal MLKemAlgorithm();
    
            public static MLKemAlgorithm MLKem512 { get; }
            public static MLKemAlgorithm MLKem768 { get; }
            public static MLKemAlgorithm MLKem1024 { get; }
    
            public string Name { get; }
    
            public int CiphertextSizeInBytes { get; }
            public int DecapsulationKeySizeInBytes { get; }
            public int EncapsulationKeySizeInBytes { get; }
            public int PrivateSeedSizeInBytes { get; }
            public int SharedSecretSizeInBytes { get; }
    
            public bool Equals(MLKemAlgorithm? other);
    
            public static bool operator ==(MLKemAlgorithm? left, MLKemAlgorithm? right);
            public static bool operator !=(MLKemAlgorithm? left, MLKemAlgorithm? right);
        }
    
        // Present in System.Security.Cryptography only
        [ExperimentalAttribute("SYSLIB5006")]
        public sealed partial class MLKemOpenSsl : MLKem
        {
            [UnsupportedOSPlatform("android")]
            [UnsupportedOSPlatform("browser")]
            [UnsupportedOSPlatform("ios")]
            [UnsupportedOSPlatform("osx")]
            [UnsupportedOSPlatform("tvos")]
            [UnsupportedOSPlatform("windows")]
            public MLKemOpenSsl(SafeEvpPKeyHandle pkeyHandle);
    
            public SafeEvpPKeyHandle DuplicateKeyHandle();
        }
    }
    
    namespace System.Security.Cryptography.X509Certificates
    {
        // Existing class
        // Present in System.Security.Cryptography only
        public sealed partial class PublicKey
        {
            [Experimental("SYSLIB5006")]
            public PublicKey(MLKem key);
    
            [Experimental("SYSLIB5006")]
            [UnsupportedOSPlatform("browser")]
            public MLKem? GetMLKemPublicKey();
        }
    
        // Existing class
        // Present in System.Security.Cryptography only
        public partial class X509Certificate2
        {
            [ExperimentalAttribute("SYSLIB5006")]
            public MLKem GetMLKemPublicKey();
    
            [ExperimentalAttribute("SYSLIB5006")]
            public MLKem GetMLKemPrivateKey();
    
            [ExperimentalAttribute("SYSLIB5006")]
            public X509Certificate2 CopyWithPrivateKey(MLKem privateKey);
        }
    
        // New class (will also be used for future algorithms)
        // Present in Microsoft.Bcl.Cryptography only
        public static class X509CertificateKeyAccessors
        {
            [ExperimentalAttribute("SYSLIB5006")]
            public static MLKem GetMLKemPublicKey(this X509Certificate2 certificate);
    
            [ExperimentalAttribute("SYSLIB5006")]
            public static MLKem GetMLKemPrivateKey(this X509Certificate2 certificate);
    
            [ExperimentalAttribute("SYSLIB5006")]
            public static X509Certificate2 CopyWithPrivateKey(this X509Certificate2 certificate, MLKem key);
        }
    }
  6. added
    api-needs-workAPI needs work before it is approved, it is NOT ready for implementation
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    and removed
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    api-needs-workAPI needs work before it is approved, it is NOT ready for implementation
    on Apr 15, 2025
  7. bartonjs commented on Apr 17, 2025

    @bartonjs
    Member

    Marking blocking because it got split by time.

  8. added
    blockingMarks issues that we want to fast track in order to unblock other important work
    on Apr 17, 2025
  9. bartonjs commented on Apr 22, 2025

    @bartonjs
    Member

    Video

    • Decapsulate(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret, out int sharedSecretBytesWritten); seems a little weird and unnecessary. If there's demand for it we can add it in the future.
    • By analogy, we cut the out-writing ones for Encapsulate
    • Encapsulate got reshaped to simplify the outs vs returns vs span-writing
    • ThrowIfDisposed seemes unnecessary
    • ImportFromEncryptedPem is password second but ImportEncryptedPkcs8PrivateKey is password first. Since that is how we did it in AsymmetricAlgorithm, we should preserve the inconsistency here.
    • X509Certificate2 has ImportFromPemFile. AsymmetricAlgorithm does not. We will not have it here, either, but can add it in the future if there's demonstrated need.
    • X509Certificate2.GetMLKemPublicKey and friends were missing their nullable return marker. They were added.
    • X509CertificateKeyAccessors.CopyWithPrivateKey and X509Certificate2.CopyWithPrivateKey disagreed on the parameter name of the private key. privateKey is the one consistent with the other algorithms.
    namespace System.Security.Cryptography
    {
        // Present in both System.Security.Cryptography and Microsoft.Bcl.Cryptography
        [ExperimentalAttribute("SYSLIB5006")]
        public abstract partial class MLKem : IDisposable
        {
            protected MLKem(MLKemAlgorithm algorithm);
    
            public static bool IsSupported { get; }
    
            public MLKemAlgorithm Algorithm { get; }
    
            public byte[] Decapsulate(byte[] ciphertext);
            public void Decapsulate(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret);
            protected abstract void DecapsulateCore(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret);
    
            public void Encapsulate(out byte[] ciphertext, out byte[] sharedSecret);
            public void Encapsulate(Span<byte> ciphertext, Span<byte> sharedSecret);
            protected abstract void EncapsulateCore(Span<byte> ciphertext, Span<byte> sharedSecret);
    
            public byte[] ExportDecapsulationKey();
            public void ExportDecapsulationKey(Span<byte> destination);
            protected abstract void ExportDecapsulationKeyCore(Span<byte> destination);
    
            public byte[] ExportEncapsulationKey();
            public void ExportEncapsulationKey(Span<byte> destination);
            protected abstract void ExportEncapsulationKeyCore(Span<byte> destination);
    
            public byte[] ExportPrivateSeed();
            public void ExportPrivateSeed(Span<byte> destination);
            protected abstract void ExportPrivateSeedCore(Span<byte> destination);
    
            public static MLKem GenerateKey(MLKemAlgorithm algorithm);
    
            public static MLKem ImportDecapsulationKey(MLKemAlgorithm algorithm, byte[] source);
            public static MLKem ImportDecapsulationKey(MLKemAlgorithm algorithm, ReadOnlySpan<byte> source);
            public static MLKem ImportEncapsulationKey(MLKemAlgorithm algorithm, byte[] source);
            public static MLKem ImportEncapsulationKey(MLKemAlgorithm algorithm, ReadOnlySpan<byte> source);
    
            public static MLKem ImportPrivateSeed(MLKemAlgorithm algorithm, byte[] source);
            public static MLKem ImportPrivateSeed(MLKemAlgorithm algorithm, ReadOnlySpan<byte> source);
    
            public void Dispose();
            protected virtual void Dispose(bool disposing);
    
    #region SPKI / PKCS8
    
            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 byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
            public byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters pbeParameters);
            public byte[] ExportEncryptedPkcs8PrivateKey(string password, PbeParameters pbeParameters);
            public string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
            public string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<char> password, PbeParameters pbeParameters);
            public string ExportEncryptedPkcs8PrivateKeyPem(string password, PbeParameters pbeParameters);
    
            public byte[] ExportPkcs8PrivateKey();
            public string ExportPkcs8PrivateKeyPem();
            public bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritten);
            protected abstract bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out int bytesWritten);
    
            public byte[] ExportSubjectPublicKeyInfo();
            public bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out int bytesWritten);
            public string ExportSubjectPublicKeyInfoPem();
    
            public static MLKem ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, ReadOnlySpan<byte> source);
            public static MLKem ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source);
            public static MLKem ImportEncryptedPkcs8PrivateKey(string password, ReadOnlySpan<byte> source);
    
            public static MLKem ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<byte> passwordBytes);
            public static MLKem ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<char> password);
            public static MLKem ImportFromEncryptedPem(string source, byte[] passwordBytes);
            public static MLKem ImportFromEncryptedPem(string source, string password);
    
            public static MLKem ImportFromPem(ReadOnlySpan<char> source);
            public static MLKem ImportFromPem(string source);
    
            public static MLKem ImportPkcs8PrivateKey(byte[] source);
            public static MLKem ImportPkcs8PrivateKey(ReadOnlySpan<byte> source);
    
            public static MLKem ImportSubjectPublicKeyInfo(byte[] source);
            public static MLKem ImportSubjectPublicKeyInfo(ReadOnlySpan<byte> source);
    #endregion
        }
    
        // Present in both System.Security.Cryptography and Microsoft.Bcl.Cryptography
        [ExperimentalAttribute("SYSLIB5006")]
        public sealed partial class MLKemAlgorithm : IEquatable<MLKemAlgorithm>
        {
            internal MLKemAlgorithm();
    
            public static MLKemAlgorithm MLKem512 { get; }
            public static MLKemAlgorithm MLKem768 { get; }
            public static MLKemAlgorithm MLKem1024 { get; }
    
            public string Name { get; }
    
            public int CiphertextSizeInBytes { get; }
            public int DecapsulationKeySizeInBytes { get; }
            public int EncapsulationKeySizeInBytes { get; }
            public int PrivateSeedSizeInBytes { get; }
            public int SharedSecretSizeInBytes { get; }
    
            public bool Equals(MLKemAlgorithm? other);
    
            public static bool operator ==(MLKemAlgorithm? left, MLKemAlgorithm? right);
            public static bool operator !=(MLKemAlgorithm? left, MLKemAlgorithm? right);
        }
    
        // Present in System.Security.Cryptography only
        [ExperimentalAttribute("SYSLIB5006")]
        public sealed partial class MLKemOpenSsl : MLKem
        {
            [UnsupportedOSPlatform("android")]
            [UnsupportedOSPlatform("browser")]
            [UnsupportedOSPlatform("ios")]
            [UnsupportedOSPlatform("osx")]
            [UnsupportedOSPlatform("tvos")]
            [UnsupportedOSPlatform("windows")]
            public MLKemOpenSsl(SafeEvpPKeyHandle pkeyHandle);
    
            public SafeEvpPKeyHandle DuplicateKeyHandle();
        }
    }
    
    namespace System.Security.Cryptography.X509Certificates
    {
        // Existing class
        // Present in System.Security.Cryptography only
        public sealed partial class PublicKey
        {
            [Experimental("SYSLIB5006")]
            public PublicKey(MLKem key);
    
            [Experimental("SYSLIB5006")]
            [UnsupportedOSPlatform("browser")]
            public MLKem? GetMLKemPublicKey();
        }
    
        // Existing class
        // Present in System.Security.Cryptography only
        public partial class X509Certificate2
        {
            [ExperimentalAttribute("SYSLIB5006")]
            public MLKem? GetMLKemPublicKey();
    
            [ExperimentalAttribute("SYSLIB5006")]
            public MLKem? GetMLKemPrivateKey();
    
            [ExperimentalAttribute("SYSLIB5006")]
            public X509Certificate2 CopyWithPrivateKey(MLKem privateKey);
        }
    
        // New class (will also be used for future algorithms)
        // Present in Microsoft.Bcl.Cryptography only
        public static class X509CertificateKeyAccessors
        {
            [ExperimentalAttribute("SYSLIB5006")]
            public static MLKem? GetMLKemPublicKey(this X509Certificate2 certificate);
    
            [ExperimentalAttribute("SYSLIB5006")]
            public static MLKem? GetMLKemPrivateKey(this X509Certificate2 certificate);
    
            [ExperimentalAttribute("SYSLIB5006")]
            public static X509Certificate2 CopyWithPrivateKey(this X509Certificate2 certificate, MLKem privateKey);
        }
    }
  10. added
    api-approvedAPI was approved in API review, it can be implemented
    and removed
    blockingMarks issues that we want to fast track in order to unblock other important work
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    on Apr 22, 2025
  11. vcsjones commented on Jun 3, 2025

    @vcsjones
    MemberAuthor

    This is implemented.

  12. locked and limited conversation to collaborators on Jul 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions