Search code examples
androidexceptionandroid-keystore

AEADBadTagException while decrypting my file Android KEystore AES Cipher


I'm trying to Encrypt and Decrypt the String using AES Algorithm and GCM mode.

My code is able to encrypt the string but I'm not able to decrypt the encoded data.

Steps followed :

Create Key()
Encrypt(file with IV)
Decryptfile(encoded data);

Fails with

java.io.IOException: javax.crypto.AEADBadTagException

Please help.

@RequiresApi(api = Build.VERSION_CODES.M)
private static void encrypt(Context context,String content, String fileName,Cipher cipher1)  throws Exception {
   final KeyGenerator keyGenerator = KeyGenerator
            .getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
    final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder("TK",
            KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            .setRandomizedEncryptionRequired(false)
            .build();
    keyGenerator.init(keyGenParameterSpec);
    final SecretKey secretKey= keyGenerator.generateKey();
    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    byte[] iv = new byte[GCM_IV_LENGTH];
    (new SecureRandom()).nextBytes(iv);
    GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
    cipher.init(Cipher.ENCRYPT_MODE, secretKey,ivSpec);
    try (FileOutputStream fileOut = context.openFileOutput(fileName, Context.MODE_PRIVATE);
         CipherOutputStream cipherOut = new CipherOutputStream(fileOut, cipher)) {
        cipherOut.write(iv);
        cipherOut.write(content.getBytes("UTF-8"));
        cipherOut.flush();
    }

}

@RequiresApi(api = Build.VERSION_CODES.M)
private static String decrypt(Context context,String fileName) throws Exception{
    String content;
    try (FileInputStream fileIn = context.openFileInput(fileName)) {
        byte[] fileIv = new byte[12];
        fileIn.read(fileIv);
        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
        keyStore.load(null);
        final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore
                .getEntry("TK", null);
        final SecretKey secretKey = secretKeyEntry.getSecretKey();
        final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        final GCMParameterSpec spec = new GCMParameterSpec(128, fileIv);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
        try (
                CipherInputStream cipherIn = new CipherInputStream(fileIn, cipher);
                InputStreamReader inputReader = new InputStreamReader(cipherIn);
                BufferedReader reader = new BufferedReader(inputReader)
        ) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            content = sb.toString();
        }
    }
    return content;
}

Exception:

java.io.IOException: javax.crypto.AEADBadTagException
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:133)
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:249)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:288)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:351)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:172)
    at java.io.BufferedReader.readLine(BufferedReader.java:335)
    at java.io.BufferedReader.readLine(BufferedReader.java:400)

Solution

  • Found the problem..

    The issue is because the code encrypted the IV as well to start of the file, instead it should have been directly to fileoutputstream and not cipheroutputstream.

    private static void encrypt(Context context,String content, String fileName,Cipher cipher1)  throws Exception {
    ...
    try (FileOutputStream fileOut = context.openFileOutput(fileName, Context.MODE_PRIVATE);
             CipherOutputStream cipherOut = new CipherOutputStream(fileOut, cipher)) {
            fileOut.write(iv); // change is here
            cipherOut.write(content.getBytes("UTF-8"));
            cipherOut.flush();
        }