I am trying to write a couple functions that can encrypt and decrypt text using AES/GCM encryption in conjunction with PBKDF2 key generation. I am transitioning my code from CTR (SIC) encryption, and the MAC check failure is killing me when all else is working.
fun encryptAESBasic(input: String, password: String): String {
val masterpw = getKey(password)
val random = SecureRandom()
val salt = ByteArray(16)
random.nextBytes(salt)
val factory: SecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
val spec: KeySpec = PBEKeySpec(masterpw.toString().toCharArray(), salt, 100, 256)
val tmp: SecretKey = factory.generateSecret(spec)
val cipher = Cipher.getInstance("AES/CTR/NoPadding")
val iv = ByteArray(16)
SecureRandom().nextBytes(iv)
cipher.init(Cipher.ENCRYPT_MODE, tmp, IvParameterSpec(iv))
val cipherText: ByteArray = cipher.doFinal(input.toByteArray(Charset.forName("UTF-8")))
val ivstring: String = Base64.encodeToString(iv, Base64.NO_WRAP)
val saltystring: String = Base64.encodeToString(salt, Base64.NO_WRAP)
val cipherstring: String = Base64.encodeToString(cipherText, Base64.NO_WRAP)
val returnstring: String = ivstring + "-" + saltystring + "-" + cipherstring
return returnstring
}
fun decryptAESBasic(text: String, password: String): String {
val arr = text.split("-")
val iv = Base64.decode(arr[0].toByteArray(Charset.forName("UTF-8")), Base64.NO_WRAP)
val salt = Base64.decode(arr[1].toByteArray(Charset.forName("UTF-8")), Base64.NO_WRAP)
val data = arr[2].toByteArray(Charset.forName("UTF-8"))
val masterpw = getKey(password)
val factory: SecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
val spec: KeySpec = PBEKeySpec(masterpw.toString().toCharArray(), salt, 100, 256)
val tmp: SecretKey = factory.generateSecret(spec)
val key: ByteArray = tmp.getEncoded()
val cipher = Cipher.getInstance("AES/CTR/NoPadding")
cipher.init(Cipher.DECRYPT_MODE, tmp, IvParameterSpec(iv))
val credential: ByteArray = cipher.doFinal(Base64.decode(data, Base64.NO_WRAP))
return credential.toString(Charset.forName("UTF-8"))
}
fun getKey(masterPass: String): ByteArray {
return masterPass.padEnd(32, '.').toByteArray(Charset.forName("UTF-8"))
}
Again, this code works, but I would like to change it from CTR to GCM but every time that I do I am met with a "mac check in GCM failed" error. Any help explaining how/why this is happening would be tremendously appreciated.
E/AndroidRuntime( 6461): Caused by: javax.crypto.AEADBadTagException: mac check in GCM failed
E/AndroidRuntime( 6461): at java.lang.reflect.Constructor.newInstance0(Native Method)
E/AndroidRuntime( 6461): at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
E/AndroidRuntime( 6461): at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(BaseBlockCipher.java:1485)
E/AndroidRuntime( 6461): at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:1217)
E/AndroidRuntime( 6461): at javax.crypto.Cipher.doFinal(Cipher.java:2055)
E/AndroidRuntime( 6461): at design.codeux.autofill_service.FlutterMyAutofillServiceKt.decryptAESBasic(FlutterMyAutofillService.kt:1003)