如何生成密钥对并以编程方式将其插入到KeyStore中(不使用Java KeyTool)?

问题描述:

我想生成一个密钥对并以编程方式将其插入到Java KeyStore中。我可以使用命令行来完成我想要的功能,但是如何使用Java代码执行此操作?如何生成密钥对并以编程方式将其插入到KeyStore中(不使用Java KeyTool)?

这是命令行:

keytool -genkeypair \ 
    -dname "cn=Unknown" \ 
    -alias main \ 
    -keyalg RSA \ 
    -keysize 4096 \ 
    -keypass 654321 \ 
    -keystore C:\\Users\\Felipe\\ks \ 
    -storepass 123456 \ 
    -validity 365 

这里是Java代码,我到目前为止有:

public static void main(String[] args) { 
    try (
     FileOutputStream fos = new FileOutputStream("C:\\Users\\Felipe\\ks"); 
    ) { 
     KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 
     keyPairGenerator.initialize(4096, SecureRandom.getInstance("SHA1PRNG")); 
     KeyPair keyPair = keyPairGenerator.generateKeyPair(); 

     Certificate[] chain = {}; 

     KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
     keyStore.load(null, null); 
     keyStore.setKeyEntry("main", keyPair.getPrivate(), "654321".toCharArray(), chain); // Error: Private key must be accompanied by certificate chain 
     keyStore.store(fos, "123456".toCharArray()); 
    } catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | IOException e) { 
     e.printStackTrace(); 
    } 
} 

但我不断收到以下错误消息:Private key must be accompanied by certificate chain

我想我应该创建一个证书并将其插入到证书数组中,但如何做到这一点?

这里是一个不错的Java函数生成程序的自签名证书(link):

private X509Certificate generateCertificate(String dn, KeyPair keyPair, int validity, String sigAlgName) throws GeneralSecurityException, IOException { 
    PrivateKey privateKey = keyPair.getPrivate(); 

    X509CertInfo info = new X509CertInfo(); 

    Date from = new Date(); 
    Date to = new Date(from.getTime() + validity * 1000L * 24L * 60L * 60L); 

    CertificateValidity interval = new CertificateValidity(from, to); 
    BigInteger serialNumber = new BigInteger(64, new SecureRandom()); 
    X500Name owner = new X500Name(dn); 
    AlgorithmId sigAlgId = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid); 

    info.set(X509CertInfo.VALIDITY, interval); 
    info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(serialNumber)); 
    info.set(X509CertInfo.SUBJECT, owner); 
    info.set(X509CertInfo.ISSUER, owner); 
    info.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic())); 
    info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); 
    info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(sigAlgId)); 

    // Sign the cert to identify the algorithm that's used. 
    X509CertImpl certificate = new X509CertImpl(info); 
    certificate.sign(privateKey, sigAlgName); 

    // Update the algorith, and resign. 
    sigAlgId = (AlgorithmId) certificate.get(X509CertImpl.SIG_ALG); 
    info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, sigAlgId); 
    certificate = new X509CertImpl(info); 
    certificate.sign(privateKey, sigAlgName); 

    return certificate; 
} 

你可以用它来从你的密钥对生成一个证书,并将其插入证书链,以使setKeyEntry()方法作业:

public static void main(String[] args) { 
    try (
     FileOutputStream fos = new FileOutputStream("C:\\Users\\Felipe\\ks"); 
    ) { 
     KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); 
     keyPairGenerator.initialize(4096, SecureRandom.getInstance("SHA1PRNG")); 
     KeyPair keyPair = keyPairGenerator.generateKeyPair(); 

     Certificate[] chain = {generateCertificate("cn=Unknown", keyPair, 365, "SHA256withRSA")}; 

     KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
     keyStore.load(null, null); 
     keyStore.setKeyEntry("main", keyPair.getPrivate(), "654321".toCharArray(), chain); 
     keyStore.store(fos, "123456".toCharArray()); 
    } catch (IOException | GeneralSecurityException e) { 
     e.printStackTrace(); 
    } 
}