Fixed
Status Update
Comments
jm...@google.com <jm...@google.com>
da...@google.com <da...@google.com>
ap...@google.com <ap...@google.com> #2
Project: platform/frameworks/support
Branch: androidx-master-dev
commit b90079595f33f58fece04026a97faa0d243acdb1
Author: Yuichi Araki <yaraki@google.com>
Date: Wed Sep 18 16:55:49 2019
Change the way to detect mismatch between POJO and query
This fixes cursor mismatch warnings with expandProjection.
Bug: 140759491
Test: QueryMethodProcessorTest
Change-Id: I7659002e5e0d1ef60fc1af2a625c0c36da0664d8
M room/compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
M room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
M room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
M room/compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
M room/compiler/src/test/kotlin/androidx/room/testing/TestProcessor.kt
https://android-review.googlesource.com/1123258
https://goto.google.com/android-sha1/b90079595f33f58fece04026a97faa0d243acdb1
Branch: androidx-master-dev
commit b90079595f33f58fece04026a97faa0d243acdb1
Author: Yuichi Araki <yaraki@google.com>
Date: Wed Sep 18 16:55:49 2019
Change the way to detect mismatch between POJO and query
This fixes cursor mismatch warnings with expandProjection.
Bug: 140759491
Test: QueryMethodProcessorTest
Change-Id: I7659002e5e0d1ef60fc1af2a625c0c36da0664d8
M room/compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
M room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
M room/compiler/src/main/kotlin/androidx/room/solver/query/result/PojoRowAdapter.kt
M room/compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
M room/compiler/src/test/kotlin/androidx/room/testing/TestProcessor.kt
Description
Once a keyset is persisted, further encryption over multiple threads works as expected.
For our app, this means that any encryption performed directly after a fresh install is potentially unable to be decrypted. Subsequent app runs don't show this behaviour.
Perhaps I am using the API incorrectly (it isn't supposed to be thread safe in the manner shown in the example code given), if this is the case then there is at the least a bug/omission in the API documentation.
This is a minimal reproduction example (androidx.security:security-crypto:1.0.0-alpha02):
// Code starts
import android.os.AsyncTask
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.security.crypto.EncryptedFile
import androidx.security.crypto.MasterKeys
import java.io.File
import java.util.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val directory = getDir(Date().time.toString(), MODE_PRIVATE)
val files = (0..9).map { index -> File(directory, index.toString()) }
exerciseBug(files)
}
private fun exerciseBug(files: Iterable<File>) {
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
val context = this
class FileEncryptor(private val file: File) : AsyncTask<Unit, Unit, Unit>() {
override fun doInBackground(vararg params: Unit?) {
val encryptedFile = EncryptedFile.Builder(
file,
context,
masterKeyAlias,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()
encryptedFile.openFileOutput().use { outputStream ->
val buffer = ByteArray(16384)
outputStream.write(buffer, 0, buffer.size)
outputStream.flush()
}
}
}
// Encrypt all the files in parallel
val fileEncryptors = files.map { file -> FileEncryptor(file) }
fileEncryptors.forEach { fileEncryptor -> fileEncryptor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) }
// Wait for them all to finish
fileEncryptors.forEach { fileEncryptor -> fileEncryptor.get() }
// Decrypt each file serially
files.forEachIndexed { index, file ->
val encryptedFile = EncryptedFile.Builder(
file,
context,
masterKeyAlias,
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
).build()
try {
encryptedFile.openFileInput().use { inputStream ->
val buffer = ByteArray(16384)
inputStream.read(buffer) // BOOM!
}
} catch (e: Exception) {
Log.e("securitycryptoracebug", "failed to decrypt file #$index", e)
}
}
}
}
// Code ends
The above code produces exceptions similar to:
java.io.IOException: No matching key found for the ciphertext in the stream.
at com.google.crypto.tink.streamingaead.InputStreamDecrypter.read(InputStreamDecrypter.java:187)
at com.google.crypto.tink.streamingaead.InputStreamDecrypter.read(InputStreamDecrypter.java:130)
at androidx.security.crypto.EncryptedFile$EncryptedFileInputStream.read(EncryptedFile.java:296)
at com.markbuer.androidxsecuritycryptoracebug.MainActivity.exerciseBug(MainActivity.kt:59)