Я провел некоторое время, анализируя проблему. Я не смог найти истинную причину, но, по крайней мере, я нашел некоторые элементы, поэтому вот они.
Многоэтапная обработка
Сначала вы говорите, что используете размер чанка: 32Kb, но это не совсем так. Вы разделяете строку на куски по 32K c (32768 символов ), а затем конвертируете каждый кусок в байтовый массив. Поскольку представление символа в UTF-8 может варьироваться от 1 до 4 байтов, ваш байтовый массив обычно будет больше , чем 32 КБ (если у вас нет только символов ASCII).
Сначала вы должны преобразуйте строку в байтовый массив, затем разбейте ее на куски по 32 КБ. Только это гарантирует размер буфера, который вы передаете в крипто API.
Ошибка на стороне клиента
Теперь о полученной трассировке стека. Вопреки тому, что кажется на первый взгляд, ошибка возникает не в doFinal()
, а в update()
. Когда вы звоните update()
, вызов делегируется на AndroidKeyStoreCipherSpiBase.engineUpdate()
. Интересная часть:
try {
flushAAD();
output = mMainDataStreamer.update(input, inputOffset, inputLen);
} catch (KeyStoreException e) {
mCachedException = e;
return null;
}
Вызывает mMainDataStreamer.update()
, что приводит к сбою и выбрасывает KeyStoreException
с кодом KM_ERROR_MEMORY_ALLOCATION_FAILED
. Но исключение перехватывается, сохраняется в mCachedException
и возвращается null
. Вот почему вы получаете null
при вызове update()
.
Когда вы звоните doFinal()
, он вызывает AndroidKeyStoreCipherSpiBase.engineDoFinal()
:
protected final byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
if (mCachedException != null) {
throw (IllegalBlockSizeException)
new IllegalBlockSizeException().initCause(mCachedException);
}
Метод видит, что есть кэшированное исключение, и выдает его (обернуто в IllegalBlockSizeException
, что совершенно не связано с реальной проблемой).
Ошибка хранилища ключей
Теперь настоящая проблема. Фактическая работа шифрования / дешифрования выполняется службой Keystore, которая является отдельным процессом, написанным на C ++. Соответствующая часть для AES находится в aes_operation. cpp.
В этом файле возвращено несколько KM_ERROR_MEMORY_ALLOCATION_FAILED
ошибок. Как следует из названия, код означает, что выделение памяти не удалось. Похоже, что по какой-то причине хранилище ключей не смогло выделить буфер. Трудно понять, почему.
Заключение
Поскольку истинная причина загадочна, я бы предложил оставить небольшой размер буфера и , изменяя процедуру разделения, как описано в начале .