IllegalBlockSizeException解密数据时“无效的输入长度”

时间:2020-05-20 06:32:53

标签: android encryption rsa

我正在开发一个android应用。

我想将一些敏感数据(jwt令牌)加密/解密为SharedPreference。

所以我写了下面的代码。

fun initKeyStore() {
    val alias = "${packageName}.rsakeypairs"
    val keyStore = KeyStore.getInstance("AndroidKeyStore").apply {
        load(null)
    }

    if (keyStore.containsAlias(alias)) {

    } else {
        SLog.d(LogTag.SECURE, "[cipher] No keypair for $alias, creating a new one")
        with(KeyPairGenerator.getInstance(KEY_ALGORITHM_RSA, "AndroidKeyStore"), {
            val spec = KeyGenParameterSpec.Builder(alias,
                    PURPOSE_ENCRYPT or PURPOSE_DECRYPT)
                    .setAlgorithmParameterSpec(RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4))
                    .setBlockModes(BLOCK_MODE_CBC)
                    .setEncryptionPaddings(ENCRYPTION_PADDING_RSA_PKCS1)
                    .setDigests(DIGEST_SHA512, DIGEST_SHA384, DIGEST_SHA256)
                    .setUserAuthenticationRequired(false)
                    .build()
            initialize(spec)
            generateKeyPair()
        })
    }

    keyEntry = keyStore.getEntry(alias, null)
}

fun String.encrypt(): String? {
    cipher.init(Cipher.ENCRYPT_MODE, (keyEntry as KeyStore.PrivateKeyEntry).certificate.publicKey)
    val bytes = this.toByteArray(Charsets.UTF_8)
    val encryptedBytes = cipher.doFinal(bytes)
    val base64EncryptedBytes = Base64.encode(encryptedBytes, Base64.DEFAULT)
    return String(base64EncryptedBytes)
}

fun String.decrypt(): String {
    cipher.init(Cipher.DECRYPT_MODE, (keyEntry as KeyStore.PrivateKeyEntry).privateKey)
    val base64EncryptedBytes = this.toByteArray(Charsets.UTF_8)
    val encryptedBytes = Base64.decode(base64EncryptedBytes, Base64.DEFAULT)
    val decryptedBytes = cipher.doFinal(encryptedBytes)
    return String(decryptedBytes)
}

但是当应用尝试解密加密的数据时,发生了异常。

    javax.crypto.IllegalBlockSizeException
        at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:513)
        at javax.crypto.Cipher.doFinal(Cipher.java:2055)
        ...
     Caused by: android.security.KeyStoreException: Invalid input length
        at android.security.KeyStore.getKeyStoreException(KeyStore.java:1539)
        at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.update(KeyStoreCryptoOperationChunkedStreamer.java:132)

我正在使用的JWT令牌的长度非常长。 (超过800个)

如果我尝试加密/解密短文本,则可以正常工作...

如何加密/解密长文本?

2 个答案:

答案 0 :(得分:0)

为了加密长文本,您可以增加密钥大小(这可能是个坏主意,因为生成此密钥会花费更多时间),或者将文本拆分为多个块,然后对这些块进行加密加一个,然后将它们另存为字符串数组。

答案 1 :(得分:0)

不对称加密的最大限制为245个字符。

它可以用长字符串的大块来固定

   object SecurePreferencesHelper {
    private const val chunkSize = 240

    private fun getNumberOfChunksKey(key: String) = "${key}_numberOfChunks"

    fun setLongStringValue(key: String, value: String) {
        val chunks = value.chunked(chunkSize)

        SecurePreferences.setValue(getNumberOfChunksKey(key), chunks.size)

        chunks.forEachIndexed { index, chunk ->
            SecurePreferences.setValue("$key$index", chunk)
        }
    }

    fun getLongStringValue(key: String): String? {
        val numberOfChunks = SecurePreferences.getIntValue(getNumberOfChunksKey(key), 0)

        if (numberOfChunks == 0) {
            return null
        }

        return (0 until numberOfChunks)
                .map { index ->
                    val string = SecurePreferences.getStringValue("$key$index", null) ?: run {
                        return null
                    }

                    string
                }.reduce { accumulator, chunk -> accumulator + chunk }
    }

    fun removeLongStringValue(key: String) {
        val numberOfChunks = SecurePreferences.getIntValue(getNumberOfChunksKey(key), 0)

        (0 until numberOfChunks).map { SecurePreferences.removeValue("$key$it") }
        SecurePreferences.removeValue(getNumberOfChunksKey(key))
    }

    fun containsLongStringValue(key: String): Boolean {
        return SecurePreferences.contains(getNumberOfChunksKey(key))
    }
}

有关参考,请参见链接

click here