Skip to content

Instantly share code, notes, and snippets.

@alfonsogoberjr
Created July 2, 2020 16:19
Show Gist options
  • Save alfonsogoberjr/424b4891c7817295a34db0581b635fc3 to your computer and use it in GitHub Desktop.
Save alfonsogoberjr/424b4891c7817295a34db0581b635fc3 to your computer and use it in GitHub Desktop.
KeyStoreManager - a Kotlin class for runtime encryption/decryption of secrets and storage within KeyStore
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.io.IOException
import java.security.*
import java.security.cert.CertificateException
import javax.crypto.*
import javax.crypto.spec.GCMParameterSpec
class KeyStoreManager {
private val transformation = "AES/GCM/NoPadding"
private val androidKeyStore = "AndroidKeyStore"
private var encryption: ByteArray? = null
private var iv: ByteArray? = null
private var keyStore: KeyStore? = null
init {
initKeyStore()
}
@Throws(
KeyStoreException::class,
CertificateException::class,
NoSuchAlgorithmException::class,
IOException::class
)
private fun initKeyStore() {
keyStore = KeyStore.getInstance(androidKeyStore)
keyStore?.load(null)
}
@Throws(
UnrecoverableEntryException::class,
NoSuchAlgorithmException::class,
KeyStoreException::class,
NoSuchProviderException::class,
NoSuchPaddingException::class,
InvalidKeyException::class,
IOException::class,
BadPaddingException::class,
IllegalBlockSizeException::class,
InvalidAlgorithmParameterException::class
)
fun decryptData(
alias: String,
encryptedData: ByteArray?,
encryptionIv: ByteArray?
): String? {
val cipher: Cipher = Cipher.getInstance(transformation)
val spec = GCMParameterSpec(128, encryptionIv)
cipher.init(Cipher.DECRYPT_MODE, getKeyStoreSecretKey(alias), spec)
return String(cipher.doFinal(encryptedData), Charsets.UTF_8)
}
@Throws(
NoSuchAlgorithmException::class,
UnrecoverableEntryException::class,
KeyStoreException::class
)
private fun getKeyStoreSecretKey(alias: String): SecretKey? {
return (keyStore?.getEntry(alias, null) as KeyStore.SecretKeyEntry).secretKey
}
@Throws(
UnrecoverableEntryException::class,
NoSuchAlgorithmException::class,
KeyStoreException::class,
NoSuchProviderException::class,
NoSuchPaddingException::class,
InvalidKeyException::class,
IOException::class,
InvalidAlgorithmParameterException::class,
SignatureException::class,
BadPaddingException::class,
IllegalBlockSizeException::class
)
fun encryptText(alias: String, textToEncrypt: String): ByteArray? {
val cipher = Cipher.getInstance(transformation)
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(alias))
iv = cipher.iv
return cipher.doFinal(textToEncrypt.toByteArray(charset("UTF-8")))
.also { encryption = it }
}
@Throws(
NoSuchAlgorithmException::class,
NoSuchProviderException::class,
InvalidAlgorithmParameterException::class
)
private fun getSecretKey(alias: String): SecretKey {
val keyGenerator: 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()
}
fun getEncryption(): ByteArray? {
return encryption
}
fun getIv(): ByteArray? {
return iv
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment