签名验证期间出现Java异常(错误解码签名字节) [英] Java Exception during signature verification (error decoding signature bytes)

查看:607
本文介绍了签名验证期间出现Java异常(错误解码签名字节)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须验证证书.我不是密码学专家,所以可能我做错了(或所有事情:)). 当代码到达最后一步(boolean b = sig.verify(CertSign);)时,它会引发异常: java.security.SignatureException:解码签名字节时出错. 有人可以帮我弄清楚我在做什么错吗?

I have to verify a certificate. I'm not an expert of cryptography, so probably I did something (or everything :) ) wrong. When the code reach the last step (boolean b = sig.verify(CertSign);), it fires an exception: java.security.SignatureException: error decoding signature bytes. Could someone help me to figure out what I'm doing wrong?

以下是显示问题的测试代码:

The following is a test code that shows the problem:

    private void test() {
        byte [] CertBody = new byte[]{(byte)0x7F,(byte)0x4E,(byte)0x81,(byte)0x82,
                               (byte)0x5F,(byte)0x29,(byte)0x01,(byte)0x00,
                               (byte)0x42,(byte)0x08,(byte)0xFB,(byte)0x55,
                               (byte)0x54,(byte)0x4F,(byte)0x02,(byte)0xFF,
                               (byte)0xFF,(byte)0x01,(byte)0x5F,(byte)0x4C,
                               (byte)0x07,(byte)0xFF,(byte)0x53,(byte)0x4D,
                               (byte)0x52,(byte)0x44,(byte)0x54,(byte)0x02,
                               (byte)0x7F,(byte)0x49,(byte)0x4E,(byte)0x06,
                               (byte)0x09,(byte)0x2B,(byte)0x24,(byte)0x03,
                               (byte)0x03,(byte)0x02,(byte)0x08,(byte)0x01,
                               (byte)0x01,(byte)0x07,(byte)0x86,(byte)0x41,
                               (byte)0x04,(byte)0x6C,(byte)0x17,(byte)0x5B,
                               (byte)0xB9,(byte)0xEF,(byte)0x5D,(byte)0x02,
                               (byte)0x20,(byte)0x51,(byte)0xCC,(byte)0xB2,
                               (byte)0x89,(byte)0x09,(byte)0x42,(byte)0x15,
                               (byte)0x85,(byte)0xD3,(byte)0x1A,(byte)0xCD,
                               (byte)0xA7,(byte)0x1B,(byte)0x08,(byte)0x4A,
                               (byte)0x48,(byte)0x8F,(byte)0x7B,(byte)0x77,
                               (byte)0x5B,(byte)0x57,(byte)0x9B,(byte)0xB7,
                               (byte)0x41,(byte)0x3B,(byte)0xDA,(byte)0x4C,
                               (byte)0xDE,(byte)0x70,(byte)0x11,(byte)0x17,
                               (byte)0xE0,(byte)0xD9,(byte)0xD1,(byte)0x0F,
                               (byte)0x74,(byte)0xD6,(byte)0x25,(byte)0xB2,
                               (byte)0x86,(byte)0xCA,(byte)0x04,(byte)0x64,
                               (byte)0x54,(byte)0x4F,(byte)0x1B,(byte)0x53,
                               (byte)0xF3,(byte)0x24,(byte)0x02,(byte)0xD3,
                               (byte)0xB3,(byte)0x74,(byte)0xEF,(byte)0xA6,
                               (byte)0xC7,(byte)0x5F,(byte)0x20,(byte)0x08,
                               (byte)0xEA,(byte)0xF4,(byte)0xBE,(byte)0xCC,
                               (byte)0x03,(byte)0x18,(byte)0x02,(byte)0xA3,
                               (byte)0x5F,(byte)0x25,(byte)0x04,(byte)0x5A,
                               (byte)0xAF,(byte)0xA9,(byte)0xDF,(byte)0x5F,
                               (byte)0x24,(byte)0x04,(byte)0x5C,(byte)0x90,
                               (byte)0xDD,(byte)0x5F};

        byte [] CertSign = new byte[]{(byte)0x3D,(byte)0x61,(byte)0x23,
                                      (byte)0xBE,(byte)0x6C,(byte)0x0B,
                                      (byte)0xC1,(byte)0x3E,(byte)0x7A,
                                      (byte)0x2D,(byte)0x60,(byte)0x3D,
                                      (byte)0x28,(byte)0xF0,(byte)0x29,
                                      (byte)0xCC,(byte)0x8C,(byte)0x55,
                                      (byte)0xF1,(byte)0x9A,(byte)0x5C,
                                      (byte)0x7E,(byte)0xBE,(byte)0xFD,
                                      (byte)0x43,(byte)0x27,(byte)0x1A,
                                      (byte)0x9D,(byte)0xA1,(byte)0x7C,
                                      (byte)0x81,(byte)0x09,(byte)0x5C,
                                      (byte)0x1D,(byte)0x26,(byte)0x27,
                                      (byte)0x76,(byte)0x73,(byte)0x74,
                                      (byte)0x87,(byte)0xF9,(byte)0x6C,
                                      (byte)0x2A,(byte)0xC9,(byte)0xA3,
                                      (byte)0x32,(byte)0x3C,(byte)0x60,
                                      (byte)0x51,(byte)0x71,(byte)0x6D,
                                      (byte)0x2F,(byte)0xC0,(byte)0xF6,
                                      (byte)0x89,(byte)0x14,(byte)0x93,
                                      (byte)0xB2,(byte)0xB6,(byte)0x87,
                                      (byte)0x21,(byte)0xAF,(byte)0x01,
                                      (byte)0x42};


        String Algorithm = "brainpoolP256r1";

        byte [] PublicPoint = new byte[]{(byte)0x04,(byte)0x68,(byte)0xF8,
                                         (byte)0xD6,(byte)0xB3,(byte)0x94,
                                         (byte)0xD2,(byte)0x8E,(byte)0x2B,
                                         (byte)0x4D,(byte)0xFA,(byte)0x36,
                                         (byte)0x52,(byte)0xAE,(byte)0xAC,
                                         (byte)0xDA,(byte)0xD3,(byte)0x19,
                                         (byte)0x21,(byte)0xC2,(byte)0x12,
                                         (byte)0x8D,(byte)0x58,(byte)0x9F,
                                         (byte)0x4E,(byte)0xF1,(byte)0xB1,
                                         (byte)0xC4,(byte)0x10,(byte)0x97,
                                         (byte)0x29,(byte)0xDC,(byte)0xA8,
                                         (byte)0xA1,(byte)0xC9,(byte)0x53,
                                         (byte)0x04,(byte)0xC8,(byte)0x77,
                                         (byte)0x4F,(byte)0x57,(byte)0xFA,
                                         (byte)0xFB,(byte)0x15,(byte)0x59,
                                         (byte)0xB9,(byte)0x2F,(byte)0x72,
                                         (byte)0x6A,(byte)0xE4,(byte)0x22,
                                         (byte)0x64,(byte)0x3E,(byte)0x1B,
                                         (byte)0x11,(byte)0x8D,(byte)0x69,
                                         (byte)0xAC,(byte)0x36,(byte)0x25,
                                         (byte)0xAD,(byte)0x1C,(byte)0x30,
                                         (byte)0x04,(byte)0xA9};

        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
           Security.addProvider(new BouncyCastleProvider());
        }

        ECNamedCurveParameterSpec params1 = ECNamedCurveTable.getParameterSpec(Algorithm);
        try {
            KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC");
            ECCurve curve = params1.getCurve();
            java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, params1.getSeed());
            java.security.spec.ECPoint point=ECPointUtil.decodePoint(ellipticCurve, PublicPoint);
            java.security.spec.ECParameterSpec params2=EC5Util.convertSpec(ellipticCurve, params1);
            java.security.spec.ECPublicKeySpec keySpec = new java.security.spec.ECPublicKeySpec(point,params2);
            ECPublicKey PK = (ECPublicKey)fact.generatePublic(keySpec);
            Signature sig;
            sig = Signature.getInstance("ECDSA", "BC");
            sig.initVerify(PK);
            sig.update(CertBody);
            boolean b = sig.verify(CertSign);
            if (b)
            {
                Logger.getLogger(CardManager.class.getName()).log(Level.INFO, "verificato");
            }
        } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException | InvalidKeyException | SignatureException ex) {
            Logger.getLogger("test").log(Level.SEVERE, null, ex);
        }
    } 

我希望b等于true(或false),但是我得到了以下异常:

I Expected to have the b equals true (or false) but instead I get the following exception:

_java.security.SignatureException: error decoding signature bytes.
    at org.bouncycastle.jcajce.provider.asymmetric.util.DSABase.engineVerify(DSABase.java:80)
    at java.security.Signature$Delegate.engineVerify(Signature.java:1223)
    at java.security.Signature.verify(Signature.java:656)_

推荐答案

造成这种情况的原因

正如问题注释中已经提到的,签名的长度与预期的长度不同.

As already mentioned in the comments to the question, the length of the signature differs from the expected length.

发生异常,因为期望使用70字节的DER编码签名,但是您的CertSign仅包含64字节.

The exception happens, since a DER encoded signature with 70 bytes is expected, but your CertSign contains only 64 bytes.

假设

由于它是64个字节,因此可以假定它是一个ECDSA签名,该签名由两个串联的BigInteger数字组成,每个数字分别为32个字节.

Since it is 64 bytes, one could assume that it is an ECDSA signature consisting of two concatenated BigInteger numbers with 32 bytes each.

将ECDSA签名转换为DER编码的签名

要将其转换为DER编码的签名,可以使用sth,例如:

To convert that to a DER encoded signature one can use sth like:

private byte[] DEREncodeSignature(byte [] signature) throws IOException {
    BigInteger r = new BigInteger(1, Arrays.copyOfRange(signature, 0, 32));
    BigInteger s = new BigInteger(1, Arrays.copyOfRange(signature, 32, 64));
    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(new ASN1Integer(r));
    v.add(new ASN1Integer(s));
    return new DERSequence(v).getEncoded(ASN1Encoding.DER);
}

然后,需要调整代码中使用签名的行,例如这样:

Then the lines in your code where you use the signature needs to be adjusted, e.g. to sth like this:

    boolean b = sig.verify(DEREncodeSignature(CertSign));
    if (b) {
        Logger.getLogger(CardManager.class.getName()).log(Level.INFO, "verificato");
    }
    else {
        Logger.getLogger(CardManager.class.getName()).log(Level.INFO, "controllo fallito");
    }

快速测试

然后异常消失了,调试控制台中的输出如下所示:

The exception is then gone, the output in the debug console looks like this:

May 11, 2019 5:09:48 PM CardManager test
INFO: controllo fallito

因此验证实际上失败了,但是您提到您希望b为true或false,所以也许这是正确的结果.但是,如果没有更多数据,则无法进行验证.

So the verification actually fails, but you mention that you expect b to be either true or false, so maybe it's the right result. But without having more data this is not possible to validate.

进一步测试

我还用您的代码快速尝试了不同的签名算法.对于他们每个人来说都是错误的.

I also quickly tried different signature algorithms with your code. For each of them one gets a false.

String[] signatureAlgorithms = new String[] {"RIPEMD160withECDSA", "SHA224withECDDSA", "SHA256withECDDSA", "SHA384withECDDSA", "SHA512withECDDSA", "SHA1withECDSA", "NONEwithECDSA", "SHA224withECDSA", "SHA256withECDSA", "SHA384withECDSA", "SHA512withECDSA", "SHA3-224withECDSA", "SHA3-256withECDSA", "SHA3-384withECDSA", "SHA3-512withECDSA"};
for(String algorithm : signatureAlgorithms) {
    Signature sig;
    Logger.getLogger(CardManager.class.getName()).log(Level.INFO, "trying aloorithm " + algorithm + ": ");
    sig = Signature.getInstance(algorithm, "BC");
    ...

仍然-没有更多数据(例如,使用过的签名算法等),很难说出不匹配的原因是什么.

Still - without further data (e.g. used signature algorithm etc.) it is difficult to say what the reason for the mismatch is.

使用不同的测试数据

为验证包括新DEREncodeSignature在内的例程是否正常运行,我对消息"Hello world!"进行了签名.使用brainpoolP256r1参数spec和SHA256withECDDSA签名算法的ECDSA生成器,则数据如下所示:

To verify that the routines including the new DEREncodeSignature is working correctly I signed the message 'Hello world!' with ECDSA generator using the brainpoolP256r1 parameter spec and SHA256withECDDSA signature algorithm, then the data looks like this:

byte[] CertBody = new byte[]{(byte) 0x48,
        (byte) 0x65, (byte) 0x6C, (byte) 0x6C,
        (byte) 0x6F, (byte) 0x20, (byte) 0x77,
        (byte) 0x6F, (byte) 0x72, (byte) 0x6C,
        (byte) 0x64, (byte) 0x21};

byte[] CertSign = new byte[]{
        (byte)0x0C,(byte)0x5B,(byte)0xE9,
        (byte)0xA4,(byte)0xF7,(byte)0xC9,
        (byte)0x5A,(byte)0x69,(byte)0x8E,
        (byte)0x91,(byte)0x50,(byte)0xB4,
        (byte)0x4E,(byte)0x33,(byte)0x14,
        (byte)0x7C,(byte)0x2F,(byte)0x15,
        (byte)0x93,(byte)0x97,(byte)0x8B,
        (byte)0xD8,(byte)0x65,(byte)0x20,
        (byte)0x1B,(byte)0x1D,(byte)0xF4,
        (byte)0x8A,(byte)0xB3,(byte)0x81,
        (byte)0x55,(byte)0x6A,

        (byte)0x96,
        (byte)0xE4,(byte)0x89,(byte)0x05,
        (byte)0x80,(byte)0xAA,(byte)0x34,
        (byte)0x3A,(byte)0x86,(byte)0x11,
        (byte)0x5F,(byte)0x0B,(byte)0x8F,
        (byte)0xF7,(byte)0xE7,(byte)0xA6,
        (byte)0x7D,(byte)0xCC,(byte)0x9C,
        (byte)0xD0,(byte)0xC8,(byte)0x94,
        (byte)0xCA,(byte)0x78,(byte)0x9C,
        (byte)0xFE,(byte)0x41,(byte)0x2A,
        (byte)0xB0,(byte)0xE1,(byte)0x7E,
        (byte)0x29,
};

byte[] PublicPoint = new byte[]{
        (byte) 0x04,
        (byte) 0x1E, (byte) 0xC8, (byte) 0xB7,
        (byte) 0x00, (byte) 0xF1, (byte) 0xFD,
        (byte) 0x06, (byte) 0x97, (byte) 0x73,
        (byte) 0x71, (byte) 0x09, (byte) 0x12,
        (byte) 0xF2, (byte) 0xB7, (byte) 0xEF,
        (byte) 0xA5, (byte) 0x23, (byte) 0xA1,
        (byte) 0xC1, (byte) 0x6C, (byte) 0xA7,
        (byte) 0xD1, (byte) 0x0C, (byte) 0x25,
        (byte) 0x6E, (byte) 0x04, (byte) 0x09,
        (byte) 0x7A, (byte) 0x62, (byte) 0xC3,
        (byte) 0x0E, (byte) 0x93, (byte) 0x54,
        (byte) 0x7F, (byte) 0x0C, (byte) 0xE4,
        (byte) 0x0F, (byte) 0xF8, (byte) 0x63,
        (byte) 0x82, (byte) 0x6D, (byte) 0x0B,
        (byte) 0x50, (byte) 0xC0, (byte) 0x59,
        (byte) 0x1F, (byte) 0xFC, (byte) 0x36,
        (byte) 0x1B, (byte) 0x0E, (byte) 0x2A,
        (byte) 0xA3, (byte) 0xD4, (byte) 0x29,
        (byte) 0x4E, (byte) 0x30, (byte) 0x91,
        (byte) 0x44, (byte) 0x28, (byte) 0x2E,
        (byte) 0x15, (byte) 0x76, (byte) 0x48,
        (byte) 0xE7
};

如果该数据已获取并通过例程(包括)运行. DEREncodeSignature,然后在调试控制台中显示以下输出:

If that data is taken and run through the routines incl. DEREncodeSignature then the following output is shown in the debug console:

May 12, 2019 12:13:42 AM CardManager test
INFO: verificato

(当然使用sig = Signature.getInstance("SHA256withECDDSA", "BC");)

这意味着对于ECDSA具有brainpoolP256r1参数spec和SHA256withECDDSA的生成数据,它将与替代测试数据一起使用.

This means that for ECDSA generated data with brainpoolP256r1 parameter spec and SHA256withECDDSA it would work with the alternative test data.

这篇关于签名验证期间出现Java异常(错误解码签名字节)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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