我正在使用RSA加密文本和解密文本。公钥和私钥是使用openssl工具生成的。
解密数据时遇到“ java.lang.ArrayIndexOutOfBoundsException:RSA块数据过多”异常。
这是RSA util类:
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);
}
}
以及加密和解密数据的代码段:
//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);
我知道原因可能是要解密的文本太长,但我只加密了“ abc”,然后解密了加密的“ abc”。如果要加密或解密的文本应比rsa私钥小11个字节,那么如何处理加密长文本?我该怎么解决?我是RSA的新手。
提前致谢!
最佳答案
您缺少代码中的某些步骤,因此无法检查。但是,有一些线索可以提示问题。您的decryptData
方法采用String参数,然后调用String.getBytes()
获取数据,然后将其解密。但是,加密的结果是字节序列,而不是任何有效String的编码。也许您打算对base64解码输入而不是调用getBytes()
。通常,要执行解密和解码,必须逆转在加密和编码过程中执行的步骤。因此,如果明文是byte [],则步骤为:
字节[]→加密→字节[]→Base64编码→字符串。
然后,在解密方向上,您必须从Base64字符串开始,顺序如下:
字符串→Base64解码→字节[]→解密→字节[]
同样,另一个不好的做法,也是许多可移植性错误的根源是使用默认值。您在两个地方使用默认值,它们都很麻烦。首先,您使用默认的no-args String.getBytes()
方法,并且大概将其与one-arg String (byte [])
构造函数进行匹配。这使用平台默认字符集,但是在不同平台上可能有所不同。因此,请始终指定一个字符集。对于大多数应用,“ UTF-8”是理想选择。其次,您在不指定填充的情况下调用Cipher.getInstance('RSA')
。 Oracle的Java和Android的Java将为您提供不同的填充,因此您的代码将无法在平台之间移植。始终指定完整的填充字符串。如果您需要可移植到较早的Java实现中,那么在这里进行选择就困难得多。 OAEP填充应该是您的首选,因此Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
可能是正确的选择。参见this进行进一步的讨论。
有关如何加密较长的文本,请参见answer from Henry。
关于android - java.lang.ArrayIndexOutOfBoundsException:RSA块的数据过多,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36544306/