From 681b37d589e1dc5ec8b893ea0dfaf09088ff009a Mon Sep 17 00:00:00 2001 From: dankito Date: Sat, 7 Nov 2020 02:11:30 +0100 Subject: [PATCH] Implemented encrypting authentication settings file --- build.gradle | 2 ++ ui/BankingAndroidApp/build.gradle | 4 ++- .../authentication/AuthenticationService.kt | 29 +++++++++++++++++-- .../banking/ui/android/di/BankingModule.kt | 2 +- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index ef98123b..05640b01 100644 --- a/build.gradle +++ b/build.gradle @@ -66,6 +66,8 @@ ext { zxingVersion = "3.3.0" + scytaleVersion = "1.0.1" + multiDexVersion = "2.0.1" appCompatVersion = "1.1.0" diff --git a/ui/BankingAndroidApp/build.gradle b/ui/BankingAndroidApp/build.gradle index e83fba51..ac65e22e 100644 --- a/ui/BankingAndroidApp/build.gradle +++ b/ui/BankingAndroidApp/build.gradle @@ -108,9 +108,11 @@ dependencies { implementation "com.otaliastudios:autocomplete:$autocompleteVersion" - implementation("com.journeyapps:zxing-android-embedded:4.1.0") { transitive = false } // transitive to use older Zxing version as ZXing 3.4.0 requires Android > 23 + implementation("com.journeyapps:zxing-android-embedded:4.1.0") { transitive = false } // transitive to use older ZXing version as ZXing 3.4.0 requires Android > 23 implementation "com.google.zxing:core:$zxingVersion" + implementation "com.yakivmospan:scytale:$scytaleVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion" diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationService.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationService.kt index 60ff7974..3d258fb4 100644 --- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationService.kt +++ b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationService.kt @@ -1,7 +1,11 @@ package net.dankito.banking.ui.android.authentication +import android.content.Context import android.util.Base64 import at.favre.lib.crypto.bcrypt.BCrypt +import com.yakivmospan.scytale.Crypto +import com.yakivmospan.scytale.Options +import com.yakivmospan.scytale.Store import net.dankito.banking.persistence.IBankingPersistence import net.dankito.banking.ui.android.security.CryptographyManager import net.dankito.banking.util.ISerializer @@ -9,9 +13,11 @@ import net.dankito.utils.multiplatform.File import net.dankito.utils.multiplatform.asString import org.slf4j.LoggerFactory import javax.crypto.Cipher +import javax.crypto.SecretKey open class AuthenticationService( + protected open val applicationContext: Context, protected open val biometricAuthenticationService: IBiometricAuthenticationService, protected open val persistence: IBankingPersistence, protected open val dataFolder: File, @@ -22,6 +28,10 @@ open class AuthenticationService( companion object { private const val AuthenticationSettingsFilename = "a" + private const val AuthenticationSettingsFileKey = "AuthenticationSettingsFileKey" + + private val AuthenticationSettingsFileKeyPassword = "AuthenticationSettingsFileKeyAuthenticationSettingsFileKeyPassword".toCharArray() // TODO: store in a secure place + private const val EncryptionKeyName = "BankingAndroidKey" private const val DefaultPasswordEncryptionKey = "AnyData" // TODO: store in a secure place @@ -219,7 +229,10 @@ open class AuthenticationService( val file = File(dataFolder, AuthenticationSettingsFilename) if (file.exists()) { - val json = file.readText() + val (key, crypto) = getAuthenticationSettingsFileKey() + val encryptedJson = file.readText() + + val json = crypto.decrypt(encryptedJson, key) return serializer.deserializeObject(json, AuthenticationSettings::class) } @@ -233,9 +246,12 @@ open class AuthenticationService( protected open fun saveAuthenticationSettings(settings: AuthenticationSettings): Boolean { try { serializer.serializeObjectToString(settings)?.let { json -> + val (key, crypto) = getAuthenticationSettingsFileKey() + val encryptedJson = crypto.encrypt(json, key) + val file = File(dataFolder, AuthenticationSettingsFilename) - file.writeText(json) + file.writeText(encryptedJson) return true } @@ -246,6 +262,15 @@ open class AuthenticationService( return false } + protected open fun getAuthenticationSettingsFileKey(): Pair { + val store = Store(applicationContext) + + val key = if (store.hasKey(AuthenticationSettingsFileKey)) store.getSymmetricKey(AuthenticationSettingsFileKey, AuthenticationSettingsFileKeyPassword) + else store.generateSymmetricKey(AuthenticationSettingsFileKey, AuthenticationSettingsFileKeyPassword) + + return Pair(key, Crypto(Options.TRANSFORMATION_SYMMETRIC)) + } + open fun generateRandomPassword(): CharArray { return generateRandomPassword(30) diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingModule.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingModule.kt index b6132601..ccfa2ea2 100644 --- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingModule.kt +++ b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingModule.kt @@ -100,7 +100,7 @@ class BankingModule(private val applicationContext: Context) { @Singleton fun provideAuthenticationService(biometricAuthenticationService: IBiometricAuthenticationService, persistence: IBankingPersistence, @Named(DataFolderKey) dataFolder: File, serializer: ISerializer) : AuthenticationService { - return AuthenticationService(biometricAuthenticationService, persistence, dataFolder, serializer) + return AuthenticationService(applicationContext, biometricAuthenticationService, persistence, dataFolder, serializer) } @Provides