55 lines
2.1 KiB
Kotlin
Raw Normal View History

2026-06-17 16:19:10 +07:00
package com.longnh15.heimdall.common
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
import kotlin.io.encoding.Base64
object TokenCrypto {
private const val PROVIDER = "AndroidKeyStore"
private const val ALIAS = "auth_token_key"
private const val TRANSFORMATION = "AES/GCM/NoPadding"
private const val IV_SIZE = 12
private const val TAG_BITS = 128
private val keystore = KeyStore.getInstance(PROVIDER).apply { load(null) }
private fun getOrCreateKey(): SecretKey {
(keystore.getEntry(ALIAS, null) as? KeyStore.SecretKeyEntry)?.let {
return it.secretKey
}
val keyGen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, PROVIDER)
keyGen.init(
KeyGenParameterSpec.Builder(
ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build()
)
return keyGen.generateKey()
}
fun encrypt(plainText: String): String {
val cipher = Cipher.getInstance(TRANSFORMATION)
cipher.init(Cipher.ENCRYPT_MODE, getOrCreateKey())
val iv = cipher.iv // 12-byte IV, generated by Keystore
val cipherText = cipher.doFinal(plainText.toByteArray(Charsets.UTF_8))
return Base64.encode(iv + cipherText) // prepend IV
}
fun decrypt(encoded: String): String {
val combined = Base64.decode(encoded)
val iv = combined.copyOfRange(0, IV_SIZE)
val cipherText = combined.copyOfRange(IV_SIZE, combined.size)
val cipher = Cipher.getInstance(TRANSFORMATION)
cipher.init(Cipher.DECRYPT_MODE, getOrCreateKey(), GCMParameterSpec(TAG_BITS, iv))
return cipher.doFinal(cipherText).toString(Charsets.UTF_8)
}
}