diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml index 2467b1348ac786..e6101a539349f9 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml @@ -2,8 +2,7 @@ + namespace="System.Security.Cryptography.Asn1"> - - - - - - - - + + + + + + + + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs index cb41a1559f8549..1dd2b4dc52f808 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs @@ -12,14 +12,14 @@ namespace System.Security.Cryptography.Asn1 internal partial struct RSAPrivateKeyAsn { internal int Version; - internal System.Numerics.BigInteger Modulus; - internal System.Numerics.BigInteger PublicExponent; - internal System.Numerics.BigInteger PrivateExponent; - internal System.Numerics.BigInteger Prime1; - internal System.Numerics.BigInteger Prime2; - internal System.Numerics.BigInteger Exponent1; - internal System.Numerics.BigInteger Exponent2; - internal System.Numerics.BigInteger Coefficient; + internal ReadOnlyMemory Modulus; + internal ReadOnlyMemory PublicExponent; + internal ReadOnlyMemory PrivateExponent; + internal ReadOnlyMemory Prime1; + internal ReadOnlyMemory Prime2; + internal ReadOnlyMemory Exponent1; + internal ReadOnlyMemory Exponent2; + internal ReadOnlyMemory Coefficient; internal readonly void Encode(AsnWriter writer) { @@ -31,14 +31,14 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) writer.PushSequence(tag); writer.WriteInteger(Version); - writer.WriteInteger(Modulus); - writer.WriteInteger(PublicExponent); - writer.WriteInteger(PrivateExponent); - writer.WriteInteger(Prime1); - writer.WriteInteger(Prime2); - writer.WriteInteger(Exponent1); - writer.WriteInteger(Exponent2); - writer.WriteInteger(Coefficient); + writer.WriteInteger(Modulus.Span); + writer.WriteInteger(PublicExponent.Span); + writer.WriteInteger(PrivateExponent.Span); + writer.WriteInteger(Prime1.Span); + writer.WriteInteger(Prime2.Span); + writer.WriteInteger(Exponent1.Span); + writer.WriteInteger(Exponent2.Span); + writer.WriteInteger(Coefficient.Span); writer.PopSequence(tag); } @@ -53,7 +53,7 @@ internal static RSAPrivateKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory rebind, out RSAPrivateKeyAsn decoded) { - Decode(ref reader, Asn1Tag.Sequence, out decoded); + Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded); } - internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, out RSAPrivateKeyAsn decoded) + internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out RSAPrivateKeyAsn decoded) { try { - DecodeCore(ref reader, expectedTag, out decoded); + DecodeCore(ref reader, expectedTag, rebind, out decoded); } catch (AsnContentException e) { @@ -80,10 +80,13 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, out } } - private static void DecodeCore(ref AsnValueReader reader, Asn1Tag expectedTag, out RSAPrivateKeyAsn decoded) + private static void DecodeCore(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out RSAPrivateKeyAsn decoded) { decoded = default; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); + ReadOnlySpan rebindSpan = rebind.Span; + int offset; + ReadOnlySpan tmpSpan; if (!sequenceReader.TryReadInt32(out decoded.Version)) @@ -91,14 +94,22 @@ private static void DecodeCore(ref AsnValueReader reader, Asn1Tag expectedTag, o sequenceReader.ThrowIfNotEmpty(); } - decoded.Modulus = sequenceReader.ReadInteger(); - decoded.PublicExponent = sequenceReader.ReadInteger(); - decoded.PrivateExponent = sequenceReader.ReadInteger(); - decoded.Prime1 = sequenceReader.ReadInteger(); - decoded.Prime2 = sequenceReader.ReadInteger(); - decoded.Exponent1 = sequenceReader.ReadInteger(); - decoded.Exponent2 = sequenceReader.ReadInteger(); - decoded.Coefficient = sequenceReader.ReadInteger(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.Modulus = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.PublicExponent = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.PrivateExponent = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.Prime1 = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.Prime2 = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.Exponent1 = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.Exponent2 = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.Coefficient = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); sequenceReader.ThrowIfNotEmpty(); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml index a0b90d25c84879..d74ed507512a39 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml @@ -2,8 +2,7 @@ + namespace="System.Security.Cryptography.Asn1"> - - + + \ No newline at end of file diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs index fbbf3cea960f26..acaf3474954359 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs @@ -11,8 +11,8 @@ namespace System.Security.Cryptography.Asn1 [StructLayout(LayoutKind.Sequential)] internal partial struct RSAPublicKeyAsn { - internal System.Numerics.BigInteger Modulus; - internal System.Numerics.BigInteger PublicExponent; + internal ReadOnlyMemory Modulus; + internal ReadOnlyMemory PublicExponent; internal readonly void Encode(AsnWriter writer) { @@ -23,8 +23,8 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) { writer.PushSequence(tag); - writer.WriteInteger(Modulus); - writer.WriteInteger(PublicExponent); + writer.WriteInteger(Modulus.Span); + writer.WriteInteger(PublicExponent.Span); writer.PopSequence(tag); } @@ -39,7 +39,7 @@ internal static RSAPublicKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory { AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet); - DecodeCore(ref reader, expectedTag, out RSAPublicKeyAsn decoded); + DecodeCore(ref reader, expectedTag, encoded, out RSAPublicKeyAsn decoded); reader.ThrowIfNotEmpty(); return decoded; } @@ -49,16 +49,16 @@ internal static RSAPublicKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory } } - internal static void Decode(ref AsnValueReader reader, out RSAPublicKeyAsn decoded) + internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory rebind, out RSAPublicKeyAsn decoded) { - Decode(ref reader, Asn1Tag.Sequence, out decoded); + Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded); } - internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, out RSAPublicKeyAsn decoded) + internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out RSAPublicKeyAsn decoded) { try { - DecodeCore(ref reader, expectedTag, out decoded); + DecodeCore(ref reader, expectedTag, rebind, out decoded); } catch (AsnContentException e) { @@ -66,13 +66,18 @@ internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, out } } - private static void DecodeCore(ref AsnValueReader reader, Asn1Tag expectedTag, out RSAPublicKeyAsn decoded) + private static void DecodeCore(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out RSAPublicKeyAsn decoded) { decoded = default; AsnValueReader sequenceReader = reader.ReadSequence(expectedTag); + ReadOnlySpan rebindSpan = rebind.Span; + int offset; + ReadOnlySpan tmpSpan; - decoded.Modulus = sequenceReader.ReadInteger(); - decoded.PublicExponent = sequenceReader.ReadInteger(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.Modulus = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + tmpSpan = sequenceReader.ReadIntegerBytes(); + decoded.PublicExponent = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); sequenceReader.ThrowIfNotEmpty(); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaManaged.RSA.cs b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaManaged.RSA.cs index ad5b058229009a..7755d12fd6a271 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaManaged.RSA.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsaManaged.RSA.cs @@ -91,21 +91,39 @@ public static RsaComponent ImportPrivateKey(RsaAlgorithm algorithm, ReadOnlySpan try { + int bytesRead; rsa = CreateRSA(); #if NET - rsa.ImportRSAPrivateKey(source, out int bytesRead); + rsa.ImportRSAPrivateKey(source, out bytesRead); +#else + try + { + AsnDecoder.ReadEncodedValue( + source, + AsnEncodingRules.BER, + out _, + out _, + out bytesRead); + + RSAKeyFormatHelper.FromPkcs1PrivateKey( + source.Slice(0, bytesRead), + rsaParameters => + { + rsa.ImportParameters(rsaParameters); + return true; + }); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } +#endif if (bytesRead != source.Length) { throw new CryptographicException(SR.Argument_PrivateKeyWrongSizeForAlgorithm); } -#else - ConvertRSAPrivateKeyToParameters(algorithm, source, (in parameters) => - { - rsa.ImportParameters(parameters); - }); -#endif } catch (CryptographicException) { @@ -124,21 +142,39 @@ public static RsaComponent ImportPublicKey(RsaAlgorithm algorithm, ReadOnlySpan< try { + int bytesRead; rsa = CreateRSA(); #if NET - rsa.ImportRSAPublicKey(source, out int bytesRead); + rsa.ImportRSAPublicKey(source, out bytesRead); +#else + try + { + AsnDecoder.ReadEncodedValue( + source, + AsnEncodingRules.BER, + out _, + out _, + out bytesRead); + + RSAKeyFormatHelper.FromPkcs1PublicKey( + source.Slice(0, bytesRead), + rsaParameters => + { + rsa.ImportParameters(rsaParameters); + return true; + }); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } +#endif if (bytesRead != source.Length) { throw new CryptographicException(SR.Argument_PublicKeyWrongSizeForAlgorithm); } -#else - ConvertRSAPublicKeyToParameters(algorithm, source, (in parameters) => - { - rsa.ImportParameters(parameters); - }); -#endif } catch (CryptographicException) { @@ -199,118 +235,6 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - -#if !NET - private delegate void ConvertRSAKeyToParametersCallback(in RSAParameters source); - - private static unsafe void ConvertRSAPublicKeyToParameters( - RsaAlgorithm algorithm, - ReadOnlySpan key, - ConvertRSAKeyToParametersCallback callback) - { - Debug.Assert(algorithm.KeySizeInBits % 8 == 0); - int modulusLength = algorithm.KeySizeInBits / 8; - RSAParameters parameters = default; - - try - { - AsnValueReader reader = new AsnValueReader(key, AsnEncodingRules.BER); - AsnValueReader sequenceReader = reader.ReadSequence(Asn1Tag.Sequence); - - parameters.Modulus = sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(); - - if (parameters.Modulus.Length != modulusLength) - { - throw new CryptographicException(SR.Cryptography_NotValidPrivateKey); - } - - parameters.Exponent = sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(); - - sequenceReader.ThrowIfNotEmpty(); - reader.ThrowIfNotEmpty(); - } - catch (AsnContentException e) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); - } - - callback(in parameters); - } - - private static unsafe void ConvertRSAPrivateKeyToParameters( - RsaAlgorithm algorithm, - ReadOnlySpan key, - ConvertRSAKeyToParametersCallback callback) - { - int modulusLength = algorithm.KeySizeInBits / 8; - int halfModulusLength = modulusLength / 2; - - RSAParameters parameters = new() - { - D = new byte[modulusLength], - P = new byte[halfModulusLength], - Q = new byte[halfModulusLength], - DP = new byte[halfModulusLength], - DQ = new byte[halfModulusLength], - InverseQ = new byte[halfModulusLength], - }; - - using (PinAndClear.Track(parameters.D)) - using (PinAndClear.Track(parameters.P)) - using (PinAndClear.Track(parameters.Q)) - using (PinAndClear.Track(parameters.DP)) - using (PinAndClear.Track(parameters.DQ)) - using (PinAndClear.Track(parameters.InverseQ)) - { - try - { - AsnValueReader reader = new AsnValueReader(key, AsnEncodingRules.BER); - AsnValueReader sequenceReader = reader.ReadSequence(Asn1Tag.Sequence); - - if (!sequenceReader.TryReadInt32(out int version)) - { - sequenceReader.ThrowIfNotEmpty(); - } - - const int MaxSupportedVersion = 0; - - if (version > MaxSupportedVersion) - { - throw new CryptographicException( - SR.Format( - SR.Cryptography_RSAPrivateKey_VersionTooNew, - version, - MaxSupportedVersion)); - } - - parameters.Modulus = sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(); - - if (parameters.Modulus.Length != modulusLength) - { - throw new CryptographicException(SR.Cryptography_NotValidPrivateKey); - } - - parameters.Exponent = sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(); - - sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(parameters.D); - sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(parameters.P); - sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(parameters.Q); - sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(parameters.DP); - sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(parameters.DQ); - sequenceReader.ReadIntegerBytes().ToUnsignedIntegerBytes(parameters.InverseQ); - - sequenceReader.ThrowIfNotEmpty(); - reader.ThrowIfNotEmpty(); - } - catch (AsnContentException e) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); - } - - callback(in parameters); - } - } -#endif } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs index a761d7264225c9..d2570a9173dc19 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs @@ -3,48 +3,47 @@ using System.Diagnostics; using System.Formats.Asn1; -using System.Numerics; namespace System.Security.Cryptography { internal static partial class KeyBlobHelpers { - internal static byte[] ToUnsignedIntegerBytes(this ReadOnlySpan span) + internal static byte[] ToUnsignedIntegerBytes(this ReadOnlyMemory memory) { - if (span.Length > 1 && span[0] == 0) + if (memory.Length > 1 && memory.Span[0] == 0) { - return span.Slice(1).ToArray(); + return memory.Slice(1).ToArray(); } - return span.ToArray(); + return memory.ToArray(); } - internal static void ToUnsignedIntegerBytes(this ReadOnlySpan span, Span destination) + internal static void ToUnsignedIntegerBytes(this ReadOnlyMemory memory, Span destination) { int length = destination.Length; - if (span.Length == length) + if (memory.Length == length) { - span.CopyTo(destination); + memory.Span.CopyTo(destination); return; } - if (span.Length == length + 1) + if (memory.Length == length + 1) { - if (span[0] == 0) + if (memory.Span[0] == 0) { - span.Slice(1).CopyTo(destination); + memory.Span.Slice(1).CopyTo(destination); return; } } - if (span.Length > length) + if (memory.Length > length) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - destination.Slice(0, destination.Length - span.Length).Clear(); - span.CopyTo(destination.Slice(length - span.Length)); + destination.Slice(0, destination.Length - memory.Length).Clear(); + memory.Span.CopyTo(destination.Slice(length - memory.Length)); } internal static void WriteKeyParameterInteger(this AsnWriter writer, ReadOnlySpan integer) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Pkcs1.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Pkcs1.cs index d8a6783f15e572..016082439bc35c 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Pkcs1.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Pkcs1.cs @@ -2,14 +2,121 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; -using System.Diagnostics; using System.Formats.Asn1; +using System.Runtime.InteropServices; using System.Security.Cryptography.Asn1; namespace System.Security.Cryptography { internal static partial class RSAKeyFormatHelper { + internal delegate TRet RSAParametersCallback(RSAParameters parameters); + + internal static unsafe TRet FromPkcs1PrivateKey( + ReadOnlySpan keyData, + RSAParametersCallback parametersReader, + bool pinAndClearParameters = true) + { + fixed (byte* ptr = &MemoryMarshal.GetReference(keyData)) + { + using (MemoryManager manager = new PointerMemoryManager(ptr, keyData.Length)) + { + return FromPkcs1PrivateKey(manager.Memory, parametersReader, pinAndClearParameters); + } + } + } + + internal static TRet FromPkcs1PrivateKey( + ReadOnlyMemory keyData, + RSAParametersCallback parametersReader, + bool pinAndClearParameters = true) + { + RSAPrivateKeyAsn key = RSAPrivateKeyAsn.Decode(keyData, AsnEncodingRules.BER); + + const int MaxSupportedVersion = 0; + + if (key.Version > MaxSupportedVersion) + { + throw new CryptographicException( + SR.Format( + SR.Cryptography_RSAPrivateKey_VersionTooNew, + key.Version, + MaxSupportedVersion)); + } + + // The modulus size determines the encoded output size of the CRT parameters. + byte[] n = key.Modulus.ToUnsignedIntegerBytes(); + int halfModulusLength = (n.Length + 1) / 2; + + RSAParameters parameters = new RSAParameters + { + Modulus = n, + Exponent = key.PublicExponent.ToUnsignedIntegerBytes(), + + D = new byte[n.Length], + P = new byte[halfModulusLength], + Q = new byte[halfModulusLength], + DP = new byte[halfModulusLength], + DQ = new byte[halfModulusLength], + InverseQ = new byte[halfModulusLength], + }; + + if (pinAndClearParameters) + { + using (PinAndClear.Track(parameters.D)) + using (PinAndClear.Track(parameters.P)) + using (PinAndClear.Track(parameters.Q)) + using (PinAndClear.Track(parameters.DP)) + using (PinAndClear.Track(parameters.DQ)) + using (PinAndClear.Track(parameters.InverseQ)) + { + return ExtractParametersWithCallback(parametersReader, ref key, ref parameters); + } + } + else + { + return ExtractParametersWithCallback(parametersReader, ref key, ref parameters); + } + + static TRet ExtractParametersWithCallback(RSAParametersCallback parametersReader, ref RSAPrivateKeyAsn key, ref RSAParameters parameters) + { + key.PrivateExponent.ToUnsignedIntegerBytes(parameters.D); + key.Prime1.ToUnsignedIntegerBytes(parameters.P); + key.Prime2.ToUnsignedIntegerBytes(parameters.Q); + key.Exponent1.ToUnsignedIntegerBytes(parameters.DP); + key.Exponent2.ToUnsignedIntegerBytes(parameters.DQ); + key.Coefficient.ToUnsignedIntegerBytes(parameters.InverseQ); + + return parametersReader(parameters); + } + } + + internal static unsafe TRet FromPkcs1PublicKey( + ReadOnlySpan keyData, + RSAParametersCallback parametersReader) + { + fixed (byte* ptr = &MemoryMarshal.GetReference(keyData)) + { + using (MemoryManager manager = new PointerMemoryManager(ptr, keyData.Length)) + { + return FromPkcs1PublicKey(manager.Memory, parametersReader); + } + } + } + + internal static TRet FromPkcs1PublicKey(ReadOnlyMemory keyData, RSAParametersCallback parametersReader) + { + RSAPublicKeyAsn key = RSAPublicKeyAsn.Decode(keyData, AsnEncodingRules.BER); + + RSAParameters parameters = new RSAParameters + { + Modulus = key.Modulus.ToUnsignedIntegerBytes(), + Exponent = key.PublicExponent.ToUnsignedIntegerBytes(), + }; + + return parametersReader(parameters); + } + internal static AsnWriter WritePkcs1PublicKey(in RSAParameters rsaParameters) { if (rsaParameters.Modulus == null || rsaParameters.Exponent == null) diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs index c3732580830a6a..7f62903d67f0f1 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs @@ -15,48 +15,17 @@ internal static partial class RSAKeyFormatHelper 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 - // and they should be moved into the RSAKeyFormatHelper.Pkcs1 (which is shared between S.S.C. and M.B.C.). - internal static void FromPkcs1PrivateKey( ReadOnlyMemory keyData, in AlgorithmIdentifierAsn algId, out RSAParameters ret) { - RSAPrivateKeyAsn key = RSAPrivateKeyAsn.Decode(keyData, AsnEncodingRules.BER); - if (!algId.HasNullEquivalentParameters()) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - const int MaxSupportedVersion = 0; - - if (key.Version > MaxSupportedVersion) - { - throw new CryptographicException( - SR.Format( - SR.Cryptography_RSAPrivateKey_VersionTooNew, - key.Version, - MaxSupportedVersion)); - } - - // The modulus size determines the encoded output size of the CRT parameters. - byte[] n = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true); - int halfModulusLength = (n.Length + 1) / 2; - - ret = new RSAParameters - { - Modulus = n, - Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true), - D = key.PrivateExponent.ExportKeyParameter(n.Length), - P = key.Prime1.ExportKeyParameter(halfModulusLength), - Q = key.Prime2.ExportKeyParameter(halfModulusLength), - DP = key.Exponent1.ExportKeyParameter(halfModulusLength), - DQ = key.Exponent2.ExportKeyParameter(halfModulusLength), - InverseQ = key.Coefficient.ExportKeyParameter(halfModulusLength), - }; + ret = FromPkcs1PrivateKey(keyData, rsaParameters => rsaParameters, pinAndClearParameters: false); } internal static void ReadRsaPublicKey( @@ -64,13 +33,7 @@ internal static void ReadRsaPublicKey( in AlgorithmIdentifierAsn algId, out RSAParameters ret) { - RSAPublicKeyAsn key = RSAPublicKeyAsn.Decode(keyData, AsnEncodingRules.BER); - - ret = new RSAParameters - { - Modulus = key.Modulus.ToByteArray(isUnsigned: true, isBigEndian: true), - Exponent = key.PublicExponent.ToByteArray(isUnsigned: true, isBigEndian: true), - }; + ret = FromPkcs1PublicKey(keyData, rsaParameters => rsaParameters); } internal static void ReadRsaPublicKey( @@ -135,19 +98,6 @@ internal static unsafe int CheckSubjectPublicKeyInfo(ReadOnlySpan source) return bytesRead; } - public static void ReadPkcs8( - ReadOnlySpan source, - out int bytesRead, - out RSAParameters key) - { - KeyFormatHelper.ReadPkcs8( - s_validOids, - source, - FromPkcs1PrivateKey, - out bytesRead, - out key); - } - internal static ReadOnlyMemory ReadPkcs8( ReadOnlyMemory source, out int bytesRead) diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj index af50013e0e9a3f..78f0acde32cf9d 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj @@ -173,6 +173,20 @@ Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.manual.cs Common\System\Security\Cryptography\Asn1\Rc2CbcParameters.xml + + Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml + + + Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml.cs + Common\System\Security\Cryptography\Asn1\RSAPrivateKeyAsn.xml + + + Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml + + + Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml.cs + Common\System\Security\Cryptography\Asn1\RSAPublicKeyAsn.xml + Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml diff --git a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index 9a20a59f785336..bc2b1a9e817464 100644 --- a/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -863,6 +863,7 @@ + diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/KeyBlobHelpers.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/KeyBlobHelpers.cs index 63cc64160d532f..22c10081c26107 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/KeyBlobHelpers.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/KeyBlobHelpers.cs @@ -1,16 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; -using System.Formats.Asn1; using System.Numerics; namespace System.Security.Cryptography { internal static partial class KeyBlobHelpers { - internal static byte[] ToUnsignedIntegerBytes(this ReadOnlyMemory memory) => memory.Span.ToUnsignedIntegerBytes(); - internal static byte[] ToUnsignedIntegerBytes(this ReadOnlyMemory memory, int length) { if (memory.Length == length) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs index e653c0fc268361..e9454c4f76a7f6 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs @@ -929,36 +929,15 @@ public virtual unsafe void ImportRSAPrivateKey(ReadOnlySpan source, out in out _, out int firstValueLength); - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, firstValueLength)) - { - ReadOnlyMemory firstValue = manager.Memory; - int localRead = firstValue.Length; - - AlgorithmIdentifierAsn ignored = default; - RSAKeyFormatHelper.FromPkcs1PrivateKey(firstValue, ignored, out RSAParameters rsaParameters); - - fixed (byte* dPin = rsaParameters.D) - fixed (byte* pPin = rsaParameters.P) - fixed (byte* qPin = rsaParameters.Q) - fixed (byte* dpPin = rsaParameters.DP) - fixed (byte* dqPin = rsaParameters.DQ) - fixed (byte* qInvPin = rsaParameters.InverseQ) + RSAKeyFormatHelper.FromPkcs1PrivateKey( + source.Slice(0, firstValueLength), + rsaParameters => { - try - { - ImportParameters(rsaParameters); - } - finally - { - ClearPrivateParameters(rsaParameters); - } - } + ImportParameters(rsaParameters); + return true; + }); - bytesRead = localRead; - } - } + bytesRead = firstValueLength; } catch (AsnContentException e) {