Android — javax.crypto.AEADBadTagException

В настоящее время я получаю исключение AEADBadTagException при попытке расшифровать зашифрованный файл. Я искал почти везде в stackoverflow и не смог найти решение, и надеюсь, что это просто небольшая ошибка, которую я сделал, или что-то связанное с кодировкой и т. д., поскольку GCM не может проверить тег, который он генерирует.

Я считаю, что проблема где-то в файле, который я пытаюсь зашифровать/расшифровать. Тот же точный код работает с изображением, однако, когда я пытаюсь зашифровать PDF, он терпит неудачу и дает мне указанную выше ошибку.

В приведенном ниже коде не используется CipherOutputStream/CipherInputStream, но я безуспешно пробовал оба варианта.

Я понимаю, что методы шифрования/дешифрования не должны быть написаны таким образом, особенно с жестко закодированными IV, но сейчас я просто пытаюсь заставить его работать, а затем должным образом защитить эти методы позже.

Я использую Android KeyStore, чтобы получить свой секретный ключ. Я знаю, что эта часть работает, так как у меня есть много других частей в приложении, использующих хранилище ключей с теми же методами. Кроме того, этот метод работает с изображением.

Ошибка возникает на cipher.doFinal(encryptedBytes). Когда я использую CipherInputStream, это происходит в CipherInputStream (EncryptedFileStream, cipher)

Вот код, а также стек ошибок, любая помощь приветствуется:

Шифрование

        val fileBytes = inputStream.readBytes()
        val cipher = Cipher.getInstance("AES/GCM/NoPadding")
        keyStoreService.checkKeyAndCreate(ALIAS_FILE_KEY)
        val key = keyStoreService.getFileKey(ALIAS_FILE_KEY)
        val iv = byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
        cipher.init(Cipher.ENCRYPT_MODE, key, GCMParameterSpec(128, iv))
        val encryptedBytes = cipher.doFinal(fileBytes)
        outputStream = FileOutputStream(file)
        outputStream.write(encryptedBytes)
        outputStream.flush()
        inputStream.close()
        outputStream.close()

Расшифровка

    val encryptedFile = File(filePath)
    val encryptedBytes = encryptedFile.readBytes()
    val cipher = Cipher.getInstance("AES/GCM/NoPadding")
    val key = keyStoreService.getFileKey(ALIAS_FILE_KEY)
    val iv = byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    cipher.init(Cipher.DECRYPT_MODE, key, GCMParameterSpec(128, iv))
    val decryptedBytes = cipher.doFinal(encryptedBytes)

    return ByteArrayInputStream(decryptedBytes)

Трассировки стека

E/AndroidRuntime: FATAL EXCEPTION: main
Process: onboard.app.passageways, PID: 15441
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:503)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
 Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
 Caused by: javax.crypto.AEADBadTagException
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:517)
    at javax.crypto.Cipher.doFinal(Cipher.java:2055)
    at passageways.android.onboard.services.EncryptionService.readEncryptedFile(EncryptionService.kt:79)
    at passageways.android.onboard.fragments.MeetingBookDialogFragment.onViewCreated(Fragment.kt:38)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1471)
    at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
    at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
    at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
    at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
    at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:733)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
 Caused by: android.security.KeyStoreException: Signature/MAC verification failed
    at android.security.KeyStore.getKeyStoreException(KeyStore.java:839)
    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)
    at javax.crypto.Cipher.doFinal(Cipher.java:2055) 
    at passageways.android.onboard.services.EncryptionService.readEncryptedFile(EncryptionService.kt:79) 
    at passageways.android.onboard.fragments.MeetingBookDialogFragment.onViewCreated(Fragment.kt:38) 
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1471) 
    at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784) 
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852) 
    at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802) 
    at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625) 
    at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411) 
    at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366) 
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273) 
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:733) 
    at android.os.Handler.handleCallback(Handler.java:873) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:193) 
    at android.app.ActivityThread.main(ActivityThread.java:6669)

person FalseNull    schedule 04.12.2018    source источник
comment
Преобразуйте Base64 перед сохранением. см. это   -  person kelalaka    schedule 05.12.2018
comment
@kelalaka: я вижу, нет причин кодировать base64.   -  person President James K. Polk    schedule 05.12.2018
comment
@kelalaka, я думаю, что Джеймс прав. Я не пытаюсь зашифровать строку, а затем сохранить ее. Я просто хочу зашифровать необработанные байты из файлов. Поскольку он работает с изображениями, я не думаю, что проблема в base64. Мне любопытно, возможно, данные PDF каким-то образом путаются с тегом, который генерируется шифром? Я проверил длину как зашифрованных данных, которые записываются, так и зашифрованных данных, которые читаются при расшифровке, и они имеют одинаковую длину. Завтра проверю, совпадают ли данные.   -  person FalseNull    schedule 05.12.2018


Ответы (1)


Оказывается, readBytes() использует размер буфера по умолчанию и возвращает только байтовый буфер, который соответствует его длине. Так что на самом деле он не возвращал мне весь файл в байтах, только до длины буфера.

Я переключился на использование CipherOutputStream, обязательно включите flush() после того, как ваше содержимое будет включено в тег!

person FalseNull    schedule 05.12.2018