Encrypt token (fix #10)

pull/653/merge
Varun Patil 2023-10-03 10:43:21 -07:00
parent 5ab50fe85d
commit eb5f998505
2 changed files with 101 additions and 16 deletions

View File

@ -1,5 +1,6 @@
package gallery.memories.service package gallery.memories.service
import SecureStorage
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.util.Log import android.util.Log
@ -16,6 +17,8 @@ class AccountService(private val mCtx: MainActivity, private val mHttp: HttpServ
val TAG = AccountService::class.java.simpleName val TAG = AccountService::class.java.simpleName
} }
private val store = SecureStorage(mCtx)
/** /**
* Login to a server * Login to a server
* @param baseUrl The base URL of the server * @param baseUrl The base URL of the server
@ -160,11 +163,7 @@ class AccountService(private val mCtx: MainActivity, private val mHttp: HttpServ
* @param password The password to store * @param password The password to store
*/ */
fun storeCredentials(url: String, user: String, password: String) { fun storeCredentials(url: String, user: String, password: String) {
mCtx.getSharedPreferences("credentials", 0).edit() store.saveCredentials(url, user, password)
.putString("memoriesUrl", url)
.putString("user", user)
.putString("password", password)
.apply()
mHttp.setBaseUrl(url) mHttp.setBaseUrl(url)
mHttp.setAuthHeader(Pair(user, password)) mHttp.setAuthHeader(Pair(user, password))
} }
@ -174,12 +173,10 @@ class AccountService(private val mCtx: MainActivity, private val mHttp: HttpServ
* @return The stored credentials * @return The stored credentials
*/ */
fun getCredentials(): Pair<String, String>? { fun getCredentials(): Pair<String, String>? {
val prefs = mCtx.getSharedPreferences("credentials", 0) val saved = store.getCredentials()
mHttp.setBaseUrl(prefs.getString("memoriesUrl", null)) if (saved == null) return null
val user = prefs.getString("user", null) mHttp.setBaseUrl(saved.first)
val password = prefs.getString("password", null) return Pair(saved.second, saved.third)
if (user == null || password == null) return null
return Pair(user, password)
} }
/** /**
@ -188,11 +185,7 @@ class AccountService(private val mCtx: MainActivity, private val mHttp: HttpServ
fun deleteCredentials() { fun deleteCredentials() {
mHttp.setAuthHeader(null) mHttp.setAuthHeader(null)
mHttp.setBaseUrl(null) mHttp.setBaseUrl(null)
mCtx.getSharedPreferences("credentials", 0).edit() store.deleteCredentials()
.remove("memoriesUrl")
.remove("user")
.remove("password")
.apply()
} }
/** /**

View File

@ -0,0 +1,92 @@
import android.content.Context
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.security.keystore.KeyProperties.KEY_ALGORITHM_AES
import android.security.keystore.KeyProperties.PURPOSE_DECRYPT
import android.security.keystore.KeyProperties.PURPOSE_ENCRYPT
import android.util.Base64
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
class SecureStorage(private val context: Context) {
private val keyStore = KeyStore.getInstance("AndroidKeyStore")
private val keyAlias = "MemoriesKey"
init {
keyStore.load(null)
if (!keyStore.containsAlias(keyAlias)) {
generateNewKey()
}
}
fun saveCredentials(url: String, username: String, token: String) {
val cipher = getCipher()
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey())
val encryptedToken = cipher.doFinal(token.toByteArray())
context.getSharedPreferences("credentials", Context.MODE_PRIVATE).edit()
.putString("url", url)
.putString("username", username)
.putString("encryptedToken", Base64.encodeToString(encryptedToken, Base64.DEFAULT))
.putString("iv", Base64.encodeToString(cipher.iv, Base64.DEFAULT))
.apply()
}
fun getCredentials(): Triple<String, String, String>? {
val sharedPreferences = context.getSharedPreferences("credentials", Context.MODE_PRIVATE)
val url = sharedPreferences.getString("url", null)
val username = sharedPreferences.getString("username", null)
val encryptedToken = sharedPreferences.getString("encryptedToken", null)
val ivStr = sharedPreferences.getString("iv", null)
if (url != null && username != null && encryptedToken != null && ivStr != null) {
val iv = Base64.decode(ivStr, Base64.DEFAULT)
val cipher = getCipher()
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), IvParameterSpec(iv))
val token = String(cipher.doFinal(Base64.decode(encryptedToken, Base64.DEFAULT)))
return Triple(url, username, token)
}
return null
}
fun deleteCredentials() {
context.getSharedPreferences("credentials", Context.MODE_PRIVATE).edit()
.remove("url")
.remove("encryptedUsername")
.remove("encryptedToken")
.remove("iv")
.apply()
}
private fun generateNewKey() {
val keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM_AES, "AndroidKeyStore")
val keyGenSpec = KeyGenParameterSpec.Builder(
keyAlias,
PURPOSE_ENCRYPT or PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(false) // Change this if needed
.build()
keyGenerator.init(keyGenSpec)
keyGenerator.generateKey()
}
private fun getCipher(): Cipher {
val transformation =
"$KEY_ALGORITHM_AES/${KeyProperties.BLOCK_MODE_CBC}/${KeyProperties.ENCRYPTION_PADDING_PKCS7}"
return Cipher.getInstance(transformation)
}
private fun getSecretKey(): SecretKey {
return keyStore.getKey(keyAlias, null) as SecretKey
}
}