使用BouncyCastle在Java中验证ECDSA签名时出错 [英] Error when verifying ECDSA signature in Java with BouncyCastle

查看:377
本文介绍了使用BouncyCastle在Java中验证ECDSA签名时出错的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经测试了一个验证ECDSA签名的解决方案(如何从EC公钥字节获取PublicKey对象?)与给定数据完美配合。

I have tested a solution to verify an ECDSA signature (How can I get a PublicKey object from EC public key bytes?) that works perfect with the given data.

这是数据:

byte[] pubKey = DatatypeConverter.parseHexBinary("049a55ad1e210cd113457ccd3465b930c9e7ade5e760ef64b63142dad43a308ed08e2d85632e8ff0322d3c7fda14409eafdc4c5b8ee0882fe885c92e3789c36a7a");
byte[] message = DatatypeConverter.parseHexBinary("54686973206973206a75737420736f6d6520706f696e746c6573732064756d6d7920737472696e672e205468616e6b7320616e7977617920666f722074616b696e67207468652074696d6520746f206465636f6465206974203b2d29");
byte[] signature = DatatypeConverter.parseHexBinary("304402205fef461a4714a18a5ca6dce6d5ab8604f09f3899313a28ab430eb9860f8be9d602203c8d36446be85383af3f2e8630f40c4172543322b5e8973e03fff2309755e654");

这是代码(打印 true ):

private static boolean isValidSignature(byte[] pubKey, byte[] message,byte[] signature) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, InvalidKeySpecException {
    Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA", new BouncyCastleProvider());
    ecdsaVerify.initVerify(getPublicKeyFromBytes(pubKey));
    ecdsaVerify.update(message);
    return ecdsaVerify.verify(signature);
}

private static PublicKey getPublicKeyFromBytes(byte[] pubKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("prime256v1");
    KeyFactory kf = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());
    ECNamedCurveSpec params = new ECNamedCurveSpec("prime256v1", spec.getCurve(), spec.getG(), spec.getN());
    ECPoint point =  ECPointUtil.decodePoint(params.getCurve(), pubKey);
    ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
    ECPublicKey pk = (ECPublicKey) kf.generatePublic(pubKeySpec);
    return pk;
}

public static void main (String[] args) {
    System.out.println(isValidSignature(pubKey, message, signature));
}

当我将签名和数据更改为示例时出现问题从已经实现的系统,输入:

final static byte[] pubKey = DatatypeConverter.parseHexBinary("0447303876C6FED5550DF3EE1136989FCD87293D54A5D8E2F2F6D7FBE9A81089B889A5917443AF33E696178CEF4C9D6A4288B2745B29AF6C8BCAD1348F78EB9F9B");
final static byte[] message = DatatypeConverter.parseHexBinary("02158001f53611a06e2d1a270000013ed9305dc2780524015110500000002d0100140092569202017aa00c5dd30000000000000000000000000000000007d1000001020001b20788b80059f48d95cdefc8c6000200200030d41e0000012016840310a50733a9870fffd0430100");
final static byte[] signature = DatatypeConverter.parseHexBinary("531F8918FF250132959B01F7F56FDFD9E6CA3EC2144E12A6DA37C281489A3D96");

新数据输出此错误:

java.security.SignatureException: error decoding signature bytes.
    at org.bouncycastle.jcajce.provider.asymmetric.util.DSABase.engineVerify(Unknown Source)
    at java.security.Signature$Delegate.engineVerify(Signature.java:1178)
    at java.security.Signature.verify(Signature.java:612)
    at its.sec.exec.TestProgram.isValidSignature(TestProgram.java:168)
    at its.sec.exec.TestProgram.execution(TestProgram.java:101)
    at its.sec.exec.TestProgram.main(TestProgram.java:55)

我认为问题与安全消息附带的签名有关,因为:

I assume the problem is about the signature that comes with the secured message because:


  • 密钥对的长度和格式与示例相同。并且是正确的,因为它来自签署消息的证书。

  • 消息本身(有效负载)不应该影响安全过程。

值得一提的是,我的文档说签名前面必须有一个名为R的字段,包含椭圆曲线点的x坐标。将生成元素乘以短暂的私钥,其长度必须与签名相同(32字节)。

Last thing worth mention is that my documentation says that the signature must be preceded by a field called "R" which "contains the x coordinate of the elliptic curve point resulting from multiplying the generator element by the ephemeral private key" and its length must be the same as the signature (32 byte).

有人能指出我的意思吗?我在这里失踪了?

Can someone point me out what I'm missing here?

编辑:解决方案

正如Peter Dettman指出的那样在他的回答中,签名格式不正确(内容也不正确),以便由 verify()方法。 这里很好主要说明的解释:

As Peter Dettman pointed in his answer, the signature was not correctly formatted (also content was incorrect too) in order to be computed by the verify() method. Here is a good explanation that mainly says that:


当在DER中编码时,此(签名)变为以下字节序列:

When encoded in DER, this (signature) becomes the following sequence of bytes:

0x30 b1 0x02 b2(vr)0x02 b3(vs)

其中:


  • b1是单字节值,等于剩余字节列表的长度(以字节为单位)(从第一个0x02到编码结束);

  • b2是单字节值,等于(vr)的长度(字节);

  • b3是一个单字节值,等于(vs)的长度(以字节为单位);

  • (vr)是值为r的有符号大端编码,最小长度;

  • (vs)是值s的签名大端编码,长度最小。

  • b1 is a single byte value, equal to the length, in bytes, of the remaining list of bytes (from the first 0x02 to the end of the encoding);
  • b2 is a single byte value, equal to the length, in bytes, of (vr);
  • b3 is a single byte value, equal to the length, in bytes, of (vs);
  • (vr) is the signed big-endian encoding of the value "r", of minimal length;
  • (vs) is the signed big-endian encoding of the value "s", of minimal length.

应用该更改,签名增长s到70个字节,执行输出没有错误。

Applying that change, signature grows to 70 bytes and the execution outputs no error.

推荐答案

BC(和其他提供商)实现的预期ECDSA签名格式work with是一个DER编码的ASN.1序列,包含两个整数值 r s 。此签名格式已在ANSI X9.62中指定。这是您提供的第一组数据中的格式(请注意签名总共70个字节)。

The expected ECDSA signature format that the BC (and other provider) implementations work with is a DER-encoded ASN.1 sequence containing two integer values r and s. This signature format has been specified in ANSI X9.62. This is the format in the first set of data you give (note that signature is a total of 70 bytes).

在第二组数据中, signature 只有32个字节,根本不是ASN.1序列。我猜这个值只是 s 的值,它缺少 r 值和ASN.1对它们进行INTEGER编码,而不是将值编码为与键大小相同的无符号大整数值。

In the second set of data, signature is only 32 bytes, and is not an ASN.1 sequence at all. I would guess that this value is only the s value, and it is missing the r value and the ASN.1 INTEGER encoding for them both, instead encoding the values as a unsigned big integer value with the same size as the key.

这篇关于使用BouncyCastle在Java中验证ECDSA签名时出错的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆