IBM 的 JCE 提供商出了什么问题?
我有一个 JCE 测试,它适用于我尝试过的所有 Sun JDK,但适用于各种 IBM J9 JDK(例如 1.6.0 build pwi3260sr8-20100409_01(SR8))。当密码在加密模式下初始化时,会发生以下异常。为什么IBM JCE不能使用自己的私钥?我的代码中遗漏了什么吗?
public void testBasicKeyGeneration() throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchProviderException, SignatureException {
KeyPairGenerator generator = KeyPairGenerator.getInstance( "RSA" );
generator.initialize( 2048 );
KeyPair pair = generator.generateKeyPair();
String data1 = "123456789012345678901234567890123456789012345678901234567890";
Cipher cipher = Cipher.getInstance( "RSA" );
cipher.init( Cipher.ENCRYPT_MODE, pair.getPrivate() );
byte[] encrypted = cipher.doFinal( data1.getBytes() );
cipher.init( Cipher.DECRYPT_MODE, pair.getPublic() );
byte[] decrypted = cipher.doFinal( encrypted );
String data2 = new String( decrypted );
assertEquals( "en/decryption failed", data1, data2 );
}
这是堆栈跟踪:
java.security.InvalidKeyException: Private key cannot be used to encrypt.
at com.ibm.crypto.provider.RSA.engineInit(Unknown Source)
at javax.crypto.Cipher.a(Unknown Source)
at javax.crypto.Cipher.a(Unknown Source)
at javax.crypto.Cipher.init(Unknown Source)
at javax.crypto.Cipher.init(Unknown Source)
at test.Test.testBasicKeyGeneration(LicenseHelperTest.java:56)
I have a JCE test that works fine with all Sun JDKs I have tried, but fails with various IBM J9 JDKs (e.g. 1.6.0 build pwi3260sr8-20100409_01(SR8)). The exception below happens when the cipher is initialized in encrypt mode. Why can the IBM JCE not use its own private key? Am I missing something in my code?
public void testBasicKeyGeneration() throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchProviderException, SignatureException {
KeyPairGenerator generator = KeyPairGenerator.getInstance( "RSA" );
generator.initialize( 2048 );
KeyPair pair = generator.generateKeyPair();
String data1 = "123456789012345678901234567890123456789012345678901234567890";
Cipher cipher = Cipher.getInstance( "RSA" );
cipher.init( Cipher.ENCRYPT_MODE, pair.getPrivate() );
byte[] encrypted = cipher.doFinal( data1.getBytes() );
cipher.init( Cipher.DECRYPT_MODE, pair.getPublic() );
byte[] decrypted = cipher.doFinal( encrypted );
String data2 = new String( decrypted );
assertEquals( "en/decryption failed", data1, data2 );
}
Here is the stack trace:
java.security.InvalidKeyException: Private key cannot be used to encrypt.
at com.ibm.crypto.provider.RSA.engineInit(Unknown Source)
at javax.crypto.Cipher.a(Unknown Source)
at javax.crypto.Cipher.a(Unknown Source)
at javax.crypto.Cipher.init(Unknown Source)
at javax.crypto.Cipher.init(Unknown Source)
at test.Test.testBasicKeyGeneration(LicenseHelperTest.java:56)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
有一个解决方案,请参阅 http://www-01.ibm.com /support/docview.wss?uid=swg1IV18625
属性。
具有可以使用私钥加密数据的
There is a solution, see http://www-01.ibm.com/support/docview.wss?uid=swg1IV18625
with the property
you can use private keys to encrypt data.
我不确定这一点,但我相信 JCE 有一个嵌入的策略,限制对公钥的加密和对私钥的解密。
在示例代码中,加密是使用私钥完成的。这将需要公钥来解密,这意味着拥有公钥的任何人都可以访问编码数据。尽管这有它的用途,但它不是可接受的模式,并且 IBM 实现可能会“保护”您免于意外创建公开可读的加密数据。
事实上,当这些被逆转时,它进行了正确的测试,这一事实往往证实了我的怀疑,但我还没有找到官方文件说明这一点。
I don't know this for sure but I believe that the JCE has an embedded policy limiting encryption to the public key and decryption to the private key.
In the example code the encryption was done with the private key. This would require the public key to decrypt, meaning that anyone with the public key could access the encoded data. Although this has it's uses it is not the accepted pattern and the IBM implementation may be "protecting" you from accidentally creating encrypted data that was publicly readable.
The fact that it tested properly when these were reversed tends to confirm my suspicions but I haven't yet found an official document stating as much.
IBM 坚持认为私钥不能用于加密,公钥不能用于解密,因此他们要么将这种人为限制视为一种功能,要么有人在这里严重困惑。
以下是我解决此问题的方法:
本质上,我使用私钥的加密材料创建了一个公钥对象。如果您想避免“公钥无法用于解密”异常,则需要执行相反的操作,使用公钥的加密材料创建私钥对象,然后使用公钥进行解密。
IBM insists private keys cannot be used for encryption and public keys cannot be used for decryption, so they either see this artificial restriction as a feature, or someone is seriously confused here.
Here is how I worked around this problem:
Essentially, I created a public key object with private key's crypto material. You will need to do the reverse, create a private key object with public key's crypto material, to decrypt with public key if you want to avoid the "Public key cannot be used to decrypt" exception.
我最近遇到了同样的问题。最终通过使用 充气城堡 实现并将此行添加到 java.security 文件
security.provider 中解决了这个问题。 1=org.bouncycastle.jce.provider.BouncyCastleProvider
I recently ran in to the same problem. This was eventually solved by using the bouncy castle implementation and adding this line to the java.security file
security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider
@T.Rob 评论说您在使用私钥加密时可能犯了一个错误。如果“每个人”都知道公钥,那么任何人都可以解密您的文件。因此,IBM 的 JCE 行为可以保护人们免受这种错误的影响。
我能明白其中的逻辑。
然而,在某些情况下,您确实需要使用私钥进行加密;例如,作为协议的一部分,需要证明您知道与已发布的公钥相对应的私钥。
如果这确实是您想要做的,您可能需要使用最新的 Sun JCE 实现(较旧的 Sun JCE 没有实现 RSA)或 Bouncy Castle。
@T.Rob commented that you may have made a mistake in encrypting with the private key. If "everyone" knows the public key, then anyone can decrypt your file. IBM's JCE behaviour is thus protecting people against this mistake.
I can see the logic of that.
However, there may be cases where you really do need to encrypt with the private key; e.g. as part of a protocol that needs to prove that you know the private key corresponding to a published public key.
If this is really what you want to do, you probably need to use a recent Sun JCE implementation (older Sun JCEs didn't implement RSA), or Bouncy Castle.
@Stephen C / @FelixM:IBM 似乎对 RSA 加密如何工作以及如何使用它完全一无所知。基本上,这两种操作(加密/解密)都必须可用于公钥和私钥。
在 SSL/TLS 握手中传输预主密钥的客户端部分需要使用公钥进行加密。服务器需要使用其私钥进行解密。但是,如果他们协商类似 ECDHE_RSA 的内容,服务器需要使用私钥对握手的部分内容进行签名 - 即使用 PrivateKey 进行加密。反之亦然,客户端需要使用服务器证书中的公钥进行解密,以验证签名的哈希值。 (证明消息的真实性)
因此,如果我尝试在最新的 IBM JDK 7 上运行 ECDHE_RSA(服务器端),则会发生以下情况:
如您所见,我们正在使用“Signature”并调用“initSign”,这确实需要一个 PrivateKey 。这证明 IBM 对这个事实一无所知,显然他们甚至不知道
有有效的回归测试!
使用其他加密货币提供商,并且不要相信 IBM,直到他们改变主意。
此致,
基督教
@Stephen C / @FelixM: IBM seems to be completely clueless about how RSA cryptography works and how it is intended to be used. Basically both operations (encrypt / decrypt) must be available for the public AND private key.
Encrypt with public key is needed to transmit the client-side part of the pre master secret in SSL/TLS handshakes. The server needs to decrypt with its private key. But if they negotiate something like ECDHE_RSA the server needs to SIGN parts of the handshake with the private key - thats encrypt with PrivateKey. Vice versa the client needs to decrypt with the public key from the certificate of the server to verify the hash value of the signature. (proving authenticity of the message)
So if I try to run ECDHE_RSA (server-side) on latest IBM JDK 7 the following happens:
As you can see we're using "Signature" and call "initSign", which requires indeed a PrivateKey. This proves IBM being clueless about this fact and obviously they don't even
have valid regression tests!
Use another crypto provider and don't believe IBM until they change their mind.
Best regards,
Christian