Otra de las competiciones tipo CTF (del inglés, 'Capture the Flag'), modalidad 'on-line' y formato 'Jeopardy' con la que me he entretenido últimamente es Access Denied CTF, y en este post pongo la solución a un reto de criptografía que resolví.
En este caso se trata de un reto sobre OTP (del inglés, ‘one-time pad’) y que, en mi opinión, presenta un nivel de dificultad medio (★★★☆☆).
Ya conté en el reto 38 que puse en este blog que, en teoría y si se cumplen ciertas condiciones, el cifrado OTP o libreta de un solo uso proporciona lo que se llama el secreto perfecto, es decir, el criptograma es indescifrable si no se conoce la clave de cifrado.
Enunciado:
Y se proporciona un archivo en python con el siguiente contenido:
Solución: en el fichero reused_key.py que se facilita con el reto se ve que hay dos textos, 'flag' y 'some_simple_text', que se cifran con una misma clave aleatoria de longitud igual a ambos, y ese es precisamente lo que hace que se rompa el cifrado perfecto, es decir, una de las condiciones necesarias para que se dé éste es precisamente que la clave no se reutilice jamás (razón por la que este método de cifrado se llama OTP - 'one-time pad'), ya que si un criptoanalista se hace con dos criptogramas cifrados con la misma clave puede obtener los textos en claro correspondientes sin demasiados problemas utilizando la técnica ‘crib dragging’.
¿Por qué puede obtener los textos en claro? Muy fácil, supongamos que tenemos dos mensajes, M1 y M2, que ciframos con la misma clave, K, y obtenemos sendos criptogramas, C1 y C2:
Si hacemos XOR de ambos criptogramas (C1 y C2):
Con lo que, con independencia de la clave utilizada (K), si voy deduciendo o infiriendo partes de uno u otro de los textos en claro (‘cribs’) iré obteniendo las partes correspondientes del otro mensaje en claro.
Y es así como actúo. En primer lugar hago XOR de ambos textos, 'flag' y 'some_simple_text':
Y, posteriormente, voy deduciendo partes de 'flag' y/o de 'some_simple_text' hasta obtener ambos textos en claro. La primera 'crib' es obvia (el inicio de la 'flag'): 'accessdenied{'.
Con lo que obtengo la primera parte del texto en claro de 'some_simple_text'.
Y así sucesivamente hasta que obtengo ambos textos en claro:
Con lo que la 'flag' es: accessdenied{n3v3r_r3u53_th3_k3y5_db5e5bac}
Comentarios
Publicar un comentario