Implemented encrypting Room database, but storing password just in plain text yet

This commit is contained in:
dankito 2020-10-06 20:04:21 +02:00
parent 20c32dbd7e
commit 0a6fa8e01a
6 changed files with 87 additions and 24 deletions

View File

@ -24,9 +24,7 @@ open class LandingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val authenticationType = authenticationService.getAuthenticationType() if (authenticationService.authenticationType == AuthenticationType.None) {
if (authenticationType == AuthenticationType.None) {
launchActivity(MainActivity::class.java) launchActivity(MainActivity::class.java)
} }
else { else {

View File

@ -2,6 +2,7 @@ package net.dankito.banking.ui.android.activities
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_login.* import kotlinx.android.synthetic.main.activity_login.*
import net.dankito.banking.ui.android.MainActivity import net.dankito.banking.ui.android.MainActivity
import net.dankito.banking.ui.android.R import net.dankito.banking.ui.android.R
@ -48,8 +49,11 @@ open class LoginActivity : BaseActivity() {
protected open fun checkEnteredPasswordAndLogIn() { protected open fun checkEnteredPasswordAndLogIn() {
if (authenticationService.isCorrectUserPassword(edtxtLoginPassword.text)) { val enteredPassword = edtxtLoginPassword.text
logIn()
if (authenticationService.isCorrectUserPassword(enteredPassword)) {
authenticationService.userLoggedInWithPassword(enteredPassword)
navigateToMainActivity()
} }
else { else {
Toast.makeText(this, R.string.activity_login_incorrect_password_entered, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.activity_login_incorrect_password_entered, Toast.LENGTH_SHORT).show()
@ -57,10 +61,11 @@ open class LoginActivity : BaseActivity() {
} }
protected open fun biometricAuthenticationSuccessful() { protected open fun biometricAuthenticationSuccessful() {
logIn() authenticationService.userLoggedInWithBiometricAuthentication()
navigateToMainActivity()
} }
protected open fun logIn() { protected open fun navigateToMainActivity() {
navigateToActivity(MainActivity::class.java) navigateToActivity(MainActivity::class.java)
} }

View File

@ -1,14 +1,16 @@
package net.dankito.banking.ui.android.authentication package net.dankito.banking.ui.android.authentication
import net.dankito.banking.persistence.IBankingPersistence
import net.dankito.banking.util.ISerializer import net.dankito.banking.util.ISerializer
import net.dankito.utils.multiplatform.File import net.dankito.utils.multiplatform.File
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
open class AuthenticationService( open class AuthenticationService(
protected val biometricAuthenticationService: IBiometricAuthenticationService, protected open val biometricAuthenticationService: IBiometricAuthenticationService,
protected val dataFolder: File, protected open val persistence: IBankingPersistence,
protected val serializer: ISerializer protected open val dataFolder: File,
protected open val serializer: ISerializer
) { ) {
companion object { companion object {
@ -29,11 +31,40 @@ open class AuthenticationService(
init { init {
authenticationType = loadAuthenticationType() authenticationType = loadAuthenticationType()
if (authenticationType == AuthenticationType.None) {
val authenticationSettings = loadAuthenticationSettings()
if (authenticationSettings == null) { // first app run -> create a default password
removeAppProtection()
}
else {
openDatabase(authenticationSettings)
}
}
} }
open fun userLoggedInWithBiometricAuthentication() {
loadAuthenticationSettings()?.let {
openDatabase(it)
}
}
open fun userLoggedInWithPassword(enteredPassword: String) {
openDatabase(enteredPassword)
}
protected open fun openDatabase(authenticationSettings: AuthenticationSettings) {
openDatabase(authenticationSettings.userPassword)
}
protected open fun openDatabase(password: String?) {
persistence.decryptData(password)
}
open fun setAuthenticationMethodToBiometric() { open fun setAuthenticationMethodToBiometric() {
if (saveUserPasswordIfChanged(null)) { if (saveNewUserPassword(generateRandomPassword())) {
if (saveAuthenticationType(AuthenticationType.Biometric)) { if (saveAuthenticationType(AuthenticationType.Biometric)) {
authenticationType = AuthenticationType.Biometric authenticationType = AuthenticationType.Biometric
} }
@ -41,7 +72,7 @@ open class AuthenticationService(
} }
open fun setAuthenticationMethodToPassword(newPassword: String) { open fun setAuthenticationMethodToPassword(newPassword: String) {
if (saveUserPasswordIfChanged(newPassword)) { if (saveNewUserPassword(newPassword)) {
if (saveAuthenticationType(AuthenticationType.Password)) { if (saveAuthenticationType(AuthenticationType.Password)) {
authenticationType = AuthenticationType.Password authenticationType = AuthenticationType.Password
} }
@ -49,7 +80,7 @@ open class AuthenticationService(
} }
open fun removeAppProtection() { open fun removeAppProtection() {
if (saveUserPasswordIfChanged(null)) { if (saveNewUserPassword(generateRandomPassword())) {
if (saveAuthenticationType(AuthenticationType.None)) { if (saveAuthenticationType(AuthenticationType.None)) {
authenticationType = AuthenticationType.None authenticationType = AuthenticationType.None
} }
@ -103,16 +134,22 @@ open class AuthenticationService(
} }
protected open fun saveUserPasswordIfChanged(userPassword: String?): Boolean { protected open fun saveNewUserPassword(newPassword: String?): Boolean {
val settings = loadOrCreateDefaultAuthenticationSettings() val settings = loadOrCreateDefaultAuthenticationSettings()
val currentPassword = settings.userPassword
if (settings.userPassword != userPassword) { if (currentPassword != newPassword) {
settings.userPassword = userPassword settings.userPassword = newPassword
return saveAuthenticationSettings(settings) if (saveAuthenticationSettings(settings)) {
persistence.changePassword(currentPassword, newPassword) // TODO: actually this is bad. If changing password fails then password is saved in AuthenticationSettings but DB has a different password
return true
}
return false
} }
return false return true
} }
protected open fun loadOrCreateDefaultAuthenticationSettings(): AuthenticationSettings { protected open fun loadOrCreateDefaultAuthenticationSettings(): AuthenticationSettings {
@ -151,4 +188,20 @@ open class AuthenticationService(
return false return false
} }
open fun generateRandomPassword(): String {
return generateRandomPassword(30)
}
open fun generateRandomPassword(passwordLength: Int): String {
val dictionary = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789§±!@#$%^&*-_=+;:|/?.>,<"
val passwordBuilder = StringBuilder()
IntRange(0, passwordLength).forEach {
passwordBuilder.append(dictionary.random())
}
return passwordBuilder.toString()
}
} }

View File

@ -0,0 +1,6 @@
package net.dankito.banking.ui.android.authentication
open class AuthenticationSettings(
var userPassword: String? = null
)

View File

@ -1,12 +1,12 @@
package net.dankito.banking.ui.android.authentication package net.dankito.banking.ui.android.authentication
enum class AuthenticationType { enum class AuthenticationType(internal val rawValue: Int) {
None, None(3),
Password, Password(7),
Biometric Biometric(9)
} }

View File

@ -89,8 +89,9 @@ class BankingModule(private val applicationContext: Context) {
@Provides @Provides
@Singleton @Singleton
fun provideAuthenticationService(biometricAuthenticationService: IBiometricAuthenticationService, @Named(DataFolderKey) dataFolder: File, serializer: ISerializer) : AuthenticationService { fun provideAuthenticationService(biometricAuthenticationService: IBiometricAuthenticationService, persistence: IBankingPersistence,
return AuthenticationService(biometricAuthenticationService, dataFolder, serializer) @Named(DataFolderKey) dataFolder: File, serializer: ISerializer) : AuthenticationService {
return AuthenticationService(biometricAuthenticationService, persistence, dataFolder, serializer)
} }
@Provides @Provides