Ebay 公钥验证在 C# 中失败,但在节点中工作
Posted
技术标签:
【中文标题】Ebay 公钥验证在 C# 中失败,但在节点中工作【英文标题】:Ebay public key verification in fails in C# but works in node 【发布时间】:2021-07-13 16:22:18 【问题描述】:我一直在尝试在 C# .net core 3.1 中验证 ebay 通知,但它拒绝签名。
我在 node.js 中有一个工作的最小示例。请注意,我必须编辑正文内容。签名验证OK。
const crypto = require('crypto');
const validateSignature = (message, signature, publicKey) =>
const verifier = crypto.createVerify('ssl3-sha1');
verifier.update(JSON.stringify(message));
return verifier.verify(`-----BEGIN PUBLIC KEY-----\n$publicKey\n-----END PUBLIC KEY-----`, signature, "base64");
;
const BODY = "redacted";
const SIG = `MEUCIG9ANqAZ3MIS6CDNcJFf/5d8VlIyHuHZlgw57HLzALl+AiEA0Egsw0y7VLvsUxKhBhivVr/Ee6O69lmkIchftQ2Fnqs=`;
const KEY = `MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZhhxXKtR+TOvtDbgTPCkSof02qgBB7IsYOyf76ilExJ/upAa/vKIKheOoCyOpcLmi4t0b4uepb7LLjmMr90FUg==`;
try
const result = validateSignature(BODY, SIG, KEY);
console.log("verification: ", result);
catch(Err)
console.error(Err);
这返回真。
这是同样的例子,在 .net core 3.1 中,内容再次被编辑
class Program
public static bool ValidateEcdsa(string bodyData, string signature, string keyString)
try
using (var ecdsa = ECDsa.Create())
var contentBytes = Encoding.UTF8.GetBytes(bodyData);
var signatureBytes = Convert.FromBase64String(signature ?? "");
var keyBytes = Convert.FromBase64String(keyString);
ecdsa.ImportSubjectPublicKeyInfo(keyBytes, out _);
bool success = ecdsa.VerifyData(contentBytes, signatureBytes, HashAlgorithmName.SHA1);
return success;
catch (Exception ex)
Console.Error.WriteLine(ex.Message);
return false;
public static string BODY = "redacted";
public static string SIG = "MEUCIG9ANqAZ3MIS6CDNcJFf/5d8VlIyHuHZlgw57HLzALl+AiEA0Egsw0y7VLvsUxKhBhivVr/Ee6O69lmkIchftQ2Fnqs=";
public static string KEY = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZhhxXKtR+TOvtDbgTPCkSof02qgBB7IsYOyf76ilExJ/upAa/vKIKheOoCyOpcLmi4t0b4uepb7LLjmMr90FUg==";
static void Main(string[] args)
var result = ValidateEcdsa(BODY, SIG, KEY);
Console.WriteLine($"verification: result");
这将毫无例外地加载公钥信息,但返回 false。
.net 示例和节点示例有什么不同?
关于开始和结束标题的注释
节点库需要---begin---
和---end---
标头。没有这个它会失败。
如果您有这些标头,.net 库将不会导入密钥,因此在此最小示例中已将其删除。
身体是一样的吗?
我无法展示原始尸体,因此必须在此处对其进行编辑。但是,我使用 sha1 哈希来确保它们在两个最小示例中是完全相同的字符串。
节点:
var shasum = crypto.createHash('sha1')
shasum.update(BODY)
console.log("hash of body data", shasum.digest('hex'))
.net:
using (SHA1Managed sha1 = new SHA1Managed())
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
var sb = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
sb.Append(b.ToString("x2"));
return sb.ToString();
这两个都给出了相同的哈希序列。
【问题讨论】:
如果您对 ---BEGIN--- 和 ---END--- 标头之间的位进行 base64 解码,您应该得到一个有效 ASN.1 的字节数组。 肯定是这样,否则它将被关闭而不是被否决。您有一个 base64 编码的密钥。您正在尝试以 utf8 格式获取其字节(为什么是所有可能的 utf8?)并将其传递给ImportRSAPublicKey
,即使它是 specifically says "如果该值是 Base64 编码或 PEM 文本格式,调用者必须在调用此方法之前对内容进行 Base64 解码”。那将是缺乏研究。
如何将密钥传递给函数?看来您需要从 BEGIN 和 END 标记之间提取它并解码 base64。
API 在这里。您可以从示例中看到它返回的内容。它看起来确实太小了,但我不知道它到底包含什么。 developer.ebay.com/api-docs/commerce/notification/resources/…
这不是 RSA 密钥,而是 ECDSA 密钥——“算法”值。
【参考方案1】:
.net ECDsa 库默认为 IEEE P1363 但 ebay 使用 RFC第3279章
你需要 .net core 5.0。
然后您可以简单地将可选参数传递给 VerifyData 方法。
bool success = ecdsa.VerifyData(contentBytes, signatureBytes, HashAlgorithmName.SHA1, DSASignatureFormat.Rfc3279DerSequence);
节点版本自动选择 RFC 3279。
您也可以使用 BouncyCastle
using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
static bool VerifyData(string bodyData, string signature, string keyString)
var pubkeyString = $"-----BEGIN PUBLIC KEY-----\nkeyString\n-----END PUBLIC KEY-----";
var data = bodyData;
var signatureBytes = Convert.FromBase64String(signature);
var pemreader = new PemReader(new StringReader(pubkeyString));
var pubkey = (AsymmetricKeyParameter)pemreader.ReadObject();
// Verify using the public key
var signer = SignerUtilities.GetSigner("SHA1withECDSA");
signer.Init(false, pubkey);
signer.BlockUpdate(Encoding.UTF8.GetBytes(data), 0, data.Length);
var success = signer.VerifySignature(signatureBytes);
return success;
这支持 .net 标准 2.0,并且与大多数版本的 .net 框架和 .net 核心兼容。
【讨论】:
对于低于 .NET 5 的版本,从 ASN.1/DER 到 r|s(或从 RFC 3279 格式到 IEEE P1363)的转换也可以自己完成/实现。不是很复杂,详细描述here。 @user9014097 我不确定如果我们得到第三方的签名和公钥,这是否会起作用。但更简单的解决方案是使用更好的库 ASN.1/DER 格式的签名始终可以转换为 r|s 格式(反之亦然)。但当然,使用支持两种格式或转换的库(例如 BouncyCastle)会更容易。 @user9014097 你能用一些代码发布一个答案来执行转换吗?r
和 s
包含在 ASN.1 签名中。 Here可以找到ASN.1格式的简单描述,从中可以看出r
和s
的位置和长度。提取r
和s
(并删除可能的符号字节)后,只需将它们连接起来:r|s
。如果我找到时间并且没有人打败我,我会发布一个实现。以上是关于Ebay 公钥验证在 C# 中失败,但在节点中工作的主要内容,如果未能解决你的问题,请参考以下文章
在 C# 中连接到 Websphere MQ 有效,但在 C++ 中失败,代码为 2058 (MQRC_Q_MGR_NAME_ERROR)
c# .net4.0验证视图状态 MAC 失败!试过网上的webconfig 节点添加配置,在网页page添加属性均无效。