How to create a digital signature using SHA256 with ECDSA algorithm in C#

笑着哭i 提交于 2019-12-11 11:48:43

问题


I have a requirement to create a signature which is a URL-Safe-Base-64-encoded SHA256+ECDSA signature of a message. This will be used to consume a remote REST service.

I have been given a HAL browser implementation which connects to them as expected and a test implementation done in SCALA.

    val token = generateToken() // Generates a random numeric token, different for each request
    val lines = line1 + "\n" + line2 + "\n" + line3 + "\n"
    val lineBytes = lines.getBytes()
    try {
        var sig = Signature.getInstance("SHA256withECDSA")
        sig.initSign(privateKey)
        sig.update(lineBytes)
        body.foreach { input => // If there is a body, sign it too
            input.reset()
            var bytes = new Array[Byte](1024)
            while (input.available() > 0) {
                val alloc = input.read(bytes)
                sig.update(bytes, 0, alloc)
            }
        }
        val encoder = new Base64(true)
        val sigString = encoder.encodeAsString(sig.sign()).replace("\r\n", "")
        val headerVal = "authentication.scheme.signed" + " username=" + username + "&token=" + token + "&signature=" + sigString

        request.addHeader("Authorization", headerVal)
    } catch {
        case e : NoSuchAlgorithmException =>
            throw new Error("No support for SHA256withECDSA! Check your Java installation.")
    }

I am trying to generate the same signature using C#.

So far this is what my Signing method looks like

private byte[] SignData(byte[] hashedMessageToSign)
{
    CngKey pkey2 = CngKey.Open(@"C:\OpenSSL-Win64\bin\MyPrivateiKeyInPkcs8Format.pem");

    using (ECDsaCng dsa = new ECDsaCng(pkey2))
    {
        //dsa.HashAlgorithm = CngAlgorithm.ECDsaP256;
        //bob.key = dsa.Key.Export(CngKeyBlobFormat.EccPublicBlob);

        byte[] data = hashedMessageToSign;

        return dsa.SignData(data);
    }
}

I am getting the code building but creating an invalid signature. Here is the calling method

        protected void btnLDiscover_Click(object sender, EventArgs e)
{
    HttpWebRequest request = WebRequest.Create("https://service.provider/path/") as HttpWebRequest;
    request.Method = "GET";
    request.ContentType = "application/bespoke.format+json; version=1";
    //request.Date = new DateTime(2015, 9, 3, 10, 40, 48);
    request.Date = new DateTime(2015, 9, 21, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second);
    request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
    request.Accept = "application/bespoke.format+json; version=1";
    request.KeepAlive = true;
    request.MaximumAutomaticRedirections = 99;
    //request.PreAuthenticate = true;

    string token = DateTime.Now.Ticks.ToString();
    string messageToSign = "GET /path/\n1\n" + token + "\n";

    string signatureString = Convert.ToBase64String(SignData(Encoding.ASCII.GetBytes(messageToSign)));
    //signatureString = RemoveControlCharacters(signatureString);
    //signatureString = HttpUtility.UrlEncode(signatureString);
    signatureString = signatureString
                        .Replace('+', '-')
                        .Replace('/', '_')
                        .Replace("=", string.Empty);

    request.Headers.Add("Authorization", "authentication.shceme.signed username=someuser&token=" + token + "&signature=" + signatureString);

    HttpWebResponse response = request.GetResponse() as HttpWebResponse;

    Encoding enc = System.Text.Encoding.GetEncoding(65001);
    StreamReader loResponseStream =
    new StreamReader(response.GetResponseStream(), enc);

    string responseString = loResponseStream.ReadToEnd();

    loResponseStream.Close();
    response.Close();

    resultTextBox.Text = responseString;
}

回答1:


If you don't mind I'm going to skip the part where you perform base 64 encoding in one code fragment but not in the other.

Unlike RSA PKCS#1 v1.5 signatures, ECDSA signatures are not deterministic. In other words, they depend on a random number generator to generate the signatures. The signatures will have a different value after each signing operation. The correctness of the value of these signatures can only be tested by verifying with the public key.




回答2:


Just in case someone is having a similar issue... It turned out that Microsoft encodes the above signature in a slightly different way to how java does it. Sorry if I'm using the wrong terminology as I have been out of this space for a little while. Essentially we had to try different signature types will we found one that decoded to the same value in both a c# and java application.



来源:https://stackoverflow.com/questions/32692748/how-to-create-a-digital-signature-using-sha256-with-ecdsa-algorithm-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!