Tema 8
Los cifrados de flujo protegen datos generando una secuencia pseudoaleatoria que se combina con el mensaje a medida que avanza. Su enfoque es distinto del cifrado por bloques: priorizan continuidad, flexibilidad y procesamiento secuencial, pero exigen una disciplina estricta en el manejo de nonces y keystream.
Después de estudiar cifrados por bloques y modos de operación, es natural pasar a la otra gran familia de la criptografía simétrica: los cifrados de flujo. Mientras que un cifrado por bloques transforma grupos fijos de datos, un cifrado de flujo genera un flujo pseudoaleatorio de bits o bytes que se combina con el mensaje de manera continua.
Este enfoque resulta especialmente útil cuando los datos llegan de forma secuencial, cuando el tamaño no está naturalmente alineado a bloques o cuando se busca baja latencia en escenarios de transmisión continua. Pero su simplicidad aparente es engañosa: reutilizar el flujo equivocado puede destruir toda la seguridad.
Un cifrado de flujo es un algoritmo simétrico que, a partir de una clave y normalmente de un nonce o vector inicial, genera una secuencia pseudoaleatoria llamada keystream. Ese flujo se combina con el texto plano para producir el texto cifrado.
La combinación más típica se hace con la operación XOR. Si luego se vuelve a aplicar XOR con el mismo keystream, se recupera el mensaje original. Esa propiedad hace que cifrado y descifrado sean conceptualmente muy similares.
El keystream puede imaginarse como una secuencia de bytes aparentemente aleatorios generada a partir de la clave. El mensaje no se transforma directamente por rondas sobre sus propios bloques, sino que se mezcla con esa secuencia.
Si el keystream es realmente impredecible y se usa una sola vez en las condiciones adecuadas, el atacante no debería poder separar el flujo del contenido original. Pero si el mismo keystream se reutiliza sobre mensajes distintos, aparecen relaciones muy peligrosas.
La operación XOR tiene una propiedad muy útil: aplicar dos veces XOR con el mismo valor revierte el efecto. Si representamos el texto plano como P, el keystream como K y el texto cifrado como C, entonces:
C = P XOR K
Y para recuperar el mensaje:
P = C XOR K
Esto hace que el cifrado de flujo sea eficiente, pero al mismo tiempo deja claro el riesgo: si dos mensajes usan el mismo flujo K, un atacante puede combinar ambos textos cifrados y eliminar el keystream de la ecuación.
La diferencia principal es que un cifrado por bloques transforma directamente bloques de datos mediante rondas internas, mientras que un cifrado de flujo produce primero un flujo pseudoaleatorio y luego lo mezcla con los datos.
| Aspecto | Cifrado por bloques | Cifrado de flujo |
|---|---|---|
| Unidad principal | Bloques fijos | Bits o bytes continuos |
| Transformación | Directa sobre el bloque | Mezcla con un keystream |
| Padding | A veces necesario | No suele requerirse |
| Riesgo típico | Modo inseguro o IV mal usado | Reutilización de keystream o nonce |
Los cifrados de flujo ofrecen varias ventajas en ciertos contextos:
Estas características los hacen atractivos en comunicaciones, protocolos livianos y entornos donde la latencia importa.
El mayor riesgo de un cifrado de flujo no suele estar en la idea general, sino en reutilizar el mismo keystream con más de un mensaje. Si eso ocurre, la seguridad se degrada gravemente porque el atacante puede combinar los textos cifrados y eliminar el flujo compartido.
Esto deja expuestas relaciones entre mensajes, y en ciertos contextos permite recuperar parcial o totalmente el contenido original.
Para evitar reutilización del mismo flujo, los cifrados de flujo modernos suelen usar un nonce junto con la clave. La combinación de ambos determina el estado inicial del generador. Mientras la clave permanezca igual, cambiar el nonce permite obtener un keystream diferente para cada mensaje.
El nonce no necesita ser secreto, pero sí debe cumplir la propiedad exigida por el algoritmo: normalmente unicidad con la misma clave. Si se repite, el flujo puede repetirse también y con ello reaparece el problema central.
Históricamente se distinguieron cifrados de flujo síncronos y autosincronizantes. En los síncronos, el keystream depende solo de la clave, nonce y estado interno; en los autosincronizantes, también depende de partes del texto cifrado previo.
Esta diferencia afecta cómo se recupera la sincronía tras errores de transmisión y cómo se comporta el sistema frente a alteraciones. Aunque hoy muchos diseños modernos se enfocan en variantes más estandarizadas, la distinción sigue siendo conceptualmente útil.
RC4 fue uno de los cifrados de flujo más conocidos y usados durante años en protocolos y aplicaciones populares. Su simplicidad y velocidad lo hicieron muy atractivo, pero con el tiempo se descubrieron sesgos y debilidades que comprometían su seguridad en varios escenarios prácticos.
El caso de RC4 es didáctico porque muestra que un algoritmo puede volverse extremadamente difundido antes de que se comprendan del todo sus debilidades. También recuerda que la revisión pública y el paso del tiempo son indispensables.
El problema de RC4 no era simplemente "ser viejo". Se observaron sesgos en las primeras salidas del keystream y vulnerabilidades explotables en protocolos reales cuando se reutilizaban contextos o se acumulaban muchas muestras cifradas.
Esto llevó a que dejara de considerarse adecuado para nuevos sistemas y fuera retirado progresivamente de estándares y recomendaciones modernas.
Entre los cifrados de flujo modernos, ChaCha20 ocupa un lugar central. Fue diseñado para ofrecer alta seguridad, buen rendimiento en software y resistencia práctica en entornos donde AES por hardware no siempre es la mejor opción.
ChaCha20 suele usarse junto con Poly1305 para construir un esquema autenticado ampliamente adoptado en protocolos modernos. Su diseño evita varias debilidades históricas vistas en generaciones anteriores de stream ciphers.
Una distinción importante es que algunos modos de operación de cifrados por bloques, como OFB o CTR, generan un comportamiento muy parecido al de un cifrado de flujo. Eso no significa que sean literalmente lo mismo, pero sí que ambos paradigmas pueden terminar produciendo un flujo pseudoaleatorio que luego se mezcla con el mensaje.
La diferencia está en la construcción interna: un stream cipher como ChaCha20 fue diseñado desde el inicio para generar flujo; CTR, en cambio, reutiliza un cifrado por bloques para producir ese efecto.
En muchos cifrados de flujo, un error en un bit del texto cifrado afecta solo el bit correspondiente del texto descifrado, sin arrastrarse a toda la secuencia. Esto puede ser útil en ciertos medios donde hay ruido o pérdidas parciales.
Sin embargo, esta misma propiedad también implica que un atacante activo podría modificar bits específicos del mensaje cifrado si el sistema no incluye autenticación. Por eso otra vez aparece la misma lección: confidencialidad no basta.
Los cifrados de flujo suelen destacar en escenarios donde interesa cifrar a medida que llegan los datos, sin esperar a completar bloques. Esto los hace atractivos en voz, video, túneles livianos, protocolos interactivos y dispositivos con restricciones particulares.
El rendimiento real depende del hardware, de la biblioteca usada y del algoritmo concreto, pero en términos conceptuales el modelo es muy adecuado para procesamiento continuo.
Un stream cipher por sí solo no protege integridad ni autenticidad. Si un atacante altera bits del texto cifrado, el descifrado producirá cambios correlacionados en el mensaje. Si no existe una verificación adicional, el sistema puede aceptar esos datos manipulados.
Por eso en la práctica moderna se prefiere usar construcciones autenticadas, como ChaCha20-Poly1305, donde el cifrado viene acompañado por una verificación criptográfica de integridad.
Los cifrados de flujo son especialmente atractivos cuando:
Los cifrados por bloques, en cambio, siguen siendo muy fuertes en almacenamiento, cifrado estructurado y sistemas donde ya existen modos y aceleración bien establecidos, como AES-GCM.
| Aspecto | Cifrado de flujo | Cifrado por bloques |
|---|---|---|
| Modelo | Keystream + mezcla con datos | Transformación directa por bloques |
| Padding | No suele requerirse | A veces sí |
| Uso continuo | Muy natural | Depende del modo |
| Riesgo crítico | Reutilización de flujo | Modo o parámetros mal usados |
| Ejemplos | ChaCha20, RC4 histórico | AES, DES, 3DES |
Los cifrados de flujo ofrecen una alternativa muy potente a los cifrados por bloques cuando el problema requiere continuidad, baja latencia y flexibilidad. Su modelo es elegante y eficiente, pero exige rigor absoluto en el manejo de nonces y autenticación complementaria.
En el próximo tema entraremos en la criptografía asimétrica, donde cambia por completo el paradigma: dejaremos de hablar de una sola clave compartida para pasar a pares de clave pública y privada.