Java:通过代码生成时,密钥库格式无效

Posted

技术标签:

【中文标题】Java:通过代码生成时,密钥库格式无效【英文标题】:Java: Invalid keystore format, when generated through code 【发布时间】:2010-12-21 11:15:39 【问题描述】:

这已被问过几次,但没有一个提供编码测试用例。这里我举一个问题的例子:

    以编程方式生成密钥库(有效) 在该商店中创建证书(有效) 将密钥库保存到磁盘(有效) 使用 keytool 列出密钥库(有效) 以编程方式加载密钥库(因 IOException: InvalidKeystoreFormat 失败)

我没有得到的是,在保存和加载中,我都使用了 KeyStore.getInstance("JKS"),但它失败了。欢迎提出任何建议!

运行时输出:

在“private.keystore”创建私钥库。 创建了密钥库,现在创建了签名者证书 创建签名者证书,保存证书 重新加载密钥库: 创建后无法加载密钥库:密钥库格式无效

测试用例来源:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import sun.security.x509.X500Name;

public class KeystoreCreator

 private String fPrivateKeyStore;
 private String fPrivateKeyStorePassword;
 private String fPrivateKeyStoreKeyPassword;
 private String fPublicKeyCipherPassword;
 private String fPrivateKeyAlias;

 /**
  * @param args
  * @throws Exception 
  */
 public static void main(String[] args) throws Exception
 
  KeystoreCreator creator = new KeystoreCreator();
   
  creator.setPrivateKeyStore("private.keystore");
  creator.setPrivateKeyStorePassword("beer123");
  
  creator.setPrivateKeyAlias("myalias");
  creator.setPrivateKeyStoreKeyPassword("beer123");
  creator.setPublicKeyCipherPassword("beer123");

  creator.initKeyStores();
 

 public KeystoreCreator()
   
 

 public void setPrivateKeyStore(String name)
 
  fPrivateKeyStore=name;
 
 public void setPrivateKeyStorePassword(String pass)
 
  fPrivateKeyStorePassword=pass;
 
 public void setPrivateKeyStoreKeyPassword(String pass)
 
  fPrivateKeyStoreKeyPassword=pass;
 
 public void setPublicKeyCipherPassword(String pass)
 
  fPublicKeyCipherPassword=pass;
 
 public void setPrivateKeyAlias(String alias)
 
  fPrivateKeyAlias=alias;
 
 
    public void initKeyStores() throws Exception
    
        OutputStream out = null;
        File f=new File(fPrivateKeyStore);
        if (f.exists())
        
         f.delete();
         if (f.exists())
         
          throw new IOException("Want to remove the keystore but can't, still reported as present after removal");
         
        
        try
        
         System.out.println("Creating private keystore at '" + fPrivateKeyStore + "'.");
         out = new FileOutputStream(fPrivateKeyStore);
         KeyStore privateKeyStore = KeyStore.getInstance("JKS");
         privateKeyStore.load(null, fPrivateKeyStorePassword.toCharArray());
         
         System.out.println("Created keystore, now created signer cert");
         X500Name x500name=getCA();
         Certificate cert = createCertificate(fPrivateKeyAlias, fPrivateKeyStoreKeyPassword, x500name, privateKeyStore);

         System.out.println("Created signer cert, saving cert");
         privateKeyStore.store(out, fPublicKeyCipherPassword.toCharArray());
         out.flush();
         out.close();
         //try to load it.
         KeyStore reloadedKeyStore = KeyStore.getInstance("JKS");
         try
         
          InputStream reloadedIs=getClass().getClassLoader().getResourceAsStream(fPrivateKeyStore);
          if (reloadedIs!=null)
          
           System.out.println("Reloading keystore:");
           reloadedKeyStore.load(reloadedIs, fPrivateKeyStorePassword.toCharArray());
          
         
         catch (Exception e)
         
          System.err.println("Failed to load the keystore after creation: "+e.getLocalizedMessage());
         
        
        catch (Exception e)
        
         System.err.println("Failed to save the keystore: "+e.getLocalizedMessage());
        
    
    
    private X500Name getCA() throws IOException
    
     return new sun.security.x509.X500Name("a","b", "c","d","e", "GB");
    
    
    public Certificate createCertificate( String alias, String keyPassword,
            sun.security.x509.X500Name x500Name, KeyStore keyStore ) throws NoSuchAlgorithmException,
            InvalidKeyException, CertificateException, SignatureException, NoSuchProviderException,
            KeyStoreException      
        sun.security.x509.CertAndKeyGen keypair = new sun.security.x509.CertAndKeyGen( "RSA", "MD5WithRSA" );
        keypair.generate( 1024 );
        PrivateKey privKey = keypair.getPrivateKey();
        X509Certificate[] chain = new X509Certificate[1];
        chain[0] = keypair.getSelfCertificate( x500Name, 7000 * 24 * 60 * 60 );
        keyStore.setKeyEntry( alias, privKey, keyPassword.toCharArray(), chain );

        Certificate cert = keyStore.getCertificate( alias );
        return cert;
    

【问题讨论】:

【参考方案1】:

    您通过写入文件在当前工作目录中创建私钥存储:new FileOutputStream(fPrivateKeyStore);

    稍后,您使用getClass().getClassLoader().getResourceAsStream(fPrivateKeyStore);从类路径中读取

我认为您正在阅读错误的文件。之前的测试中已经有另一个名称为private.keystore。要验证,您可能需要打印出两个文件的绝对文件路径,例如new File(fPrivateKeyStore).getAbsolutePath() 并将其与 getClass().getClassLoader().getResource(fPrivateKeyStore).toFileURL(); 进行比较

【讨论】:

【参考方案2】:

我可能遗漏了一些东西,但为什么不直接使用 FileInputStream 重新加载私钥存储?

InputStream reloadedIs = new FileInputStream(fPrivateKeyStore);

(我不确定这是否能解决问题,我只是在扫描您的代码时注意到它)

【讨论】:

以上是关于Java:通过代码生成时,密钥库格式无效的主要内容,如果未能解决你的问题,请参考以下文章

PhoneGap Android - 在 Ubuntu 下生成的密钥库格式无效

java.io.IOException:无效的密钥库格式

无效的密钥库格式

无法启动嵌入式 Tomcat 服务器 - 无效的密钥库格式

Mac OS Flutter 构建 appbundle 失败:密钥库格式无效

keytool 错误: java.io.IOException: Invalid keystore format