Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rsa ToXmlString is not supported on .NET Core 2.0 #874

Closed
myloveCc opened this issue Aug 21, 2017 · 11 comments

Comments

@myloveCc
Copy link

commented Aug 21, 2017

rsa.ToXmlString(true) is not supported on .NET Core 2.0

 var rsa = RSA.Create(2048);
 var privateKey = rsa.ToXmlString(true);    // //not supported exception
@bartonjs

This comment has been minimized.

Copy link
Member

commented Aug 21, 2017

Yep. In .NET Framework networking, XML, and cryptography all live in one library (mscorlib). In .NET Core they're in three separate libraries, and making this method work requires a circle:

  • XML needs networking, because (even though we discourage it) DTDs can initiate downloads.
  • Networking needs cryptography because TLS/https have X.509 certificates.
  • Cryptography needs XML for ToXmlString/FromXmlString.

The easiest link to snip is the ToXmlString/FromXmlString methods.

Technically ToXmlString can be written without XML (like in .NET Framework's implementation, but FromXmlString requires an XML parser.

My recommendation would be to make a public static string ToXmlString(this RSAParameters rsaParameters) method, and a public static RSAParameters FromXmlString(string xml) method; borrowing from NetFx and CoreFx's SignedXml; and to ultimately try moving off of the XML representations.

@myloveCc

This comment has been minimized.

Copy link
Author

commented Aug 22, 2017

This feature is not difficult, and I have been achieved in my project。

using System;
using System.Security.Cryptography;
using System.Xml;
using Newtonsoft.Json;
using NETCore.Encrypt.Shared;
using NETCore.Encrypt.Internal;

namespace NETCore.Encrypt.Extensions.Internal
{

    internal static class RSAKeyExtensions
    {
        #region JSON
        internal static void FromJsonString(this RSA rsa, string jsonString)
        {
            Check.Argument.IsNotEmpty(jsonString, nameof(jsonString));
            try
            {
                var paramsJson = JsonConvert.DeserializeObject<RSAParametersJson>(jsonString);

                RSAParameters parameters = new RSAParameters();

                parameters.Modulus = paramsJson.Modulus != null ? Convert.FromBase64String(paramsJson.Modulus) : null;
                parameters.Exponent = paramsJson.Exponent != null ? Convert.FromBase64String(paramsJson.Exponent) : null;
                parameters.P = paramsJson.P != null ? Convert.FromBase64String(paramsJson.P) : null;
                parameters.Q = paramsJson.Q != null ? Convert.FromBase64String(paramsJson.Q) : null;
                parameters.DP = paramsJson.DP != null ? Convert.FromBase64String(paramsJson.DP) : null;
                parameters.DQ = paramsJson.DQ != null ? Convert.FromBase64String(paramsJson.DQ) : null;
                parameters.InverseQ = paramsJson.InverseQ != null ? Convert.FromBase64String(paramsJson.InverseQ) : null;
                parameters.D = paramsJson.D != null ? Convert.FromBase64String(paramsJson.D) : null;
                rsa.ImportParameters(parameters);
            }
            catch
            {
                throw new Exception("Invalid JSON RSA key.");
            }
        }

        internal static string ToJsonString(this RSA rsa, bool includePrivateParameters)
        {
            RSAParameters parameters = rsa.ExportParameters(includePrivateParameters);

            var parasJson = new RSAParametersJson()
            {
                Modulus = parameters.Modulus != null ? Convert.ToBase64String(parameters.Modulus) : null,
                Exponent = parameters.Exponent != null ? Convert.ToBase64String(parameters.Exponent) : null,
                P = parameters.P != null ? Convert.ToBase64String(parameters.P) : null,
                Q = parameters.Q != null ? Convert.ToBase64String(parameters.Q) : null,
                DP = parameters.DP != null ? Convert.ToBase64String(parameters.DP) : null,
                DQ = parameters.DQ != null ? Convert.ToBase64String(parameters.DQ) : null,
                InverseQ = parameters.InverseQ != null ? Convert.ToBase64String(parameters.InverseQ) : null,
                D = parameters.D != null ? Convert.ToBase64String(parameters.D) : null
            };

            return JsonConvert.SerializeObject(parasJson);
        }
        #endregion

        #region XML

        public static void FromXmlString(this RSA rsa, string xmlString)
        {
            RSAParameters parameters = new RSAParameters();

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xmlString);

            if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
            {
                foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
                {
                    switch (node.Name)
                    {
                        case "Modulus": parameters.Modulus = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "Exponent": parameters.Exponent = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "P": parameters.P = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "Q": parameters.Q = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "DP": parameters.DP = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "DQ": parameters.DQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "InverseQ": parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                        case "D": parameters.D = (string.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                    }
                }
            }
            else
            {
                throw new Exception("Invalid XML RSA key.");
            }

            rsa.ImportParameters(parameters);
        }

        public static string ToXmlString(this RSA rsa, bool includePrivateParameters)
        {
            RSAParameters parameters = rsa.ExportParameters(includePrivateParameters);

            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
                  parameters.Modulus != null ? Convert.ToBase64String(parameters.Modulus) : null,
                  parameters.Exponent != null ? Convert.ToBase64String(parameters.Exponent) : null,
                  parameters.P != null ? Convert.ToBase64String(parameters.P) : null,
                  parameters.Q != null ? Convert.ToBase64String(parameters.Q) : null,
                  parameters.DP != null ? Convert.ToBase64String(parameters.DP) : null,
                  parameters.DQ != null ? Convert.ToBase64String(parameters.DQ) : null,
                  parameters.InverseQ != null ? Convert.ToBase64String(parameters.InverseQ) : null,
                  parameters.D != null ? Convert.ToBase64String(parameters.D) : null);
        }

        #endregion
    }
}
@Petermarcu

This comment has been minimized.

Copy link
Member

commented Aug 30, 2017

@danmosemsft can you get this moved over to dotnet/corefx to be tracked as an issue there?

@danmosemsft

This comment has been minimized.

Copy link
Member

commented Aug 30, 2017

Issue moved to dotnet/corefx #23686 via ZenHub

@Korporal

This comment has been minimized.

Copy link

commented Mar 4, 2018

@myloveCc @bartonjs @danmosemsft @Petermarcu - Hi.

I'm seeing the same problem but I must say the "solution" here is rather unimpressive. If after all these years we've come back full circle and the much lauded "code reuse" promised by .Net is now nothing more than copying/pasting source code. then we're in trouble.

The reason is I think obvious, frantically copying snippets of code every time we encounter an "issue" leads to fragility, once we actually get a non-trivial app constructed and we test it, we have much more work to do to prove if our code is flawed or something in the hand-copied-framewrork-support-logic is somehow in error, perhaps copied wrongly for example.

May I suggest that in situations like this at the very least Microsoft formally publish a recommended workaround until the platform itself gets the proper support. At least this way we'd be sure we're all using the same workaround and reduce risk.

How are companies expected to build rock solid mission critical applications when fundamental parts of their system (in this case stuff associated with identity, encryption and authentication) are gleaned by copying/pasting snippets from Github issues!

Given Microsoft's desire to be a strong player in cloud hosting it is absolutely astonishing that something as fundamental as this is apparently overlooked.

Thanks

timotei pushed a commit to timotei/RestSharp that referenced this issue Mar 15, 2018

timotei
Handle RsaSha1 properly in .NET Core 2.0
There are some issues on .NET's side about the
missing functionality of RSACryptoServiceProvider
ToXmlString/FromXmlString:

* dotnet/corefx#23686
* dotnet/core#874

So, let's do it ourselves, and if in the future we'll
get it in the .NET itself, we can remove this code

@timotei timotei referenced this issue Mar 15, 2018

Merged

Handle RsaSha1 properly in .NET Core 2.0 #1097

2 of 5 tasks complete
@Mitch-Wheat

This comment has been minimized.

Copy link

commented Aug 21, 2018

Totally agree with @Korporal: it is utterly astonishing and very disappointing that such a basic issue still exists a year later.

I made a design decision to go with Azure, and I'm totally regretting it. Azure Functions V1 are plagued with assembly version issues (most notably the reliance on Newtonsoft.JSON v9.0.1), Azure functions V2 seem to have been in preview mode for an embarassing amount of time.

At this rate I'll be moving to AWS.

Psypher9 added a commit to Psypher9/RestSharp that referenced this issue Sep 7, 2018

Get Latest from upstream Fork (#1)
* Adding usage of WebRequest.DefaultWebProxy to address restsharp#1066

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* Using the exact name provided in DeserializeAs attribute, if any, on Deserialization

* Removed unnecessary abstraction

* Added a request configurator

* Handle RsaSha1 properly in .NET Core 2.0

There are some issues on .NET's side about the
missing functionality of RSACryptoServiceProvider
ToXmlString/FromXmlString:

* dotnet/corefx#23686
* dotnet/core#874

So, let's do it ourselves, and if in the future we'll
get it in the .NET itself, we can remove this code

* Extract FromXmlString2 into a separate file

* Move the pragma into the extension method

* Add a test for FromXmlString

* Add more tests

* Added the configurator method to the interface
Build should be Release
Added some XML docs

* Trying to fix the AppVeyor build

* Fixes restsharp#1059

* Fixes restsharp#976

* Fixes restsharp#1093

* Removed Tuple package

* Added a request configurator

* Fix Proxy in .NET Core 2.0, Add Proxy Test

* Added semicolon test

* Renamed the test

* Don't use compiled Regexes and make sure they are all static

* Fixes restsharp#1104

* fix Codacy issue

* Fixes restsharp#1126

* Adding dotnet restore

@Psypher9 Psypher9 referenced this issue Sep 18, 2018

Closed

Get Latest from upstream Fork (#1) #2

0 of 5 tasks complete
@MapleWithoutWords

This comment has been minimized.

Copy link

commented Jan 6, 2019

We hope to solve this problem as soon as possible.

@gsantopaolo

This comment has been minimized.

Copy link

commented Jan 7, 2019

Wondering why this issue is closed. The problem is still there, at least on UWP.
@myloveCc 's solution seems pretty neat, why don't implement it?

@bartonjs

This comment has been minimized.

Copy link
Member

commented Jan 7, 2019

Wondering why this issue is closed.

dotnet/core isn't the right place for issues like this. This one belongs in dotnet/corefx.

dotnet/corefx#23686 is open, and marked for .NET Core 3.0.

@Mani0811

This comment has been minimized.

Copy link

commented Jan 14, 2019

@myloveCc How This will be solved with extension method .? RSA have an implementation for hiding that we need to derive the class. According to my understanding .

public abstract partial class RSA : AsymmetricAlgorithm
    {
        public override void FromXmlString(string xmlString)
        {
            throw new PlatformNotSupportedException();
        }

        public override string ToXmlString(bool includePrivateParameters)
        {
            throw new PlatformNotSupportedException();
        }
    }
@secwxx

This comment has been minimized.

Copy link

commented May 9, 2019

RSAParametersJson

it works, thanks.
seems RSAParametersJson class is missing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
10 participants
You can’t perform that action at this time.