2017-10-19 148 views
2

我使用OpenSSL生成公共和私人DSA键和运行以下命令:无法获取读取DSA钥匙从.PEM文件

openssl dsaparam -out dsaparam.pem 1024 
openssl gendsa -out dsaprivkey.pem dsaparam.pem 
openssl req -new -x509 -key dsaprivkey.pem -out dsacert.pem 

,并使用以下两种方法来加载这些键:

public static PrivateKey loadPrivateKey() throws Exception { 
    String privateKeyPEM = FileUtils.readFileToString(new File("/Keys/dsaprivkey.pem"), StandardCharsets.UTF_8); 

    // strip of header, footer, newlines, whitespaces 
    privateKeyPEM = privateKeyPEM 
      .replace("-----BEGIN DSA PRIVATE KEY-----", "") 
      .replace("-----END DSA PRIVATE KEY-----", "") 
      .replaceAll("\\s", ""); 

    // decode to get the binary DER representation 
    byte[] privateKeyDER = Base64.getDecoder().decode(privateKeyPEM); 

    KeyFactory keyFactory = KeyFactory.getInstance("DSA"); 
    PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyDER)); 
    return privateKey; 
} 

public static PublicKey loadPublicKey() throws Exception { 
    String publicKeyPEM = FileUtils.readFileToString(new File("/Keys/dsacert.pem"), StandardCharsets.UTF_8); 

    // strip of header, footer, newlines, whitespaces 
    publicKeyPEM = publicKeyPEM 
      .replace("-----BEGIN CERTIFICATE-----", "") 
      .replace("-----END CERTIFICATE-----", "") 
      .replaceAll("\\s", ""); 

    // decode to get the binary DER representation 
    byte[] publicKeyDER = Base64.getDecoder().decode(publicKeyPEM); 

    KeyFactory keyFactory = KeyFactory.getInstance("DSA"); 
    PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyDER)); 
    return publicKey; 
} 

但是,我无法读取公钥和私钥。

当我尝试读取的公钥,我得到:

java.security.spec.InvalidKeySpecException: Inappropriate key specification: IOException: ObjectIdentifier() -- data isn't an object ID (tag = -96) 

当我尝试读取私钥,我得到:

Exception in thread "main" java.security.spec.InvalidKeySpecException: Inappropriate key specification: IOException : algid parse error, not a sequence 

如果有人遇到同样的情况,我会真的很感谢关于这个问题的任何帮助

+1

你应该猫的公共或私人的关键之一。我怀疑它是“公钥”和“主题公钥信息”之间的区别,后者具有算法和OID。另请参阅[如何读取.pem文件以获取私钥和​​公钥](https://stackoverflow.com/q/11787571/608639),[从文件加载RSA公钥](https://stackoverflow.com/q/11410770/608639),[Android上的PEM文件中的PublicKey,Java](https://stackoverflow.com/q/45464949/608639)等。只需将RSA交换为DSA即可。 – jww

回答

3

你没有生成私钥和公钥,你正在生成私钥和(X.509)证书。证书包含公钥但是公钥不一样。

要读取Java中的X.509证书,使用CertificateFactory(通常直接从文件)(see javadoc online)没有KeyFactory(在密钥依赖*Spec类)。与KeyFactory(s)不同,CertificateFactory可以处理PEM或DER输入,所以你不需要自己去执行strip-BEGIN/END和de-base64(除非你想)。

对于私钥,你有一个问题类似于但不同于一个WWW所评论的问题。对于公用密钥文件(您没有),OpenSSL默认使用Java调用X509EncodedKeySpec和OpenSSL内部调用PUBKEY的SubjectPublicKeyInfo格式。然而,对于私人密钥文件的OpenSSL使用它自己的“传统”的格式标准化PKCS8格式,但Java的PKCS8EncodedKeySpec只支持这些第二,你的命令所使用的第一,以及它们之间的转换代码是不不重要的。你有三个或可能四个选择:

  • 使用OpenSSL转换为PKCS8未加密: openssl pkcs8 -topk8 -nocrypt -in dsaprivkey.pem -out dsaprivfixed.pem # or in 1.0.0 up openssl pkey -in dsaprivkey.pem -out dsaprivfixed.pem

    现在你可以用不同的线张贴代码读取此删除是-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----DSA。作为一项小改进,如果您使用getMimeDecoder,则不需要自行去除空白。

  • 产生PKCS8(未加密),开始时,在OpenSSL的1.0.0起来: # you can generate the key within req instead of separately: openssl dsaparam -out params size openssl req -new -newkey dsa:params -x509 -nodes -keyout private.pem \ -out cert.pem # -nodes really means "don't encrypt key" for hysterical raisins # or in config file set encrypt_rsa_key=no (yes even for other algos!) # or omit it and set encrypt_key=no (more sensible) # # or you can use (new) genpkey instead of (old) gendsa: openssl dsaparam -out params size openssl genpkey -paramfile params -out private.pem openssl req -new -x509 -key private.pem -out cert.pem

    现在你在同样的情况是如上。

  • 使用BouncyCastle中的PEM功能来读取传统格式。
    Reading elliptic curve private key from file with BouncyCastle
    How to Load RSA Private Key From File

  • 阅读传统格式(如你现在做的),并重建PKCS8 ASN.1编码,然后在PKCS8使用KeyFactory。这很复杂,我不推荐它。我确实有一个RSA(这更简单)的例子,但我无法找到它;如果可能的话,稍后会添加