简体   繁体   中英

Bouncycastle ECDSA signature verification is OK after signing but fails at next run when reloading public key, message and signatue

I am testing a bouncy castle signature verification. Interestingly it verifies ok after the signing, but when running a new instance with the public key, message and signature if always fails. I am using the same verification routine right after signature generation and the next run which is a simple java code. (The whole story might not be relevant, but I am trying to crate a CA certificate of a javacard public key, and need to sign the resulting certificate. Right after generating the certificate and signing, the verification always passes, but when running the next instance to verify the public key certificate it fails.) I would kindly ask for a feedback if this has happened to any one else. I am pretty much assume that the code is correct since it works right after signing. If code is nevertheless required I will clean it up and post it, but it is similar to code examples found on the net.

public class VerifyEccSignature {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
    boolean verify;
    Provider prov=new BouncyCastleProvider();
    Signature ecdsaSign;
    Security.addProvider(prov);

    // Card Public Key
    byte[] pubKey = HexAdapter.toBin("04cd7a82795bf691232e409ebe10039be6167d15b07e19da0c417c830d4db8b9d8f6919113468a1f650125545cc0bca619ec3be88723889fb439b71dee3e1dbad3");

    // Certificate to sign ()
    byte[] cert=HexAdapter.toBin("48656C6C6F576F726C64");

    // Signature returned by chip
    byte[] sigBytes=HexAdapter.toBin("30450220459408F84F45A1F960C3260D8191083617C016ADC721E5162F667D8E01BAEBCD0221008BE3EFD1F09363653B699CA39174D265218911023DA0DCBD04C1F44228D5E5FD");

    try {            
        // Get rpivate key
        KeyFactory keyFactory = KeyFactory.getInstance("ECDSA",prov);
        PKCS8EncodedKeySpec spec=new PKCS8EncodedKeySpec(HexAdapter.toBin("308193020100301306072A8648CE3D020106082A8648CE3D0301070479307702010104200BF4B825E8B758853A49E01EAA45905E249B580421C7306A8EC85B4F4229675DA00A06082A8648CE3D030107A14403420004CD7A82795BF691232E409EBE10039BE6167D15B07E19DA0C417C830D4DB8B9D8F6919113468A1F650125545CC0BCA619EC3BE88723889FB439B71DEE3E1DBAD3"));
        PrivateKey priv = keyFactory.generatePrivate(spec);
        ecdsaSign = java.security.Signature.getInstance("SHA256withECDSA",prov);

        // Generate signature of first run
        byte[] cc="HelloWorld".getBytes();
        ecdsaSign.initSign(priv);
        ecdsaSign.update(cc);            
        byte[] signature=ecdsaSign.sign();
        System.out.println("data " + HexAdapter.toHex(cc));
        System.out.println("signature= "+HexAdapter.toHex(signature));

        // Convert it to export format required for Tachograph certificate
        byte[] rawSignature=VerifySignature.getRawSignature(signature);

        // Setup verifing class
        VerifySignature vv=new VerifySignature(prov);

        // Verify current run
        verify=vv.verify(pubKey, ByteBuffer.wrap(cc), rawSignature);
        System.out.println("cc verify signature. Result: "+verify);

        // Verify previous run whre signature is copied into cert from output of previous run
        verify=vv.verify(pubKey, ByteBuffer.wrap(cert), sigBytes);

        // Output information required for verification and to copy over to next run
        System.out.println("pubkey "+HexAdapter.toHex(pubKey));
        System.out.println("cert "+HexAdapter.toHex(cert));     
        System.out.println("sig "+HexAdapter.toHex(sigBytes));

    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(TestCaSignerEcc.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeyException ex) {
        Logger.getLogger(VerifyEccSignature.class.getName()).log(Level.SEVERE, null, ex);
    } catch (SignatureException ex) {
        Logger.getLogger(VerifyEccSignature.class.getName()).log(Level.SEVERE, null, ex);
    } catch (Exception ex) {
        Logger.getLogger(VerifyEccSignature.class.getName()).log(Level.SEVERE, null, ex);
    }

}

}

Verifying:

public class VerifySignature {
Provider prov;
Signature ecdsaSign;

public VerifySignature(Provider prov) {
    this.prov = prov;
}

public boolean verify(byte[] pubKey, ByteBuffer plainCert, byte[] rawSignature){

    boolean verify=false;

    try {              
        ECPublicKey pp= decodeKey(prov,pubKey);

        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(/*r*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(rawSignature,0,32))));
        v.add(/*s*/new ASN1Integer(new BigInteger(1, Arrays.copyOfRange(rawSignature,32,32*2))));
        byte[] sigDer = new DERSequence(v).getEncoded();
        System.out.println("v "+v);

        // Verify signature
        ecdsaSign = java.security.Signature.getInstance("SHA256withECDSA",prov);
        ecdsaSign.initVerify(pp);
        ecdsaSign.update(plainCert);
        verify = ecdsaSign.verify(sigDer);
        System.out.println(" - Singnature verified: "+verify);

    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(TestCaSignerEcc.class.getName()).log(Level.SEVERE, null, ex);
    } catch (InvalidKeySpecException | SignatureException | InvalidKeyException | IOException ex) {
        Logger.getLogger(VerifyEccSignature.class.getName()).log(Level.SEVERE, null, ex);
    } catch (NoSuchProviderException ex) {
        Logger.getLogger(VerifySignature.class.getName()).log(Level.SEVERE, null, ex);
    }
    return verify;
}

public static ECPublicKey decodeKey(Provider prov, byte[] encoded) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException{
    java.security.spec.ECPoint point = new java.security.spec.ECPoint(  new BigInteger(1, Arrays.copyOfRange(encoded,1,33)), 
                                                                        new BigInteger(1, Arrays.copyOfRange(encoded,33,65))
                                                                        );

    ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec(/*"secp256r1""prime256v1*/"P-256");
    KeyFactory fact = KeyFactory.getInstance("ECDSA",prov);
    ECCurve curve = params.getCurve();
    java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, params.getSeed());

    java.security.spec.ECParameterSpec params2=EC5Util.convertSpec(ellipticCurve, params);
    java.security.spec.ECPublicKeySpec keySpec = new java.security.spec.ECPublicKeySpec(point,params2);
    ECPublicKey pubKey=(ECPublicKey) fact.generatePublic(keySpec);
    return pubKey;
}

private static ASN1Primitive toAsn1Primitive(byte[] data) throws Exception
{
    try (ByteArrayInputStream inStream = new ByteArrayInputStream(data);
            ASN1InputStream asnInputStream = new ASN1InputStream(inStream);) 
    {
        return asnInputStream.readObject();
    }
}

public static byte[] getRawSignature(byte[] signed)throws Exception{
        ASN1Primitive asn1 = toAsn1Primitive(signed);
        byte[] rawSignature=new byte[0x40];
        byte[] tt;
        int ptr=0;
        if (asn1 instanceof ASN1Sequence) {
            ASN1Sequence asn1Sequence = (ASN1Sequence) asn1;
            ASN1Encodable[] asn1Encodables = asn1Sequence.toArray();
            for (ASN1Encodable asn1Encodable : asn1Encodables) {
                ASN1Primitive asn1Primitive = asn1Encodable.toASN1Primitive();
                if (asn1Primitive instanceof ASN1Integer) {
                    ASN1Integer asn1Integer = (ASN1Integer) asn1Primitive;
                    BigInteger integer = asn1Integer.getValue();
                    tt=BigIntegers.asUnsignedByteArray(asn1Integer.getValue());
                    System.arraycopy(tt, 0, rawSignature, ptr,  0x20);
                    ptr+=0x20;
                }
            }
        }
    return rawSignature;
}

}

Sorry to bother you all. It seems I have been injecting the signature directly, intsead of converting it to raw format before converting it back to ASN1 during verification. My oversight. Peter

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM