我正在尝试使用cxf和sprint加密传出的SOAP标头。由于我与spring的配置,我最终为我的客户使用outInterceptor:
'
<bean id="encryptOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken Timestamp Encrypt" />
<entry key="passwordCallbackRef" value-ref="passwordCallback" />
<entry key="user" value="mykey" />
<entry key="encryptionPropFile" value="keystore.properties" />
</map>
</constructor-arg>
</bean>
`
因此,它最终调用
`org.apache.ws.security.message.WSSecEncryptedKey.prepareInternal()`
方法,我通过调试器逐步找到它的源:
try {
**cipher.init(Cipher.ENCRYPT_MODE, remoteCert);**
} catch (InvalidKeyException e) {
throw new WSSecurityException(
WSSecurityException.FAILED_ENCRYPTION, null, null, e
);
}
在这一点上,它抛出:"无效密钥用法"异常。
我最终编写了一个测试java类,在其中手动读取证书,然后尝试使用Cipher.ENCRYPT_MODE参数初始化Cipher,最后我得到了同样的例外。下面是具体的片段:
InputStream inStream = new FileInputStream("our_cert.cer");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert =(X509Certificate)cf.generateCertificate(inStream);
inStream.close();
// Read the public key from certificate file
RSAPublicKey pubkey = (RSAPublicKey) cert.getPublicKey();
cipher.init(Cipher. ENCRYPT_MODE, certif); // it breaks at this point
我用替换了最后一行
cipher.init(Cipher. PRIVATE_KEY, certif);
一切顺利。
不过,我认为这不是正确的密钥用法,我认为ENCRYPT_MODE也应该有效。
通过查看证书密钥使用部分,我注意到它的密钥使用定义为:
ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
Key_Encipherment
]
并且其中没有其他关键部分
从其操作方式来看,Cipher.init(..)仅适用于DigitalSignature(即Cipher.PRIVATE_KEY),而不适用于 因此,我的问题是,是否有可能没有为该证书正确定义KeyUsage。我不是密码学专家,但我读到的一些留言板建议,如果keyUsage是关键的,它可能需要使用数据加密以及… 谢谢你的帮助!
KEY_Encipher(例如
Cipher.ENCRYPT_MODE
仔细阅读源代码,有两个条件会引发该异常,其中一个是永远不会发生的错误,另一个是检查有问题的证书是否支持有问题的操作。
if (critSet != null && !critSet.isEmpty()
&& critSet.contains(KEY_USAGE_EXTENSION_OID)) {
boolean[] keyUsageInfo = cert.getKeyUsage();
// keyUsageInfo[2] is for keyEncipherment;
// keyUsageInfo[3] is for dataEncipherment.
if ((keyUsageInfo != null) &&
(((opmode == Cipher.ENCRYPT_MODE) &&
(keyUsageInfo.length > 3) &&
(keyUsageInfo[3] == false)) ||
((opmode == Cipher.WRAP_MODE) &&
(keyUsageInfo.length > 2) &&
(keyUsageInfo[2] == false)))) {
throw new InvalidKeyException("Wrong key usage");
}
}
这表明您使用的证书对加密无效。也许您试图使用公钥证书进行加密?
代码似乎没有检查像PRIVATE_KEY这样总是无效的opmode,只是检查像ENCRYPT_MODE这样有时无效的opmode,这可能就是为什么它对测试代码很好的原因。
最近遇到了这个问题。只要创建正确,就可以使用公钥证书进行加密。证书应具有密钥使用对象ID(ObjectId:2.5.29.15 Criticality=true),设置为"b0"(10110000),基本上启用了数据加密位。否则,您将遇到错误的密钥使用错误。任何CA颁发的证书都会将密钥使用关键性设置为true。自签名证书(如在dev/shadbox环境中)不会将关键性设置为true,因此这些证书可以工作,当然前提是您设置为信任它们。我尝试使用服务器上的公钥证书,但遇到了这个错误。然后,我们的IT部门获得了适用于数据加密的正确公钥证书,它开始为我工作。