Java Exception during signature verification (error decoding signature bytes)

好久不见. 提交于 2020-03-04 07:11:48

问题


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);
        }
    } 

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)_

回答1:


Reason for the Exception

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

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

Assumptions

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

Conversion of ECDSA signature to DER encoded signature

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");
    }

Quick Test

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

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.

Further Tests

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.

Use Different Test Data

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
};

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

(using sig = Signature.getInstance("SHA256withECDDSA", "BC"); of course)

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



来源:https://stackoverflow.com/questions/55742269/java-exception-during-signature-verification-error-decoding-signature-bytes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!