验证 RSA 密钥是否与 Java 中的 X.509 证书匹配 [英] Validate if RSA key matches X.509 certificate in Java

查看:183
本文介绍了验证 RSA 密钥是否与 Java 中的 X.509 证书匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 RSA 密钥和一个 X.509 证书,用于 SSL 连接.

I have a RSA Key and a X.509 Certificate which I use for SSL connections.

密钥和证书以 PEM 格式(由 OpenSSL 生成)存储在文件中,并在 Apache HTTP 服务器环境中使用.

The key and certificate are stored in files in PEM format (generated by OpenSSL) and used in an Apache HTTP server environment.

是否有一种简单的方法可以仅使用 Java 代码(无需执行 openssl 二进制文件并解析输出)来验证密钥是否与证书匹配,例如使用 Java 安全性和/或 Bouncycastle 库方法?

Is there an easy way to validate if the key matches the certificate using only Java code (without executing the openssl binary and parsing the output), for example by using Java security and/or Bouncycastle library methods?

推荐答案

以下代码将 SHA-1 与公钥和私钥内的模数进行比较.每个对的模数应该是唯一的(除非您的密钥对生成机制或随机生成器当然被破坏了).

The following code compares the SHA-1 over the modulus within the public and private key. The modulus should be unique for each pair (unless you key pair generation mechanism or random generator is broken of course).

请注意,以下代码要求密钥采用未加密的 PKCS#8 格式.最好使用 PKCS#12 并在 KeyStore 中加载二进制 PKCS#12 文件(提供密码).

Note that the following code requires the key to be in unencrypted PKCS#8 format. It may be better to use PKCS#12 instead and load the binary PKCS#12 file in a KeyStore (providing the password).

openssl pkcs8 -topk8 -in key.pem -out keypk8.pem -nocrypt

最后是 Java 代码:

And finally the Java code:

import static org.bouncycastle.util.encoders.Hex.toHexString;

import java.io.ByteArrayInputStream;
import java.io.FileReader;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;

import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

public class CompareCertAndKey {

    /**
     * Checks if the certificate and RSA private key match.
     * 
     * @param args the path to the certificate file in args[0] and that of the private key in args[1]
     */
    public static void main(String[] args) {
        try {
            final PemReader certReader = new PemReader(new FileReader(args[0]));
            final PemObject certAsPemObject = certReader.readPemObject();
            if (!certAsPemObject.getType().equalsIgnoreCase("CERTIFICATE")) {
                throw new IllegalArgumentException("Certificate file does not contain a certificate but a " + certAsPemObject.getType());
            }
            final byte[] x509Data = certAsPemObject.getContent();
            final CertificateFactory fact = CertificateFactory.getInstance("X509");
            final Certificate cert = fact.generateCertificate(new ByteArrayInputStream(x509Data));
            if (!(cert instanceof X509Certificate)) {
                throw new IllegalArgumentException("Certificate file does not contain an X509 certificate");
            }

            final PublicKey publicKey = cert.getPublicKey();
            if (!(publicKey instanceof RSAPublicKey)) {
                throw new IllegalArgumentException("Certificate file does not contain an RSA public key but a " + publicKey.getClass().getName());
            }

            final RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
            final byte[] certModulusData = rsaPublicKey.getModulus().toByteArray();

            final MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
            final byte[] certID = sha1.digest(certModulusData);
            final String certIDinHex = toHexString(certID);


            final PemReader keyReader = new PemReader(new FileReader(args[1]));
            final PemObject keyAsPemObject = keyReader.readPemObject();
            if (!keyAsPemObject.getType().equalsIgnoreCase("PRIVATE KEY")) {
                throw new IllegalArgumentException("Key file does not contain a private key but a " + keyAsPemObject.getType());
            }

            final byte[] privateKeyData = keyAsPemObject.getContent();
            final KeyFactory keyFact = KeyFactory.getInstance("RSA");
            final KeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyData);
            final PrivateKey privateKey = keyFact.generatePrivate(keySpec);
            if (!(privateKey instanceof RSAPrivateKey)) {
                throw new IllegalArgumentException("Key file does not contain an X509 encoded private key");
            }
            final RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
            final byte[] keyModulusData = rsaPrivateKey.getModulus().toByteArray();
            final byte[] keyID = sha1.digest(keyModulusData);
            final String keyIDinHex = toHexString(keyID);

            System.out.println(args[0] + " : " + certIDinHex);
            System.out.println(args[1] + " : " + keyIDinHex);
            if (certIDinHex.equalsIgnoreCase(keyIDinHex)) {
                System.out.println("Match");
                System.exit(0);
            } else {
                System.out.println("No match");
                System.exit(-1);
            }
        } catch (Exception e) {
            e.printStackTrace(System.err);
            System.exit(-2);
        }
    }
}

这篇关于验证 RSA 密钥是否与 Java 中的 X.509 证书匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆