如果 public 密钥的算法是 EC,如何验证 Java 中的签名?

How to validate a signature in Java if the public key's algorithm is EC?

给定一个人的 X509 证书对象。 (对象的类型是 sun.security.x509.X509CertImpl)。这个人用他的私钥签署了一个字符串。鉴于此人在签署上述 String 对象时所做的签名。

我的任务是验证这个签名,但遇到了困难。

当我尝试使用以下代码验证签名时:

    ...
    X509Certificate x509Certificate = getCertificate(certificate);

    Signature signature = Signature.getInstance("SHA256withECDSA");

    signature.initVerify(x509Certificate.getPublicKey());

    signature.update(unsignedData);
    boolean bool = signature.verify(signatureToVerify);
    System.out.println("The signature is " + (bool ? "" : "NOT") + " valid");

我得到java.security.SignatureException: Could not verify signature

你有什么想法吗?我怎样才能让它发挥作用?

已编辑: 最后,我设法让它工作了,但还不明白原因: 在将签名传递给验证方法之前,我需要对其进行以下修改:

    byte[] rBytes = Arrays.copyOfRange(signatureHash, 0, 32);
    byte[] sBytes = Arrays.copyOfRange(signatureHash, 32, 64);

    BigInteger r = new BigInteger(1, rBytes);
    BigInteger s = new BigInteger(1, sBytes);

    ASN1Integer asn1R = new ASN1Integer(r);
    ASN1Integer asn1S = new ASN1Integer(s);

    DERSequence seq = new DERSequence(new ASN1Integer[]{asn1R, asn1S});
    byte[] signatureToVerify2 = seq.getEncoded();
    // verifying the signatureToVerify2 instead of the original brings success
    boolean bool = signature.verify(signatureToVerify2);

这是一个(半)工作的应用程序,供进一步参考,当故事中涉及 ECDSA 时验证签名:

import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERSequence;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;

public class SignatureTest {

    public static void main(String[] args) throws CertificateException, InvalidKeyException, SignatureException, NoSuchAlgorithmException, IOException {
        byte[] certificateAsByteArray = ...;
        byte[] dataToVerifyAsByteArray = ...;
        byte[] signatureHashAsByteArray = ...;

        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(certificateBytes);
        X509Certificate x509Certificate = (X509Certificate) certFactory.generateCertificate(in);

        Signature signature = Signature.getInstance("SHA256withECDSA");

        signature.initVerify(x509Certificate.getPublicKey());

        signature.update(dataToVerifyAsHexaString);

        byte[] rBytes = Arrays.copyOfRange(signatureHash, 0, 32);
        byte[] sBytes = Arrays.copyOfRange(signatureHash, 32, 64);

        ASN1Integer asn1R = new ASN1Integer(rBytes);
        ASN1Integer asn1S = new ASN1Integer(sBytes);

        DERSequence seq = new DERSequence(new ASN1Integer[] {asn1R, asn1S});

        boolean isSignatureOK = signature.verify(seq.getEncoded());

        System.out.println("The signature is " + (isSignatureOK ? "" : "NOT ") + "VALID");
    }
}