-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
As part of the Post-Quantum Cryptography effort, we should add support for the IETF Composite Modular-Lattice Digital Signature Algorithm (Composite ML-DSA).
As a signature algorithm, Composite ML-DSA should be available as a primitive, as well as integrated into:
- X509Certificate2
- SignedXml
- COSE
- TLS (no API required, carried with the certificate)
The name of the Composite ML-DSA algorithm is the name of the ML-DSA algorithm prepended with "Composite": CompositeMLDsa.
namespace System.Security.Cryptography
{
[Experimental("SYSLIB5006")]
public abstract class CompositeMLDsa : IDisposable
{
public static bool IsSupported { get; }
public static bool IsAlgorithmSupported(CompositeMLDsaAlgorithm algorithm);
protected CompositeMLDsa(CompositeMLDsaAlgorithm algorithm);
// TODO: Are the EC-DSA and EdDSA signatures fixed length? If not, this needs "Max"
public int SignatureSizeInBytes { get; }
public void Dispose();
public int SignData(
ReadOnlySpan<byte> data,
Span<byte> destination,
ReadOnlySpan<byte> context = default);
public bool VerifyData(
ReadOnlySpan<byte> data,
ReadOnlySpan<byte> signature,
ReadOnlySpan<byte> context = default);
public int SignPreHash(
ReadOnlySpan<byte> hash,
Span<byte> destination,
HashAlgorithmName preHashAlgorithm,
ReadOnlySpan<byte> context = default);
public bool SignPreHash(
ReadOnlySpan<byte> hash,
ReadOnlySpan<byte> signature,
HashAlgorithmName preHashAlgorithm,
ReadOnlySpan<byte> context = default);
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);
public string ExportPkcs8PrivateKeyPem();
public byte[] ExportEncryptedPkcs8PrivateKey(
ReadOnlySpan<char> password,
PbeParameters pbeParameters);
public byte[] ExportEncryptedPkcs8PrivateKey(
ReadOnlySpan<byte> passwordBytes,
PbeParameters pbeParameters);
public bool TryExportEncryptedPkcs8PrivateKey(
ReadOnlySpan<char> password,
PbeParameters pbeParameters,
Span<byte> destination,
out int bytesWritten);
public bool TryExportEncryptedPkcs8PrivateKey(
ReadOnlySpan<byte> passwordBytes,
PbeParameters pbeParameters,
Span<byte> destination,
out int bytesWritten);
public string ExportEncryptedPkcs8PrivateKeyPem(
ReadOnlySpan<char> password,
PbeParameters pbeParameters);
public string ExportEncryptedPkcs8PrivateKeyPem(
ReadOnlySpan<byte> passwordBytes,
PbeParameters pbeParameters);
/* TODO: Should we export the Composite ML-DSA formats not in SPKI/PKCS8? */
public static CompositeMLDsa GenerateKey(CompositeMLDsaAlgorithm algorithm);
public static CompositeMLDsa ImportSubjectPublicKeyInfo(ReadOnlySpan<byte> source);
public static CompositeMLDsa ImportPkcs8PrivateKey(ReadOnlySpan<byte> source);
public static CompositeMLDsa ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, ReadOnlySpan<byte> source);
public static CompositeMLDsa ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source);
public static CompositeMLDsa ImportFromPem(ReadOnlySpan<char> source);
public static CompositeMLDsa ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<char> password);
public static CompositeMLDsa ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<byte> passwordBytes);
protected void ThrowIfDisposed();
protected virtual void Dispose(bool disposing);
protected abstract void SignDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte> context, Span<byte> destination);
protected abstract bool VerifyDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte> context, ReadOnlySpan<byte> signature);
protected abstract void SignPreHashCore(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> context, HashAlgorithmName preHashAlgorithm, Span<byte> destination);
protected abstract bool VerifyPreHashCore(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> context, HashAlgorithmName preHashAlgorithm, ReadOnlySpan<byte> signature);
/* TODO: Define protected abstracts for export */
}
[DebuggerDisplay("{Name,nq}")]
[Experimental("SYSLIB5006")]
public sealed class CompositeMLDsaAlgorithm
{
private CompositeMLDsaAlgorithm();
public static CompositeMLDsaAlgorithm MLDsa44WithRSA2048Pss { get; }
public static CompositeMLDsaAlgorithm MLDsa44WithRSA2048Pkcs15 { get; }
public static CompositeMLDsaAlgorithm MLDsa44WithEd25519 { get; }
public static CompositeMLDsaAlgorithm MLDsa44WithECDsaP256 { get; }
public static CompositeMLDsaAlgorithm MLDsa65WithRSA3072Pss { get; }
public static CompositeMLDsaAlgorithm MLDsa65WithRSA3072Pkcs15 { get; }
public static CompositeMLDsaAlgorithm MLDsa65WithRSA4096Pss { get; }
public static CompositeMLDsaAlgorithm MLDsa65WithRSA4096Pkcs15 { get; }
public static CompositeMLDsaAlgorithm MLDsa65WithECDsaP384 { get; }
public static CompositeMLDsaAlgorithm MLDsa65WithECDsaBrainpoolP256r1 { get; }
public static CompositeMLDsaAlgorithm MLDsa65WithEd25519 { get; }
public static CompositeMLDsaAlgorithm MLDsa87WithECDsaP384 { get; }
public static CompositeMLDsaAlgorithm MLDsa87WithECDsaBrainpoolP384r1 { get; }
public static CompositeMLDsaAlgorithm MLDsa87WithEd448 { get; }
public string Name { get; }
// TODO: Are the EC-DSA and EdDSA signatures fixed length? If not, this needs "Max"
public int SignatureSizeInBytes { get; }
}
[Experimental("SYSLIB5006")]
public class CompositeMLDsaCng : CompositeMLDsa
{
public CompositeMLDsaCng(CngKey key);
// On ECDsaCng this is an allocating property. Changed to a method here.
public CngKey GetCngKey();
}
[Experimental("SYSLIB5006")]
public class CompositeMLDsaOpenSsl : CompositeMLDsa
{
public CompositeMLDsaOpenSsl(SafeEvpPKeyHandle keyHandle);
public SafeEvpPKeyHandle DuplicateKeyHandle();
}
}
namespace System.Security.Cryptography.X509Certificates
{
// Extension class to enable porting to Microsoft.Bcl.Cryptography
[Experimental("SYSLIB5006")]
public sealed class CompositeMLDsaCertificateExtensions
{
public static CompositeMLDsa GetCompositeMLDsaPublicKey(this X509Certificate2 certificate);
public static CompositeMLDsa GetCompositeMLDsaPrivateKey(this X509Certificate2 certificate);
}
public partial class CertificateRequest
{
[Experimental("SYSLIB5006")]
public CertificateRequest(string subjectName, CompositeMLDsa key);
[Experimental("SYSLIB5006")]
public CertificateRequest(X500DistinguishedName subjectName, CompositeMLDsa key);
}
#if NET10_OR_GREATER
public partial class X509SignatureGenerator
{
[Experimental("SYSLIB5006")]
public static X509SignatureGenerator CreateForCompositeMLDsa(CompositeMLDsa key);
}
#endif
}
#if NET10_OR_GREATER
namespace System.Security.Cryptography.Pkcs
{
public partial class CmsSigner
{
[Experimental("SYSLIB5006")]
public CmsSigner(
X509Certificate2 certificate,
CompositeMLDsa privateKey,
SubjectIdentifierType signerIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier);
}
}
#endif
namespace System.Security.Cryptography.Cose
{
public partial class CoseSigner
{
// As PrivateKey is marked as non-nullable, this will set it to an instance of a non-public type that wraps the key.
[Experimental("SYSLIB5006")]
public CoseSigner(CompositeMLDsa key);
}
}julealgon