I'm trying to encrypt a simple string using AES encryption.
Currently I'm generating a secrect key using KeyGenerator
and I'm generating a random IV with 16 bytes using Secure Random
The problem is, when I run this code:
@RequiresApi(Build.VERSION_CODES.M)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val random = SecureRandom()
val iv = ByteArray(12)
random.nextBytes(iv)
aesKeystoreAESWrapper = AES_WRAPPER()
aesKeystoreAESWrapper.createSymmetricKey()
val teste = aesKeystoreAESWrapper.encrypt("OLA MALTA", iv)
val result = aesKeystoreAESWrapper.decrypt(teste, iv)
ola.text = result
}
I get a RunTime Execption: javax.crypto.AEADBadTagException
I can't figure out where the problem is, I tried to search in multiple websites but I couldn't find the awnser.
This is my AES code:
class AES_WRAPPER {
fun ByteArray.fromBytetoString() = String(this,Charsets.UTF_8)
companion object{
const val AES_NOPAD_TRANS = "AES/GCM/NoPadding" //Format - ”Algorithm/Mode/Padding”
const val ANDROID_KEYSTORE = "AndroidKeyStore"
const val KEY_ALIAS = "Keyalaisasf"
}
private fun createKeyStore(): KeyStore {
val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE)
keyStore.load(null)
return keyStore
}
@RequiresApi(23)
fun createSymmetricKey() : SecretKey {
try{
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE)
val keyGenParameterSpec = KeyGenParameterSpec.Builder(
KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(false)
.build()
keyGenerator.init(keyGenParameterSpec)
return keyGenerator.generateKey()
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException("Failed to create a symmetric key", e)
} catch (e: NoSuchProviderException) {
throw RuntimeException("Failed to create a symmetric key", e)
} catch (e: InvalidAlgorithmParameterException) {
throw RuntimeException("Failed to create a symmetric key", e)
}
}
fun encrypt(data: String, initVector: ByteArray) : ByteArray{
val iv = GCMParameterSpec(128, initVector)
val cipher = Cipher.getInstance(AES_NOPAD_TRANS)
cipher.init(Cipher.ENCRYPT_MODE, getSymmetricKey(), iv)
val encrypted = cipher.doFinal(data.toByteArray())
return encrypted
}
fun decrypt(data: ByteArray, initVector: ByteArray) : String{
val iv = GCMParameterSpec(128, initVector)
val cipher = Cipher.getInstance(AES_NOPAD_TRANS)
cipher.init(Cipher.DECRYPT_MODE, getSymmetricKey(), iv)
val decrypted = cipher.doFinal(data)
return decrypted.fromBytetoString()
}
@SuppressLint("NewApi")
fun getSymmetricKey(): SecretKey {
/*val keysore = keyStore.getEntry(KEY_ALIAS, null) as KeyStore.SecretKeyEntry
return keysore.secretKey*/
val keyStore = createKeyStore()
if(!isKeyExists(keyStore)){
createSymmetricKey()
}
return keyStore.getKey(KEY_ALIAS,null) as SecretKey
}
fun isKeyExists(keyStore : KeyStore): Boolean {
val aliases = keyStore.aliases()
while (aliases.hasMoreElements()) {
return (KEY_ALIAS == aliases.nextElement())
}
return false
}
}
UPDATE, LOGCAT:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: io.github.andre00nogueira.myapplication, PID: 10135
java.lang.RuntimeException: Unable to start activity ComponentInfo{io.github.andre00nogueira.myapplication/io.github.andre00nogueira.myapplication.MainActivity}: javax.crypto.AEADBadTagException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: javax.crypto.AEADBadTagException
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:517)
at javax.crypto.Cipher.doFinal(Cipher.java:2055)
at io.github.andre00nogueira.myapplication.WRAPPER.decrypt(WRAPPER.kt:73)
at io.github.andre00nogueira.myapplication.MainActivity.onCreate(MainActivity.kt:29)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: android.security.KeyStoreException: Signature/MAC verification failed
at android.security.KeyStore.getKeyStoreException(KeyStore.java:1292)
at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:224)
at android.security.keystore.AndroidKeyStoreAuthenticatedAESCipherSpi$BufferAllOutputUntilDoFinalStreamer.doFinal(AndroidKeyStoreAuthenticatedAESCipherSpi.java:373)
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)
The problem is caused by the isKeyExists()
function, which should check if KEY_ALIAS
is contained in the keystore. However, the current implementation only checks the first alias found by aliases.nextElement()
against KEY_ALIAS
and returns with this result. Therefore this function only works reliably if there is exactly one alias in the keystore. With more than one alias this leads to a false negative result if KEY_ALIAS
is in the keystore but not found as first by aliases.nextElement()
. As a consequence, different keys are created for encryption and decryption, which raises the AEADBadTagException during decryption.
The problem can be solved if in isKeyExists()
the return statement in the while loop is replaced by
if (KEY_ALIAS == aliases.nextElement()) return true
or alternatively, as suggested in Michael's comment, if isKeyExists(keyStore)
is replaced by keyStore.containsAlias(KEY_ALIAS)
in getSymmetricKey()
.