Created
July 2, 2020 16:19
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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