IOS. Как AES расшифровывать большой файл, если файл слишком велик, чтобы загрузить его все в память?
Я знаю, как AES шифрует и расшифровывает NSData
, но для этого требуется сначала загрузить весь файл в память.
Скажем, у меня есть зашифрованный файл размером 50 МБ под названием data.dat.enc
, как я могу его дешифровать в файл data.dat
без необходимости сначала загружать его все в память?
Ответы
Ответ 1
EDIT: этот код был расширен http://github.com/rnapier/RNCryptor.
RNCryptManager - хороший пример того, как это сделать. Он исходит из примера кода главы 11 iOS5: PTL. Посмотрите:
+ (BOOL)decryptFromStream:(NSInputStream *)fromStream
toStream:(NSOutputStream *)toStream
password:(NSString *)password
error:(NSError **)error;
Предполагается, что соль и IV были добавлены к потоку (все это объяснено в книге). Для более общей дискуссии о шифровании AES см. Правильное шифрование с помощью AES с помощью CommonCrypto.
Пример его использования см. в CPCryptController.m в том же проекте.
Если есть достаточный интерес, я мог бы вытащить этот объект и поддержать его как автономный проект, а не как образец кода образца. Это кажется разумно полезным для людей. Но это не так сложно интегрировать как есть.
Более общий ответ заключается в том, что вы создаете криптор с CCCryptorCreate
, а затем делаете вызовы CCCryptorUpdate
для каждого блока. Затем вы вызываете CCCryptorFinal
, чтобы закончить работу.
Ответ 2
У вас есть два варианта (и здесь я описываю только процесс шифрования, но дешифрование аналогично):
Использовать потоковый шифр (например, AES-CTR)
Вы инициализируете шифр с 16-байтовым ключом и по-настоящему случайным 16-байтным nonce, записываете nonce, загружаете первую часть, шифруете ее, записываете результат, загружаете вторую часть и так далее.
Обратите внимание, что вы должны инициализировать шифр только один раз. Размер куска может быть произвольным;
это даже не обязательно должно быть одинаковым каждый раз.
Используйте блок-шифр с режимом цепочки с одним проходом, например AES128-CBC
Вы инициализируете шифр с 16-байтовым ключом, генерируете случайный 16-байтовый IV, записываете IV, записываете общую длину файла, загружаете первую часть, шифруете ее вместе с IV, записываете результат, загружаете второй фрагмент, зашифруйте с использованием последних 16 байтов предыдущего зашифрованного блока как IV, запишите результат и т.д. Размер фрагмента должен быть кратным 16 байтам; опять же, это не обязательно должно быть одинаковым каждый раз. Возможно, вам понадобится заполнить последний блок нулями.
В обоих случаях
Вы должны вычислить криптографический хеш исходного незашифрованного файла (например, используя SHA-256) и записать его, когда шифрование завершено. Это довольно просто: вы инициализируете хеш в самом начале и загружаете каждый блок в него, как только он загружается (в том числе nonce/IV и, возможно, поле длины). На стороне расшифровки вы делаете то же самое. В конце концов, вы должны убедиться, что вычисленный дайджест соответствует тому, который пришел с зашифрованным файлом.
Как это можно сделать на iOS? Я боюсь, что я не знаком с платформой, но CCCypt, похоже, соответствует счету.
EDIT: nonce/IV и длина также хэшируются.