Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Verified Commit 369c3d75 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

EN: Allow exporting key of current day

This requires rotating the daily TEK when exporting
parent 0e0ac35e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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." />

            <LinearLayout
                android:id="@+id/grant_permission_view"
+12 −11
Original line number Diff line number Diff line
@@ -34,11 +34,14 @@ private const val AES_BLOCK_SIZE = 16

private const val AEM_ALGORITHM = "AES/CTR/NoPadding"

val currentIntervalNumber: Long
    get() = floor(System.currentTimeMillis() / 1000.0 / ROLLING_WINDOW_LENGTH).toLong()
val currentIntervalNumber: Int
    get() = floor(System.currentTimeMillis() / 1000.0 / ROLLING_WINDOW_LENGTH).toInt()

val currentRollingStartNumber: Long
    get() = floor(currentIntervalNumber.toDouble() / ROLLING_PERIOD).toLong() * ROLLING_PERIOD
val currentDayRollingStartNumber: Int
    get() = getDayRollingStartNumber(currentIntervalNumber)

fun getDayRollingStartNumber(intervalNumber: Int) = (floor(currentIntervalNumber.toDouble() / ROLLING_PERIOD).toLong() * ROLLING_PERIOD).toInt()
fun getPeriodInDay(intervalNumber: Int) = intervalNumber - getDayRollingStartNumber(intervalNumber)

val nextKeyMillis: Long
    get() {
@@ -47,18 +50,16 @@ val nextKeyMillis: Long
        return (currentWindowEnd - System.currentTimeMillis()).coerceAtLeast(0)
    }

fun TemporaryExposureKey.TemporaryExposureKeyBuilder.setCurrentRollingStartNumber(): TemporaryExposureKey.TemporaryExposureKeyBuilder =
        setRollingStartIntervalNumber(currentRollingStartNumber.toInt())

fun TemporaryExposureKey.TemporaryExposureKeyBuilder.generate(): TemporaryExposureKey.TemporaryExposureKeyBuilder {
fun generateTemporaryExposureKey(intervalNumber: Int): TemporaryExposureKey.TemporaryExposureKeyBuilder = TemporaryExposureKey.TemporaryExposureKeyBuilder().apply {
    var keyData = ByteArray(16)
    SecureRandom().nextBytes(keyData)
    setKeyData(keyData)
    setRollingPeriod(ROLLING_PERIOD)
    return this
    setRollingStartIntervalNumber(intervalNumber)
    setRollingPeriod((ROLLING_PERIOD - getPeriodInDay(intervalNumber)))
}

fun generateCurrentTemporaryExposureKey(): TemporaryExposureKey = TemporaryExposureKey.TemporaryExposureKeyBuilder().generate().setCurrentRollingStartNumber().build()
fun generateCurrentDayTemporaryExposureKey(): TemporaryExposureKey = generateTemporaryExposureKey(currentDayRollingStartNumber).build()
fun generateIntraDayTemporaryExposureKey(intervalNumber: Int = currentIntervalNumber): TemporaryExposureKey = generateTemporaryExposureKey(intervalNumber).build()

@TargetApi(21)
fun TemporaryExposureKey.generateRpiKey(): SecretKeySpec {
+33 −20
Original line number Diff line number Diff line
@@ -15,14 +15,11 @@ import android.database.sqlite.SQLiteOpenHelper
import android.os.Parcel
import android.os.Parcelable
import android.util.Log
import com.google.android.gms.nearby.exposurenotification.CalibrationConfidence
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey
import kotlinx.coroutines.*
import okio.ByteString
import org.json.JSONObject
import org.microg.gms.nearby.exposurenotification.Constants.TOKEN_A
import java.io.File
import java.lang.Runnable
import java.nio.ByteBuffer
@@ -111,7 +108,7 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit

    fun dailyCleanup(): Boolean = writableDatabase.run {
        val start = System.currentTimeMillis()
        val rollingStartTime = currentRollingStartNumber * ROLLING_WINDOW_LENGTH * 1000 - TimeUnit.DAYS.toMillis(KEEP_DAYS.toLong())
        val rollingStartTime = currentDayRollingStartNumber * ROLLING_WINDOW_LENGTH * 1000 - TimeUnit.DAYS.toMillis(KEEP_DAYS.toLong())
        val advertisements = delete(TABLE_ADVERTISEMENTS, "timestamp < ?", longArrayOf(rollingStartTime))
        Log.d(TAG, "Deleted on daily cleanup: $advertisements adv")
        if (start + MAX_DELETE_TIME < System.currentTimeMillis()) return@run false
@@ -533,8 +530,9 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
        }
    }

    private fun findOwnKeyAt(rollingStartNumber: Int, database: SQLiteDatabase = readableDatabase): TemporaryExposureKey? = database.run {
        query(TABLE_TEK, arrayOf("keyData", "rollingStartNumber", "rollingPeriod"), "rollingStartNumber = ?", arrayOf(rollingStartNumber.toString()), null, null, null).use { cursor ->
    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,9 +600,21 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
        }
    }

    val allKeys: List<TemporaryExposureKey> = 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 ->
    fun exportKeys(database: SQLiteDatabase = writableDatabase): List<TemporaryExposureKey> = 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)
            }
            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<TemporaryExposureKey>()
                while (cursor.moveToNext()) {
                    list.add(TemporaryExposureKey.TemporaryExposureKeyBuilder()
@@ -615,6 +625,9 @@ class ExposureDatabase private constructor(private val context: Context) : SQLit
                }
                list
            }
        } finally {
            database.endTransaction()
        }
    }

    val rpiHistogram: Map<Long, Long>
@@ -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)
        }
+1 −1
Original line number Diff line number Diff line
@@ -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()
            }