GVi*_*i82 3 java encryption android cryptography kotlin
我正在使用增量加密,并结合 Android KeyStore 提供程序。
val cipher = Cipher.getInstance(TRANSFORMATION)
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey())
val chunks = textToEncrypt.chunked(CHUNK_SIZE)
val encryptedChunks: MutableList<ByteArray?> = mutableListOf()
chunks.forEachIndexed { index, chunk ->
if (index == chunks.size - 1) {
encryptedChunks.add(cipher.doFinal(chunk.toByteArray(StandardCharsets.UTF_8)))
} else {
encryptedChunks.add(cipher.update(chunk.toByteArray(StandardCharsets.UTF_8)))
}
}
val result = encryptedChunks.filterNotNull().reduce { acc, item -> acc.plus(item) }
Run Code Online (Sandbox Code Playgroud)
这些是我正在使用的常量:
const val TRANSFORMATION = "AES/GCM/NoPadding"
const val CHUNK_SIZE = 32768 // 32KiB
Run Code Online (Sandbox Code Playgroud)
现在,这段代码已经在 30 多种不同的设备上进行了严格测试,除了一部手机(配备 Android 7.0 的 Xperia XA)之外,从未出现过任何问题。对于这款手机,如果输入 ( textToEncrypt) 足够小,可以将所有内容加密在单个块中,那么就可以了,但如果输入较大(通常在 100KiB 左右),则需要更多块,那么它将无法对数据进行加密。这就是我得到的:
Caused by javax.crypto.IllegalBlockSizeException
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:491)
at javax.crypto.Cipher.doFinal(Cipher.java:2056)
Caused by android.security.KeyStoreException: Memory allocation failed
at android.security.KeyStore.getKeyStoreException(KeyStore.java:685)
at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.update(KeyStoreCryptoOperationChunkedStreamer.java:132)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineUpdate(AndroidKeyStoreCipherSpiBase.java:338)
at javax.crypto.Cipher.update(Cipher.java:1683)
Run Code Online (Sandbox Code Playgroud)
注意:仅对于此设备,cipher.update()返回 null ENCRYPT_MODE,这就是为什么在我的代码中我允许返回 null,然后丢弃它们以形成加密数据。这意味着cipher.doFinal应该一次性返回整个加密数据。
编辑:所以显然仅对于这款手机来说,块大小不太好:它不能是 32Kb,但 8Kb 工作正常
扩展奥利维尔的答案。他确定异常是由 引发的mMainDataStreamer.update()。如果您查看AndroidKeyStoreCipherSpiBase类,您将看到它是KeyStoreCryptoOperationChunkedStreamermMainDataStreamer类的实例。这是一个有趣的部分:
// Binder buffer is about 1MB, but it's shared between all active transactions of the process.
// Thus, it's safer to use a much smaller upper bound.
private static final int DEFAULT_MAX_CHUNK_SIZE = 64 * 1024;
Run Code Online (Sandbox Code Playgroud)
在我们的例子中,使用默认的最大块大小。DEFAULT_MAX_CHUNK_SIZE对块大小设置上限。如果您将更大的块传递给该cipher.update()方法,它们将被切成DEFAULT_MAX_CHUNK_SIZE. 正如您所看到的,即使是 Android 开发人员也没有新的精确的安全块大小,并且不得不自己猜测(在您的情况下不成功)。
但是,请注意,Binder缓冲区用于将这些块传递到加密过程并从中返回结果。而且它的大小只有1MB左右。
也许这个特定设备上有一个异常小的 Binder 缓冲区?您可以尝试使用该答案来研究它:/sf/answers/1796624511/
在未来的设备上,您可以使用:
IBinder.getSuggestedMaxIpcSizeBytes()
Run Code Online (Sandbox Code Playgroud)
https://developer.android.com/reference/android/os/IBinder#getSuggestedMaxIpcSizeBytes()
| 归档时间: |
|
| 查看次数: |
842 次 |
| 最近记录: |