java.io.IOException:在解密子字符串时最终确定密码时出错

时间:2016-12-15 23:54:36

标签: encryption android-keystore

我遇到了一个我不确定正确修复的问题。我用这个帖子作为参考:

java.lang.IllegalArgumentException: bad base-64 when decrypting string

基本上我将一个字符串拆分成块并加密每个块。但是,当它以相同的方式解密时,它永远不会起作用。它总是给我这个恼人的例外:

" java.io.IOException:最终确定密码错误"

基本上我将字符串拆分如下:

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));
}

1 个答案:

答案 0 :(得分:1)

RSA 不适合批量加密,因为它非常慢(与 AES 相比,超过1000倍)。而是使用对称加密算法,如 AES ,如果可以的话。如果您需要 RSA 的两个密钥,请使用Hybrid加密,使用随机对称密钥对数据进行加密,然后使用 RSA <加密该密钥/ strong> key。

对称加密的另一个好处是,库自动支持批量加密,您无需在加密前将数据切换成小块。