Android java.lang.ArrayIndexOutOfBoundsException:RSA块的数据太多
我正在使用RSA加密文本和解密文本。公钥和私钥是使用openssl工具生成的。 我在解密数据时遇到了“java.lang.ArrayIndexOutOfBoundsException:RSA块的数据太多”异常 以下是RSA util类:Android java.lang.ArrayIndexOutOfBoundsException:RSA块的数据太多,android,rsa,Android,Rsa,我正在使用RSA加密文本和解密文本。公钥和私钥是使用openssl工具生成的。 我在解密数据时遇到了“java.lang.ArrayIndexOutOfBoundsException:RSA块的数据太多”异常 以下是RSA util类: package studio.uphie.app; import android.util.Base64; import java.security.KeyFactory; import java.security.NoSuchAlgorithmExcept
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的新手
提前谢谢 通常,您会为对称密码(如AES)生成一个随机密钥,并使用它来加密您的付费负载 然后,RSA仅用于加密此随机密钥。这不仅解决了长度问题,还具有其他一些优点:
- 对称密码通常要快得多
- 如果消息发送给多个接收者,只需为每个接收者专门添加加密密钥,则主要内容可以相同
- 您的代码中缺少一些步骤,因此无法进行检查。然而,有一些线索表明存在问题。您的
decryptData
方法接受一个字符串参数,然后调用String.getBytes()
获取数据,然后对数据进行解密。但是,加密的结果是一个字节序列,它不是任何有效字符串的编码。也许您想对输入进行base64解码,而不是调用getBytes()
。一般来说,要执行解密和解码,必须反转加密和编码期间执行的步骤。因此,如果明文是字节[],则步骤如下:
字节[]→ 加密→ 字节[]→ Base64编码→ 绳子
然后,在以Base64字符串开始的解密方向上,必须按照以下顺序:
串→ Base64解码→ 字节[]→ 解密→ 字节[]
另外,另一个问题是默认值的使用,这是一个糟糕的做法,也是许多可移植性错误的根源。您在两个地方使用默认值,它们都很麻烦。首先,您使用的是默认的no-args方法,可能与one-arg构造函数相匹配。这将使用平台默认字符集,但在不同平台上可能会有所不同。因此,请始终指定一个字符集。对于大多数应用,“UTF-8”是理想的选择。其次,您正在调用Cipher.getInstance('RSA')
,而不指定填充。Oracle的Java和Android的Java将为您提供不同的填充,因此您的代码将无法在平台之间移植。始终指定完整的填充字符串。在这里,如果您需要可移植到较旧的Java实现,那么选择就不那么困难了。OAEP填充应该是您的首选,因此Cipher.getInstance(“RSA/ECB/OAEPWithSHA-256和mgf1padding”)代码>可能是正确的选择。有关进一步讨论,请参阅
至于如何加密较长的文本,请参见。最后,我这样修改了我的代码,它们工作得很好:
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;
}
}
如果有什么不对劲,你还是可以提醒我。谢谢詹姆斯和亨利的回答。是的,是的。RSA不能加密长文本,而长文本是一种密码,通常与系统计量密码(AES或DES)一起使用,以加密系统计量密码的secrect密钥。系统计量密码加密任何文本。谢谢谢谢你的帮助!也许我从这个问题中得到了很多。Openssl生成不可读的字节序列:公钥和私钥,并将它们转换为可读的base64编码文本。加密或解密时,密码需要文本和密钥的字节码。我接受了你的建议,修改了我的rsa-util类,它工作得很好。我正在为Python服务器开发Java客户端,确切的格式化示例帮助了我很多!我花了大约2小时才找到这个,请为其他像我一样的人投票:]