Add temp repository encryption (#131)

This commit is contained in:
l-jonas
2018-12-13 10:27:07 +01:00
committed by GitHub
parent fa30beb9d5
commit f3d51f0cb9
9 changed files with 160 additions and 6 deletions
+1
View File
@@ -88,4 +88,5 @@ dependencies {
implementation 'com.github.apl-devs:appintro:v4.2.3'
implementation project(':syncthing-repository-android')
implementation project(':syncthing-temp-repository-encryption')
}
@@ -8,6 +8,7 @@ import kotlinx.coroutines.launch
import net.syncthing.java.client.SyncthingClient
import net.syncthing.java.core.configuration.Configuration
import net.syncthing.java.core.exception.ExceptionReport
import net.syncthing.java.repository.EncryptedTempRepository
import net.syncthing.repository.android.SqliteIndexRepository
import net.syncthing.repository.android.TempDirectoryLocalRepository
import net.syncthing.repository.android.database.RepositoryDatabase
@@ -49,7 +50,11 @@ class LibraryInstance (
}
}
private val tempRepository = TempDirectoryLocalRepository(File(context.filesDir, "temp_repository"))
private val tempRepository = EncryptedTempRepository(
TempDirectoryLocalRepository(
File(context.filesDir, "temp_repository")
)
)
val isListeningPortTaken = checkIsListeningPortTaken() // this must come first to work correctly
val configuration = Configuration(configFolder = context.filesDir)
@@ -58,7 +63,7 @@ class LibraryInstance (
repository = SqliteIndexRepository(
database = RepositoryDatabase.with(context),
closeDatabaseOnClose = false,
clearTempStorageHook = { tempRepository.deleteAllData() }
clearTempStorageHook = { tempRepository.deleteAllTempData() }
),
tempRepository = tempRepository,
exceptionReportHandler = { ex ->
+1 -1
View File
@@ -1 +1 @@
include ':app', ':syncthing-repository-android', ':syncthing-repository-default', ':syncthing-relay-client', ':syncthing-bep', ':syncthing-core', ':syncthing-client', ':syncthing-discovery', ':syncthing-client-cli'
include ':app', ':syncthing-repository-android', ':syncthing-repository-default', ':syncthing-relay-client', ':syncthing-bep', ':syncthing-core', ':syncthing-client', ':syncthing-discovery', ':syncthing-client-cli', ':syncthing-temp-repository-encryption'
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2016 Davide Imbriaco
* Copyright (C) 2018 Jonas Lochmann
*
* This Java file is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -22,4 +23,6 @@ interface TempRepository: Closeable {
fun popTempData(key: String): ByteArray
fun deleteTempData(keys: List<String>)
fun deleteAllTempData()
}
@@ -1,3 +1,16 @@
/*
* Copyright (C) 2018 Jonas Lochmann
*
* This Java file is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.syncthing.repository.android
import net.syncthing.java.core.interfaces.TempRepository
@@ -14,7 +27,7 @@ class TempDirectoryLocalRepository(private val directory: File): TempRepository
directory.mkdirs()
// there could be garbage from the previous session which we don't need anymore
deleteAllData()
deleteAllTempData()
}
override fun pushTempData(data: ByteArray): String {
@@ -59,10 +72,10 @@ class TempDirectoryLocalRepository(private val directory: File): TempRepository
}
override fun close() {
deleteAllData()
deleteAllTempData()
}
fun deleteAllData() {
override fun deleteAllTempData() {
directory.listFiles().forEach { file ->
if (file.isFile) {
file.delete()
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2016 Davide Imbriaco
* Copyright (C) 2018 Jonas Lochmann
*
* This Java file is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -227,6 +228,14 @@ class SqlRepository(databaseFolder: File) : Closeable, IndexRepository, TempRepo
}
}
override fun deleteAllTempData() {
getConnection().use { connection ->
connection.prepareStatement("DELETE FROM temporary_data").use { statement ->
statement.executeUpdate()
}
}
}
companion object {
private const val VERSION = 13
}
@@ -0,0 +1,10 @@
apply plugin: 'java-library'
apply plugin: 'kotlin'
dependencies {
implementation (project(':syncthing-core')) {
exclude group: 'commons-logging', module:'commons-logging'
exclude group: 'org.slf4j'
exclude group: 'ch.qos.logback'
}
}
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2018 Jonas Lochmann
*
* This Java file is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.syncthing.java.repository
import net.syncthing.java.core.interfaces.TempRepository
import java.io.IOException
import java.security.MessageDigest
import java.security.SecureRandom
import java.util.*
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
class EncryptedTempRepository(private val otherRepository: TempRepository): TempRepository {
companion object {
private val secureRandom = SecureRandom()
}
private val keyStorage = Collections.synchronizedMap(mutableMapOf<String, EncryptedTempRepositoryItem>())
override fun pushTempData(data: ByteArray): String {
val (encrypted, config) = encrypt(data)
val key = otherRepository.pushTempData(encrypted)
keyStorage[key] = config
return key
}
override fun popTempData(key: String) = decrypt(otherRepository.popTempData(key), keyStorage.remove(key)!!)
override fun deleteTempData(keys: List<String>) {
keys.forEach { keyStorage.remove(it) }
otherRepository.deleteTempData(keys)
}
override fun deleteAllTempData() {
keyStorage.clear()
otherRepository.deleteAllTempData()
}
override fun close() {
keyStorage.clear()
otherRepository.close()
}
private fun encrypt(input: ByteArray): Pair<ByteArray, EncryptedTempRepositoryItem> {
val cryptoSpec = EncryptedTempRepositoryItem(
key = ByteArray(16).apply { secureRandom.nextBytes(this) },
iv = ByteArray(16).apply { secureRandom.nextBytes(this) },
sha512 = sha512(input)
)
val output = Cipher.getInstance("AES/GCM/NoPadding").apply {
init(
Cipher.ENCRYPT_MODE,
SecretKeySpec(cryptoSpec.key, "AES"),
GCMParameterSpec(128, cryptoSpec.iv)
)
}.doFinal(input)
return output to cryptoSpec
}
private fun decrypt(input: ByteArray, config: EncryptedTempRepositoryItem): ByteArray {
val output = Cipher.getInstance("AES/GCM/NoPadding").apply {
init(
Cipher.DECRYPT_MODE,
SecretKeySpec(config.key, "AES"),
GCMParameterSpec(128, config.iv)
)
}.doFinal(input)
if (!sha512(output).contentEquals(config.sha512)) {
throw IOException("temporarily file was modified")
}
return output
}
private fun sha512(data: ByteArray): ByteArray = MessageDigest.getInstance("SHA-512").digest(data)
}
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2018 Jonas Lochmann
*
* This Java file is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.syncthing.java.repository
internal class EncryptedTempRepositoryItem(
val iv: ByteArray,
val key: ByteArray,
val sha512: ByteArray
)