From 369c3d7557f54339c6fe8fba924e4c87f851fa03 Mon Sep 17 00:00:00 2001 From: Marvin W Date: Fri, 11 Dec 2020 11:51:53 +0100 Subject: [PATCH] EN: Allow exporting key of current day This requires rotating the daily TEK when exporting --- ...xposure_notifications_confirm_activity.xml | 2 +- .../gms/nearby/exposurenotification/Crypto.kt | 23 ++++---- .../exposurenotification/ExposureDatabase.kt | 53 ++++++++++++------- .../ExposureNotificationServiceImpl.kt | 2 +- 4 files changed, 47 insertions(+), 33 deletions(-) diff --git a/play-services-nearby-core-ui/src/main/res/layout/exposure_notifications_confirm_activity.xml b/play-services-nearby-core-ui/src/main/res/layout/exposure_notifications_confirm_activity.xml index cdad35f2..0056fb70 100644 --- a/play-services-nearby-core-ui/src/main/res/layout/exposure_notifications_confirm_activity.xml +++ b/play-services-nearby-core-ui/src/main/res/layout/exposure_notifications_confirm_activity.xml @@ -39,7 +39,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" - tools:text="Your phonre needs to use Bluetooth to securely collect and share IDs with other phones that are nearby.\n\nCorona Warn can notify you if you were exposed to someone who reported to be diagnosed positive.\n\nThe date, duration, and signal strength associated with an exposure will be shared with the app." /> + tools:text="Your phone needs to use Bluetooth to securely collect and share IDs with other phones that are nearby.\n\nCorona Warn can notify you if you were exposed to someone who reported to be diagnosed positive.\n\nThe date, duration, and signal strength associated with an exposure will be shared with the app." /> + private fun findOwnKeyAt(intervalNumber: Int, database: SQLiteDatabase = readableDatabase): TemporaryExposureKey? = database.run { + val dayRollingStartNumber = getDayRollingStartNumber(intervalNumber) + query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber >= ? AND (rollingStartNumber + rollingPeriod) < ?", arrayOf(dayRollingStartNumber.toString(), intervalNumber.toString()), null, null, "rollingStartNumber DESC").use { cursor -> if (cursor.moveToNext()) { TemporaryExposureKey.TemporaryExposureKeyBuilder() .setKeyData(cursor.getBlob(0)) @@ -602,18 +600,33 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit } } - val allKeys: List = readableDatabase.run { - val startRollingNumber = (currentRollingStartNumber - 14 * ROLLING_PERIOD) - query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber >= ? AND rollingStartNumber < ?", arrayOf(startRollingNumber.toString(), currentIntervalNumber.toString()), null, null, null).use { cursor -> - val list = arrayListOf() - while (cursor.moveToNext()) { - list.add(TemporaryExposureKey.TemporaryExposureKeyBuilder() - .setKeyData(cursor.getBlob(0)) - .setRollingStartIntervalNumber(cursor.getLong(1).toInt()) - .setRollingPeriod(cursor.getLong(2).toInt()) - .build()) + fun exportKeys(database: SQLiteDatabase = writableDatabase): List = database.run { + database.beginTransactionNonExclusive() + try { + val intervalNumber = currentIntervalNumber + val key = findOwnKeyAt(intervalNumber, database) + if (key != null && intervalNumber != key.rollingStartIntervalNumber) { + // Rotate key + update(TABLE_TEK, ContentValues().apply { + put("rollingPeriod", intervalNumber - key.rollingStartIntervalNumber) + }, "rollingStartNumber = ?", arrayOf(key.rollingStartIntervalNumber.toString())) + storeOwnKey(generateIntraDayTemporaryExposureKey(intervalNumber), database) } - list + database.setTransactionSuccessful() + val startRollingNumber = (getDayRollingStartNumber(intervalNumber) - 14 * ROLLING_PERIOD) + query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber >= ? AND (rollingStartNumber + rollingPeriod) <= ?", arrayOf(startRollingNumber.toString(), intervalNumber.toString()), null, null, null).use { cursor -> + val list = arrayListOf() + while (cursor.moveToNext()) { + list.add(TemporaryExposureKey.TemporaryExposureKeyBuilder() + .setKeyData(cursor.getBlob(0)) + .setRollingStartIntervalNumber(cursor.getLong(1).toInt()) + .setRollingPeriod(cursor.getLong(2).toInt()) + .build()) + } + list + } + } finally { + database.endTransaction() } } @@ -733,9 +746,9 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit private fun ensureTemporaryExposureKey(): TemporaryExposureKey = writableDatabase.let { database -> database.beginTransactionNonExclusive() try { - var key = findOwnKeyAt(currentRollingStartNumber.toInt(), database) + var key = findOwnKeyAt(currentIntervalNumber.toInt(), database) if (key == null) { - key = generateCurrentTemporaryExposureKey() + key = generateCurrentDayTemporaryExposureKey() storeOwnKey(key, database) } database.setTransactionSuccessful() @@ -747,7 +760,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit val currentRpiId: UUID? get() { - val key = findOwnKeyAt(currentRollingStartNumber.toInt()) ?: return null + val key = findOwnKeyAt(currentIntervalNumber.toInt()) ?: return null val buffer = ByteBuffer.wrap(key.generateRpiId(currentIntervalNumber.toInt())) return UUID(buffer.long, buffer.long) } diff --git a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt index e91e6ea2..40a58b67 100644 --- a/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt +++ b/play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt @@ -146,7 +146,7 @@ class ExposureNotificationServiceImpl(private val context: Context, private val val status = confirmPermission(CONFIRM_ACTION_KEYS) val response = when { status.isSuccess -> ExposureDatabase.with(context) { database -> - database.allKeys + database.exportKeys() } else -> emptyList() }