Skip to content

Commit

Permalink
Merge pull request #77 from frontegg/FR-18199-fix-masterkey
Browse files Browse the repository at this point in the history
  • Loading branch information
frontegg-david authored Oct 3, 2024
2 parents a772a0c + 939fc2c commit 638f554
Showing 1 changed file with 93 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,114 @@ package com.frontegg.android.services
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Log
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.frontegg.android.utils.CredentialKeys
import java.security.KeyStore
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey

open class CredentialManager(context: Context) {

open class CredentialManager(val context: Context) {
companion object {
private const val SHARED_PREFERENCES_NAME: String =
"com.frontegg.services.CredentialManager"
private val TAG = CredentialManager::class.java.simpleName
}

private val sp: SharedPreferences;
private var sp: SharedPreferences;

private fun createKeyStore(): KeyStore {
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
keyStore.deleteEntry(MasterKey.DEFAULT_MASTER_KEY_ALIAS)
return keyStore
}

fun clearSharedPreference(context: Context) {
context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE).edit().clear()
.apply()
}

private fun createSecretKey(alias: String): SecretKey {
val keyGenerator =
KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")

keyGenerator.init(
KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
)

return keyGenerator.generateKey()
}

private fun getSecretKey(keyStore: KeyStore, alias: String): SecretKey {
return if (keyStore.containsAlias(alias)) {
(keyStore.getEntry(alias, null) as KeyStore.SecretKeyEntry).secretKey
} else {
this.createSecretKey(alias)
}
}

init {
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)

try {
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
sp = EncryptedSharedPreferences.create(
context,
SHARED_PREFERENCES_NAME,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
} catch (e: Exception) {
val cause: Throwable = e.cause!!
if (cause.message!!.contains("Signature/MAC verification failed")) {
Log.w(TAG, "Master key is corrupted. Recreating the master key")
// Recreate the Master Key
val masterKey = reinitializeMasterKey()

// Recreate EncryptedSharedPreferences
sp = EncryptedSharedPreferences.create(
context,
SHARED_PREFERENCES_NAME,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
} else {
// Handle other exceptions
throw e
}
}
}

private fun reinitializeMasterKey(): MasterKey {
val keyStore = this.createKeyStore()
getSecretKey(keyStore, SHARED_PREFERENCES_NAME)
clearSharedPreference(this.context)
return MasterKey.Builder(context)
.setKeyGenParameterSpec(
KeyGenParameterSpec.Builder(
MasterKey.DEFAULT_MASTER_KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build()
)
.build()
sp = EncryptedSharedPreferences.create(
context,
SHARED_PREFERENCES_NAME,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}

/**
Expand Down

0 comments on commit 638f554

Please sign in to comment.