2017-10-19 207 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(這更簡單)的例子,但我無法找到它;如果可能的話,稍後會添加