我正在开发一个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个)
如果我尝试加密/解密短文本,则可以正常工作...
如何加密/解密长文本?
答案 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))
}
}
有关参考,请参见链接