简体   繁体   English

使用 OpenSSL 生成的密钥和证书验证 Java 中的签名

[英]Verify a signature in Java using OpenSSL generated key and certificate

The Java 8 code below results in the message "signature NOT signed by matching key" and I can't understand why.下面的 Java 8 代码导致消息“签名未由匹配密钥签名”,我不明白为什么。 Any ideas why its not verifying?任何想法为什么不验证?

My best guess is that it is something to do with the way the private key or certificate are being generated by openssl, but from my reseach it seems I'm using the correct commands.我最好的猜测是,这与 openssl 生成私钥或证书的方式有关,但从我的研究来看,我似乎使用了正确的命令。 What I'm trying to do is load a private key, sign a message, then verify the signature against a public key contained in an x509 certificate.我想要做的是加载一个私钥,签署一条消息,然后根据 x509 证书中包含的公钥验证签名。

The privatekey.pkcs8.key file was generated using MS windows based openssl using the following commands: privatekey.pkcs8.key 文件是使用以下命令使用基于 MS Windows 的 openssl 生成的:

openssl.exe" genrsa -out privatekey.pem 1024
openssl pkcs8 -in privatekey.pem -inform PEM -topk8 -out privatekey.pkcs8.key -outform DER -nocrypt

The publickey.cer was also generated using MS windows based openssl, using the following commands: publickey.cer 也是使用基于 MS windows 的 openssl 生成的,使用以下命令:

openssl req -x509 -key privatekey.pem -days 365 -out publickey.cer -new

The Java code I've been using in an attempt to verify the signature is as follows:我一直在尝试验证签名的 Java 代码如下:

public static void main(String[] args) throws Exception{ 
    new TestSigs();
}

public TestSigs {
    byte[] signature = generateSignatureForMessage("src/cryptoprivatekey.pkcs8.key", "Hello");
    verifySignature("src/crypto/publickey.cer", signature);
}

public byte[] generateSignatureForMessage(String privateKeyPath, String message) throws Exception {
    RSAPrivateKey privKey = loadPrivateRSAKeyFromFile(privateKeyPath);
    Signature s = Signature.getInstance("SHA256withRSA");
    s.initSign(privKey);
    s.update(ByteBuffer.wrap(message.getBytes()));
    byte[] signature = s.sign();
    return signature;
}

private void verifySignature(String publicKeyPath, byte[] signature) throws Exception {
    Certificate cert = loadCertificate(publicKeyPath);
    Signature s = Signature.getInstance("SHA256withRSA");
    s.initVerify(cert);
    if(s.verify(signature)) {
        System.out.println("signature signed by matching key");
    } else {
        System.out.println("signature NOT signed by matching key");
    }
}

private Certificate loadCertificate(String filename) throws FileNotFoundException, CertificateException {
    FileInputStream fis = new FileInputStream(filename);
    BufferedInputStream bis = new BufferedInputStream(fis);
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    return cf.generateCertificate(bis);
}

private RSAPrivateKey loadPrivateRSAKeyFromFile(String keyPath) throws Exception {
    byte[] privKeyBytes = loadRSAKeyBytesFromFile(keyPath);
    KeyFactory kFact = KeyFactory.getInstance("RSA");
    KeySpec ks = new PKCS8EncodedKeySpec(privKeyBytes);
    return (RSAPrivateKey)kFact.generatePrivate(ks);
}

Your signature (no pun) of the verifySignature method is a tell tale that your implementation can not work.您对verifySignature方法的签名( verifySignature关语)表明您的实现无法工作。 For a Signature to be checked, the processor needs to hava access to both the signed data, and the signature.要检查Signature ,处理器需要访问签名数据和签名。 Which your method does not provide :您的方法不提供:

private void verifySignature(String publicKeyPath, byte[] signature)

I suggest you modify it to be symetrical to the generateSignatureForMessage method, that is :我建议您将其修改为与generateSignatureForMessage方法对称,即:

  1. You feed the signature object the content it needs to work (the content to be signed for signature, the signed content for signature checking)您向签名对象提供它需要工作的内容(签名的内容,签名检查的签名内容)
  2. You ask the signature object to perform the work ( sign , or verify )您要求签名对象执行工作( signverify

Which add up to an implementation akin to :加起来就是一个类似于:

private void verifySignature(String publicKeyPath, byte[] signature, byte[] signedContent) throws Exception {
    Certificate cert = loadCertificate(publicKeyPath);
    Signature s = Signature.getInstance("SHA256withRSA");
    s.initVerify(cert);
    s.update(signedContent);
    if(s.verify(signature)) {
        System.out.println("signature signed by matching key");
    } else {
        System.out.println("signature NOT signed by matching key");
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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