Skip to content
Snippets Groups Projects
Commit bdbcbbe5 authored by Taras's avatar Taras
Browse files

Keys store+preferences key saving

parent 96faae3c
No related branches found
No related tags found
No related merge requests found
package org.futo.circles.core.provider
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64
import org.matrix.android.sdk.api.extensions.tryOrNull
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.SecretKeySpec
import javax.crypto.spec.GCMParameterSpec
import javax.inject.Inject
class KeyStoreProvider @Inject constructor() {
private val keyStore = KeyStore.getInstance("AndroidKeyStore")
class KeyStoreProvider @Inject constructor(
private val preferencesProvider: PreferencesProvider
) {
private val keyStore
get() = KeyStore.getInstance(ANDROID_KEYS_TORE).apply { load(null) }
fun storeBsSpekePrivateKey(keyBytes: ByteArray, keyId: String) {
storeKey(keyBytes, "$ORG_FUTO_SSSS_KEY_PREFIX.$keyId")
tryOrNull {
val alias = "$ORG_FUTO_SSSS_KEY_PREFIX.$keyId"
val masterKey = getOrGenerateMasterKeyIfNotExist(alias)
?: throw IllegalArgumentException("Failed to get master key")
val encrypted = encryptData(keyBytes, masterKey)
preferencesProvider.storeBSspekeEncryptedPrivateKeyBase64(alias, encrypted)
}
}
fun getBsSpekePrivateKey(keyId: String): ByteArray? = getKey("$ORG_FUTO_SSSS_KEY_PREFIX.$keyId")
fun getBsSpekePrivateKey(keyId: String): ByteArray? = tryOrNull {
val alias = "$ORG_FUTO_SSSS_KEY_PREFIX.$keyId"
val masterKey = getOrGenerateMasterKeyIfNotExist(alias)
?: throw IllegalArgumentException("Failed to get master key")
val encrypted = preferencesProvider.getBSspekeEncryptedPrivateKeyBase64(alias)
?: throw IllegalArgumentException("Not saved in preferences $alias")
decryptData(encrypted, masterKey)
}
private fun storeKey(keyBytes: ByteArray, alias: String) = tryOrNull {
val secretKey: SecretKey = SecretKeySpec(keyBytes, "AES")
keyStore.load(null)
val protectionParameter = KeyStore.PasswordProtection(null)
val secretKeyEntry = KeyStore.SecretKeyEntry(secretKey)
keyStore.setEntry(alias, secretKeyEntry, protectionParameter)
private fun getOrGenerateMasterKeyIfNotExist(alias: String): SecretKey? {
if (!keyStore.containsAlias(alias)) {
KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYS_TORE).apply {
init(
KeyGenParameterSpec.Builder(
alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setKeySize(KEY_SIZE)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
)
generateKey()
}
}
return keyStore.getKey(alias, null) as? SecretKey
}
private fun encryptData(data: ByteArray, masterKey: SecretKey): String {
val cipher = Cipher.getInstance(AES_NO_PADDING)
cipher.init(Cipher.ENCRYPT_MODE, masterKey)
val ivString = Base64.encodeToString(cipher.iv, Base64.DEFAULT)
val encryptedBytes: ByteArray = cipher.doFinal(data)
return ivString + IV_SEPARATOR + Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
}
private fun getKey(alias: String): ByteArray? = tryOrNull {
keyStore.load(null)
val secretKey = keyStore.getKey(alias, null) as SecretKey
secretKey.encoded
private fun decryptData(encryptedData: String, masterKey: SecretKey): ByteArray {
val (iv64, encrypted64) = encryptedData.split(IV_SEPARATOR)
val cipher = Cipher.getInstance(AES_NO_PADDING)
val spec = GCMParameterSpec(KEY_SIZE, Base64.decode(iv64, Base64.DEFAULT))
cipher.init(Cipher.DECRYPT_MODE, masterKey, spec)
return cipher.doFinal(Base64.decode(encrypted64, Base64.DEFAULT))
}
companion object {
private const val AES_NO_PADDING = "AES/GCM/NoPadding"
private const val IV_SEPARATOR = "]"
private const val KEY_SIZE = 128
private const val ANDROID_KEYS_TORE = "AndroidKeyStore"
private const val ORG_FUTO_SSSS_KEY_PREFIX = "org.futo.ssss.key"
}
}
......@@ -95,6 +95,15 @@ class PreferencesProvider @Inject constructor(
getSharedPreferences().edit(true) { putStringSet(NOT_RESTORED_SESSION, set) }
}
fun getBSspekeEncryptedPrivateKeyBase64(alias: String): String? {
return getSharedPreferences().getString(alias, null)
}
fun storeBSspekeEncryptedPrivateKeyBase64(alias: String, key: String) {
getSharedPreferences().edit { putString(alias, key) }
}
companion object {
private const val PREFERENCES_NAME = "circles_preferences"
private const val DEV_MODE_KEY = "developer_mode"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment