java - 使用 OpenSSL 生成的 key 和证书在 Java 中验证签名

标签 java signature

下面的 Java 8 代码导致消息“签名未由匹配 key 签名”,我不明白为什么。有什么想法为什么不验证吗?

我最好的猜测是它与 openssl 生成私钥或证书的方式有关,但从我的研究来看,我似乎使用了正确的命令。我想要做的是加载一个私钥,签署一条消息,然后根据 x509 证书中包含的公钥验证签名。

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

publickey.cer 也是使用基于 MS windows 的 openssl 生成的,使用以下命令:

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

我一直在尝试验证签名的 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);
}

最佳答案

verifySignature 方法的签名(无双关语)说明您的实现无法正常工作。对于要检查的 Signature,处理器需要同时访问已签名的数据和签名。您的方法没有提供:

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

我建议您将其修改为与 generateSignatureForMessage 方法对称,即:

  1. 你给签名对象提供它需要工作的内容(待签名的内容用于签名,已签名的内容用于签名检查)
  2. 您要求签名对象执行工作(签名,或验证)

这加起来类似于一个实现:

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

关于java - 使用 OpenSSL 生成的 key 和证书在 Java 中验证签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36303236/

相关文章:

java - Java 中低效的 XML 解析

module - 透明签名归属的惊人行为

amazon-web-services - 不是你,是我们 我们现在无法完成您的请求。请稍后再试 - awsapps 登录

c++ - int32_t main()与int main()

signature - 我可以在 Perl 6 中使用独立签名作为签名吗?

python - 从变量名列表构建函数签名

java - 显示从 json 响应中检索到的所有内容

java - 替代反射以生成随机子类的对象

java - 如何获得焦点所有者?

java - 使用 nameFilters 排除特定类型的项目