Imagen: Nitin Jain, Birgit Stiller, Imran Khan, Dominique Elser, Christoph Marquardt & Gerd Leuchs (2016) "Attacks on practical quantum key distribution systems (and how to prevent them)". DOI: 10.1080/00107514.2016.1148333
Seguridad computacional: un sistema es seguro computacionalmente si cualquier algoritmo probabilístico en tiempo polinomial solo puede romper el algoritmo con probabilidad negligible en
Informalmente: un atacante no puede descifrar el mensaje:
Con la seguridad computacional hay que definir el objetivo: "quiero un sistema criptográfico que mantenga este mensaje secreto durante los próximos 100 años"
La criptografía computacionalmente segura permite
Hay que usar una clave lo suficientemente grande como para que no sea posible hacer fuerza bruta pero lo suficientemente pequeña como para que el sistema sea práctico para usar
El NIST recomienda (2020, sección 5.6.3) claves en las que un atacante
tenga que hacer
Es decir, según el NIST antes de 2030 las claves han de tener una longitud mínima de
A partir del 2030 prevé recomendar
Es decir: con una clave de 128 bits podemos cifrar un mensaje de cualquier longitud, y es razonable que nadie pueda descifrarlo en un futuro previsible
En cifrado simétrico, el tamaño en bits de su clave es igual a la fortaleza del sistema
Otras recomendaciones: https://www.keylength.com/en/compare/
NIST: The most important approach is to be flexible; the use of implementations and applications that can most easily be adapted to the cryptographic security offerings and a plan for transitioning to them offer the best solution
La amenaza conocida que puede modificar el calendario es la computación cuántica
Recuerda: definimos un que un algoritmo está criptográficamente roto si se conoce un ataque más eficiente que la fuerza bruta
Para la criptografía simétrica, buscaremos algoritmos computacionalmente seguros y que no estén rotos
Cuando la comunidad criptográfica rompe un algoritmo, se sustituye por otro
... pero es mejor prevenir: los algoritmos caducan y se cambian antes de que estén rotos
Flujo | Bloque |
---|---|
Más rápido | Más lento (a menos que exista ayuda del hardware) |
Fácil de programar: pequeños dispositivos | Más complejo |
Implementado en software | Implementado en hardware |
RC4, ChaCha20 | 3DES, AES |
Es una implementación práctica de one-time-pad (cifrado perfecto, Vernam)
Recuerda: para cifrado perfecto necesitábamos una clave tan larga como el mensaje
Para después hacer:
En cifrado de flujo lo que haremos es generar una
...a partir de una clave
para después hacer:
La función PRNG (Pseudo Random Number Generator) es un generador de bits que tiene como entrada una semilla (que será la clave de cifrado
La velocidad del cifrado depende totalmente de la velocidad del PRNG, porque el XOR es instantáneo
Un PRNG es un algoritmo determinista que extiende una semilla realmente aleatoria, resultando en una secuencia que parece ser uniformemente aleatoria.
Definición formal:
PRNG: Dado
Una función PRNG es realmente PRNG (es decir, útil en criptografía) si ningún atacante puede distingir entre las secuencia generada y una fuente aleatoria aleatoria uniforme RNG con una probabilidad diferente de
Fuente aleatorio uniforme RNG: medios físicos, no algorítmicos. Por ejemplo, generadores cuánticos.
Encontrarás más información en el Anexo 2
Información adicional: https://www.incibe-cert.es/blog/comprobando-aleatoriedad
Con la semilla (la clave), la secuencia queda determinada en su totalidad, que es lo que nos interesa.
La seguridad del cifrado depende del generador PRNG utilizado...
...y de que nunca se envíen dos mensajes cifrados con la misma clave
(vamos a repetir esto muchas veces en el curso)
Lorenz SZ fue una máquina alemana de cifrado de flujo, rota porque un operador envió dos mensajes diferentes seguidos sin cambiar la clave.
En las próximas transparencias, exploraremos cómo podemos diseñar un cifrado de flujo a partir de un PRNG, y cómo la solución más obvia... no funciona
Supongamos que tenemos una función PRNG, y usamos una clave k como semilla del PRNG para cifrar un flujo de datos en una conexión
Si ciframos dos mensajes cifrados
¡Un atacante puede hacer XOR de los dos textos cifrados y obtener el XOR de los textos en claro!
Nunca hay que usar la misma clave (ni generada) con dos mensajes diferentes
Información adicional: Chosen plaintext attacks
Cambiamos la clave (la semilla del PRNG) en cada transmisión
Esto es correcto pero costoso, y volvemos a los problemas de la confidencilidad perfecta: cómo distribuimos una clave diferente para cada mensaje
Generar variaciones de las claves en cada transmisión
Supongamos que la semilla no es directamente la clave, sino una función de la clave y otro parámetro
Y
Ahora la semilla "es diferente" con cada tranmisión
Pero tenemos que asumir que un atacante conoce
Curiosamente: ¡esto es correcto!: reservar algunos bits de la clave para un contador:
SESAMO_1, SESAMO_2, SESAMO_3...
Este elemento se conoce como nonce y forma parte de muchos algoritmos criptográficos
Debemos generar un
Si tenemos una comunicación bidireccional como HTTPS (TLS) hace falta:
El cifrado de flujo es tan seguro como:
ChaCha es el algoritmo de cifrado simétrico de flujo más usado
Un comentario rápido sobre RC4/ARC4/RCFOUR:
Basado en Salsa20 (2017), de Daniel J. Bernstein
ChaCha20 (RFC 8439, 2018), es la variante estandarizada
Cifrado simétrico de flujos de bytes. Claves de 256 bits.
Sustituto "de facto" para el antes ubicuo RC4. Se usa en:
/dev/urandom
de Linuximport json
from base64 import b64encode
from Crypto.Cipher import ChaCha20
from Crypto.Random import get_random_bytes
# Configuración
plaintext = b'Attack at dawn'
key = get_random_bytes(32)
cipher = ChaCha20.new(key=key)
nonce = b64encode(cipher.nonce).decode('utf-8')
# Cifrado
ciphertext = cipher.encrypt(plaintext)
ct = b64encode(ciphertext).decode('utf-8')
result = json.dumps({'nonce':nonce, 'ciphertext':ct})
# Mensaje
{"nonce": "IZScZh28fDo=", "ciphertext": "ZatgU1f30WDHriaN8ts="}
Base64 se utiliza para representar información binaria como cadena imprimible
> echo '¡Qué tal estás!' | base64
wqFRdcOpIHRhbCBlc3TDoXMhCg==
> dd count=1 bs=16 if=/dev/random 2>/dev/null
???n??????;N%
> dd count=1 bs=16 if=/dev/random 2>/dev/null | base64
D87WM0+4j5vYzLpHhJFMTA==
Base64 NO ES UN CIFRADO. Es una CODIFICACIÓN para representar cadenas binarias como texto. A veces se usa también para representar texto (ej: correos electrónicos) y ahorrar problemas con letras acentuadas.
Recuerda:
# La clave key se ontiene por canal seguro
# el receptor recibe el mensaje anterior {nonce, ciphertext}
nonce = b64decode(received['nonce'])
ciphertext = b64decode(received['ciphertext'])
cipher = ChaCha20.new(key=key, nonce=nonce)
plaintext = cipher.decrypt(ciphertext)
print("The message was " + plaintext)
. | . | . | . |
---|---|---|---|
"expa" | "nd 3" | "2-by" | "te k" |
Key | Key | Key | Key |
Key | Key | Key | Key |
Pos. | Pos. | Nonce | Nonce |
0x657870616e642033322d62797465206b
es un número "no llevo nada en la manga"Aplicada sobre 4 palabras de 32 bits, las difunde:
QR(a, b, c, d)
a += b; d ^= a; d <<<= 16;
c += d; b ^= c; b <<<= 12;
a += b; d ^= a; d <<<= 8;
c += d; b ^= c; b <<<= 7;
Solo tiene sumas, rotaciones y XOR: es una función ARX, que impide ataques de canal lateral por timing.
#define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
#define QR(a, b, c, d) ( \
a += b, d ^= a, d = ROTL(d,16), \
c += d, b ^= c, b = ROTL(b,12), \
a += b, d ^= a, d = ROTL(d, 8), \
c += d, b ^= c, b = ROTL(b, 7))
#define ROUNDS 20
void chacha_block(uint32_t out[16], uint32_t const in[16])
{
int i;
uint32_t x[16];
for (i = 0; i < 16; ++i)
x[i] = in[i];
// 10 loops × 2 rounds/loop = 20 rounds
for (i = 0; i < ROUNDS; i += 2) {
// Odd round
QR(x[0], x[4], x[ 8], x[12]); // column 0
QR(x[1], x[5], x[ 9], x[13]); // column 1
QR(x[2], x[6], x[10], x[14]); // column 2
QR(x[3], x[7], x[11], x[15]); // column 3
// Even round
QR(x[0], x[5], x[10], x[15]); // diagonal 1 (main diagonal)
QR(x[1], x[6], x[11], x[12]); // diagonal 2
QR(x[2], x[7], x[ 8], x[13]); // diagonal 3
QR(x[3], x[4], x[ 9], x[14]); // diagonal 4
}
for (i = 0; i < 16; ++i)
out[i] = x[i] + in[i];
}
Fuente: Wikipedia)
... la comunidad aún no está segura de cómo usarlo ...
Nonce length | Description | Max data | If random nonce and same key |
---|---|---|---|
8 bytes (default) | The original ChaCha20 designed by Bernstein. | No limitations | Max 200 000 mensajes, el contador limita |
12 bytes | The TLS ChaCha20 as defined in RFC7539. | 256 GB | Max 13 billions messages |
24 bytes | XChaCha20, still in draft stage. | 256 GB | No limitations |
The Salsa20 family of stream ciphers, Daniel J. Bernstein, 2007
Ninguna conocida, siempre que se cumplan las condiciones de uso: no se puede repetir clave y nonce.
El cifrado de bloque es lo que hacía el cifrado Vignère: cortar el texto en claro en bloques de la misma longitud de la clave y cifrar cada uno de los bloques
Si tenemos mensajes más largos que
El cifrado de bloque es el más utilizado con el cifrado simétrico: es rápido y no necesita exigentes o lentos algoritmos PRNG.
El cifrado de bloque se suele definir como una serie de permutaciones.
Hay dos clases de cifrado de bloque. Es decir, dos maneras de implementar PRP:
Fijate: igual que los cifrados clásicos.
Por si solas, las 2 clases básicas de cifrado de bloque son inseguras pero combinándolas podemos obtener seguridad creciente.
A partir de ahora utilizaremos
Para un bloque de longitud
m | c |
---|---|
Igual que en Vigenère, podríamos recuperar el texto con análisis frecuencial
Para un bloque de longitud
m | c |
---|---|
No solo la frecuencia de los símbolos de entrada se mantiene, si no que los propios símbolos se mantiene (aunque en posiciones diferentes)
Si componemos el cifrado total como una serie de
Cada clave
Etapas o rounds: los cifrados de sustitución y transposición se agrupan en parejas y se aplican varias veces (con diferentes claves) hasta obtener un cifrado seguro
El objetivo de la criptografía moderna es maximizar la difusión y la confusión (según Shannon)
Unas palabras sobre TDES (NIST SP 800-67, 2017)
Desarrollado por Vincent Rijmen y Joan Daemen (aka: Rijndael), que ganaron el concurso celebrado por el NIST para sustituir a DES en 2001.
AES (FIPS 197, 2001) es un cifrado de bloque:
background: https://whatsupcourtney.com/wp-content/uploads/2017/10/Things-to-do-in-Leuven-52-e1560945504897.jpeg
Parte de una matriz de estado que se va modificando durante 10, 12 o 14 rondas según sea el tamaño de clave. Inicialmente: la matriz de estado es el texto en claro.
KeyExpansion
: se derivan round keys a partir de la clave de cifrado usando el algoritmo AES key schedule. Necesarias: una por etapa, y una más.AddRoundKey
: SubBytes
: sustitución de bytes en función de una tabla fija de 256 entradasShiftRows
: transposición de bytes fijaMixColumns
: 4 multiplicaciones modulares de 4 Bytes, valores fijosAddRoundKey
: "sustitución de bytes en función de una tabla fija de 256 entradas"
"transposición de bytes fija"
"4 multiplicaciones modulares de 4 Byte, valores fijos"
"
Cada una de las etapas (rounds) utiliza una subclave
Cada una de les subclaves
Nota 1: las subclaves se aplican (
Nota 2: hacen falta más etapas en los AES de clave larga para "aplicar" el mayor espacio de claves sobre el mensaje en claro
La estadística del mensaje en claro aparece en el texto cifrado.
Ahora los bloques son de 16 B, no de 1 B por tanto la estadística es menos importante
(|bloque|=
Un cifrado debe parecerse a esto:
Esta "vulnerabilidad" es una propiedad de todos los cifrados de bloque
La contramedida es la misma para todos: no cifrar nunca bloque a bloque, sino cifrar parte del bloque anterior en el bloque actual.
Este encadenamiento se denomina modo de operación y no es opcional
Si acumulamos estado durante el cifrado, podemos utilizar este estado sobre el cifrado del siguiente bloque:
Fallo obvio: está usando la misma clave para cifrar mensajes diferentes.
Eso nunca se puede hacer.
No se debe usar AES en modo ECB
Desventaja: perder un bloque implica que la sincronización se pierde
Ventaja: puede preparse el cifrado antes de necesitarlo
Ventaja: perder bloques no afecta a la capacidad de descifrado
Vector de inicialización (IV) cumple la misma función que un nonce: semilla inicial
Impide que el mismo mensaje se cifre de la misma manera
Se tiene que transmitir al receptor, y no hace falta que sea secreto: puede enviarse en el primer mensaje sin cifrar
AES_128_CTR
es efectivamente un cifrado de flujo, siendo
AES puede usarse también con "modos autenticados": detectan si el atacante ha cambiado algún byte durante la comunicación
Información adicional, de la librería que usamos en los ejercicios: https://pycryptodome.readthedocs.io/en/latest/src/cipher/aes.html
Explicación del modo GCM: https://www.youtube.com/watch?v=-fpVv_T4xwA&t=747
En la actualidad, el modo más usado en comunicaciones en AES-GCM
https://www.highgo.ca/2019/08/08/the-difference-in-five-modes-in-the-aes-encryption-algorithm/
https://stackoverflow.com/questions/1220751/how-to-choose-an-aes-encryption-mode-cbc-ecb-ctr-ocb-cfb
Hay distintos ataques que permiten realizar búsquedas de forma más rápida que un ataque de fuerza bruta
AES ha perdido fortaleza pero aún está aguantando.
Se considera que la criptografía simétrica es robusta ante la computación cuántica, pero tendremos que doblar el tamaño de la clave
RANDOM XOR MENSAJE
.Ejercicios de profesor:
Alternativamente, podéis hacer los ejercicios de AES de https://www.cryptohack.org
La confidencialidad es perfecta en cifrados tipo Vernam si la clave: - Es perfectamente aleatorio - Solo se usa una vez - Es tan larga como el mensaje Es decir: hay que distribuir claves tan grandes como mensajes de una forma secreta antes de poder distribuir un mensaje. Esto no es práctico. Hoy veremos como solucionarlo: - Relajando la confidencialidad perfecta a la confidencialidad computacional - Usando algoritmos de cifrado simétrico
Transparencia recordatorio Desde que los matemáticos entraron en la criptografía, existe definiciones de todos los términos tan exactas y formales como incomprensibles para un profano Cosas que implica: - Dado un texto cifrado, no conocemos nada de su texto en claro - Dado un texto cifrado, el mensaje en claro podría ser cualquiera: Si el cifrado es XHAJSJXXNFHFDOIOJUMNFNNNF existe una clave que descifra "ATACAREMOS A LAS 8 EN PUNTO" y otra que descifra "SE HA QUEDADO BUENA TARDE", así que un atacante no puede distinguir el mensaje real de todos los mensajes falsos posibles. Es decir: ni siquiera por fuerza bruta podemos atacar el sistema de cifrado, porque no sabremos si el mensaje que hemos obtenido es el bueno
Desde que los matemáticos entraron en la criptografía, existe definiciones de todos los términos tan exactas y formales como incomprensibles para un profano Lo importante es que relajamos el sistema lo suficiente como para que, por un tiempo determinado, ningún atacante con unos recursos razonables pueda descifrar el mensaje
Recordad: en el cifrado de Verman no sabíamos si habíamos encontrado una clave porque, dado un mensaje cifrado, existe una clave que puede dar cualquier mensaje imaginable con la misma longitud que el original Ahora no sucede así: si al descifrar por fuerza bruta encontramos algo con sentido, con gran probabilidad hemos encontrado la clave y el mensaje es el original Recordad: los ordenadores mejoran constantemente. Los algoritmos se diseñan para que, con la tecnología actual, se tarde miles de años en hacer fuerza bruta. Pero la tecnología mejora con el tiempo, y eso también se tiene en cuenta: aunque "se venda" que un cifrado "no puede romperse en miles de años", en realidad eso es relativo a la tecnología actual y el algoritmo tiene una caducidad de unas pocas décadas. La mejor estrategia puede ser simplemente esperar 20 años para tener un ordenador que haga esa misma fuerza bruta de forma instantánea
Recordad: los ordenadores mejoran constantemente. Los algoritmos se diseñan para que, con la tecnología actual, se tarde miles de años en hacer fuerza bruta. Pero la tecnología mejora con el tiempo, y eso también se tiene en cuenta: aunque "se venda" que un cifrado "no puede romperse en miles de años", en realidad eso es relativo a la tecnología actual y el algoritmo tiene una caducidad de unas pocas décadas. La mejor estrategia puede ser simplemente esperar 20 años para tener un ordenador que haga esa misma fuerza bruta de forma instantánea
algunos sistemas necesitan claves mucho más largas que la media de claves que tiene que probar un atacante para descifrarlos. Esto sucede en los sistemas asimétricos, por ejemplo. La fortaleza en estos sistemas es menor que la longitud de la clave
¿Qué pasa con la criptografía cuántica? El cifrado asimétrico se verá más afectado que el simétrico https://csrc.nist.gov/projects/post-quantum-cryptography
Nosotros veremos en detalle los algoritmos ChaCha20 y AES, que los dos más utilizados actualmente
Recordatorio: este es el esquema para hacer un cifrador de flujo.
Een lenguage comprensible: simplemente por inspección de la salida no podríamos saber si es un salida realmente al azar o fruto de un algoritmo determinista Fíjate que "en tiempo polinomial" siempre lo entendemos como "en un tiempo razonable" La confidencialidad perfecta decía que el algoritmo era seguro aunque el adversario tuviese recursos infonitos. La seguridad computacional, era segura ante adversarios con recursos limitados (de tiempo o de computación o de ambas). Ese requisito "recursos limitados" en matemática forma se exprea como "en tiempo polinomial"
Curiosidad: "un atacante no puede distinguir... con una probabilidad..." En análisis criptográfico, se analiza el protocolo como un juego. Los atacantes o los usuarios plantean un juego e intentan adivinar algo. Aquí el usuario le da al atacante un número y le pregunta "¿esto lo he sacado de un RNG o de un PRNG?". La pregunta se hace muchas veces. El atacante gana si puede adivinarlo más de la mitad de las veces. Seguimos. Los ordenadores no pueden generar números realmente aleatorios ya que solo usan algoritmos. Para generar números realmente aleatorios es necesaria ayuda externa: pulsaciones de teclado, movimiento de ratón... Fíjate que incluso las pulsaciones de teclado no son del todo aleatorias: después de una vocal es posible que venta una consonante. Por la noche habrá menos pulsaciones que durante el día... Son fuentes mejores de aletoriedad, pero no perfectas
Qué puede hacer un atacante con el xor de los textos en claro: - Análisis frecuencia: La "clave para cifrar m2" es m1, que ya no es aleatorio y permite el análisis de frecuencias. - Si partes de m1 son conocidas, es aún más sencillo descifrar partes de m2 Es decir, este esquema falla ante ataques de "chosen plaintext attacks": si el enemigo puede forzarnos a cifrar algo, el sistema está roto. Los algotitmos se diseñan para ser resistenentes a ciertos problemas. Por ejemplo, ese "chosen plantext attack", que es un juego como el que hemos visto antes. Puedes encontrar otros ataques en: https://en.wikipedia.org/wiki/Attack_model Mira el ejemplo de ataque japonés en el Pacífico de wikipedia
**Nota**: hasta hace poco, un buen algoritmo PRNG no es sencillo de hacer, o no es rápido. Hasta la aparición de Salsa20, la falta de buenos algoritmos PRNG hacían preferir el cifrado simétrico de bloque que veremos en un momento.
ChaCha20 es muy nuevo, pero ha tenido un éxito rápido. Es especialmente interesante en móviles, que tienen procesaror ARM y no están optimizados para otros cifradores como AES
Cosas para fijarse: la salida se codifica en Base64 y el nonce se envía con la comunicación
ChaCha20 es el algoritmo generador PRNG, y su dalida después hace XOR con el mensaje El algorutmos es así: - Creación de una matriz de 512 bits: clave, nonce, pos=0 - 10 veces: - QR(columnas) - QR(filas) - La salida es la matriz de 512 bist (con un paso previo y sencillo de difusion) Cada ejecución de ChaCha20 genera un flujo de 512 bits. El primero con pos=0. Si se necesita un nuevo flujo porque el mensaje es más largo, entonces se genera otra matriz con pos=1 y se generan otros 512 bits. Y después pos=2, pos=3.... Los bits que no hemos usado pueden descartarse.
Nota importante: la figura muestra un confrado de bloque totalmente inseguro, como veremos en un momento Fíjate: los bloques no tienen memoria, al contrario de lo que pasaba en el cifrado de flujo. Veremos que esto es una de sus debilidades.
DES es un algoritmo de IBM que lo empezó todo: probó que era posible la confidencialidad computacional, es decir, conseguir un sistema que un atacante no pudiese romper en un tiempo razonable. DES ha quedadado obsoleto no porque esté roto, sino porque su espacio de claves es muy pequeño: se pueden probar todas las claves de 56 bits en pocas horas. Pero al combinarlo tres veces, con tres claves diferentes, y aumentar su espacio de claves hasta 112 bits, el sistema 3DES es seguro hasta el 2030, según la opinión del NIST
AES fue desarrollado por Vincent Rijmen y Joan Daemen en el COSIC de la KU Leuven, Bélgica. Es totalmente ubicuo en la seguridad actual: se usa para todo, en todos lados. ChaCha20 es el único algoritmo que puee hacerle sombra. Hay hardware especializado en cifrar y descifrar AES, entre ellas las CPUs de computadora de sobremesa.
Fíjate: - el algoritmo de cifrado es diferente el algoritmo de descifrado. Se diseñó para optimizar el cifrado. - Hay una etapa de expación de clave: de una clave con un tamaño determinado sacamos "subclaves" para cada una de las etapas.
Añade **difusión**: los bits de salida dependerán de varios bits de entrada.
Aquí es donde entran las subclaves, diferentes en cada una de las etapas, y la operación XOR que finalmente cifra el bloque. El nuevo estado se pasa entonces a la siguiente etapa.
La autenticación es un servicio que aún no hemos visto, pero tenemos casi toda la segunda parte de la asignatura para ello. Hasta ahora solo nos preocupábamos de mantener la información secreta, pero no hemos comprobado la identidad de la persona que está hablando. AES tiene algunos modos de uso avanzados que permiten también comprobar esta identidad. Pero aún necesitamos un poco de teoría.