解密我的文件时出现 AEADBadTagException Android KEystore AES 密码

AEADBadTagException while decrypting my file Android KEystore AES Cipher

我正在尝试使用 AES 算法和 GCM 模式加密和解密字符串。

我的代码能够加密字符串,但我无法解密编码数据。

遵循的步骤:

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

失败

java.io.IOException: javax.crypto.AEADBadTagException

请帮忙。

@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;
}

异常:

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)

找到问题..

问题是因为代码也将 IV 加密到文件的开头,而不是它应该直接到 fileoutputstream 而不是 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();
    }