2011-03-08 23 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。

感谢, 约杰什

相关问题