1

I have some legacy .NET Framework code for signing and checking signatures which I need to port to .NET Core.

This is the existing .NET Framework code:

public static bool CheckSignature_NetFramework(string payload, string signature, string publicKey)
{
    try
    {
        using (var rsa = RSA.Create())
        using (var shaHash = SHA256.Create())
        {
            rsa.FromXmlString(publicKey);
            var hash = shaHash.ComputeHash(Encoding.UTF8.GetBytes(payload));
            var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
            rsaDeformatter.SetHashAlgorithm("SHA256");
            return rsaDeformatter.VerifySignature(hash, Convert.FromBase64String(signature));
        }
    }
    catch
    {
        return false;
    }
}

public static string CreateSignature_NetFramework(string payload, string privateKey)
{
    using (var rsa = RSA.Create())
    using (var shaHash = SHA256.Create())
    {
        rsa.FromXmlString(privateKey);
        var hash = shaHash.ComputeHash(Encoding.UTF8.GetBytes(payload));
        var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
        rsaFormatter.SetHashAlgorithm("SHA256");
        return Convert.ToBase64String(rsaFormatter.CreateSignature(hash));
    }
}

And this is what I came up with for the equivalent .NET Core implementation:

public static bool CheckSignature_NetCore(string payload, string signature, string publicKey)
{
    try
    {
        using (var rsa = RSA.Create())
        using (var shaHash = SHA256.Create())
        {
            rsa.FromXmlString(publicKey);
            var hash = shaHash.ComputeHash(Encoding.UTF8.GetBytes(payload));
            return rsa.VerifyData(hash, Convert.FromBase64String(signature), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }
    }
    catch
    {
        return false;
    }
}

public static string CreateSignature_NetCore(string payload, string privateKey)
{
    using (var rsa = RSA.Create())
    using (var shaHash = SHA256.Create())
    {
        rsa.FromXmlString(privateKey);
        var hash = shaHash.ComputeHash(Encoding.UTF8.GetBytes(payload));
        return Convert.ToBase64String(rsa.SignData(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
    }
}

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 = Convert.FromBase64String(node.InnerText); break;
                case "Exponent": parameters.Exponent = Convert.FromBase64String(node.InnerText); break;
                case "P": parameters.P = Convert.FromBase64String(node.InnerText); break;
                case "Q": parameters.Q = Convert.FromBase64String(node.InnerText); break;
                case "DP": parameters.DP = Convert.FromBase64String(node.InnerText); break;
                case "DQ": parameters.DQ = Convert.FromBase64String(node.InnerText); break;
                case "InverseQ": parameters.InverseQ = Convert.FromBase64String(node.InnerText); break;
                case "D": parameters.D = Convert.FromBase64String(node.InnerText); break;
            }
        }
    }
    else
    {
        throw new Exception("Invalid XML RSA key.");
    }

    rsa.ImportParameters(parameters);
}

I can successfully verify a signature which was created using the same environment. But verifying a signature created with CreateSignature_NetFramework using CheckSignature_NetCore fails.

So it looks like my .NET Core implementation is not the exact equivalent to the .NET Framework implementation.

How can I verify a signature created using CreateSignature_NetFramework in .NET Core?

2
  • which version of .NET core do you use? Commented Feb 8, 2018 at 8:38
  • The code above is in a netstandard1.5 class library. Commented Feb 8, 2018 at 8:48

2 Answers 2

2

You used VerifyData, but you have precomputed the hash value, so you should use VerifyHash, or let VerifyData do the hashing for you.

That is, you want either:

rsa.FromXmlString(privateKey);

var sig = rsa.SignData(
    Encoding.UTF8.GetBytes(payload),
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1));

Or

rsa.FromXmlString(privateKey);
var hash = shaHash.ComputeHash(Encoding.UTF8.GetBytes(payload));
var sig = rsa.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
Sign up to request clarification or add additional context in comments.

Comments

0

I ran into the same issue today. I had to port over some legacy code to .NET CORE 2.

Here is what I did.

//<TargetFramework>net46</TargetFramework>    
private bool hasValidSignature(string accessToken)
{
    JwtParts jwt = new JwtParts(accessToken);
    var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(jwt.Header, ".", jwt.Payload));

    byte[] signature = (new JwtBase64UrlEncoder()).Decode(jwt.Signature);

    X509Certificate2 cert = publicCertService.GetPublicCertificate();
    RSACryptoServiceProvider pub = (RSACryptoServiceProvider)cert.PublicKey.Key;

    bool res = pub.VerifyData(bytesToSign, "2.16.840.1.101.3.4.2.1", signature);

    return res;
}

Thanks to bartonjs in this post for pointing me to the correct solution. ( https://github.com/dotnet/corefx/issues/26682)

I used JWT (https://github.com/jwt-dotnet/jwt) to split appart the accessToken and get the Header and Payload.

private bool HasValidSignature(string accessToken)
{
    JwtParts jwt = new JwtParts(accessToken);
    var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(jwt.Header, ".", jwt.Payload));

    byte[] signature = (new JwtBase64UrlEncoder()).Decode(jwt.Signature);

    X509Certificate2 cert = new X509Certificate2(publicCertService.GetPublicCertificate());

    RSA rsa = cert.GetRSAPublicKey();

    bool res =  rsa.VerifyData(bytesToSign, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

    return res;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.