java.io.IOException: 解密子字符串时最终确定密码时出错
java.io.IOException: Error while finalizing cipher while decrypting sub-strings
我 运行 遇到了一个问题,我不确定正确的解决方法。我用这个线程作为参考:
基本上我将一个字符串分成块并加密每个块。但是当需要以同样的方式解密时,它永远不会起作用。它总是给我这个烦人的异常:
"java.io.IOException: Error while finalizing cipher"
基本上我将字符串拆分如下:
static public class RSAString {
private ArrayList<String> mChunkList = new ArrayList<String>();
RSAString() {
mChunkList.clear();
}
public ArrayList<String> getChunkList() {
return mChunkList;
}
RSAString(String stringSrc) {
if (stringSrc.length() < CHUNK_SIZE) {
mChunkList.add(stringSrc);
} else {
int j = 0;
for (int i = 0; i < stringSrc.length() / CHUNK_SIZE; i++) {
String subString = stringSrc.substring(j, j + CHUNK_SIZE);
mChunkList.add(subString);
j += CHUNK_SIZE;
}
int leftOver = stringSrc.length() % CHUNK_SIZE;
if (leftOver > 0) {
String subString = stringSrc.substring(j, j + leftOver);
mChunkList.add(subString);
}
}
}
}
然后我用这个密码解密:
// This **DOES NOT** work
final String AndroidOpenSSLString = "AndroidOpenSSL";
final String AndroidKeyStoreBCWorkaroundString = "AndroidKeyStoreBCWorkaround";
mProvider = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? AndroidOpenSSLString : AndroidKeyStoreBCWorkaroundString;
Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", mProvider);
outCipher.init(Cipher.DECRYPT_MODE, mPrivateKey);
for (String chunkEncrypted : rsaEcryptedText.getChunkList()) {
byte[] cipherText = chunkEncrypted.getBytes("UTF-8");
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, Base64.NO_WRAP)), outCipher);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte) nextByte);
}
byte[] bytes = new byte[values.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i);
}
decryptedString += new String(bytes, 0, bytes.length, "UTF-8");
cipherInputStream.close();
cipherInputStream.reset();
}
我发现的唯一解决方法是在每个新的子字符串中重新初始化密码。喜欢下面的技巧:
for (String chunkEncrypted : rsaEcryptedText.getChunkList()) {
// This works, but I am re-initializing the out cypher every time!
// super slow!!! WHY DO I HAVE TO DO THIS?
Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", mProvider);
outCipher.init(Cipher.DECRYPT_MODE, mPrivateKey);
byte[] cipherText = chunkEncrypted.getBytes("UTF-8");
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, Base64.NO_WRAP)), outCipher);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte) nextByte);
}
byte[] bytes = new byte[values.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i);
}
decryptedString += new String(bytes, 0, bytes.length, "UTF-8");
cipherInputStream.close();
cipherInputStream.reset();
}
我的修复程序的问题是它使解密速度变慢。此外,即使我的子字符串尺寸较小(子字符串 int CHUNK_SIZE = 64),我仍然遇到相同的异常。
无论如何,我不知道是否有人能指出我用 RSA 加密解密长字符串的正确方法。
这是加密代码——不确定它在这种情况下是否重要——但它总是有效的:
Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", mProvider);
inCipher.init(Cipher.ENCRYPT_MODE, mPublicKey);
RSAString rsaStringPlainText = new RSAString(plainText);
for (String chunkPlain : rsaStringPlainText.getChunkList()) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
outputStream, inCipher);
cipherOutputStream.write(chunkPlain.getBytes("UTF-8"));
cipherOutputStream.flush();
cipherOutputStream.close();
byte[] ecryptedText = Base64.encode(outputStream.toByteArray(), Base64.NO_WRAP);
encryptedStringOut.mChunkList.add(new String(ecryptedText));
}
RSA 不适合批量加密,因为它非常慢(与 AES 相比超过 1000 倍)。如果可以,请改用 AES 等对称加密算法。如果您需要 RSA 的两个密钥,请使用 Hybrid 加密,其中您使用随机对称密钥加密数据,然后使用 RSA 加密该密钥键。
对称加密的另一个好处是库自动支持批量加密,您无需在加密前将数据分成小块。
我 运行 遇到了一个问题,我不确定正确的解决方法。我用这个线程作为参考:
基本上我将一个字符串分成块并加密每个块。但是当需要以同样的方式解密时,它永远不会起作用。它总是给我这个烦人的异常:
"java.io.IOException: Error while finalizing cipher"
基本上我将字符串拆分如下:
static public class RSAString {
private ArrayList<String> mChunkList = new ArrayList<String>();
RSAString() {
mChunkList.clear();
}
public ArrayList<String> getChunkList() {
return mChunkList;
}
RSAString(String stringSrc) {
if (stringSrc.length() < CHUNK_SIZE) {
mChunkList.add(stringSrc);
} else {
int j = 0;
for (int i = 0; i < stringSrc.length() / CHUNK_SIZE; i++) {
String subString = stringSrc.substring(j, j + CHUNK_SIZE);
mChunkList.add(subString);
j += CHUNK_SIZE;
}
int leftOver = stringSrc.length() % CHUNK_SIZE;
if (leftOver > 0) {
String subString = stringSrc.substring(j, j + leftOver);
mChunkList.add(subString);
}
}
}
}
然后我用这个密码解密:
// This **DOES NOT** work
final String AndroidOpenSSLString = "AndroidOpenSSL";
final String AndroidKeyStoreBCWorkaroundString = "AndroidKeyStoreBCWorkaround";
mProvider = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? AndroidOpenSSLString : AndroidKeyStoreBCWorkaroundString;
Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", mProvider);
outCipher.init(Cipher.DECRYPT_MODE, mPrivateKey);
for (String chunkEncrypted : rsaEcryptedText.getChunkList()) {
byte[] cipherText = chunkEncrypted.getBytes("UTF-8");
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, Base64.NO_WRAP)), outCipher);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte) nextByte);
}
byte[] bytes = new byte[values.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i);
}
decryptedString += new String(bytes, 0, bytes.length, "UTF-8");
cipherInputStream.close();
cipherInputStream.reset();
}
我发现的唯一解决方法是在每个新的子字符串中重新初始化密码。喜欢下面的技巧:
for (String chunkEncrypted : rsaEcryptedText.getChunkList()) {
// This works, but I am re-initializing the out cypher every time!
// super slow!!! WHY DO I HAVE TO DO THIS?
Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", mProvider);
outCipher.init(Cipher.DECRYPT_MODE, mPrivateKey);
byte[] cipherText = chunkEncrypted.getBytes("UTF-8");
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, Base64.NO_WRAP)), outCipher);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte) nextByte);
}
byte[] bytes = new byte[values.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i);
}
decryptedString += new String(bytes, 0, bytes.length, "UTF-8");
cipherInputStream.close();
cipherInputStream.reset();
}
我的修复程序的问题是它使解密速度变慢。此外,即使我的子字符串尺寸较小(子字符串 int CHUNK_SIZE = 64),我仍然遇到相同的异常。
无论如何,我不知道是否有人能指出我用 RSA 加密解密长字符串的正确方法。
这是加密代码——不确定它在这种情况下是否重要——但它总是有效的:
Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", mProvider);
inCipher.init(Cipher.ENCRYPT_MODE, mPublicKey);
RSAString rsaStringPlainText = new RSAString(plainText);
for (String chunkPlain : rsaStringPlainText.getChunkList()) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
outputStream, inCipher);
cipherOutputStream.write(chunkPlain.getBytes("UTF-8"));
cipherOutputStream.flush();
cipherOutputStream.close();
byte[] ecryptedText = Base64.encode(outputStream.toByteArray(), Base64.NO_WRAP);
encryptedStringOut.mChunkList.add(new String(ecryptedText));
}
RSA 不适合批量加密,因为它非常慢(与 AES 相比超过 1000 倍)。如果可以,请改用 AES 等对称加密算法。如果您需要 RSA 的两个密钥,请使用 Hybrid 加密,其中您使用随机对称密钥加密数据,然后使用 RSA 加密该密钥键。
对称加密的另一个好处是库自动支持批量加密,您无需在加密前将数据分成小块。