Ошибка расшифровки файла, зашифрованного с помощью EncryptedFile на Android - PullRequest
1 голос
/ 20 февраля 2020

Я шифрую файл, созданный в приложении android, в службе Bluetooth. Позже в другом классе я хочу расшифровать этот файл и загрузить его на сервер.

Для шифрования я использую библиотеку AndroidX androidx.security:security-crypto:1.0.0-alpha02, которая является оберткой вокруг Дзынь. Я прочитал все документы и руководства для разработчиков по EncryptedFile, EncryptedFile.Builder и т. Д.

Я шифрую файл следующим образом:

String keySetAlias = "BilboBaggins";
String keySetPref = "Hobbits";

EncryptedFile m_StudyChannelEncryptedFile = new EncryptedFile.Builder(
    filePath,
    getApplicationContext(),
    masterKeyAlias,
   EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).setKeysetAlias(keySetAlias).setKeysetPrefName(keySetPref).build();
m_output = m_StudyChannelEncryptedFile.openFileOutput();

Отсюда я могу написать в файл, как в обычном FileOutputStream, и, глядя на данные, записанные в памяти телефона, я могу подтвердить, что они зашифрованы.

Перед загрузкой я пытаюсь сделать то же самое в другом классе и затем расшифруйте его.

String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
String keySetAlias = "BilboBaggins";
String keySetPref = "Hobbits";

EncryptedFile encryptedFile = new EncryptedFile.Builder(
  filePath,
  getApplicationContext(),
  masterKeyAlias,
  EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB).setKeysetAlias(keySetAlias).setKeysetPrefName(keySetPref).build();
// Read channel data file  
FileInputStream fChannel = encryptedFile.openFileInput();
m_Dat1Size = fChannel.available();

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

Я считаю, что, предоставив ему местоположение keySetAlias, keySetPref конструктор EncryptedFile должен иметь возможность инициализировать экземпляр EncryptedFile с правильными ключами.

Буду признателен за любую помощь или понимание!

Спасибо, Майкл

Ответы [ 2 ]

0 голосов
/ 20 февраля 2020

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

class AESEncryptDecrypt private constructor() {
private val secretKey: SecretKey
private val iV: AlgorithmParameterSpec

init {
    this.secretKey = createAESKey(randomString()) as SecretKey
    this.iV = IvParameterSpec(AES_IV.toByteArray())
}

/**
 * Encrypt File
 * @param file : File to Encrypt
 */
fun encryptFile(file: File): ByteArray {
    var cipher: Cipher? = null
    try {
        cipher = Cipher.getInstance(AES_TRANSFORMATION)
        cipher!!.init(Cipher.ENCRYPT_MODE, secretKey, iV)
    } catch (e: NoSuchAlgorithmException) {
        e.printStackTrace()
    } catch (e: NoSuchPaddingException) {
        e.printStackTrace()
    } catch (e: InvalidAlgorithmParameterException) {
        e.printStackTrace()
    } catch (e: InvalidKeyException) {
        e.printStackTrace()
    }
    return cipher!!.doFinal(file.readBytes())
}

/**
 * Encrypt Bytes
 * @param byteArray : Plain Bytes to Encrypted Bytes
 */
fun encryptBytes(byteArray: ByteArray): ByteArray {
    var cipher: Cipher? = null
    try {
        cipher = Cipher.getInstance(AES_TRANSFORMATION)
        cipher!!.init(Cipher.ENCRYPT_MODE, secretKey, iV)
    } catch (e: NoSuchAlgorithmException) {
        e.printStackTrace()
    } catch (e: NoSuchPaddingException) {
        e.printStackTrace()
    } catch (e: InvalidAlgorithmParameterException) {
        e.printStackTrace()
    } catch (e: InvalidKeyException) {
        e.printStackTrace()
    }
    return cipher!!.doFinal(byteArray)
}

/**
 * Decrypt File
 * @param file : File to Decrypt
 */
fun decryptFile(file: File): ByteArray {
    var cipher: Cipher? = null
    try {
        cipher = Cipher.getInstance(AES_TRANSFORMATION)
        cipher!!.init(Cipher.DECRYPT_MODE, secretKey, iV)
    } catch (e: NoSuchAlgorithmException) {
        e.printStackTrace()
    } catch (e: NoSuchPaddingException) {
        e.printStackTrace()
    } catch (e: InvalidAlgorithmParameterException) {
        e.printStackTrace()
    } catch (e: InvalidKeyException) {
        e.printStackTrace()
    }
    return cipher!!.doFinal(file.readBytes())
}


companion object {

    private var INSTANCE: AESEncryptDecrypt? = null

    fun getInstance() =
        INSTANCE ?: synchronized(AESEncryptDecrypt::class.java) {
            INSTANCE ?: AESEncryptDecrypt()
                .also { INSTANCE = it }
        }

    private fun createAESKey(keyValue: String): Key {
        if (keyValue.length != AES_RANDOM_STRING_LENGTH)
            try {
                throw Exception("Key must be exactly 16 characters")
            } catch (e: Exception) {
                e.printStackTrace()
            }
        return SecretKeySpec(keyValue.toByteArray(), AES_TRANSFORMATION)
    }

    private fun randomString(): String {
        return "ABCDE12345ABCDE1"
    }
}
}

Значения констант указаны ниже

const val AES_IV = "abcaqwerabcaqwer"
const val AES_TRANSFORMATION = "AES/CBC/PKCS7Padding"
const val AES_RANDOM_STRING = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$"
const val AES_RANDOM_STRING_LENGTH = 16

Я использовал для шифрования и дешифрования файлов изображений. Сначала файл хранится в незашифрованном виде, а затем я использовал функцию

Для шифрования: FileUtils.writeByteArrayToFile (file, AESEncryptDecrypt.getInstance (). EncryptBytes (byteArray))

AESEncryptDancery ( .encryptBytes (byteArray) сделал мой файл зашифрованным во-вторых, FileUtils.writeByteArrayToFile - это функция, из которой я перезаписываю свой файл и делаю его зашифрованным.

Для расшифровки:

val file: File? = getFile()
FileUtils.writeByteArrayToFile(
                        file, AESEncryptDecrypt.getInstance().decryptFile(file)
                    )

Примечание: FileUtils.writeByteArrayToFile используется из зависимости, как упомянуто ниже: (Во-вторых, эта функция из зависимости, как упомянуто.)

implementation 'org.apache.commons:commons-lang3:3.7'
0 голосов
/ 20 февраля 2020

Для InputStream экземпляров нельзя полагаться на возвращаемое значение available для возврата общего количества байтов, которое можно прочитать:

Возвращает оценку из количество оставшихся байтов, которые могут быть прочитаны (или пропущены) из этого входного потока без блокировки при следующем вызове метода для этого входного потока.

Для файлов в одной и той же системе имеет смысл, что это всегда количество байтов, «оставленных» до конца файла. Однако для других потоков available - это в основном подсказка о том, сколько байтов вы должны запросить. Для дешифрования available() может просто вернуть количество байтов, которые уже доступны после дешифрования. Вполне возможно, что зашифрованный текст расшифровывается только по запросу и поэтому возвращает 0.


Для определенных c шифров также может быть сложно определить, достигнут ли конец потока из-за на открытый текст, требующий распаковку (ECB / CB C) или проверку и удаление тега аутентификации (GCM). Это может усложнить расчет available. Реализация API может просто решить просто вернуть 0 всегда (что означает, что вызов read может всегда блокировать ).

...