package com.bitcointxoko.gudariwallet.security 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 android.util.Base64 object SecretManager { private const val KEY_ALIAS = "lnbits_api_key" private const val KEYSTORE_PROVIDER = "AndroidKeyStore" private const val TRANSFORMATION = "AES/GCM/NoPadding" private const val GCM_TAG_LENGTH = 128 /** Generate (or retrieve) the AES key in the Keystore */ private fun getOrCreateKey(): SecretKey { val keyStore = KeyStore.getInstance(KEYSTORE_PROVIDER).apply { load(null) } keyStore.getKey(KEY_ALIAS, null)?.let { return it as SecretKey } val keyGen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER) keyGen.init( KeyGenParameterSpec.Builder( KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) // Require device lock screen to be set up .setUserAuthenticationRequired(false) .build() ) return keyGen.generateKey() } /** Encrypt a plaintext string; returns Base64(IV + ciphertext) */ fun encrypt(plaintext: String): String { val cipher = Cipher.getInstance(TRANSFORMATION) cipher.init(Cipher.ENCRYPT_MODE, getOrCreateKey()) val iv = cipher.iv val ciphertext = cipher.doFinal(plaintext.toByteArray(Charsets.UTF_8)) val combined = iv + ciphertext return Base64.encodeToString(combined, Base64.DEFAULT) } /** Decrypt a Base64(IV + ciphertext) string */ fun decrypt(encoded: String): String { val combined = Base64.decode(encoded, Base64.DEFAULT) val iv = combined.copyOfRange(0, 12) val ciphertext = combined.copyOfRange(12, combined.size) val cipher = Cipher.getInstance(TRANSFORMATION) cipher.init(Cipher.DECRYPT_MODE, getOrCreateKey(), GCMParameterSpec(GCM_TAG_LENGTH, iv)) return String(cipher.doFinal(ciphertext), Charsets.UTF_8) } }