user34537
user34537

Reputation:

Why isn't JSON serializing all values and how can I force it?

My code is below, it throws an exception because prv and pub are equal. It only serializes 2 members. I looked at RSAParameters and maybe it isn't showing me some attributes because I'm using .net core 2 but I see nothing to say not to serialize those members. Is there a way to force json.net to serialize those members? How do I save my private key? Write a function by hand?

using(var rsa = System.Security.Cryptography.RSA.Create())
{
    var prv = rsa.ExportParameters(true);
    var pub = rsa.ExportParameters(false);
    var prvtext = Newtonsoft.Json.JsonConvert.SerializeObject(prv);
    var pubtext = Newtonsoft.Json.JsonConvert.SerializeObject(pub);
    if (prvtext == pubtext)
        throw new Exception();
}

The class is

#region Assembly System.Security.Cryptography.Algorithms, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Users\acidzombie24\.nuget\packages\microsoft.netcore.app\2.0.0\ref\netcoreapp2.0\System.Security.Cryptography.Algorithms.dll
#endregion

namespace System.Security.Cryptography
{
    //
    // Summary:
    //     Represents the standard parameters for the System.Security.Cryptography.RSA algorithm.
    public struct RSAParameters
    {
        //
        // Summary:
        //     Represents the D parameter for the System.Security.Cryptography.RSA algorithm.
        public byte[] D;
        //
        // Summary:
        //     Represents the DP parameter for the System.Security.Cryptography.RSA algorithm.
        public byte[] DP;
        //
        // Summary:
        //     Represents the DQ parameter for the System.Security.Cryptography.RSA algorithm.
        public byte[] DQ;
        //
        // Summary:
        //     Represents the Exponent parameter for the System.Security.Cryptography.RSA algorithm.
        public byte[] Exponent;
        //
        // Summary:
        //     Represents the InverseQ parameter for the System.Security.Cryptography.RSA algorithm.
        public byte[] InverseQ;
        //
        // Summary:
        //     Represents the Modulus parameter for the System.Security.Cryptography.RSA algorithm.
        public byte[] Modulus;
        //
        // Summary:
        //     Represents the P parameter for the System.Security.Cryptography.RSA algorithm.
        public byte[] P;
        //
        // Summary:
        //     Represents the Q parameter for the System.Security.Cryptography.RSA algorithm.
        public byte[] Q;
    }
}

Upvotes: 0

Views: 907

Answers (3)

Xiaoy312
Xiaoy312

Reputation: 14477

You can use a custom DefaultContractResolver to ignore the effect of [NonSerialized]:

public class RSAContractResolver : DefaultContractResolver
{
  protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
  {
    IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
    if (type == typeof(RSAParameters))
    {
        foreach(var property in properties)
        {
            property.Ignored = false;
        }
    }

    return properties;
  }
}

Usage:

var settings = new JsonSerializerSettings { ContractResolver = new RSAContractResolver() };
var prvtext = Newtonsoft.Json.JsonConvert.SerializeObject(prv, settings);

Upvotes: 1

Michael
Michael

Reputation: 2123

You could also use a CustomConverter... Something like this:

public class RsaConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(RSAParameters);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var obj = JObject.Load(reader);
        var param = new RSAParameters();

        param.D = Convert.FromBase64String((string)obj["D"]);
        // other properties...

        return param;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var obj = (JObject)JToken.FromObject(value);
        RSAParameters param = (RSAParameters)value;

        if (obj["D"] == null && param.D != null) obj.Add("D", Convert.ToBase64String(param.D));
        // other properties...

        obj.WriteTo(writer);
    }
}

Upvotes: 0

gunr2171
gunr2171

Reputation: 17578

Yes, fields on the RSAParameters struct are marked with [NonSerialized].

Here's the github commit that fixes that, or an image of the commit in case the link dies.

Before that commit only the Exponent and Modulus properties were allowed to be serialized.

You'll need to wait for that commit to make it to a nuget package release. Based on the pull request this will be in version 2.1.0.

Upvotes: 2

Related Questions