2012-03-15 13 views
16

Sé cómo AES encriptar y descifrar un NSData, pero eso requiere cargar primero todo el archivo en la memoria.IOS: ¿cómo descifro AES un archivo grande si el archivo es demasiado grande para cargarlo todo en la memoria?

Digamos que tengo un archivo cifrado de 50mb llamado data.dat.enc, ¿cómo puedo descifrarlo en un archivo data.dat sin tener que cargarlo primero en la memoria?

+0

¿Por qué no dividir los datos antes de encriptarlos, luego desencriptarlos y volver a armarlos? –

+0

@PRNDLDevelopmentStudios Sí, supongo que haré eso si es necesario, pero tengo varios archivos grandes, y sería más difícil administrar un montón de archivos divididos. – Kyle

+0

Puede intentar comprimir los datos antes del cifrado, pero no sé si la relación de compresión sería lo suficientemente alta como para importar realmente. ¿Tal vez abrir una conexión SSL a un servidor, cargar los datos cifrados, descifrar el servidor y enviar de vuelta? –

Respuesta

15

EDITAR: Este código ha sido desarrollado por http://github.com/rnapier/RNCryptor.


RNCryptManager es un buen ejemplo de cómo hacer esto. Viene del código de ejemplo del Capítulo 11 de iOS5:PTL. Mira:

+ (BOOL)decryptFromStream:(NSInputStream *)fromStream 
       toStream:(NSOutputStream *)toStream 
       password:(NSString *)password 
        error:(NSError **)error; 

Se supone que la sal y IV se han colocado al comienzo de la corriente (todo esto se explica en el libro). Para una discusión más general sobre encriptación AES, vea Properly encrypting with AES with CommonCrypto.

Para ver un ejemplo de su uso, consulte CPCryptController.m en el mismo proyecto.

Si hay suficiente interés, podría sacar este objeto y apoyarlo como un proyecto independiente en lugar de solo como un código de muestra. Parece razonablemente útil para las personas. Pero no es tan difícil de integrar tal como está.

La respuesta más general es que crea un cryptor con CCCryptorCreate y luego realiza llamadas a CCCryptorUpdate para cada bloque. Luego, llama al CCCryptorFinal para finalizar todo.

+0

+1 No puedo culpar a esa respuesta. Podría haber adivinado que habría una función de actualización en alguna parte de alguna manera. –

+0

Acabo de terminar de probarlo. ¡Muchas gracias! Funciona perfectamente :) – Kyle

+0

@Rob En mis pruebas, he descubierto que descifrar un archivo cifrado con la contraseña incorrecta a veces puede devolver 'verdadero' desde esta función (aproximadamente el 0,5% del tiempo). El archivo "descifrado" resultante no está realmente descifrado, solo son datos basura, pero la función aún devuelve 'true'. ¿Es esto un comportamiento intencional? Si es así, ¿cómo puedo detectar si el descifrado fue realmente exitoso? – Kyle

0

tiene dos opciones (y aquí sólo describen el proceso de cifrado, pero descifrado es similar):

Utilice un cifrado de flujo (como AES-CTR)

inicializar el sistema de cifrado con una 16 byte key y verdaderamente aleatorio de 16 bytes nonce, escriba el nonce, cargue la primera pieza, encripte, escriba el resultado, cargue una segunda pieza y así sucesivamente. Tenga en cuenta que debe inicializar el cifrado solo una vez. El tamaño de la pieza puede ser arbitrario; ni siquiera necesita ser el mismo cada vez.

utilizar un cifrado de bloques con un modo de encadenamiento de una sola pasada, por ejemplo AES128-CBC

Usted inicializar el sistema de cifrado con la clave de 16 bytes, generar un azar de 16 bytes IV, escribir el IV, escriba el total longitud del archivo, cargue la primera pieza, encripte junto con IV, escriba el resultado, cargue una segunda pieza, cifre usando los últimos 16 bytes del bloque cifrado anterior como IV, escriba el resultado, y así sucesivamente. El tamaño de la pieza debe ser un múltiplo de 16 bytes; nuevamente, ni siquiera necesita ser el mismo cada vez. Es posible que deba rellenar el último bloque con ceros.

En ambos casos

Debe calcular el hash criptográfica del archivo original sin cifrar (por ejemplo, usando SHA-256) y escribirlo una vez finalizada la encriptación. Eso es bastante fácil: inicializa el hash desde el principio y alimenta cada bloque tan pronto como se carga (incluido nonce/IV y posiblemente el campo de longitud). En el lado de descifrado, haces lo mismo. Eventualmente, debe verificar que el compendio calculado coincida con el que vino con el archivo cifrado.

¿Cómo se puede hacer eso en iOS? Me temo que no estoy familiarizado con la plataforma, pero CCCypt parece ajustarse a la factura.

EDITAR: nonce/IV y longitud son hash también.

+3

Antes que nada, hay muchos problemas con el uso de RC4, lea la página de wikipedia. RC4 no usa un IV, aunque algunas implementaciones pueden llamar a un elemento un IV. El segundo párrafo, usando AES128-CBC es absolutamente bueno como solución, excepto por el relleno con cero. Solo calcular un hash sobre el texto plano no es una buena idea, aunque solo sea porque se filtraría información sobre dicho texto sin formato (cifrar el mismo texto sin formato dos veces y comparar los resultados, para nombrar un problema). –

+0

Si publica su solución CBC como una respuesta por separado, proponga usar el relleno PKCS # 7 en lugar de relleno cero. Estaré encantado de votarlo. Este es rechazado debido a los muchos errores adicionales. –

+0

Tenga en cuenta que el código original del OP casi seguramente usa CBC. Es el predeterminado en las bibliotecas de iOS. Casi nunca hay una razón para usar EBC (el otro modo), independientemente de si está encriptando/descifrando todos a la vez o "mientras avanza". El relleno PKCS # 7 también es el único relleno admitido por las bibliotecas de iOS, por lo que es probable que ya esté en uso también (a menos que la carga útil no requiera relleno). –

Cuestiones relacionadas