【问题标题】:How to verify signature with x509 certificate using EC-key in c# payconiq如何在 c# payconiq 中使用 EC-key 验证 x509 证书的签名
【发布时间】:2022-10-04 22:15:36
【问题描述】:

我正在尝试验证我在 Payconiq(支付平台)的回调中获得的签名

签名是根据这个逻辑放在一起的

JWS 表示这些由点 (.) 分隔的逻辑值:

  • 何塞标头
  • JWS 有效负载(不包括在内)
  • JWS 签名

将按照以下说明生成签名:

jws = base64URLEncode(何塞 标头)..base64URLEncode(alg(base64URLEncode(JOSE Header).base64URLEncode(请求正文)))

我现有的数据是:

  1. 证书 -> https://ext.payconiq.com/certificates 实际证书->

    MIIE1zCCBH2gAwIBAgIQHzgeQOjemgrfp6IwTS5XfzAKBggqhkjOPQQDAjCBjzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIEVDQyBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMB4XDTIxMTEyMzAwMDAwMFoXDTIyMTIyNDIzNTk1OVowKDEmMCQGA1UEAxMdZXMuc2lnbmF0dXJlLmV4dC5wYXljb25pcS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARIpLe02lsuMs6G1lQQRw3Zo4GlBwxi1h7EDD6GC9MxYRkkxOQMrJ1UKD3ni4dXcCZjHyv2GGvWhNICOaCso9Elo4IDHzCCAxswHwYDVR0jBBgwFoAU9oUKOxGG4QR9DqoLLNLuzGR7e64wHQYDVR0OBBYEFHUsvJY0jGLPbsoGZeOmkk09+ADEMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBJBgNVHSAEQjBAMDQGCysGAQQBsjEBAgIHMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAECATCBhAYIKwYBBQUHAQEEeDB2ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29FQ0NEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTBLBgNVHREERDBCgh1lcy5zaWduYXR1cmUuZXh0LnBheWNvbmlxLmNvbYIhd3d3LmVzLnNp Z25hdHVyZS5leHQucGF5Y29uaXEuY29tMIIBewYKKwYBBAHWeQIEAgSCAWsEggFnAWUAdQBGpVXrdfqRIDC1oolp9PN9ESxBdL79SbiFq/L8cP5tRwAAAX1MZuRtAAAEAwBGMEQCIErmMHlQjPe/aNTo08NiFGS2hlKeBU5Ubrl9OG7myLWcAiB4bWXL8HOl2oNVci3Cv0RMnNTyMHIrAm8Lw9QQq/UxTQB1AEHIyrHfIkZKEMahOglCh15OMYsbA+vrS8do8JBilgb2AAABfUxm5DUAAAQDAEYwRAIgNEbgqCHIAjLqhRGBmiHRAqNwX5qI1GSlfAbqVq4V/W0CIHRCmucjmXpbVKzPsOfJ6RBPHWSUJJSjiGLf1QTtvliDAHUAKXm+8J45OSHwVnOfY6V35b5XfZxgCvj5TV0mXCVdx4QAAAF9TGbj/QAABAMARjBEAiAlPQGU1X34G+wtrYEpGFodWifIfxfeOwKx9o3qjVr4LAIgUQenz7z8a0zIC5XATCAwEG3uXnbATrl+ss5cu6YqvPowCgYIKoZIzj0EAwIDSAAwRQIhAN5vKyEhzWAj6Wc6bhr8l9YXIGn4e4dNVSYeHcRoK0AkAiAhhXJkG+SzWyp/bFJeCfXbnWw59mww9GOOkoNizKCG6w==

    1. body -> 回调后调用的主体

    { "PaymentId": "8016ab30f89882a72c6827e6", “转账金额”:100, “小费金额”:0, “总金额”:100, “货币”:“欧元”, “金额”:100, “描述”:“betaling Webshop Patisserie Stefan”, “参考”:“5902”, "CreatedAt": "2022-06-28T09: 50: 58.298Z", "ExpireAt": "2022-06-28T10: 10: 58.298Z", “状态”:“成功”, “债务人”:{ “姓名”:“内森”, “伊班”:“***51944” } }

    1. 签名,它是回调调用的标头

    eyJ0eXAiOiJKT1NFK0pTT04iLCJraWQiOiJlcy5zaWduYXR1cmUuZXh0LjIwMjIiLCJhbGciOiJFUzI1NiIsImh0dHBzOi8vcGF5Y29uaXEuY29tL2lhdCI6IjIwMjItMDYtMjhUMDk6NTE6MTQuNzE0MjU0WiIsImh0dHBzOi8vcGF5Y29uaXEuY29tL2p0aSI6ImU0OWIzNmNhM2EzM2I4ODIiLCJodHRwczovL3BheWNvbmlxLmNvbS9wYXRoIjoiaHR0cHM6Ly90ZXN0LnBhdGlzc2VyaWVzdGVmYW4ubmV0L2FwaS93ZWJzaG9wY29udHJvbGxlci9DYWxsYmFja1BheWNvbmlxIiwiaHR0cHM6Ly9wYXljb25pcS5jb20vaXNzIjoiUGF5Y29uaXEiLCJodHRwczovL3BheWNvbmlxLmNvbS9zdWIiOiI2MjVlN2ZmMDFlMjRiNzA0NDI5MWNkYzUiLCJjcml0IjpbImh0dHBzOi8vcGF5Y29uaXEuY29tL2lhdCIsImh0dHBzOi8vcGF5Y29uaXEuY29tL2p0aSIsImh0dHBzOi8vcGF5Y29uaXEuY29tL3BhdGgiLCJodHRwczovL3BheWNvbmlxLmNvbS9pc3MiLCJodHRwczovL3BheWNvbmlxLmNvbS9zdWIiXX0..SIG71tYh8l0rRn7n7Bg3e1goWIloBlSwdkkXhXjIHZlelhNgKM4GJcFbimk-sIpdNl8XEOtKHVx_Tf93​​P3V-GA

    我尝试了多种方法,包括:

    • C# signature verification using ECDSA with SHA256 certificate => 这个例子有效,但我的验证总是返回 false

    • 与此相同,它在尝试验证时总是返回 false

      var verified = false;
      byte[] dataToBeVerifiedByteArray = 
      Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));
      //this gets the string of the certificate mentioned above
      byte[] cerBytes = Convert.FromBase64String(jwk.X5cValues.First().Waarde);
      X509Certificate2 cer = new(cerBytes);
      ECDsa ECDKey = cer.GetECDsaPublicKey();
      ECParameters ECDsaPublicParam = ECDKey.ExportParameters(false);
      using (var ecdsa = ECDsa.Create())
      {
          ecdsa.ImportParameters(ECDsaPublicParam);
          verified = ecdsa.VerifyData(dataToBeVerifiedByteArray, 
          Encoding.UTF8.GetBytes(signature), HashAlgorithmName.SHA256);
      };
      
      return verified;
      }
      

    谁能看到我做错了什么我找不到任何解决方案。有一个文档,他们只是参考 IETF 关于签名验证 -> https://datatracker.ietf.org/doc/html/rfc7515#section-5.2

    Payconiq 文档 -> https://developer.payconiq.com/online-payments-dock/#the-callback-signature

【问题讨论】:

    标签: c# cryptography x509certificate ecdsa


    【解决方案1】:

    您的规范/场景说签名是用 base64url 编码的,但不是用 base64 解码它,而是将文本重新编码为 UTF-8。

    您还不必要地克隆了公钥(并且不要处理您最初获得的克隆)。

    ...
    
    using (ECDsa ecdsa = cer.GetECDsaPublicKey())
    {
        return ecdsa.VerifyData(
            dataToBeVerifiedByteArray,
            Base64UrlDecode(signature),
            HashAlgorithmName.SHA256);
    }
    

    您的示例“签名”似乎仍然是两个连接的数据片段,一个看起来可能是 JOSE 标头的 JSON 对象,以及可能是 secp256r1 曲线上 ECDSA 的 IEEE P1363A 格式签名的 64 个字节。

    【讨论】:

    • 确实就像我的问题开始中提到的那样,签名是这样构建的jws = base64URLEncode(JOSE Header)..base64URLEncode(alg(base64URLEncode(JOSE Header).base64URLEncode(Request Body)))。但我会尝试让它与第一个更改一起工作
    • 我按照您的建议更改了我的代码,还更改了签名,以便我只取签名的最后一部分,因为它给签名中的拆分字符一个错误。 using (ECDsa ecdsa = cer.GetECDsaPublicKey()) { return ecdsa.VerifyData( dataToBeVerifiedByteArray, WebEncoders.Base64UrlDecode(signature.Split("..")[1]), HashAlgorithmName.SHA256); } 但不幸的是,它仍然返回我的签名无效。
    • @NathanT。您的 toBeVerified 可能是 Base64Url 解码的值,但您使用的是编码值的 UTF-8。
    • 所以我需要将其解码为base64url,而不是使用Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(body));
    • 但是我的 ToBeVerified 的数据只是一个序列化的 Json 对象。即使我想要,我也无法对其进行 Base64Url 解码
    【解决方案2】:

    我找到了 Payconiq 的 Github 页面,其中有一个 C# 示例(但仍然是 .NET Framework)来验证他们的签名。但是......至于现在,我没有让它工作。也许它可以帮助你...

    https://github.com/payconiq/CSharp-v2-merchant-callback-verification/blob/master/MerchantCallbackApi/MerchantCallbackApi.cs

    或者你同时得到它的工作?我在完全相同的问题上苦苦挣扎,还需要与 Payconiq 集成...如果您通过知道找到了一个可行的解决方案,您会在这里分享它来帮助我(可能还有其他人):-)

    【讨论】:

      猜你喜欢
      • 2015-03-03
      • 1970-01-01
      • 2016-02-26
      • 1970-01-01
      • 1970-01-01
      • 2015-10-09
      • 2011-02-14
      • 1970-01-01
      • 2021-05-13
      相关资源
      最近更新 更多