En este post incluyo y comento un script en python para el cifrado y descifrado utilizando la escítala espartana.
Antes de poner el script, comentar cómo se cifraba y descifraba manualmente.
El cifrado utilizando la escítala se basa en sendas varas de grosor igual o similar que debían estar en posesión del emisor y del receptor del mensaje secreto.
Para cifrar un mensaje el emisor enrollaba una cinta de cuero en su vara y escribía el mensaje longitudinalmente en la cinta:
Después desenrollaba la cinta y se la enviaba al receptor del mensaje.
De esta forma el mensaje secreto "ESCITALAEJEMPLODECIFRADO" escrito en una cinta de cuero en la que en cada una de las vueltas de ésta sobre la vara se mostrasen tres filas, al ser desenrollada la cinta se leería: "EEESJCCEIIMFTPRALALODADO".
Para descifrar un mensaje el receptor enrollaba la cinta de cuero que había recibido en su vara y leía longitudinalmente la letras que se mostraban en la cinta:
En el script las funciones de cifrado y descifrado se implementan de la siguiente manera:
- Cifrar:
Se puede pensar en la escítala como una tabla o matriz de i filas y j columnas. En el ejemplo que se muestra en la figura anterior y que veremos más adelante al ejecutar el script, de 3 filas y 8 columnas.
El número de filas sería el grosor de la escítala, lo que puede considerarse como la clave; tanto emisor como receptor tienen que tener una vara del mismo o similar grosor, es decir, deben compartir la misma clave (cifrado simétrico), para que el mensaje secreto pueda comunicarse del primero al segundo con éxito.
Para cifrar basta con transponer la tabla o matriz que resulta de escribir longitudinalmente el texto en claro en la cinta de cuero enrollada en la escítala, o lo que es lo mismo intercambiar las filas por columnas, y leer el resultado por filas. El número de columnas se calcula a partir de la longitud del texto en claro y del grosor (número de filas): si el resto de dividir la longitud del texto plano entre el grosor de la escítala es cero, el número de columnas será el cociente de dicha división; si el resto es diferente de cero, el número de columnas será el cociente de dicha división más 1.
En el ejemplo anterior: como resto(longitud texto plano / grosor escítala) = resto(24 / 3) = 0, entonces número de columnas = cociente(longitud texto plano / grosor escítala) = cociente(24 / 3) = 8.
Lo que en el script se implementa mediante el cálculo indicado en el párrafo anterior y dos bucles anidados:
- Descifrar:
Para descifrar basta con transponer la tabla o matriz transpuesta que se obtuvo en el cifrado, es decir transponer una tabla (intercambiar filas por columnas) con un número de columnas igual que el grosor de la escítala y en la que se incluyen, de la primera fila a la última y dentro de cada fila de la primera columna a la última, todos los caracteres del criptograma, y leer el resultado por filas.
Lo que en el script se implementa mediante dos bucles anidados:
for i in range(0,int(grosor)):
for j in range(j,len(criptograma),int(grosor)):
texto_claro+=criptograma[j]
j=i+1
- Script python del cifrado utilizando la escítala espartana:
El script es el siguiente:
#!/usr/bin/env python # -*- coding: utf-8 -*- # LA ESCÍTALA ESPARTANA: # # Cifra y descifra textos en claro y criptogramas, respectivamente, # utilizando la escítala espartana. # # http://mikelgarcialarragan.blogspot.com/ import re from unicodedata import normalize # FUNCIÓN DE CIFRADO: def cifrar(texto_claro, grosor): criptograma = '' if len(texto_claro)%int(grosor)==0: longitud=len(texto_claro)//int(grosor) else: longitud=len(texto_claro)//int(grosor)+1 texto_claro=texto_claro.ljust(int(grosor)*longitud) j=0 for i in range(0,int(longitud)): for j in range(j,len(texto_claro),int(longitud)): criptograma+=texto_claro[j] j=i+1 return criptograma # FUNCIÓN DE DESCIFRADO: def descifrar(criptograma, grosor): texto_claro = '' j=0 for i in range(0,int(grosor)): for j in range(j,len(criptograma),int(grosor)): texto_claro+=criptograma[j] j=i+1 return texto_claro # MENÚ: # Se presenta el menú para que se seleccione una opción. def main(): salir = False while not salir: print ("") print ("*** MENÚ *****************************************") print ("1. Cifrar.") print ("2. Descifrar.") print ("3. Salir.") print ("") opcion = input("Por favor, seleccione una opción: ") if opcion == "1": print ("") print ("--- CIFRAR:") # Cifrar: Se introducen el texto en claro y el grosor de la escítala (número de filas). # Se convierten los caracteres del texto en claro a mayúsculas y se eliminan de él # los espacios, las tildes, diéresis, etc. texto_claro = grosor = "*" while not texto_claro.isalpha(): texto_claro = input('Texto en claro a cifrar: ').upper() texto_claro = texto_claro.replace(' ','') texto_claro = re.sub(r"([^n\u0300-\u036f]|n(?!\u0303(?![\u0300-\u036f])))[\u0300-\u036f]+", r"\1", normalize("NFD", texto_claro), 0, re.I) texto_claro = normalize("NFC", texto_claro) if texto_claro.isalpha(): print ("[+] Texto en claro a cifrar:", texto_claro) while not grosor.isnumeric(): grosor = input('Grosor de la escítala (número de filas): ') if grosor.isnumeric(): print ("[+] Grosor de la escítala (número de filas):", grosor) criptograma = cifrar(texto_claro, grosor) print ("[+] Criptograma:", criptograma) else: print ("*** ERROR: El grosor de la escítala (número de filas) debe ser numérico.") else: print ("*** ERROR: El texto en claro a cifrar sólo debe contener caracteres alfabéticos.") elif opcion == "2": print ("") print ("--- DESCIFRAR:") # Descifrar: Se introducen el criptograma y el grosor de la escítala (número de filas). # Se convierten los caracteres del criptograma a mayúsculas y se eliminan de él # los espacios, las tildes, diéresis, etc. criptograma = grosor = "*" while not criptograma.isalpha(): criptograma = input('Criptograma a descifrar: ').upper() criptograma = re.sub(r"([^n\u0300-\u036f]|n(?!\u0303(?![\u0300-\u036f])))[\u0300-\u036f]+", r"\1", normalize("NFD", criptograma), 0, re.I) criptograma = normalize("NFC", criptograma) criptograma = criptograma.replace(' ','ñ') if criptograma.isalpha(): criptograma = criptograma.replace('ñ',' ') print ("[+] Criptograma a descifrar:", criptograma) while not grosor.isnumeric(): grosor = input('Grosor de la escítala (número de filas):') if grosor.isnumeric(): print ("[+] Grosor de la escítala (número de filas):", grosor) texto_claro = descifrar(criptograma, grosor) print ("[+] Texto en claro:", texto_claro) criptograma = criptograma.replace(' ','') else: print ("*** ERROR: El grosor de la escítala (número de filas) debe ser numérico.") else: print ("*** ERROR: El criptograma a descifrar sólo debe contener caracteres alfabéticos.") elif opcion == "3": print ("*** FIN ******************************************") salir = True else: print ("*** ERROR: Opción no válida.") if __name__ == '__main__': main()
Lo ejecuto:
- Cifrar:
- Descifrar:
Comentarios
Publicar un comentario