En este post incluyo y comento un script en python para el cifrado y descifrado utilizando el cifrado de Polibio.
Antes de poner el script, comentar cómo se cifraba y descifraba manualmente.
El cifrado de Polibio se basa en una tabla de 5 x 5 (5 filas y 5 columnas) cuyas celdas o casillas se completan, desde la primera a la última fila, y en cada una de ellas desde la primera a la última columna, con las letras del alfabeto (la "I" y la "J" comparten celda, y "Ñ" excluida), de la siguiente forma:
En el script las funciones de cifrado y descifrado se implementan de la siguiente manera:
- Cifrar:
Para cifrar se sustituía cada carácter del texto en claro por el dígito de la fila y el dígito de la columna en cuya intersección se encontraba éste. Por ejemplo: la letra "E" se sustituía por 15.
En el script el cifrado se implementa de la siguiente manera:
str((alfabeto.find(caracter)//5)+1) + str((alfabeto.find(caracter)%5)+1)
- alfabeto.find(caracter): el método find() encuentra la primera ocurrencia del valor especificado en una cadena de caracteres y devuelve la posición que ésta ocupa. La primera posición es 0 y si no se encuentra el valor devuelve -1.
En el script encuentra la ocurrencia del carácter del texto en claro en el alfabeto y devuelve su posición en el mismo (de 0 a 24).
Por ejemplo, si el carácter fuese la "E" devolvería 4.
- //: el operador // obtiene el cociente de dividir el operando 1 entre el operando 2.
- %: el operador % obtiene el resto de dividir el operando 1 entre el operando 2.
- (alfabeto.find(caracter)//5)+1): obtiene el primer dígito correspondiente al cifrado del carácter, que es el correspondiente a la fila en la que se halla éste.
Por ejemplo, si el carácter fuese la "E" devolvería el cociente de 4/5 más 1, es decir, 0 + 1 = 1.
- (alfabeto.find(caracter)%5)+1): obtiene el segundo dígito correspondiente al cifrado del carácter, que es el correspondiente a la columna en la que se halla éste.
Por ejemplo, si el carácter fuese la "E" devolvería el resto de 4/5 más 1, es decir, 4 + 1 = 5.
La concatenación de estos dos último dígitos da como resultado el par de dígitos que le corresponden en el criptograma al carácter a cifrar. si el carácter fuese la "E" el par de dígitos sería 15.
- Descifrar:
De forma recíproca, para descifrar se sustituía cada par de dígitos del criptograma por la letra que se encontraba en la intersección de la fila (primer dígito) y columna (segundo dígito). Por ejemplo: el par de dígitos 15 se sustituía por la "E".
En el script el descifrado se implementa de la siguiente manera:
str(alfabeto[((int(digito1)-1)*5) + (int(digito2)-1)])
alfabeto[((int(digito1)-1)*5) + (int(digito2)-1)]: obtiene el carácter descifrado buscando el que se encuentra en el alfabeto en la posición que resulta de la suma del primer dígito que le correspondió en el cifrado menos 1 y multiplicado por 5 (número de columnas) más el segundo dígito que le correspondió en el cifrado menos 1.
Por ejemplo, si el par de dígitos de un carácter a descifrar es 15, ((1 - 1) * 5) + (5 - 1) = 0 + 4 = 4, que es la posición en la que se encuentra la letra "E" en el alfabeto.
- Script python del cifrado de Polibio:
El script es el siguiente:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# CIFRADO DE POLIBIO
#
# Cifra y descifra textos en claro y criptogramas, respectivamente,
# utilizando el cifrado de Polibio.
#
# http://mikelgarcialarragan.blogspot.com/
import re
from unicodedata import normalize
# ALFABETO:
alfabeto = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
# FUNCIÓN DE CIFRADO:
def cifrar(texto_claro):
criptograma = ''
for caracter in texto_claro:
criptograma = criptograma + str((alfabeto.find(caracter)//5)+1) + str((alfabeto.find(caracter)%5)+1)
return criptograma
# FUNCIÓN DE DESCIFRADO:
def descifrar(criptograma):
texto_claro = ''
for i in range(0,len(criptograma)-1,2):
digito1 = criptograma[i]
digito2 = criptograma[i+1]
texto_claro = texto_claro + str(alfabeto[((int(digito1)-1)*5) + (int(digito2)-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 introduce el texto en claro. Se convierten los caracteres a mayúsculas,
# el carácter "J" se sustituye por "I" y la letra "Ñ" por "N", y se eliminan los espacios,
# las tildes, diéresis, etc.
texto_claro = "*"
while not texto_claro.isalpha():
texto_claro = input('Texto en claro a cifrar: ').upper()
texto_claro = texto_claro.replace('J','I')
texto_claro = texto_claro.replace('Ñ','N')
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)
criptograma = cifrar(texto_claro)
print ("[+] Criptograma:", criptograma)
else:
print ("*** ERROR: El texto en claro a cifrar sólo debe contener caracteres alfabéticos.")
elif opcion == "2":
print ("")
print ("--- DESCIFRAR:")
# Descifrar: Se introduce el criptograma.
criptograma = "*"
while not criptograma.isnumeric() or len(criptograma)%2 != 0:
criptograma = input('Criptograma a descifrar: ')
if criptograma.isnumeric():
for digito in criptograma:
if int(digito) < 1 or int(digito) > 5:
criptograma = "*"
break
if criptograma.isnumeric():
if len(criptograma)%2 == 0:
print ("[+] Criptograma a descifrar:", criptograma)
texto_claro = descifrar(criptograma)
print ("[+] Texto en claro:", texto_claro)
else:
print ("*** ERROR: El criptograma debe tener un número par de dígitos.")
else:
print ("*** ERROR: El criptograma a descifrar sólo debe contener dígitos del 1 al 5.")
else:
print ("*** ERROR: El criptograma a descifrar sólo debe contener dígitos.")
elif opcion == "3":
print ("*** FIN ******************************************")
salir = True
else:
print ("*** ERROR: Opción no válida.")
if __name__ == '__main__':
main()
Lo ejecuto:
- Cifrar:
Nótese que el script ha sustituido el carácter "j" que se ha introducido en el texto en claro a cifrar por "I", ya que "I" y "J" comparten la misma celda en el cuadrado de Polibio. Además, si se hubiera introducido la letra "Ñ" el script la habría sustituido por "N".
- Descifrar:
Comentarios
Publicar un comentario