我正在尝试使用 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),但不适用于 Key_Encipherment(即Cipher. ENCRYPT_MODE)。
所以我的问题是,是否有可能没有为该证书正确定义KeyUsage 。我不是密码学专家,但我正在阅读的一些留言板建议如果 keyUsage 很关键,它可能还需要使用 DATA_ENCIPHERMENT ...</p>
谢谢你的帮助!