Java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block

I use RSA to encrypt text and decrypt text. The public key and private key are generated using the openssl tool. When decrypting the data, I came across "java.lang.ArrayIndexOutOfBoundsException exception: too much data for RSA block".

Here is the RSA usage class:

package studio.uphie.app; import android.util.Base64; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; /** * Created by Uphie on 2016/4/11. */ public class RSA { private static String RSA = "RSA"; /** * * @param text text to be encrypted * @param pub_key rsa public key * @return encrypted data in byte-array form */ public static byte[] encryptData(String text, String pub_key) { try { byte[] data = text.getBytes(); PublicKey publicKey = getPublicKey(Base64.decode(pub_key.getBytes(), Base64.DEFAULT)); Cipher cipher = Cipher.getInstance(RSA); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); } catch (Exception e) { e.printStackTrace(); return null; } } /** * * @param text text to be decrypted * @param pri_key rsa private key * @return */ public static byte[] decryptData(String text, String pri_key) { try { byte[] data = text.getBytes(); PrivateKey privateKey = getPrivateKey(Base64.decode(pri_key.getBytes(),Base64.DEFAULT)); Cipher cipher = Cipher.getInstance(RSA); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); } catch (Exception e) { //"java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block" exception occurs here. return null; } } /** * * @param keyBytes * @return * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ public static PublicKey getPublicKey(byte[] keyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException { X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA); return keyFactory.generatePublic(keySpec); } /** * * @param keyBytes * @return * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException */ public static PrivateKey getPrivateKey(byte[] keyBytes) throws NoSuchAlgorithmException, InvalidKeySpecException { PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA); return keyFactory.generatePrivate(keySpec); } } 

And the fragment that encrypts and decrypts the data:

  //encrypt byte[] e = RSA.encryptData(text, PUBLIC_KEY); String result = Base64.encodeToString(e, Base64.DEFAULT); tv_encrypted.setText(result); //decrypt byte[] d = RSA.decryptData(text, PRIVATE_KEY); String result = Base64.encodeToString(d, Base64.DEFAULT); tv_decrypted.setText("Decrypted result:\n" + result); 

I know the reason is that the text to be decrypted is too long, but I just encrypt "abc" and then decrypt the encrypted "abc". And how to handle encryption of long text if the text to be encrypted or decrypted should be 11 bytes less than the rsa private key? How can i do this? I am new to RSA.

Thanks in advance!

+1
source share
3 answers

You are missing some steps in the code, which makes verification impossible. However, there are a few tips to suggest a problem. Your decryptData method takes a String argument and then calls String.getBytes() to get the data, which is then decrypted. However, the result of encryption is a sequence of bytes that is not the encoding of any valid string. Perhaps you wanted base64 to decode the input instead of calling getBytes() . In general, to perform decryption and decoding, you must undo the actions that you performed during encryption and encoding. So, if the plaintext is a byte [], then the following steps:

byte [] β†’ Encrypt β†’ byte [] β†’ Base64 encode β†’ String.

then in the direction of decryption, you start with the Base64 line, you should:

String β†’ Base64 decode β†’ byte [] β†’ decrypt β†’ byte []

Also, another problem that is bad practice and the source of many portability errors is the use of default values. You use the default settings in two places, and they are both unpleasant. First, you use the default no-args method String.getBytes() and presumably map this to a single-arg String (byte []) . This uses the default character set for the platform, but it may vary across platforms. Therefore, always specify a character set. For most applications, UTF-8 is the perfect choice. Secondly, you call Cipher.getInstance('RSA') without specifying a Cipher.getInstance('RSA') . Oracle Java and Android Java will provide you with various add-ons and therefore your code will not be portable between platforms. Always indicate the complete string. The choice here is a bit trickier if you need portability for older Java implementations. Canceling OAEP should be your first choice, therefore Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); probably the right choice. See more details.

How to encrypt longer texts, see answer from Henry .

+5
source

Fianlly I changed my codes like this and they work well:

  public static String encryptData(String text, String pub_key) { try { byte[] data = text.getBytes("utf-8"); PublicKey publicKey = getPublicKey(Base64.decode(pub_key.getBytes("utf-8"), Base64.DEFAULT)); Cipher cipher = Cipher.getInstance(RSA); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return Base64.encodeToString(cipher.doFinal(data),Base64.DEFAULT); } catch (Exception e) { e.printStackTrace(); return null; } } public static String decryptData(String text, String pri_key) { try { byte[] data =Base64.decode(text,Base64.DEFAULT); PrivateKey privateKey = getPrivateKey(Base64.decode(pri_key.getBytes("utf-8"),Base64.DEFAULT)); Cipher cipher = Cipher.getInstance(RSA); cipher.init(Cipher.DECRYPT_MODE, privateKey); return new String(cipher.doFinal(data),"utf-8"); } catch (Exception e) { return null; } } 

If something seems wrong, you can remind me. Thanks for the response of James and Henry.

+1
source

Usually you generate a random secret key for a symmetric cipher (for example, AES) and use it to encrypt your payment load.

RSA is only used to encrypt this random key. This not only solves the length problem, but also has some other advantages:

  • Symmetric ciphers are usually much faster.
  • If the message is sent to several receivers, for each recipient you need to add only an encrypted key, the main content may be the same.
0
source

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


All Articles