Check version of backup files against expected version from metadata

and throw security exception if it does not match
diff --git a/app/src/main/java/com/stevesoltys/seedvault/header/HeaderReader.kt b/app/src/main/java/com/stevesoltys/seedvault/header/HeaderReader.kt
index 9c023d5..192aa82 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/header/HeaderReader.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/header/HeaderReader.kt
@@ -5,10 +5,11 @@
 import java.io.IOException
 import java.io.InputStream
 import java.nio.ByteBuffer
+import java.security.GeneralSecurityException
 
 internal interface HeaderReader {
     @Throws(IOException::class, UnsupportedVersionException::class)
-    fun readVersion(inputStream: InputStream): Byte
+    fun readVersion(inputStream: InputStream, expectedVersion: Byte): Byte
 
     @Deprecated("")
     @Throws(SecurityException::class)
@@ -21,11 +22,14 @@
 
 internal class HeaderReaderImpl : HeaderReader {
 
-    @Throws(IOException::class, UnsupportedVersionException::class)
-    override fun readVersion(inputStream: InputStream): Byte {
+    @Throws(IOException::class, UnsupportedVersionException::class, GeneralSecurityException::class)
+    override fun readVersion(inputStream: InputStream, expectedVersion: Byte): Byte {
         val version = inputStream.read().toByte()
         if (version < 0) throw IOException()
         if (version > VERSION) throw UnsupportedVersionException(version)
+        if (expectedVersion != version) throw GeneralSecurityException(
+            "Expected version ${expectedVersion.toInt()}, but got ${version.toInt()}"
+        )
         return version
     }
 
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt
index 4cf3bb2..6769036 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt
@@ -20,10 +20,10 @@
 import java.security.GeneralSecurityException
 
 private class FullRestoreState(
+    val version: Byte,
     val token: Long,
     val packageInfo: PackageInfo
 ) {
-    var version: Byte? = null
     var inputStream: InputStream? = null
 }
 
@@ -55,8 +55,8 @@
      * It is possible that the system decides to not restore the package.
      * Then a new state will be initialized right away without calling other methods.
      */
-    fun initializeState(token: Long, packageInfo: PackageInfo) {
-        state = FullRestoreState(token, packageInfo)
+    fun initializeState(version: Byte, token: Long, packageInfo: PackageInfo) {
+        state = FullRestoreState(version, token, packageInfo)
     }
 
     /**
@@ -94,8 +94,7 @@
             Log.i(TAG, "First Chunk, initializing package input stream.")
             try {
                 val inputStream = plugin.getInputStreamForPackage(state.token, state.packageInfo)
-                val version = headerReader.readVersion(inputStream)
-                state.version = version
+                val version = headerReader.readVersion(inputStream, state.version)
                 if (version == 0.toByte()) {
                     crypto.decryptHeader(inputStream, version, packageName)
                     state.inputStream = inputStream
@@ -132,9 +131,8 @@
     private fun copyInputStream(outputStream: OutputStream): Int {
         val state = this.state ?: throw IllegalStateException("no state")
         val inputStream = state.inputStream ?: throw IllegalStateException("no stream")
-        val version = state.version ?: throw IllegalStateException("no version")
 
-        if (version == 0.toByte()) {
+        if (state.version == 0.toByte()) {
             // read segment from input stream and decrypt it
             val decrypted = try {
                 crypto.decryptSegment(inputStream)
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt
index 9ec0f30..5ee74ed 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt
@@ -17,10 +17,12 @@
 import com.stevesoltys.seedvault.header.getADForKV
 import libcore.io.IoUtils.closeQuietly
 import java.io.IOException
+import java.security.GeneralSecurityException
 import java.util.ArrayList
 import javax.crypto.AEADBadTagException
 
 private class KVRestoreState(
+    val version: Byte,
     val token: Long,
     val packageInfo: PackageInfo,
     /**
@@ -57,8 +59,13 @@
      *
      * @param pmPackageInfo single optional [PackageInfo] to optimize restore of @pm@
      */
-    fun initializeState(token: Long, packageInfo: PackageInfo, pmPackageInfo: PackageInfo? = null) {
-        state = KVRestoreState(token, packageInfo, pmPackageInfo)
+    fun initializeState(
+        version: Byte,
+        token: Long,
+        packageInfo: PackageInfo,
+        pmPackageInfo: PackageInfo? = null
+    ) {
+        state = KVRestoreState(version, token, packageInfo, pmPackageInfo)
     }
 
     /**
@@ -98,6 +105,9 @@
         } catch (e: SecurityException) {
             Log.e(TAG, "Security exception while reading backup records", e)
             TRANSPORT_ERROR
+        } catch (e: GeneralSecurityException) {
+            Log.e(TAG, "General security exception while reading backup records", e)
+            TRANSPORT_ERROR
         } catch (e: UnsupportedVersionException) {
             Log.e(TAG, "Unsupported version in backup: ${e.version}", e)
             TRANSPORT_ERROR
@@ -140,14 +150,14 @@
     /**
      * Read the encrypted value for the given key and write it to the given [BackupDataOutput].
      */
-    @Throws(IOException::class, UnsupportedVersionException::class, SecurityException::class)
+    @Throws(IOException::class, UnsupportedVersionException::class, GeneralSecurityException::class)
     private suspend fun readAndWriteValue(
         state: KVRestoreState,
         dKey: DecodedKey,
         out: BackupDataOutput
     ) = plugin.getInputStreamForRecord(state.token, state.packageInfo, dKey.base64Key)
         .use { inputStream ->
-            val version = headerReader.readVersion(inputStream)
+            val version = headerReader.readVersion(inputStream, state.version)
             val packageName = state.packageInfo.packageName
             val value = if (version == 0.toByte()) {
                 crypto.decryptHeader(inputStream, version, packageName, dKey.key)
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt
index 4c77e92..500be24 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt
@@ -200,6 +200,7 @@
         val state = this.state ?: throw IllegalStateException("no state")
 
         if (!state.packages.hasNext()) return NO_MORE_PACKAGES
+        val version = state.backupMetadata.version
         val packageInfo = state.packages.next()
         val packageName = packageInfo.packageName
 
@@ -208,13 +209,13 @@
                 // check key/value data first and if available, don't even check for full data
                 kv.hasDataForPackage(state.token, packageInfo) -> {
                     Log.i(TAG, "Found K/V data for $packageName.")
-                    kv.initializeState(state.token, packageInfo, state.pmPackageInfo)
+                    kv.initializeState(version, state.token, packageInfo, state.pmPackageInfo)
                     state.currentPackage = packageName
                     TYPE_KEY_VALUE
                 }
                 full.hasDataForPackage(state.token, packageInfo) -> {
                     Log.i(TAG, "Found full backup data for $packageName.")
-                    full.initializeState(state.token, packageInfo)
+                    full.initializeState(version, state.token, packageInfo)
                     state.currentPackage = packageName
                     TYPE_FULL_STREAM
                 }
diff --git a/app/src/test/java/com/stevesoltys/seedvault/header/HeaderReaderTest.kt b/app/src/test/java/com/stevesoltys/seedvault/header/HeaderReaderTest.kt
index 7a16769..7765d1e 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/header/HeaderReaderTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/header/HeaderReaderTest.kt
@@ -26,7 +26,7 @@
         val input = byteArrayOf(VERSION)
         val inputStream = ByteArrayInputStream(input)
 
-        assertEquals(VERSION, reader.readVersion(inputStream))
+        assertEquals(VERSION, reader.readVersion(inputStream, VERSION))
     }
 
     @Test
@@ -34,7 +34,7 @@
         val input = ByteArray(0)
         val inputStream = ByteArrayInputStream(input)
         assertThrows(IOException::class.javaObjectType) {
-            reader.readVersion(inputStream)
+            reader.readVersion(inputStream, VERSION)
         }
     }
 
@@ -43,7 +43,7 @@
         val input = byteArrayOf((VERSION + 1).toByte())
         val inputStream = ByteArrayInputStream(input)
         assertThrows(UnsupportedVersionException::class.javaObjectType) {
-            reader.readVersion(inputStream)
+            reader.readVersion(inputStream, VERSION)
         }
     }
 
@@ -52,7 +52,7 @@
         val input = byteArrayOf((-1).toByte())
         val inputStream = ByteArrayInputStream(input)
         assertThrows(IOException::class.javaObjectType) {
-            reader.readVersion(inputStream)
+            reader.readVersion(inputStream, VERSION)
         }
     }
 
@@ -61,7 +61,16 @@
         val input = byteArrayOf(Byte.MAX_VALUE)
         val inputStream = ByteArrayInputStream(input)
         assertThrows(UnsupportedVersionException::class.javaObjectType) {
-            reader.readVersion(inputStream)
+            reader.readVersion(inputStream, Byte.MAX_VALUE)
+        }
+    }
+
+    @Test
+    fun `unexpected version throws exception`() {
+        val input = byteArrayOf(VERSION + 1)
+        val inputStream = ByteArrayInputStream(input)
+        assertThrows(UnsupportedVersionException::class.javaObjectType) {
+            reader.readVersion(inputStream, VERSION)
         }
     }
 
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt
index 668cea6..9764377 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt
@@ -54,7 +54,7 @@
     @Test
     fun `initializing state leaves a state`() {
         assertFalse(restore.hasState())
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
         assertTrue(restore.hasState())
     }
 
@@ -68,7 +68,7 @@
 
     @Test
     fun `getting InputStream for package when getting first chunk throws`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         coEvery { plugin.getInputStreamForPackage(token, packageInfo) } throws IOException()
         every { fileDescriptor.close() } just Runs
@@ -81,10 +81,10 @@
 
     @Test
     fun `reading version header when getting first chunk throws`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
-        every { headerReader.readVersion(inputStream) } throws IOException()
+        every { headerReader.readVersion(inputStream, VERSION) } throws IOException()
         every { fileDescriptor.close() } just Runs
 
         assertEquals(
@@ -95,11 +95,11 @@
 
     @Test
     fun `reading unsupported version when getting first chunk`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
         every {
-            headerReader.readVersion(inputStream)
+            headerReader.readVersion(inputStream, VERSION)
         } throws UnsupportedVersionException(unsupportedVersion)
         every { fileDescriptor.close() } just Runs
 
@@ -111,10 +111,10 @@
 
     @Test
     fun `getting decrypted stream when getting first chunk throws`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns VERSION
+        every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } throws IOException()
         every { fileDescriptor.close() } just Runs
 
@@ -127,10 +127,10 @@
     @Test
     fun `getting decrypted stream when getting first chunk throws general security exception`() =
         runBlocking {
-            restore.initializeState(token, packageInfo)
+            restore.initializeState(VERSION, token, packageInfo)
 
             coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
-            every { headerReader.readVersion(inputStream) } returns VERSION
+            every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
             every { crypto.newDecryptingStream(inputStream, ad) } throws GeneralSecurityException()
             every { fileDescriptor.close() } just Runs
 
@@ -139,7 +139,7 @@
 
     @Test
     fun `full chunk gets decrypted`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         initInputStream()
         readAndEncryptInputStream(encrypted)
@@ -153,10 +153,10 @@
 
     @Test
     fun `full chunk gets decrypted from version 0`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(0.toByte(), token, packageInfo)
 
         coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns 0.toByte()
+        every { headerReader.readVersion(inputStream, 0.toByte()) } returns 0.toByte()
         every {
             crypto.decryptHeader(inputStream, 0.toByte(), packageInfo.packageName)
         } returns VersionHeader(0.toByte(), packageInfo.packageName)
@@ -173,13 +173,29 @@
     }
 
     @Test
+    fun `unexpected version aborts with error`() = runBlocking {
+        restore.initializeState(Byte.MAX_VALUE, token, packageInfo)
+
+        coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
+        every {
+            headerReader.readVersion(inputStream, Byte.MAX_VALUE)
+        } throws GeneralSecurityException()
+        every { inputStream.close() } just Runs
+        every { fileDescriptor.close() } just Runs
+
+        assertEquals(TRANSPORT_ERROR, restore.getNextFullRestoreDataChunk(fileDescriptor))
+        restore.abortFullRestore()
+        assertFalse(restore.hasState())
+    }
+
+    @Test
     fun `three full chunk get decrypted and then return no more data`() = runBlocking {
         val encryptedBytes = Random.nextBytes(MAX_SEGMENT_LENGTH * 2 + 1)
         val decryptedInputStream = ByteArrayInputStream(encryptedBytes)
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns VERSION
+        every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
         every { outputFactory.getOutputStream(fileDescriptor) } returns outputStream
         every { fileDescriptor.close() } just Runs
@@ -197,7 +213,7 @@
 
     @Test
     fun `aborting full restore closes stream, resets state`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         initInputStream()
         readAndEncryptInputStream(encrypted)
@@ -212,7 +228,7 @@
 
     private fun initInputStream() {
         coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns VERSION
+        every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
     }
 
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/KVRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/KVRestoreTest.kt
index 975977a..05a8337 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/KVRestoreTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/KVRestoreTest.kt
@@ -22,6 +22,7 @@
 import org.junit.jupiter.api.Test
 import java.io.IOException
 import java.io.InputStream
+import java.security.GeneralSecurityException
 import kotlin.random.Random
 
 @Suppress("BlockingMethodInNonBlockingContext")
@@ -60,7 +61,7 @@
 
     @Test
     fun `listing records throws`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         coEvery { plugin.listRecords(token, packageInfo) } throws IOException()
 
@@ -69,12 +70,12 @@
 
     @Test
     fun `reading VersionHeader with unsupported version throws`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         getRecordsAndOutput()
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
         every {
-            headerReader.readVersion(inputStream)
+            headerReader.readVersion(inputStream, VERSION)
         } throws UnsupportedVersionException(unsupportedVersion)
         streamsGetClosed()
 
@@ -84,11 +85,11 @@
 
     @Test
     fun `error reading VersionHeader throws`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         getRecordsAndOutput()
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
-        every { headerReader.readVersion(inputStream) } throws IOException()
+        every { headerReader.readVersion(inputStream, VERSION) } throws IOException()
         streamsGetClosed()
 
         assertEquals(TRANSPORT_ERROR, restore.getRestoreData(fileDescriptor))
@@ -97,11 +98,11 @@
 
     @Test
     fun `decrypting stream throws`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         getRecordsAndOutput()
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns VERSION
+        every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } throws IOException()
         streamsGetClosed()
 
@@ -111,11 +112,11 @@
 
     @Test
     fun `decrypting stream throws security exception`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         getRecordsAndOutput()
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns VERSION
+        every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } throws SecurityException()
         streamsGetClosed()
 
@@ -125,11 +126,11 @@
 
     @Test
     fun `writing header throws`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         getRecordsAndOutput()
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns VERSION
+        every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
         every { decryptedInputStream.readBytes() } returns data
         every { output.writeEntityHeader(key, data.size) } throws IOException()
@@ -141,11 +142,11 @@
 
     @Test
     fun `writing value throws`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         getRecordsAndOutput()
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns VERSION
+        every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
         every { decryptedInputStream.readBytes() } returns data
         every { output.writeEntityHeader(key, data.size) } returns 42
@@ -158,11 +159,11 @@
 
     @Test
     fun `writing value succeeds`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         getRecordsAndOutput()
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns VERSION
+        every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
         every { decryptedInputStream.readBytes() } returns data
         every { output.writeEntityHeader(key, data.size) } returns 42
@@ -175,11 +176,11 @@
 
     @Test
     fun `writing value uses old v0 code`() = runBlocking {
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(0.toByte(), token, packageInfo)
 
         getRecordsAndOutput()
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns 0.toByte()
+        every { headerReader.readVersion(inputStream, 0.toByte()) } returns 0.toByte()
         every {
             crypto.decryptHeader(inputStream, 0.toByte(), packageInfo.packageName, key)
         } returns VersionHeader(VERSION, packageInfo.packageName, key)
@@ -193,23 +194,38 @@
     }
 
     @Test
+    fun `unexpected version aborts with error`() = runBlocking {
+        restore.initializeState(Byte.MAX_VALUE, token, packageInfo)
+
+        getRecordsAndOutput()
+        coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
+        every {
+            headerReader.readVersion(inputStream, Byte.MAX_VALUE)
+        } throws GeneralSecurityException()
+        streamsGetClosed()
+
+        assertEquals(TRANSPORT_ERROR, restore.getRestoreData(fileDescriptor))
+        verifyStreamWasClosed()
+    }
+
+    @Test
     fun `writing two values succeeds`() = runBlocking {
         val data2 = getRandomByteArray()
         val inputStream2 = mockk<InputStream>()
         val decryptedInputStream2 = mockk<InputStream>()
-        restore.initializeState(token, packageInfo)
+        restore.initializeState(VERSION, token, packageInfo)
 
         getRecordsAndOutput(listOf(key64, key264))
         // first key/value
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key64) } returns inputStream
-        every { headerReader.readVersion(inputStream) } returns VERSION
+        every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
         every { decryptedInputStream.readBytes() } returns data
         every { output.writeEntityHeader(key, data.size) } returns 42
         every { output.writeEntityData(data, data.size) } returns data.size
         // second key/value
         coEvery { plugin.getInputStreamForRecord(token, packageInfo, key264) } returns inputStream2
-        every { headerReader.readVersion(inputStream2) } returns VERSION
+        every { headerReader.readVersion(inputStream2, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream2, ad) } returns decryptedInputStream2
         every { decryptedInputStream2.readBytes() } returns data2
         every { output.writeEntityHeader(key2, data2.size) } returns 42
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt
index bafef62..7bf5314 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt
@@ -10,6 +10,7 @@
 import android.os.ParcelFileDescriptor
 import com.stevesoltys.seedvault.coAssertThrows
 import com.stevesoltys.seedvault.getRandomString
+import com.stevesoltys.seedvault.header.VERSION
 import com.stevesoltys.seedvault.metadata.EncryptedBackupMetadata
 import com.stevesoltys.seedvault.metadata.MetadataReader
 import com.stevesoltys.seedvault.metadata.PackageMetadata
@@ -213,7 +214,7 @@
         restore.startRestore(token, packageInfoArray)
 
         coEvery { kv.hasDataForPackage(token, packageInfo) } returns true
-        every { kv.initializeState(token, packageInfo) } just Runs
+        every { kv.initializeState(VERSION, token, packageInfo) } just Runs
 
         val expected = RestoreDescription(packageInfo.packageName, TYPE_KEY_VALUE)
         assertEquals(expected, restore.nextRestorePackage())
@@ -226,7 +227,7 @@
 
         coEvery { kv.hasDataForPackage(token, packageInfo) } returns false
         coEvery { full.hasDataForPackage(token, packageInfo) } returns true
-        every { full.initializeState(token, packageInfo) } just Runs
+        every { full.initializeState(VERSION, token, packageInfo) } just Runs
 
         val expected = RestoreDescription(packageInfo.packageName, TYPE_FULL_STREAM)
         assertEquals(expected, restore.nextRestorePackage())
@@ -249,14 +250,14 @@
         restore.startRestore(token, packageInfoArray2)
 
         coEvery { kv.hasDataForPackage(token, packageInfo) } returns true
-        every { kv.initializeState(token, packageInfo) } just Runs
+        every { kv.initializeState(VERSION, token, packageInfo) } just Runs
 
         val expected = RestoreDescription(packageInfo.packageName, TYPE_KEY_VALUE)
         assertEquals(expected, restore.nextRestorePackage())
 
         coEvery { kv.hasDataForPackage(token, packageInfo2) } returns false
         coEvery { full.hasDataForPackage(token, packageInfo2) } returns true
-        every { full.initializeState(token, packageInfo2) } just Runs
+        every { full.initializeState(VERSION, token, packageInfo2) } just Runs
 
         val expected2 = RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
         assertEquals(expected2, restore.nextRestorePackage())
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt
index b0ee983..43469e2 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt
@@ -61,7 +61,7 @@
         kvRestore,
         fullRestore,
         metadataReader
-    ).apply { beforeStartRestore(metadata) }
+    ).apply { beforeStartRestore(metadata.copy(version = 0x00)) }
 
     private val fileDescriptor = mockk<ParcelFileDescriptor>(relaxed = true)
     private val appData = ("562AB665C3543120FC794D7CDA3AC18E5959235A4D" +