使用带有曲线 secp224k1 的私钥签署 ECDSA
Posted
技术标签:
【中文标题】使用带有曲线 secp224k1 的私钥签署 ECDSA【英文标题】:Signing ECDSA with private key with curve secp224k1 【发布时间】:2019-10-17 05:47:11 【问题描述】:我想得到 ECDSA secp224k1 的签名。我无法从手册中获得与 CoinFLEX Authentication Process 示例中相同的签名。我正在使用 C# BouncyCastle。
为什么我的代码无法获取手册页的签名?
// manual page's step 7
byte[] fortyByteMessage = fromHexStringToByteArr("0x00000000 00000001").Concat(fromHexStringToByteArr("0x6b347302 2e6b9b5a f2fe5d1d ae7cf5bf")).Concat(fromHexStringToByteArr("0xf08c98ca f1fd82e8 cea9825d bff04fd0")).ToArray();
// manual page's step 9
byte[] privateKey = fromHexStringToByteArr("0xb89ea7fc d22cc059 c2673dc2 4ff40b97 83074646 86560d0a d7561b83");
// manual page's step 10
X9ECParameters spec = ECNamedCurveTable.GetByName("secp224k1");
ECDomainParameters domain = new ECDomainParameters(spec.Curve, spec.G, spec.N);
ECDsaSigner signer = new ECDsaSigner(new HMacDsaKCalculator(new Sha224Digest()));
signer.Init(true, new ECPrivateKeyParameters(new BigInteger(privateKey), domain));
BigInteger[] signature = signer.GenerateSignature(fortyByteMessage);
byte[] r = signature[0].ToByteArray().SkipWhile(b => b == 0x00).Reverse().ToArray(); // (r) r should be 0x3fb77a9d 7b5b2a68 209e76f6 872078c5 791340d5 989854ad a3ab735e, but not.
Console.WriteLine(BitConverter.ToString(r).Replace("-", string.Empty).ToLower());
预期的 byteArr(第 10 步 r 值):
r = 0x3fb77a9d 7b5b2a68 209e76f6 872078c5 791340d5 989854ad a3ab735e<br>
我的 byteArr (这是错误的值,因为它与 step 10 r 值不同)
r = 0x1e3b3f4f 7401ff9d 827b7222 47823919 452d3adb effa7aa4 52a0879e<br>
另一个功能:
static byte[] fromHexStringToByteArr(string paramHexString)
string hexString = paramHexString.Substring(2).Replace(" ", "");
byte[] result = new byte[hexString.Length / 2];
int cur = 0;
for (int i = 0; i < hexString.Length; i = i + 2)
string w = hexString.Substring(i, 2);
result[cur] = Convert.ToByte(w, 16);
cur++;
return result;
【问题讨论】:
【参考方案1】:根据instructions 的第 10 步,应该签名的不是 40 字节消息,而是该消息的 SHA224-hash:客户端签署 40 的 28 字节 SHA-224 摘要-字节消息...。请注意,GenerateSignature
方法不会自动对数据进行哈希处理,即必须显式地对数据进行哈希处理,另请参阅here 和这些examples。
Org.BouncyCastle.Math.BigInteger.ToByteArray
-方法(在 C# 代码中使用)以大端格式输出字节数组(与 .Net 不同,其System.Numerics.BigInteger.ToByteArray
-方法使用小端格式)。因此,不需要反转字节顺序(使用Reverse
-方法)。
通过这些修改,签名是:
r = 0x1781ff4997b48d389f518df75001c4b6564082956228d74dd0321656
s = 0x0aadc68cf78dc75d44fb300f200465e72a70826ec2d5577d49b62e59
然而,它仍然与说明中显示的签名不同。
在 C# 代码中,ECDsaSigner
-instance 使用 HMacDsaKCalculator
-instance 创建,基于 RFC6979 生成 确定性 签名。当使用ECDSA 创建签名时,k
参数是随机选择的,用于非确定性 ECDSA,而在确定性变体中,它是根据特定算法从消息和私钥创建的(在 RFC6979 中描述) ,见here。因此,确定性变体为相同的消息和私钥生成相同的签名,而非确定性变体生成不同的签名。
可能签名之间的差异是由 CoinFLEX 使用非确定性变体引起的。不幸的是,这些说明没有详细说明所使用的 ECDSA 程序。
更新:
两种变体,确定性和非确定性,都提供有效 ECDSA 签名!在确定性变体(RFC6979 来自 2013 年 8 月)之前,只有非确定性变体,请参阅 here。
我在 Linux (Debian) 机器上安装并测试了 sign_secp224k1
-tool。正如怀疑的那样,该工具为 same 私钥和 same 消息生成 不同 签名,显然使用了非确定性变体。这也可以从源代码中轻松验证:签名使用ecp_sign
-方法计算,该方法随机使用/dev/urandom
确定k
-值。
因此很明显,C# 代码使用确定性变体生成的签名通常无法匹配sign_secp224k1
-工具使用非确定性变体生成的签名。
【讨论】:
这是一个用于认证的签名。所以我认为这不是随机的。以下网址是规范,但我很难阅读。 github.com/coinflex-exchange/libecp#sign_secp224k1 非确定性变体生成 有效 ECDSA 签名,就像确定性变体一样!我还测试了sign_secp224k1
-tool,确实它使用了 non-deterministic 变体,请参阅我的答案中的更新部分。
当我运行上面提供的相同代码时,我得到异常 System.ArgumentException: 'Scalar is not in the interval [1, n - 1] Parameter name: d' mecause my value of new BigInteger(privateKey)
是-7517217624485429887806670580524002717199604937162964340004446921853 你是怎么跑的?
new BigInteger(1, privateKey)
修复了我的崩溃问题,但 api 仍然返回“您发送的签名不正确”。错误。 kyounoii,你设法让它运行了吗?
@LukAss741 - 您应该在 SO 上发布一个新问题,准确描述您的问题以及解决问题所需的所有信息。如果需要,您可以在此处参考此问题/答案。以上是关于使用带有曲线 secp224k1 的私钥签署 ECDSA的主要内容,如果未能解决你的问题,请参考以下文章