TCP / IP: ¿Cuál es la forma correcta de transferir datos? Comprimir los datos cifrados o cifrar los datos comprimidos?

Si los datos que está transportando son principalmente de naturaleza textual, comprima primero . Si los datos son aleatorios (p. Ej., Imágenes), simplemente no comprima. No hay ninguna situación en la que deba comprimir después del cifrado.

Para entender por qué, primero considere que la compresión es efectivamente el proceso de encontrar patrones en sus datos y representarlos de forma abreviada. Además, tenga en cuenta que (la mayoría) las cifras producen datos aleatorios efectivos. La posibilidad de encontrar patrones sustanciales es bastante baja.

¿No convencido? Probemos con algunos datos. Aquí hay un guión rápido de ruby ​​para jugar. Supongo que AES es el cifrado preferido, y zlib para la compresión:

require 'open-uri' require 'openssl' require 'zlib' def encrypt(data) cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc') cipher.encrypt cipher.random_key cipher.random_iv result = cipher.update data result + cipher.final end def compare(data) compressed_first = encrypt(Zlib::Deflate.deflate(data)) encrypted_first = Zlib::Deflate.deflate(encrypt(data)) # compression first %, encryption first % [compressed_first.size.to_f / data.size.to_f, encrypted_first.size.to_f / data.size.to_f] end def analyze(results) c_first_sum, s_first_sum = results.reduce([0.0, 0.0]) { |m,p| [m[0] + p[0], m[1] + p[1]] } [c_first_sum / results.size, s_first_sum / results.size] end 

Primero, datos textuales fácilmente comprimibles (páginas de wikipedia aleatorias):

 > analyze 100.times.map { compare(open('http://en.wikipedia.org/wiki/Special:Random').read) } [0.2731796088382172, 1.0026829439942453] 

En esencia, al comprimir primero, la carga útil resultante es un 27% del tamaño de la fuente original de datos textuales / web. Sin embargo, cuando se cifra primero, la carga útil es ligeramente mayor que los datos de entrada.

Tenga en cuenta que cuando va al otro extremo de datos en su mayoría aleatorios (como una imagen o datos cifrados), la compresión termina aumentando el tamaño de la salida. Esto es lo que podemos ver desde el segundo valor.

Hay dos razones para comprimir antes de cifrar.

1) Cuando comprime, aumenta la densidad de entropía, es decir, reduce las “redundancias” que pueden usarse para intentar descifrar los datos. En teoría, esto debería mejorar la calidad del cifrado y dificultar el descifrado de sus datos sin la clave.

2) Un buen cifrado debería producir datos que parezcan aleatorios, que a su vez no se pueden comprimir. Entonces necesitas comprimir primero. Incluso puede usar la compresión como prueba: si nota que sus datos cifrados se pueden comprimir (más allá de la reducción razonable de algunos encabezados de datos), esto puede indicar una debilidad en el cifrado.

Sin embargo, también puedo pensar en un par de razones para no hacer exactamente lo anterior.

1) En la práctica, los errores de compresión (o la ausencia de) pueden usarse como “pistas” de alta calidad durante un ataque de fuerza bruta de sus datos cifrados, es decir, el atacante no necesita “comprender” los datos para medir el éxito , pero se vuelve suficiente para ver si la compresión produce errores o no. Hace muchos años escribí un procesador de texto para las computadoras Amiga que hizo lo que estamos hablando, es decir, comprimió los datos antes de cifrarlos. Idealmente, los dos deben escribirse de la mano, de modo que si ingresa la clave de cifrado incorrecta, por ejemplo, todavía obtiene algún tipo de texto con palabras reales (solo no sus palabras), en lugar de un error. Sin embargo, a menudo no lo son.

2) Debido a que cambia la longitud de los datos en función de los patrones que contiene, la compresión puede exponer una superficie de ataque adicional. Incluso si el cifrado se aplica a los datos comprimidos, haciéndolo “seguro”, el tamaño real de los datos (si no se ve afectado por el cifrado) aún podría revelar algo. Por ejemplo, ¿varía el tamaño como resultado de probar diferentes contraseñas o partes de contraseñas? En el mundo de las redes, hay ataques que aprovechan la compresión TLS y HTTP antes del cifrado desde este ángulo. Nuevamente, en mi humilde opinión esto expone la necesidad de diseñar la compresión y el cifrado de la mano, teniendo en cuenta toda la imagen.

Usted menciona la necesidad de “transferir datos”. Si se refiere a archivos, y si su medio de transferencia es propenso a errores, es posible que desee agregar una capa externa de compresión no tanto para la compresión en sí, sino porque los formatos de archivo comprimido como ZIP, RAR y otros tienen buenas capacidades de suma de comprobación, así podrá reconocer más fácilmente las transferencias corruptas porque darán un error cuando abra el archivo. Entonces, en un escenario basado en archivos, podría comprimir, cifrar y luego comprimir nuevamente (o simplemente usar una opción de archivo sin comprimir en su software, que aún le daría la comprobación de errores). Pero luego publicó esta pregunta en TCP / IP, por lo que tal vez tenga una capa separada para rastrear errores de todos modos.

Algunos sistemas de archivos cifrados (como NTFS EFS) le permiten comprimir los datos o cifrarlos, pero no ambos. Según esta discusión, una mejor solución (desde una perspectiva de entropía) podría ser requerir una compresión preliminar como parte de la solución de cifrado. Y lo mismo se aplicaría a su pregunta aplicada a las transferencias de datos. Con la debida consideración de los posibles ángulos de ataque, tales como errores de compresión y exploits de tamaño de datos.