在 C# 中使用 ECDSA 验证签名,其中签名由 Java 生成

问题描述

我正在尝试使用 C# 处理 eBay marketplace account deletion/closure notification。您在 POST 端点收到通知,其中包含 JSON 正文和标头,其中包含 base64 编码的 JSON 对象,该对象包含验证请求所需的一些属性。要进行验证,您需要从 another eBay endpoint 获取公钥,并使用它来根据带有 JSON 对象的标头中的 base64 编码签名属性来验证 JSON 正文。我试图将 eBay's Java SDK for event notification 翻译成 C#,但到目前为止无法验证 C# 代码中的任何内容。这是 Java 代码

String json = "{\"Metadata\":{\"topic\":\"MARKETPLACE_ACCOUNT_DELETION\",\"schemaVersion\":\"1.0\",\"deprecated\":false},\"notification\":{\"notificationId\":\"49feeaeb-4982-42d9-a377-9645b8479411_33f7e043-fed8-442b-9d44-791923bd9a6d\",\"eventDate\":\"2021-03-19T20:43:59.462Z\",\"publishDate\":\"2021-03-19T20:43:59.679Z\",\"publishAttemptCount\":1,\"data\":{\"username\":\"test_user\",\"userId\":\"ma8vp1jySJC\",\"eiasToken\":\"nY+sHZ2PrBmdj6wVnY+sEZ2PrA2dj6wJnY+gAZGEpwmdj6x9nY+seQ==\"}}}";byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
String encodedPublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZhhxXKtR+TOvtDbgTPCkSof02qgBB7IsYOyf76ilExJ/upAa/vKIKheOoCyOpcLmi4t0b4uepb7LLjmMr90FUg==";
byte[] decodedPublicKey = Base64.getDecoder().decode(encodedPublicKey);
java.security.PublicKey pk = keyFactory.generatePublic(new X509EncodedKeySpec(decodedPublicKey));
String encodedSignature = "MEYCIQCfxfIWuxmWcIBQJ9c5/X7iGDJqs2RCGsBEaAjinyrrfAIhAIV6wGcTiBuV5KJUif2hokyrL+Q9ssHkad+mx2nEE25w";
byte[] decodedSignature = Base64.getDecoder().decode(encodedSignature);
String signatureType = String.format("%swith%s","SHA1","ECDSA");
Signature sig = Signature.getInstance(signatureType);
sig.initVerify(pk);
sig.update(jsonBytes);
Boolean validationResult = sig.verify(decodedSignature);
System.out.println(validationResult);

这是我的C#翻译:

var json = "{\"Metadata\":{\"topic\":\"MARKETPLACE_ACCOUNT_DELETION\",\"eiasToken\":\"nY+sHZ2PrBmdj6wVnY+sEZ2PrA2dj6wJnY+gAZGEpwmdj6x9nY+seQ==\"}}}";
var jsonBytes = Encoding.UTF8.GetBytes(json);
var encodedPublicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZhhxXKtR+TOvtDbgTPCkSof02qgBB7IsYOyf76ilExJ/upAa/vKIKheOoCyOpcLmi4t0b4uepb7LLjmMr90FUg==";
var decodedPublicKey = Convert.FromBase64String(encodedPublicKey);
ReadOnlySpan<byte> ebayPublicKeySpan = new ReadOnlySpan<byte>(decodedPublicKey);
using var ecdsaVerify = ECDsa.Create();
ecdsaVerify.ImportSubjectPublicKeyInfo(ebayPublicKeySpan,out _);
var encodedSignature = "MEYCIQCfxfIWuxmWcIBQJ9c5/X7iGDJqs2RCGsBEaAjinyrrfAIhAIV6wGcTiBuV5KJUif2hokyrL+Q9ssHkad+mx2nEE25w";
var decodedSignature = Convert.FromBase64String(encodedSignature);
var verified = ecdsaVerify.VerifyData(jsonBytes,decodedSignature,HashAlgorithmName.SHA1);
Console.WriteLine(verified);

我很确定我的 C# 方面是正确的。如果我自己生成密钥,导出公钥,创建签名,将公钥导入新的ECDsa实例,尝试验证数据,验证成功。

var json = "{\"Metadata\":{\"topic\":\"MARKETPLACE_ACCOUNT_DELETION\",\"eiasToken\":\"nY+sHZ2PrBmdj6wVnY+sEZ2PrA2dj6wJnY+gAZGEpwmdj6x9nY+seQ==\"}}}";
var jsonBytes = Encoding.UTF8.GetBytes(json);
using var ecdsaGenerate = ECDsa.Create();
ecdsaGenerate.GenerateKey(ECCurve.NamedCurves.nistP256);
var exportedPublicKey = ecdsaGenerate.ExportSubjectPublicKeyInfo();
var generatedSignature = ecdsaGenerate.SignData(jsonBytes,HashAlgorithmName.SHA1);
using var ecdsaGenerateVerify = ECDsa.Create();
ReadOnlySpan<byte> generatedPublicKey = new ReadOnlySpan<byte>(exportedPublicKey);
ecdsaGenerateVerify.ImportSubjectPublicKeyInfo(exportedPublicKey,out _);
var generatedVerify = ecdsaGenerateVerify.VerifyData(jsonBytes,generatedSignature,HashAlgorithmName.SHA1);
Console.WriteLine(generatedVerify);

我在调试时唯一注意到的另一件事是 Java 使用有符号字节,而 C# 是无符号字节,但我认为框架会考虑类似的情况。除此之外,我完全被正在发生的事情难住了。我在 C# 中使用了正确的类吗?也许解码错误

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)