2011-03-08 70 views
11

好的,這是另一個「我沒有真正想法從哪裏開始」的問題,所以希望答案很簡單。但是,我並不知道要搜索什麼,而迄今爲止我的嘗試並沒有發揮太大的作用。如何讀取用於OpenSAML的私鑰?

我想讀從(目前上盤)文件中的私鑰。最終,密鑰將駐留在數據庫中,但這一點足夠好,而且這種差異對解析密鑰材料沒有任何真正的影響。我已經能夠創建一個擁有公鑰部分(由調試器確認)的實例,但我似乎無法弄清楚如何讀取私有部分。生成密鑰對爲:

openssl genrsa 512 > d:\host.key 
openssl req -new -x509 -nodes -sha1 -days 365 -key d:\host.key > d:\host.cert 

,我知道,512位RSA密鑰很久以前破然而,對於試圖獲得API的工作,我認爲沒有理由耗盡系統熵供應不必要)

代碼到目前爲止是:

import org.opensaml.xml.security.credential.Credential; 
import org.opensaml.xml.security.x509.BasicX509Credential; 

private Credential getSigningCredential() 
throws java.security.cert.CertificateException, IOException { 
    BasicX509Credential credential = new BasicX509Credential(); 

    credential.setUsageType(UsageType.SIGNING); 

    // read public key 
    InputStream inStream = new FileInputStream("d:\\host.cert"); 
    CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
    X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream); 
    inStream.close(); 
    credential.setEntityCertificate(cert); 

    // TODO: read private key 

    // done. 
    return credential; 
} 

但我怎麼讀文件host.keycredential私鑰部分,這樣我就可以使用生成Credential實例簽名數據?

回答

19

BasicX509Credential不是標準Java的一部分;我想你正在談論來自OpenSAML的org.opensaml.xml.security.x509.BasicX509Credential

你想要一個PrivateKey,你將與credential.setPrivateKey()設置。爲了得到一個PrivateKey,你必須首先轉換私鑰到Java可以讀出,即PKCS#8格式:

openssl pkcs8 -topk8 -nocrypt -outform DER <D:\host.key> D:\host.pk8 

然後,從Java:

RandomAccessFile raf = new RandomAccessFile("d:\\host.pk8", "r"); 
byte[] buf = new byte[(int)raf.length()]; 
raf.readFully(buf); 
raf.close(); 
PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(buf); 
KeyFactory kf = KeyFactory.getInstance("RSA"); 
PrivateKey privKey = kf.generatePrivate(kspec); 

就萬事大吉了!你有你的PrivateKey

默認情況下,openssl自己的格式寫入鍵(RSA密鑰,PKCS#8恰好是圍繞該格式的包裝),它對其進行編碼在PEM,其中Base64的一個頭和頁腳。普通Java不支持這兩種特性,因此轉換爲PKCS#8。 -nocrypt選項是因爲PKCS#8支持可選的基於密碼的私鑰加密。

警告:你真的真的想要使用更長的RSA密鑰。 512位弱;一個512位的RSA密鑰在1999年被打破了幾百臺電腦。 2011年,隨着12年的技術進步,人們應該認爲幾乎任何人都可以破解512位RSA密鑰。因此,使用1024位RSA密鑰至少(最好是2048位;使用密鑰時的計算開銷並不差,您仍然可以每秒執行數百個簽名)。

+0

是,BasicX509Credential是OpenSAML,我們對此深感抱歉監督。我一定會試試這個。是的,我完全清楚,512位RSA密鑰並不是安全的,但是這個特殊的設置完全是爲了試圖讓所有東西都能正常工作,所以密鑰長度並不是問題。 – 2011-03-08 14:31:02

+0

似乎像一個魅力工作,非常感謝你!當然,我的簽名代碼似乎被破壞了,但至少根據調試器,我從磁盤上的兩個文件中獲得了適當的「Credential」。在旅途中... – 2011-03-08 14:45:07

+0

謝謝。我在Windows上重定向< and >時遇到了很多麻煩,所以可能需要使用-in和-out開關替換它們。 – 2013-02-19 17:30:25

1

此問題與SAML相關,並且對於想要檢索用於簽署XMLObject的私鑰的用戶也是相關的。上述答案的偉大工程,它也可以檢索的密鑰庫中的私有密鑰以及:

 Properties sigProperties = new Properties(); 

    sigProperties.put("org.apache.ws.security.crypto.provider","org.apache.ws.security.components.crypto.Merlin"); 
    sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.type","jks"); 
    sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.password","keypass"); 
    sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.alias","keyalias"); 
    sigProperties.put("org.apache.ws.security.crypto.merlin.keystore.file","keystore.jks"); 

    Crypto issuerCrypto = CryptoFactory.getInstance(sigProperties); 

    String issuerKeyName = (String) sigProperties.get("org.apache.ws.security.crypto.merlin.keystore.alias"); 

    //See http://ws.apache.org/wss4j/xref/org/apache/ws/security/saml/ext/AssertionWrapper.html 'signAssertion' method 
    // prepare to sign the SAML token 
    CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS); 
    cryptoType.setAlias(issuerKeyName); 
    X509Certificate[] issuerCerts = issuerCrypto.getX509Certificates(cryptoType); 
    if (issuerCerts == null) { 
     throw new WSSecurityException(
       "No issuer certs were found to sign the SAML Assertion using issuer name: " 
         + issuerKeyName); 
    } 

    String password = ADSUnitTestUtils.getPrivateKeyPasswordFromAlias(issuerKeyName); 

    PrivateKey privateKey = null; 
    try { 
     privateKey = issuerCrypto.getPrivateKey(issuerKeyName, password); 
    } catch (Exception ex) { 
     throw new WSSecurityException(ex.getMessage(), ex); 
    } 


    BasicX509Credential signingCredential = new BasicX509Credential(); 
    signingCredential.setEntityCertificate(issuerCerts[0]); 
    signingCredential.setPrivateKey(privateKey); 

    signature.setSigningCredential(signingCredential); 

這比要求的原始查詢更多的代碼,但看起來他們正試圖獲得在BasicX509Credential。

感謝, 約傑什