diff --git a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs index 0e23b6c4663b33..e05e22b942ddd9 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs @@ -1,6 +1,7 @@ // 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; using System.Diagnostics.CodeAnalysis; using System.Formats.Asn1; @@ -25,27 +26,35 @@ public abstract class CompositeMLDsa : IDisposable #pragma warning restore SA1001 #endif { - private static readonly string[] s_knownOids = - [ - Oids.MLDsa44WithRSA2048PssPreHashSha256, - Oids.MLDsa44WithRSA2048Pkcs15PreHashSha256, - Oids.MLDsa44WithEd25519PreHashSha512, - Oids.MLDsa44WithECDsaP256PreHashSha256, - Oids.MLDsa65WithRSA3072PssPreHashSha512, - Oids.MLDsa65WithRSA3072Pkcs15PreHashSha512, - Oids.MLDsa65WithRSA4096PssPreHashSha512, - Oids.MLDsa65WithRSA4096Pkcs15PreHashSha512, - Oids.MLDsa65WithECDsaP256PreHashSha512, - Oids.MLDsa65WithECDsaP384PreHashSha512, - Oids.MLDsa65WithECDsaBrainpoolP256r1PreHashSha512, - Oids.MLDsa65WithEd25519PreHashSha512, - Oids.MLDsa87WithECDsaP384PreHashSha512, - Oids.MLDsa87WithECDsaBrainpoolP384r1PreHashSha512, - Oids.MLDsa87WithEd448PreHashShake256_512, - Oids.MLDsa87WithRSA3072PssPreHashSha512, - Oids.MLDsa87WithRSA4096PssPreHashSha512, - Oids.MLDsa87WithECDsaP521PreHashSha512, - ]; + private static readonly KeyFormatHelper.StringLookup s_knownOids = +#if NET9_0_OR_GREATER + new(SearchValues.Create([ +#else + new([ +#endif + Oids.MLDsa44WithRSA2048PssPreHashSha256, + Oids.MLDsa44WithRSA2048Pkcs15PreHashSha256, + Oids.MLDsa44WithEd25519PreHashSha512, + Oids.MLDsa44WithECDsaP256PreHashSha256, + Oids.MLDsa65WithRSA3072PssPreHashSha512, + Oids.MLDsa65WithRSA3072Pkcs15PreHashSha512, + Oids.MLDsa65WithRSA4096PssPreHashSha512, + Oids.MLDsa65WithRSA4096Pkcs15PreHashSha512, + Oids.MLDsa65WithECDsaP256PreHashSha512, + Oids.MLDsa65WithECDsaP384PreHashSha512, + Oids.MLDsa65WithECDsaBrainpoolP256r1PreHashSha512, + Oids.MLDsa65WithEd25519PreHashSha512, + Oids.MLDsa87WithECDsaP384PreHashSha512, + Oids.MLDsa87WithECDsaBrainpoolP384r1PreHashSha512, + Oids.MLDsa87WithEd448PreHashShake256_512, + Oids.MLDsa87WithRSA3072PssPreHashSha512, + Oids.MLDsa87WithRSA4096PssPreHashSha512, + Oids.MLDsa87WithECDsaP521PreHashSha512, +#if NET9_0_OR_GREATER + ], StringComparison.Ordinal)); +#else + ]); +#endif private const int MaxContextLength = 255; diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs index a20e3b0e92d9bf..d77e45f1ec33a6 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs @@ -10,10 +10,7 @@ namespace System.Security.Cryptography { internal static class DSAKeyFormatHelper { - private static readonly string[] s_validOids = - { - Oids.Dsa, - }; + private static readonly KeyFormatHelper.StringLookupArray s_validOids = new([Oids.Dsa]); internal static void ReadDsaPrivateKey( ReadOnlyMemory xBytes, diff --git a/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs index 1b5059af55b09d..a9d8eee531602e 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/EccKeyFormatHelper.cs @@ -17,10 +17,7 @@ internal static class EccKeyFormatHelper // there's no real point reading anything bigger than this (for now). private const int MaxFieldBitSize = 661; - private static readonly string[] s_validOids = - { - Oids.EcPublicKey, - }; + private static readonly KeyFormatHelper.StringLookupArray s_validOids = new([Oids.EcPublicKey]); internal static void ReadSubjectPublicKeyInfo( ReadOnlySpan source, diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs index cfb0caf8693cb5..70be845c28a1e5 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs @@ -15,7 +15,7 @@ internal static partial class KeyFormatHelper internal delegate TRet ReadOnlySpanFunc(ReadOnlySpan span); internal static unsafe void ReadEncryptedPkcs8( - string[] validOids, + IStringLookup validOids, ReadOnlySpan source, ReadOnlySpan password, KeyReader keyReader, @@ -32,7 +32,7 @@ internal static unsafe void ReadEncryptedPkcs8( } internal static unsafe void ReadEncryptedPkcs8( - string[] validOids, + IStringLookup validOids, ReadOnlySpan source, ReadOnlySpan passwordBytes, KeyReader keyReader, @@ -55,7 +55,7 @@ internal static unsafe void ReadEncryptedPkcs8( } private static void ReadEncryptedPkcs8( - string[] validOids, + IStringLookup validOids, ReadOnlyMemory source, ReadOnlySpan password, KeyReader keyReader, @@ -73,7 +73,7 @@ private static void ReadEncryptedPkcs8( } private static void ReadEncryptedPkcs8( - string[] validOids, + IStringLookup validOids, ReadOnlyMemory source, ReadOnlySpan passwordBytes, KeyReader keyReader, @@ -91,7 +91,7 @@ private static void ReadEncryptedPkcs8( } private static void ReadEncryptedPkcs8( - string[] validOids, + IStringLookup validOids, ReadOnlyMemory source, ReadOnlySpan password, ReadOnlySpan passwordBytes, diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs index e175342014a982..f1528d00a2ba75 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; +using System.Collections.Generic; using System.Diagnostics; using System.Formats.Asn1; using System.Runtime.InteropServices; @@ -14,7 +15,7 @@ internal static partial class KeyFormatHelper internal delegate void KeyReader(ReadOnlyMemory key, in AlgorithmIdentifierAsn algId, out TRet ret); internal static unsafe void ReadSubjectPublicKeyInfo( - string[] validOids, + IStringLookup validOids, ReadOnlySpan source, KeyReader keyReader, out int bytesRead, @@ -30,7 +31,7 @@ internal static unsafe void ReadSubjectPublicKeyInfo( } internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( - string[] validOids, + IStringLookup validOids, ReadOnlyMemory source, out int bytesRead) { @@ -49,7 +50,7 @@ internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } - if (Array.IndexOf(validOids, spki.Algorithm.Algorithm) < 0) + if (!validOids.Contains(spki.Algorithm.Algorithm)) { throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey); } @@ -59,7 +60,7 @@ internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( } private static void ReadSubjectPublicKeyInfo( - string[] validOids, + IStringLookup validOids, ReadOnlyMemory source, KeyReader keyReader, out int bytesRead, @@ -80,7 +81,7 @@ private static void ReadSubjectPublicKeyInfo( throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } - if (Array.IndexOf(validOids, spki.Algorithm.Algorithm) < 0) + if (!validOids.Contains(spki.Algorithm.Algorithm)) { throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey); } @@ -90,7 +91,7 @@ private static void ReadSubjectPublicKeyInfo( } internal static unsafe void ReadPkcs8( - string[] validOids, + IStringLookup validOids, ReadOnlySpan source, KeyReader keyReader, out int bytesRead, @@ -106,7 +107,7 @@ internal static unsafe void ReadPkcs8( } internal static ReadOnlyMemory ReadPkcs8( - string[] validOids, + IStringLookup validOids, ReadOnlyMemory source, out int bytesRead) { @@ -116,7 +117,7 @@ internal static ReadOnlyMemory ReadPkcs8( int read = reader.PeekEncodedValue().Length; PrivateKeyInfoAsn.Decode(ref reader, source, out PrivateKeyInfoAsn privateKeyInfo); - if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm) < 0) + if (!validOids.Contains(privateKeyInfo.PrivateKeyAlgorithm.Algorithm)) { throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey); } @@ -131,7 +132,7 @@ internal static ReadOnlyMemory ReadPkcs8( } private static void ReadPkcs8( - string[] validOids, + IStringLookup validOids, ReadOnlyMemory source, KeyReader keyReader, out int bytesRead, @@ -143,7 +144,7 @@ private static void ReadPkcs8( int read = reader.PeekEncodedValue().Length; PrivateKeyInfoAsn.Decode(ref reader, source, out PrivateKeyInfoAsn privateKeyInfo); - if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm) < 0) + if (!validOids.Contains(privateKeyInfo.PrivateKeyAlgorithm.Algorithm)) { throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey); } @@ -204,5 +205,27 @@ internal static AsnWriter WritePkcs8( writer.PopSequence(); return writer; } + + internal interface IStringLookup + { + bool Contains(string value); + } + + internal sealed class StringLookupArray(string[] backingArray) : IStringLookup + { + public bool Contains(string value) => Array.IndexOf(backingArray, value) >= 0; + } + +#if NET9_0_OR_GREATER + internal sealed class StringLookup(SearchValues backingSearchValues) : IStringLookup + { + public bool Contains(string value) => backingSearchValues.Contains(value); + } +#else + internal sealed class StringLookup(HashSet backingSet) : IStringLookup + { + public bool Contains(string value) => backingSet.Contains(value); + } +#endif } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs index 1c9a498a273e49..a563176c7630fb 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs @@ -32,12 +32,12 @@ public abstract partial class MLDsa : IDisposable #pragma warning restore SA1001 #endif { - private protected static readonly string[] KnownOids = + private protected static readonly KeyFormatHelper.StringLookupArray KnownOids = new( [ Oids.MLDsa44, Oids.MLDsa65, Oids.MLDsa87, - ]; + ]); private const int MaxContextLength = 255; diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs b/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs index 6230f02f81241b..933511f41dc75d 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs @@ -27,7 +27,7 @@ namespace System.Security.Cryptography [Experimental(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)] public abstract partial class MLKem : IDisposable { - private static readonly string[] s_knownOids = [Oids.MlKem512, Oids.MlKem768, Oids.MlKem1024]; + private static readonly KeyFormatHelper.StringLookupArray s_knownOids = new([Oids.MlKem512, Oids.MlKem768, Oids.MlKem1024]); private bool _disposed; diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs index c3732580830a6a..f1638976a5ab4e 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs @@ -10,10 +10,7 @@ namespace System.Security.Cryptography { internal static partial class RSAKeyFormatHelper { - private static readonly string[] s_validOids = - { - Oids.Rsa, - }; + private static readonly KeyFormatHelper.StringLookupArray s_validOids = new([Oids.Rsa]); // TODO Currently reading PKCS#1 keys uses BigInteger which is not optimal and uses APIs that are not // available downlevel. These methods should eventually be replaced with a more efficient implementation diff --git a/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs index cb84efa593e61e..097b4e4096c764 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs @@ -32,21 +32,29 @@ public abstract partial class SlhDsa : IDisposable #pragma warning restore SA1001 #endif { - private static readonly string[] s_knownOids = - [ - Oids.SlhDsaSha2_128s, - Oids.SlhDsaShake128s, - Oids.SlhDsaSha2_128f, - Oids.SlhDsaShake128f, - Oids.SlhDsaSha2_192s, - Oids.SlhDsaShake192s, - Oids.SlhDsaSha2_192f, - Oids.SlhDsaShake192f, - Oids.SlhDsaSha2_256s, - Oids.SlhDsaShake256s, - Oids.SlhDsaSha2_256f, - Oids.SlhDsaShake256f, - ]; + private static readonly KeyFormatHelper.StringLookup s_knownOids = +#if NET9_0_OR_GREATER + new(SearchValues.Create([ +#else + new([ +#endif + Oids.SlhDsaSha2_128s, + Oids.SlhDsaShake128s, + Oids.SlhDsaSha2_128f, + Oids.SlhDsaShake128f, + Oids.SlhDsaSha2_192s, + Oids.SlhDsaShake192s, + Oids.SlhDsaSha2_192f, + Oids.SlhDsaShake192f, + Oids.SlhDsaSha2_256s, + Oids.SlhDsaShake256s, + Oids.SlhDsaSha2_256f, + Oids.SlhDsaShake256f, +#if NET9_0_OR_GREATER + ], StringComparison.Ordinal)); +#else + ]); +#endif private const int MaxContextLength = 255; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECAlgorithm.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECAlgorithm.cs index 5060b889ed12ae..92aa6d068f517f 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECAlgorithm.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/ECAlgorithm.cs @@ -13,11 +13,8 @@ namespace System.Security.Cryptography /// public abstract class ECAlgorithm : AsymmetricAlgorithm { - private static readonly string[] s_validOids = - { - Oids.EcPublicKey, - // ECDH and ECMQV are not valid in this context. - }; + // ECDH and ECMQV are not valid in this context. + private static readonly KeyFormatHelper.StringLookupArray s_validOids = new([Oids.EcPublicKey]); private protected static readonly KeySizes[] s_defaultKeySizes = {