Solución al reto de dificultad media sobre criptografía que he puesto recientemente en este blog y en el que se ve involucrado el criptosistema de cifrado simétrico más utilizado, AES ('Advanced Encryption Standard'), en el modo de operación CBC ('Cipher Block Chaining') de los algoritmos de cifrado por bloques. Su enunciado decía lo siguiente:
"Para resolver este reto se necesita conocer cómo funciona el modo CBC de los cifradores por bloques. Demuestra que tú sí conoces dicho funcionamiento y obtén la solución de este reto con las siguientes pistas:
- Los primeros 14 de los 16 caracteres de la clave: '5rjIubT&Op_$3D'.
- Los tres últimos Bytes del cuarto bloque del criptograma: b1607e.
- El quinto bloque completo del criptograma: 925275279e9ca54278d6636884970397.
- Mensaje en claro: 'Veamos si eres capaz de encontrar la flag, que es el vector de inicializacion-IV'".
Antes de pasar a explicar la solución de este reto, comparto cómo lo preparé. Para ello, con objeto de cifrar el texto en claro del desafío utilicé una de las muchas herramientas 'online' existentes:
En el gráfico anterior se pueden ver las pistas que se dan para resolver este reto e, incluso, la solución, es decir, el vector de inicialización (IV): 336e63306e37723464305f336c5f4956 (en hexadecimal) o, lo que es lo mismo, 3nc0n7r4d0_3l_IV (en ASCII). Cualquiera de ambas respuestas sería válida como respuesta a este desafío.
Pruebo a descifrarlo para ver si lo he hecho correctamente:
¡Todo listo! ;)
Solución: Dicho lo anterior, me olvido de todo ello, me dispongo a intentar resolver el reto.
Decía en el enunciado que para resolver este desafío es necesario conocer cómo funciona el modo CBC ('Cipher Block Chaining') de los algoritmos de cifrado por bloques. El funcionamiento del descifrado en este modo de operación se muestra en la siguiente figura:
Doy los siguientes pasos:
1º) Obtención de la clave AES:
Conozco el quinto bloque completo y los tres últimos Bytes del cuarto bloque del criptograma o texto cifrado, y el mensaje en claro o texto plano completo, por lo que puedo utilizar la fuerza bruta para obtener los dos últimos caracteres de la clave y así tenerla entera:
a) Relleno con ceros los Bytes desconocidos del cuarto bloque del criptograma.
b) Realizo fuerza bruta sobre los dos últimos caracteres de la clave AES hasta que los tres últimos caracteres del quinto bloque del texto plano que obtenga sean iguales a los tres últimos caracteres del quinto bloque del texto plano conocido, es decir, "-IV".
Creo un pequeño script en python para ello:
from Crypto.Cipher import AES
import binascii
def descifrado(criptograma,clave,IV):
aes=AES.new(clave,AES.MODE_CBC,IV)
return aes.decrypt(criptograma)
caracteres='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ '
clave_catorce_primeros_caracteres='5rjIubT&Op_$3D'
criptograma_cuarto_bloque='00000000000000000000000000b1607e'
criptograma_quinto_bloque='925275279e9ca54278d6636884970397'
texto_plano='Veamos si eres capaz de encontrar la flag, que es el vector de inicializacion-IV'
# Obtener clave AES
clave_AES_encontrada=''
for i in caracteres:
for j in caracteres:
clave_fuerza_bruta=clave_catorce_primeros_caracteres+i+j
texto_plano_quinto_bloque_fuerza_bruta=descifrado(binascii.unhexlify( criptograma_quinto_bloque),clave_fuerza_bruta,binascii.unhexlify(criptograma_cuarto_bloque))
if str(texto_plano_quinto_bloque_fuerza_bruta).endswith(texto_plano[78:81]):
clave_AES_encontrada=clave_fuerza_bruta
break
if clave_AES_encontrada!='':
print''
print'[+] Obtencion de la clave AES mediante descifrado por fuerza bruta del quinto bloque del criptograma:',texto_plano_quinto_bloque_fuerza_bruta,'; Clave AES:',clave_AES_encontrada
break
if clave_AES_encontrada=='':
print'[-] No se ha encontrado la clave AES.'
Lo ejecuto:
Como resultado obtengo que la clave de cifrado es: "5rjIubT&Op_$3Dv%", es decir. los dos caracteres que faltaban son: "v%".
2º) Obtención del resto de bloques del criptograma (del 1 al 4) y del vector de inicialización (IV):
Y, tras esta breve explicación, el script en python completo para obtener la solución de este reto es:
from Crypto.Cipher import AES
import binascii
def descifrado(criptograma,clave,IV):
aes=AES.new(clave,AES.MODE_CBC,IV)
return aes.decrypt(criptograma)
caracteres='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ '
clave_catorce_primeros_caracteres='5rjIubT&Op_$3D'
criptograma_cuarto_bloque='00000000000000000000000000b1607e'
criptograma_quinto_bloque='925275279e9ca54278d6636884970397'
texto_plano='Veamos si eres capaz de encontrar la flag, que es el vector de inicializacion-IV'
# Obtener clave AES
clave_AES_encontrada=''
for i in caracteres:
for j in caracteres:
clave_fuerza_bruta=clave_catorce_primeros_caracteres+i+j
texto_plano_quinto_bloque_fuerza_bruta=descifrado(binascii.unhexlify( criptograma_quinto_bloque),clave_fuerza_bruta,binascii.unhexlify(criptograma_cuarto_bloque))
if str(texto_plano_quinto_bloque_fuerza_bruta).endswith(texto_plano[78:81]):
clave_AES_encontrada=clave_fuerza_bruta
break
if clave_AES_encontrada!='':
print''
print'[+] Obtencion de la clave AES mediante descifrado por fuerza bruta del quinto bloque del criptograma:',texto_plano_quinto_bloque_fuerza_bruta,'; Clave AES:',clave_AES_encontrada
break
# Obtener resto de bloques del criptograma
if clave_AES_encontrada!='':
criptograma_cuarto_bloque=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_quinto_bloque),clave_AES_encontrada,texto_plano[64:81]))
print'[+] Cuarto bloque del criptograma :',criptograma_cuarto_bloque
criptograma_tercer_bloque=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_cuarto_bloque),clave_AES_encontrada,texto_plano[48:64]))
print'[+] Tercer bloque del criptograma :',criptograma_tercer_bloque
criptograma_segundo_bloque=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_tercer_bloque),clave_AES_encontrada,texto_plano[32:48]))
print'[+] Segundo bloque del criptograma :',criptograma_segundo_bloque
criptograma_primer_bloque=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_segundo_bloque),clave_AES_encontrada,texto_plano[16:32]))
print'[+] Primer bloque del criptograma :',criptograma_primer_bloque
# Obtener vector de inicializacion (IV)
vector_inicializacion=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_primer_bloque),clave_AES_encontrada,texto_plano[0:16]))
print'[+] Vector de inicializacion (hex) :',vector_inicializacion
print'[+] Vector de inicializacion (ascii):',vector_inicializacion.decode('hex')
else:
print'[-] No se ha encontrado la clave AES.'
Lo ejecuto:
Por lo que la solución a este reto es: 3nc0n7r4d0_3l_IV.
******** PRÓXIMO RETO
Reto 32: "Flipando un poco".
"Para resolver este reto se necesita conocer cómo funciona el modo CBC de los cifradores por bloques. Demuestra que tú sí conoces dicho funcionamiento y obtén la solución de este reto con las siguientes pistas:
- Los primeros 14 de los 16 caracteres de la clave: '5rjIubT&Op_$3D'.
- Los tres últimos Bytes del cuarto bloque del criptograma: b1607e.
- El quinto bloque completo del criptograma: 925275279e9ca54278d6636884970397.
- Mensaje en claro: 'Veamos si eres capaz de encontrar la flag, que es el vector de inicializacion-IV'".
Antes de pasar a explicar la solución de este reto, comparto cómo lo preparé. Para ello, con objeto de cifrar el texto en claro del desafío utilicé una de las muchas herramientas 'online' existentes:
En el gráfico anterior se pueden ver las pistas que se dan para resolver este reto e, incluso, la solución, es decir, el vector de inicialización (IV): 336e63306e37723464305f336c5f4956 (en hexadecimal) o, lo que es lo mismo, 3nc0n7r4d0_3l_IV (en ASCII). Cualquiera de ambas respuestas sería válida como respuesta a este desafío.
Pruebo a descifrarlo para ver si lo he hecho correctamente:
¡Todo listo! ;)
Solución: Dicho lo anterior, me olvido de todo ello, me dispongo a intentar resolver el reto.
Decía en el enunciado que para resolver este desafío es necesario conocer cómo funciona el modo CBC ('Cipher Block Chaining') de los algoritmos de cifrado por bloques. El funcionamiento del descifrado en este modo de operación se muestra en la siguiente figura:
Doy los siguientes pasos:
1º) Obtención de la clave AES:
Conozco el quinto bloque completo y los tres últimos Bytes del cuarto bloque del criptograma o texto cifrado, y el mensaje en claro o texto plano completo, por lo que puedo utilizar la fuerza bruta para obtener los dos últimos caracteres de la clave y así tenerla entera:
a) Relleno con ceros los Bytes desconocidos del cuarto bloque del criptograma.
b) Realizo fuerza bruta sobre los dos últimos caracteres de la clave AES hasta que los tres últimos caracteres del quinto bloque del texto plano que obtenga sean iguales a los tres últimos caracteres del quinto bloque del texto plano conocido, es decir, "-IV".
Creo un pequeño script en python para ello:
from Crypto.Cipher import AES
import binascii
def descifrado(criptograma,clave,IV):
aes=AES.new(clave,AES.MODE_CBC,IV)
return aes.decrypt(criptograma)
caracteres='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ '
clave_catorce_primeros_caracteres='5rjIubT&Op_$3D'
criptograma_cuarto_bloque='00000000000000000000000000b1607e'
criptograma_quinto_bloque='925275279e9ca54278d6636884970397'
texto_plano='Veamos si eres capaz de encontrar la flag, que es el vector de inicializacion-IV'
# Obtener clave AES
clave_AES_encontrada=''
for i in caracteres:
for j in caracteres:
clave_fuerza_bruta=clave_catorce_primeros_caracteres+i+j
texto_plano_quinto_bloque_fuerza_bruta=descifrado(binascii.unhexlify( criptograma_quinto_bloque),clave_fuerza_bruta,binascii.unhexlify(criptograma_cuarto_bloque))
if str(texto_plano_quinto_bloque_fuerza_bruta).endswith(texto_plano[78:81]):
clave_AES_encontrada=clave_fuerza_bruta
break
if clave_AES_encontrada!='':
print''
print'[+] Obtencion de la clave AES mediante descifrado por fuerza bruta del quinto bloque del criptograma:',texto_plano_quinto_bloque_fuerza_bruta,'; Clave AES:',clave_AES_encontrada
break
if clave_AES_encontrada=='':
print'[-] No se ha encontrado la clave AES.'
Lo ejecuto:
Como resultado obtengo que la clave de cifrado es: "5rjIubT&Op_$3Dv%", es decir. los dos caracteres que faltaban son: "v%".
2º) Obtención del resto de bloques del criptograma (del 1 al 4) y del vector de inicialización (IV):
Ahora conozco la clave y puedo "empezar por el final":
si Pi = Dk(Ci) XOR Ci-1
entonces:
Ci-1 = Dk(Ci) XOR Pi
Donde: C0 = IV (vector de inicialización)
from Crypto.Cipher import AES
import binascii
def descifrado(criptograma,clave,IV):
aes=AES.new(clave,AES.MODE_CBC,IV)
return aes.decrypt(criptograma)
caracteres='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ '
clave_catorce_primeros_caracteres='5rjIubT&Op_$3D'
criptograma_cuarto_bloque='00000000000000000000000000b1607e'
criptograma_quinto_bloque='925275279e9ca54278d6636884970397'
texto_plano='Veamos si eres capaz de encontrar la flag, que es el vector de inicializacion-IV'
# Obtener clave AES
clave_AES_encontrada=''
for i in caracteres:
for j in caracteres:
clave_fuerza_bruta=clave_catorce_primeros_caracteres+i+j
texto_plano_quinto_bloque_fuerza_bruta=descifrado(binascii.unhexlify( criptograma_quinto_bloque),clave_fuerza_bruta,binascii.unhexlify(criptograma_cuarto_bloque))
if str(texto_plano_quinto_bloque_fuerza_bruta).endswith(texto_plano[78:81]):
clave_AES_encontrada=clave_fuerza_bruta
break
if clave_AES_encontrada!='':
print''
print'[+] Obtencion de la clave AES mediante descifrado por fuerza bruta del quinto bloque del criptograma:',texto_plano_quinto_bloque_fuerza_bruta,'; Clave AES:',clave_AES_encontrada
break
# Obtener resto de bloques del criptograma
if clave_AES_encontrada!='':
criptograma_cuarto_bloque=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_quinto_bloque),clave_AES_encontrada,texto_plano[64:81]))
print'[+] Cuarto bloque del criptograma :',criptograma_cuarto_bloque
criptograma_tercer_bloque=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_cuarto_bloque),clave_AES_encontrada,texto_plano[48:64]))
print'[+] Tercer bloque del criptograma :',criptograma_tercer_bloque
criptograma_segundo_bloque=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_tercer_bloque),clave_AES_encontrada,texto_plano[32:48]))
print'[+] Segundo bloque del criptograma :',criptograma_segundo_bloque
criptograma_primer_bloque=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_segundo_bloque),clave_AES_encontrada,texto_plano[16:32]))
print'[+] Primer bloque del criptograma :',criptograma_primer_bloque
# Obtener vector de inicializacion (IV)
vector_inicializacion=binascii.hexlify(descifrado(binascii.unhexlify( criptograma_primer_bloque),clave_AES_encontrada,texto_plano[0:16]))
print'[+] Vector de inicializacion (hex) :',vector_inicializacion
print'[+] Vector de inicializacion (ascii):',vector_inicializacion.decode('hex')
else:
print'[-] No se ha encontrado la clave AES.'
Lo ejecuto:
******** PRÓXIMO RETO
Reto 32: "Flipando un poco".
Comentarios
Publicar un comentario