java.lang.ArrayIndexOutOfBoundsException:RSA块的数据过多 [英] java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block

查看:83
本文介绍了java.lang.ArrayIndexOutOfBoundsException:RSA块的数据过多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用RSA加密文本和解密文本.公钥和私钥是使用openssl工具生成的.解密数据时,我遇到"java.lang.ArrayIndexOutOfBoundsException:RSA块的数据过多"异常.

这是RSA util类:

  package studio.uphie.app;导入android.util.Base64;导入java.security.KeyFactory;导入java.security.NoSuchAlgorithmException;导入java.security.PrivateKey;导入java.security.PublicKey;导入java.security.spec.InvalidKeySpecException;导入java.security.spec.PKCS8EncodedKeySpec;导入java.security.spec.X509EncodedKeySpec;导入javax.crypto.Cipher;/***由Uphie在2016/4/11创建.*/公共类RSA {私有静态字符串RSA ="RSA";/**** @param文本要加密的文本* @param pub_key rsa公钥* @以字节数组形式返回加密的数据*/公共静态字节[] cryptoData(字符串文本,字符串pub_key){尝试 {byte [] data = text.getBytes();PublicKey publicKey = getPublicKey(Base64.decode(pub_key.getBytes(),Base64.DEFAULT));密码cipher = Cipher.getInstance(RSA);cipher.init(Cipher.ENCRYPT_MODE,publicKey);返回cipher.doFinal(data);} catch(Exception e){e.printStackTrace();返回null;}}/**** @param文本文本将被解密* @param pri_key rsa私钥* @返回*/公共静态字节[]解密数据(字符串文本,字符串pri_key){尝试 {byte [] data = text.getBytes();PrivateKey privateKey = getPrivateKey(Base64.decode(pri_key.getBytes(),Base64.DEFAULT));密码cipher = Cipher.getInstance(RSA);cipher.init(Cipher.DECRYPT_MODE,privateKey);返回cipher.doFinal(data);} catch(Exception e){//java.lang.ArrayIndexOutOfBoundsException:RSA块的数据过多"异常在这里发生.返回null;}}/**** @参数keyBytes* @返回* @抛出NoSuchAlgorithmException* @抛出InvalidKeySpecException*/公共静态PublicKey getPublicKey(byte [] keyBytes)引发NoSuchAlgorithmException,InvalidKeySpecException {X509EncodedKeySpec keySpec =新的X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(RSA);返回keyFactory.generatePublic(keySpec);}/**** @参数keyBytes* @返回* @抛出NoSuchAlgorithmException* @抛出InvalidKeySpecException*/公共静态PrivateKey getPrivateKey(byte [] keyBytes)抛出NoSuchAlgorithmException,InvalidKeySpecException {PKCS8EncodedKeySpec keySpec =新的PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(RSA);返回keyFactory.generatePrivate(keySpec);}} 

以及加密和解密数据的代码段:

 //加密byte [] e = RSA.encryptData(text,PUBLIC_KEY);字符串结果= Base64.encodeToString(e,Base64.DEFAULT);tv_encrypted.setText(result);//解密byte [] d = RSA.decryptData(text,PRIVATE_KEY);字符串结果= Base64.encodeToString(d,Base64.DEFAULT);tv_decrypted.setText(解密结果:\ n" +结果); 

我知道原因可能是要解密的文本太长,但是我只加密了"abc",然后解密了加密的"abc".如果要加密或解密的文本应比rsa私钥小11个字节,那么如何处理加密长文本?我该怎么解决?我是RSA的新手.

提前谢谢!

解决方案

您在代码中缺少一些步骤,因此无法检查.但是,有一些线索可以提示问题.您的 decryptData 方法采用String参数,然后调用 String.getBytes()来获取数据,然后将其解密.但是,加密的结果是字节序列,而不是任何有效String的编码.也许您打算对base64解码输入而不是调用 getBytes().通常,要执行解密和解码,必须逆转在加密和编码过程中执行的步骤.因此,如果明文是byte [],则步骤为:

byte []→加密→字节[]→Base64编码→字符串.

然后,在解密方向上,您必须以Base64字符串开头,依次为:

字符串→Base64解码→字节[]→解密→字节[]

另外,一个不好的做法,也是许多可移植性错误的根源,是默认设置的使用.您在两个地方使用默认值,它们都很麻烦.首先,您使用默认的无参数 String.getBytes() 方法,并可能将其与一个参数 Cipher.getInstance('RSA').Oracle的Java和Android的Java将为您提供不同的填充,因此您的代码将无法在平台之间移植.始终指定完整的填充字符串.如果您需要可移植到较早的Java实现中,那么在这里进行选择就困难得多.OAEP填充应该是您的首选,因此 Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); 可能是正确的选择.参见以进行进一步的讨论.>

有关如何加密较长的文本,请参见

Here is the RSA util 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 snippet that encrypts and decrypts 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 may be that the text to be decrypted is too long , but I just encrypt "abc" and then decrypt the encrypted "abc". And how to handle encrypting long text if the text to be encrypted or decrypted should be 11 bytes less than the rsa private key? How can I do to solve it? I'm new to RSA.

Thanks in advance!

解决方案

You are missing some steps in your code which makes it impossible to check. However, there are a few clues 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 which is not the encoding of any valid String. Perhaps you meant to base64 decode the input instead of calling getBytes(). In general to perform decryption and decoding you must reverse the steps you performed during encryption and encoding. So, if the plaintext is a byte[] then the steps are:

byte [] → Encrypt → byte [] → Base64 encode → String.

then, in the decrypt direction you start with a Base64 string, you must, in order:

String → Base64 decode → byte [] → decrypt → byte []

Also, another issue which is bad practice and a source of many portability bugs is the use of defaults. You are using defaults in two places and they're both troublesome. First you are using the default no-args String.getBytes() method, and presumably matching that up with the one-arg String (byte []) constructor. This use the platform default character set, but this can differ on different platforms. Therefore always specify a character set. For most applications 'UTF-8' is an ideal choice. Secondly, you are calling Cipher.getInstance('RSA') without specifying padding. Oracle's Java and Android's Java will give you different padding and thus your code will not be portable between the platforms. Always specify the complete padding string. Here the choice is little more difficult if you need portability to older Java implementations. OAEP padding should be your first choice, so Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); is probably the right choice. See this for further discussion.

As for how to encrypt longer texts, see the answer from Henry.

这篇关于java.lang.ArrayIndexOutOfBoundsException:RSA块的数据过多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆