Verifying ECDSA signature with BouncyCastle(使用 BouncyCastle 验证 ECDSA 签名)
问题描述
我正在测试 BouncyCastle 以使用 ECDSA、nist P251 验证签名.(Xamarin 的加密 API 还没有实现,我开始使用 Bouncy Castle lib.)
I'm testing BouncyCastle for verifying signature with ECDSA, nist P251.
(Xamarin's crypto API not implemented yet, I started to use Bouncy Castle lib.)
无论如何,我在下面的代码中面临的是......方法 B 与 C# API 一起正常工作,方法 A 不是.A 方法的 ECPoint 看起来有问题,但我无法查看详细信息.
Anyway, What I'm facing with below code, is...
method B is working correctly with C# API, method A isn't.
The ECPoint of A method looks problem but I can't check the details.
(我已检查,但无法修复.)
(I've checked, but couldn't fix.)
我应该如何更改 A 方法?欢迎任何想法.提前致谢.
How should I change the A method? Any idea is welcome.Thanks in advance.
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace TestMe
{
class Program
{
public static byte[] HexStringToByteArray(string Hex)
{
byte[] Bytes = new byte[Hex.Length / 2];
int[] HexValue = new int[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D,
0x0E, 0x0F };
for (int x = 0, i = 0; i < Hex.Length; i += 2, x += 1)
{
Bytes[x] = (byte)(HexValue[Char.ToUpper(Hex[i + 0]) - '0'] << 4 |
HexValue[Char.ToUpper(Hex[i + 1]) - '0']);
}
return Bytes;
}
static void Main(string[] args)
{
String sig
= "e1f5cecccedfe5228d9331098e84b69a0675cdd9ac066ecfada7fea761f52a4cde902a0abd362883127230326fb556af14e894d39a3e14437aaa4134a3476c84";
String msg = "00000000dcb320137ddd6f825660750ab655219fad66951c64f0420be8ac902975197ed2b0da54cd3d502d34dd04c8d74b2958a0b8792ae4730df6d25a6969bcad9f93a7d6229e5a0100000017cf5242732bba21a0b0e7dad7102cf7bdb2c8d7a665045816a886d7";
String pub = "b679e27513e2fff8fdeb54409c242776f3517f370440d26885de574a0b0e5309a9de4ea055b0bf302d9f00875f80e28cd29bb95a48aa53746d7de9465123dbb7";
A(HexStringToByteArray(msg), HexStringToByteArray(sig), HexStringToByteArray(pub));
B(HexStringToByteArray(msg), HexStringToByteArray(sig), HexStringToByteArray(pub));
}
//incorrect
static void A(byte[] message, byte[] signature, byte[] pubkey)
{
BigInteger x = new BigInteger(1, pubkey.Take(32).ToArray());
BigInteger y = new BigInteger(1, pubkey.Skip(32).ToArray());
X9ECParameters ecParams = NistNamedCurves.GetByName("P-256");
ECDomainParameters domainParameters = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H, ecParams.GetSeed());
var G = ecParams.G;
Org.BouncyCastle.Math.EC.ECCurve curve = ecParams.Curve;
Org.BouncyCastle.Math.EC.ECPoint q = curve.CreatePoint(x, y);
ECPublicKeyParameters pubkeyParam = new ECPublicKeyParameters(q, domainParameters);
var verifier = SignerUtilities.GetSigner("SHA-256withECDSA");
verifier.Init(false, pubkeyParam);
verifier.BlockUpdate(message, 0, message.Length);
bool result = verifier.VerifySignature(signature);
Console.WriteLine("result: " + result);
}
// correct
static void B(byte[] message, byte[] signature, byte[] pubkey)
{
var Q = new System.Security.Cryptography.ECPoint();
var param = new ECParameters();
Q.X = pubkey.Take(32).ToArray();
Q.Y = pubkey.Skip(32).ToArray();
param.Curve = System.Security.Cryptography.ECCurve.NamedCurves.nistP256;
param.Q = Q;
var ecdsa = ECDsa.Create(param);
bool result = ecdsa.VerifyData(message, signature, HashAlgorithmName.SHA256);
Console.WriteLine("result: " + result);
}
}
}
推荐答案
您使用充气城堡验证签名的代码是正确的.问题在于签名格式.
Your code to verify signature with bouncy castle is correct. Problem is in signature format.
ECDSA 签名基本上是两个数字,通常称为 r 和 s.在您示例的签名中,这两个数字只是连接在一起.它们每个都是 32 字节,所以你的签名是 64 字节.
ECDSA signature is basically two numbers, usually called r and s. In signature from your example, those 2 numbers are just concatenated together. Each of them is 32 bytes, so your signature is 64 bytes.
这种格式(连接数字)是 .NET api 所期望的,但不是 Bouncy Castle 所期望的.Bouncy Castle 期望签名是 DER 编码的(就像规范规定的那样).
That format (concatenated numbers) is what .NET api expects, but NOT what Bouncy Castle expects. Bouncy Castle expects signature to be DER-encoded (like specification states it should be).
因此,您需要将签名从当前格式转换"为 BC 期望的格式,如下所示:
So you need to "convert" signature from current format to format BC expects, like this:
// expected format is SEQUENCE {INTEGER r, INTEGER s}
var derSignature = new DerSequence(
// first 32 bytes is "r" number
new DerInteger(new BigInteger(1, signature.Take(32).ToArray())),
// last 32 bytes is "s" number
new DerInteger(new BigInteger(1, signature.Skip(32).ToArray())))
.GetDerEncoded();
然后验证这个签名(现在是 70 字节):
Then verify this signature (it's 70 bytes by the way now):
bool result = verifier.VerifySignature(derSignature);
它会正常工作的.
这篇关于使用 BouncyCastle 验证 ECDSA 签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用 BouncyCastle 验证 ECDSA 签名
基础教程推荐
- 如果有人提交恶意软件Nuget包怎么办? 2022-01-01
- 当值可以是对象或空数组时反序列化 JSON 2022-01-01
- Moq It.Is<>不匹配 2022-01-01
- .NET SerialPort DataReceived 事件未触发 2022-01-01
- Azure Functions:CosmosDBTrigger 未在 Visual Studio 中触发 2022-01-01
- WPF 模态进度窗口 2022-01-01
- 我应该在后面的代码中直接使用 Linq To SQL 还是使 2022-01-01
- C# 从 List<List<int>> 中删除重 2022-01-01
- 禁止输入少量字符,例如'<'、'&a 2022-01-01
- 如何使用 .Net 检查 Active Directory 服务器是否已启动并正在运行? 2022-01-01
