Criptografía en Python: Cifrado cesar y vigenère

Una categoría que nos solemos encontrar mucho en los CTFs son los retos de criptografía y criptoanálisis, así que en esta serie de tutoriales iremos haciendo un repaso tanto de su funcionamiento como su implementación en python de distintos algoritmos de criptografía clásica.

El cifrado clásico es el cifrado basado en la sustitución y transposición de sus caracteres:

Transposición: La transposición consiste en alterar el orden de los elementos de un mensaje.

Sustitución: Las unidades de texto plano son sustituidas con texto cifrado siguiendo un sistema regular; las «unidades» pueden ser una sola letra, pares de letras, tríos de letras, mezclas de lo anterior, entre otros.

Clasificación de los sistemas de cifrado clásico

Algoritmo de Cesar

Quizás este sea uno de los algoritmos más simples y más conocidos, se trata de un cifrado de sustitución basado en el desplazamiento de sus letras por la letra que ocupa tres posiciones mas a la derecha.Este método debe su nombre a Julio César, que lo usaba para comunicarse con sus generales.

Como ejemplo si quisiéramos cifrar el texto «HOLAMUNDO» el mundo cifrado seria «KRODPXQGR»

La imagen tiene un atributo ALT vacío; su nombre de archivo es caesar.png

Este algoritmo es generalizable, es decir, la rotación de los caracteres no solo puede ser de 3 ,sino que puede ser de cualquier número de 1 al 25, aunque las más comunes son de rotación 3 (Cesar normal) y de rotación 13 (ROT13)

Implementación en python:

La implementación es ultra sencilla, solo necesitamos crear una función a la que le pasaremos dos parametros el texto y el desplazamiento.

  • Cifrado
def caesar_cipher(text,desp):
   cipher = ""
   for i in range(len(text)): #Para cada letra del texto
      char = text[i]
      if (char.islower()):
          cipher += chr((ord(char) + desp - 97) % 26 + 97) #97 letra minuscula (a)
      else:
          cipher += chr((ord(char) + desp-65) % 26 + 65) # Prima letra mayuscula (A) 
    return cipher

No hay mucho que explicar en este código, la única parte que merece aclaración es la linea:

cipher += chr((ord(char) + desp-65) % 26 + 65) # Prima letra mayuscula (A) 

Aquí básicamente obtenemos el numero ASCII correspondiente a la letra a cifrar supongamos que recibimos 68 que corresponde a la D, le sumamos el desplazamiento en este caso 3 , con lo que obtenemos 71 (G), y le restamos 65 que corresponde con el primer carácter del alfabeto, la A mayúscula, con los quedamos con un 6 y sobre eso aplicamos la operación modulo, para asegurarnos de que el numero resultado quede entre 1 y 26 , una vez obtenido el resultado modulo 26 le volvemos a sumar la A.

  • Descifrado
def caesar_decipher(text,desp):
plain = ""
for i in range(len(text)):
   char = text[i]
   if (char.islower()):
       plain += chr((ord(char) -97-desp) % 26 + 97)
    else:
       plain += chr((ord(char) -65-desp) % 26 + 65)
return plain

Del descifrado no hay mucho que comentar es como la operación de cifrado solo que cambiando las sumas por restas

Criptoanalisis al algoritmo de cesar:

Analizar un criptograma cifrado con cesar es muy sencillo, para ello existen varios metodos el primero y mas intuitivo es al tener solo 26 combinaciones posibles diferentes, probar todas las combinaciones posibles

def caesar_brute(text):
   for i in range(26):
      print(chr(65+i)+": "+caesar_decipher(text,i))

Pero esta no es la única forma al ser un cifrado de sustitución monoalfabética, es decir que cada letra A siempre va a corresponder a una D, podemos utilizar las regularidades del lenguaje para averiguar la correspondencia entre las letras. Básicamente sabemos que hay letras mas frecuentes que otras, por ejemplo en Español la W no suele usar casi nunca mientras que otra letra como la E aparece en un montón de palabras. Así que si conocemos el idioma del texto original podemos comparar la frecuencia de aparición de las letras, esto es lo que se conoce como análisis de frecuencia.

Frecuencia de las letras (%) en español.
Extraído de Intypedia. Diapositivas. Lección 1. Historia de la criptografía y su desarrollo en Europa.

Veamoslo con un ejemplo, suponed que tenemos el texto cifrado:

Js zs qzlfw ij qf Rfshmf, ij hzdt strgwj st vznjwt fhtwifwrj, st mf rzhmt ynjrut vzj anaíf zs mnifqlt ij qtx ij qfsef js fxynqqjwt, fifwlf fsynlzf, wthís kqfht d lfqlt htwwjitw. Zsf tqqf ij fqlt ráx afhf vzj hfwsjwt, xfqunhós qfx ráx sthmjx, izjqtx d vzjgwfsytx qtx xágfitx, qfsyjofx qtx anjwsjx, fqlús ufqtrnst ij fñfinizwf qtx itrnsltx, htsxzrífs qfx ywjx ufwyjx ij xz mfhnjsif.
Analisis de frecuencia: generado utilizando Cryptool 2.1

Como vemos en el texto cifrado las letras mas frecuentes son la F y la T , que muy probablemente corresponda a una de las 3 letras más frecuentes del Español [e,a,o]. Ahora es cuestión de fijarse y mirar si hay alguna distancia común entre la F y la T y alguna de esas 3 letras. Como podemos ver la distancia de la F a la A es de 5 la distancia de la T a la O también es de 5 , por lo que probablemente el desplazamiento utilizado es de 5.

Algoritmo de Vigenère

Vigenère se trata de un algoritmo de cifrado simétrico polialfabético. Fue conocido como la cifra indescifrable, resistió durante casi 300 años al criptoanálisis. Básicamente consiste en varias series de cifrado cesar general, por ello para implementar vigenere es necesario también implementar cesar. (De ahí que lo trate en el mismo post)

En la antigüedad al no existir ordenadores no se ponían a calcular el cesar por cada letra si no que se utilizaba la siguiente tabla para cifrar con vigenere donde se cogía la intersección entre la fila (dada por el texto plano) y la columna (dada por la letra de la clave)

El algoritmo prosigue de la siguiente forma: Se introduce una clave de longitud menor o igual al texto, si es menor que el texto se repite cíclicamente hasta ser de la misma longitud. Vigenere utiliza para cifrar cada letra, el desplazamiento asociado a la letra de la clave que le corresponde:

 ej: m:HOLAATODOS --> HOLAATODOS 
     c:dos        --> DOSDOSDOSD
     m:           --> KCDDOLRRGV

Implementación en Python:

  • Cifrado
def vigenere_cipher(plain,clave):
result = ""
for i in range(0,len(plain)): #Para todo el texto
   desp = get_desp(clave[i % len(clave)]) #Desplazamiento asociado a la letra clave
   result +=(caesar_cipher(plain[i],desp)) #Ciframos la letra con caesar 
return result
  • Descifrado

Como la función de cifrado solo que se llama a la función de descifrado de cesar, en vez de la cifrado

def vigenere_decipher(text,clave):
result = ""
for i in range(0,len(text)): #Para todo el texto
desp = get_desp(clave[i % len(clave)]) #Obtenemos el desplazamiento asociado a la clave
result +=(caesar_decipher(text[i],desp)) #desciframos la letra con caesar para el desplazamiento dado
return result

En cuanto al criptoanalisis de Vigenère, al ser un cifrado de sustitución polialfabetico no es posible apliacar el analisis de frecuencia, ya que no existe una correlación tan clara entre el texto clave y cifrado. Entonces como se puede criptoanalizar? Pues bien lo veremos en detalle en el proximo post de criptografia en python

3 respuestas a “Criptografía en Python: Cifrado cesar y vigenère

Add yours

  1. Hola, muchas gracias por el post antes que nada. Sólo tengo una duda y es: ¿Qué significa ‘get_desp’ en el cifrado y descifrado en la clave Vigenère? ¿No debería dar error por tener una variable o función no definida? Un saludo

    Me gusta

    1. Hola, get_desp es el nombre de una función auxiliar para obtener el desplazamiento de la letra, tenéis el código completo en el enlace de github aunque lo puedes implementar fácilmente así: return (ord(char.upper())-65) , siendo char la el nombre del parametro.Un saludo

      Me gusta

Deja un comentario

Esta web funciona gracias a WordPress.com.

Subir ↑

Diseña un sitio como este con WordPress.com
Comenzar