add app lock secruity and support for saving mib credentials
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
package sh.sar.basedbank.util
|
||||
|
||||
import android.content.Context
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties
|
||||
import android.util.Base64
|
||||
import java.security.KeyStore
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.KeyGenerator
|
||||
import javax.crypto.SecretKey
|
||||
import javax.crypto.spec.GCMParameterSpec
|
||||
|
||||
class CredentialStore(context: Context) {
|
||||
|
||||
private val prefs = context.getSharedPreferences("credential_store", Context.MODE_PRIVATE)
|
||||
private val keyAlias = "basedbank_credential_key"
|
||||
private val transformation = "AES/GCM/NoPadding"
|
||||
|
||||
data class MibCredentials(val username: String, val passwordHash: String, val otpSeed: String)
|
||||
|
||||
fun hasMibCredentials(): Boolean = prefs.contains("mib_enc_username")
|
||||
|
||||
fun saveMibCredentials(username: String, passwordHash: String, otpSeed: String) {
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit()
|
||||
.putString("mib_enc_username", encrypt(username, key))
|
||||
.putString("mib_enc_password_hash", encrypt(passwordHash, key))
|
||||
.putString("mib_enc_otp_seed", encrypt(otpSeed, key))
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun loadMibCredentials(): MibCredentials? {
|
||||
val key = getOrCreateKey()
|
||||
val encUsername = prefs.getString("mib_enc_username", null) ?: return null
|
||||
val encHash = prefs.getString("mib_enc_password_hash", null) ?: return null
|
||||
val encSeed = prefs.getString("mib_enc_otp_seed", null) ?: return null
|
||||
return try {
|
||||
MibCredentials(
|
||||
decrypt(encUsername, key),
|
||||
decrypt(encHash, key),
|
||||
decrypt(encSeed, key)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun clearMibCredentials() {
|
||||
prefs.edit()
|
||||
.remove("mib_enc_username")
|
||||
.remove("mib_enc_password_hash")
|
||||
.remove("mib_enc_otp_seed")
|
||||
.apply()
|
||||
}
|
||||
|
||||
private fun getOrCreateKey(): SecretKey {
|
||||
val ks = KeyStore.getInstance("AndroidKeyStore").also { it.load(null) }
|
||||
ks.getKey(keyAlias, null)?.let { return it as SecretKey }
|
||||
|
||||
val spec = KeyGenParameterSpec.Builder(
|
||||
keyAlias,
|
||||
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
|
||||
)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
||||
.setKeySize(256)
|
||||
.build()
|
||||
|
||||
return KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
|
||||
.also { it.init(spec) }
|
||||
.generateKey()
|
||||
}
|
||||
|
||||
private fun encrypt(plaintext: String, key: SecretKey): String {
|
||||
val cipher = Cipher.getInstance(transformation)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key)
|
||||
val iv = cipher.iv
|
||||
val ct = cipher.doFinal(plaintext.toByteArray())
|
||||
return Base64.encodeToString(iv, Base64.NO_WRAP) + ":" + Base64.encodeToString(ct, Base64.NO_WRAP)
|
||||
}
|
||||
|
||||
private fun decrypt(encoded: String, key: SecretKey): String {
|
||||
val parts = encoded.split(":")
|
||||
val iv = Base64.decode(parts[0], Base64.NO_WRAP)
|
||||
val ct = Base64.decode(parts[1], Base64.NO_WRAP)
|
||||
val cipher = Cipher.getInstance(transformation)
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, GCMParameterSpec(128, iv))
|
||||
return String(cipher.doFinal(ct))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user