What happened to the IBM JCE vendor?

I have a JCE test that works fine with all the Sun JDKs I tried, but it doesn't work with various IBM J9 JDKs (e.g. 1.6.0 build pwi3260sr8-20100409_01 (SR8)). The exception below occurs when a cipher is initialized in encryption mode. Why can't IBM JCE use its 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) 
+4
source share
6 answers

I do not know this for sure, but I believe that JCE has a built-in policy restricting encryption for the public key and decryption for the private key.

In the sample code, encryption was performed using the private key. This requires that the public key be decrypted, which means that anyone who has a public key can access the encoded data. Although this is used, it is not an accepted template, and the IBM implementation can "protect" you from accidentally creating encrypted data that is publicly available.

The fact that it was tested correctly when they were canceled, as a rule, confirms my suspicions, but I have not yet found an official document that states the same.

+5
source

There is a solution, see http://www-01.ibm.com/support/docview.wss?uid=swg1IV18625

with property

 -Dcom.ibm.crypto.provider.DoRSATypeChecking=false 

You can use secret keys to encrypt data.

+5
source

IBM insists that private keys cannot be used for encryption, and public keys cannot be used for decryption, so they either see this artificial restriction as a function, or someone is seriously confused here.

Here's how I worked on this issue:

 RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) ks.getKey(keyAlias, ksPassword.trim().toCharArray()); RSAPublicKeySpec spec = new RSAPublicKeySpec(privateKey.getModulus(),privateKey.getPrivateExponent()); Key fakePublicKey = KeyFactory.getInstance("RSA").generatePublic(spec); encryptCipher.init(Cipher.ENCRYPT_MODE, fakePublicKey); 

Essentially, I created a public key object with cryptographic material with a private key. You will need to do the opposite, create a private key object with cryptographic material with a public key in order to decrypt using the public key if you want to avoid excluding the public key for decryption.

+3
source

I recently ran into the same problem. This was finally resolved by implementing the bouncy castle and adding this line to the java.security file

security.provider.1 = org.bouncycastle.jce.provider.BouncyCastleProvider

+3
source

@ T.Rob commented that you might have made a mistake while encrypting with the private key. If "everyone" knows the public key, everyone can decrypt your file. Thus, the behavior of IBM JCE protects people from this error.

I see the logic of this.

However, there may be times when you really need to encrypt with the private key; for example, as part of a protocol that must prove that you know the private key corresponding to the published public key.

If this is really what you want to do, you may have to use the recent Sun JCE implementation (older Sun JCEs did not implement RSA) or Bouncy Castle.

+2
source

@Stephen C / @ FelixM: IBM does not seem to know at all how RSA cryptography works and how it is intended for use. Basically, both operations (encryption / decryption) should be available for public and private keys.

Public key encryption is required to transmit the client part of the pre private key in SSL / TLS messages. The server needs to decrypt it with a secret key. But if they are negotiating something like ECDHE_RSA, the server needs to REGISTER parts of the handshake using the private key - this is encryption using PrivateKey. Conversely, the client must decrypt using the public key from the server certificate in order to verify the hash value of the signature. (message authentication)

So, if I try to run ECDHE_RSA (server side) on the latest IBM JDK 7, the following will happen:

 java.security.InvalidKeyException: Private key cannot be used to encrypt. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614) at java.lang.Thread.run(Thread.java:777) at com.ibm.crypto.provider.RSASSL.engineInit(Unknown Source) at javax.crypto.Cipher.init(Unknown Source) at javax.crypto.Cipher.init(Unknown Source) at java.security.Signature$CipherAdapter.engineInitSign(Signature.java:1239) at java.security.Signature$Delegate.init(Signature.java:1116) at java.security.Signature$Delegate.chooseProvider(Signature.java:1076) at java.security.Signature$Delegate.engineInitSign(Signature.java:1140) at java.security.Signature.initSign(Signature.java:522) at net.vx4.lib.tls.core.TLSSignature.createSignature(TLSSignature.java:120) 

As you can see, we use "Signature" and call "initSign", which really requires PrivateKey. This proves that IBM is unaware of this fact, and obviously they do not even have valid regression tests!

Use a different cryptography provider and don't trust IBM until they change their mind.

Regards, Christian

+2
source

Source: https://habr.com/ru/post/1338029/


All Articles