El cifrado de César es un tipo de cifrado simple que se basa en el uso de un sólo alfabeto, por lo regular, ordenado. Se emplea una llave para realizar la sustitución. Por ejemplo, si la llave vale 1 y el mensaje es ‘A’, entonces, el mensaje cifrado será ‘B’, y así sucesivamente.
A diferencia de otros algoritmos, como el de Vigenére, se emplea una sola llave para cifrar todo el mensaje.
Para saber más sobre el método de César, este es un libro excelente Cryptography Decrypted
Implementación
Vamos a crear cuatro funciones para el algoritmo:
- get_alphabet()
- get_index()
- crypt()
- decrypt()
La función get_alphabet() devolverá una lista con todos los elementos del alfabeto y otros, como números lo que se desee agregar.
def get_alphabet():
"""Devuelve una lista con mayusculas, minuscula, numeros y un espacio"""
alphabet = []
# mayusculas:65-90
for i in range(65,91):
alphabet.append(chr(i))
# minusculas:97-122
for i in range(97,123):
alphabet.append(chr(i))
# numeros
for i in range(10):
alphabet.append(str(i))
# espacio
#alphabet.append(" ")
return alphabet
La función get_index() se usa para validar la llave. En nuestro caso el alfabeto consta de 62 elementos (length), por lo que nuestro índice máximo (max_index) dentro de la lista es de 61 y el índice mínimo (min_index) es 0. Para que un índice sea válido, debe estar en este rango.
En teoría, el algoritmo sólo sirve para un cierto valor de llaves. En un alfabeto de 25 elementos, habrá un máximo de 25 llaves distintas, ya que después se repetirán los valores, es decir, si la llave vale 26, producirá el mismo cifrado que la llave con valor de 1.
def get_index(index = 0, length = 0):
"""Devuelve un indice valido dentro de un rango, evitando desbordamiento"""
min_index = 0 # indice minimo
max_index = length - 1 # indice maximo = longitud - 1
while True:
# index excede el limite superior
if index > max_index:
index -= length
# index es menor al limite inferior
elif index < min_index:
index += length
# index es valido
else:
break
return index
La función crypt() recibe dos parámetros, el mensaje a cifrar y la llave. Inicia con la declaración de variables. Enseguida, recorre cada letra del mensaje. Si la letra se encuentra dentro de alphabet, se devolverá su índice dentro de la lista. Sino es así, letter no existe dentro de alphabet, provocando una excepción y continuando con la siguiente letra.
La sustitución se realiza de esta forma. Se incrementa index el valor de key y se guarda en move. Si move no fuese un índice válido se evaluará con get_index(). Por ejemplo, si move vale 63 excede el valor de max_index, por lo que se devolverá 1.
Por último se agrega el elemento de alphabet en la posición move al crypted.
def crypt(message = "", key = 0):
"""Cifra un mensaje usando sustitucion"""
crypted = "" # mensaje cifrado
alphabet = get_alphabet() # alfabeto
length = len(alphabet) # longitud del alfabeto
index = 0 # indice de la letra en el alfabeto
for letter in message:
# se obtiene el indice de letter dentro de alphabet, si existe
try:
index = alphabet.index(letter) # indice dentro del alfabeto
except:
print "No existe %s en el alfabeto" % (letter,)
continue
# se obtiene la nueva posicion, evitando desbordamiento
move = index + key # nueva posicion
move = get_index(move,length)
# debug
if debug:
print "move %d"%(move,)
crypted += alphabet[move] # agrega la letra al mensaje cifrado
#debug
if debug:
print "%s = %s" % (alphabet[index],alphabet[move])
return crypted
La función decrypt() es similar a la anterior, pero en lugar de incrementar el valor de key, se decrementa.
def decrypt(message = "", key = 0):
"""Decifra un mensaje usando sustitucion"""
decrypted = "" # mensaje decifrado
alphabet = get_alphabet() # alfabeto
length = len(alphabet) # longitud del alfabeto
index = 0
for letter in message:
try:
index = alphabet.index(letter) # indice dentro del alfabeto
except:
print "No existe %s en el alfabeto" % (letter,)
continue
move = index - key # nueva posicion
move = get_index(move,length)
# debug
if debug:
print "move %d"%(move,)
decrypted += alphabet[move] # agrega al mensaje decifrado
#debug
if debug:
print "%s = %s" % (alphabet[index],alphabet[move])
return decrypted
Por último, este es todo el código. Al final, se manda llamar la función crypted() y se imprime el mensaje cifrado.
#!/usr/bin/python
debug = False
# Cifrado por sustitucion
def get_alphabet():
"""Devuelve una lista con mayusculas, minuscula, numeros y un espacio"""
alphabet = []
# mayusculas:65-90
for i in range(65,91):
alphabet.append(chr(i))
# minusculas:97-122
for i in range(97,123):
alphabet.append(chr(i))
# numeros
for i in range(10):
alphabet.append(str(i))
# espacio
#alphabet.append(" ")
return alphabet
def get_index(index = 0, length = 0):
"""Devuelve un indice valido dentro de un rango, evitando desbordamiento"""
min_index = 0 # indice minimo
max_index = length - 1 # indice maximo = longitud - 1
while True:
# index excede el limite superior
if index > max_index:
index -= length
# index es menor al limite inferior
elif index < min_index:
index += length
# index es valido
else:
break
return index
def crypt(message = "", key = 0):
"""Cifra un mensaje usando sustitucion"""
crypted = "" # mensaje cifrado
alphabet = get_alphabet() # alfabeto
length = len(alphabet) # longitud del alfabeto
index = 0 # indice de la letra en el alfabeto
for letter in message:
# se obtiene el indice de letter dentro de alphabet, si existe
try:
index = alphabet.index(letter) # indice dentro del alfabeto
except:
print "No existe %s en el alfabeto" % (letter,)
continue
# se obtiene la nueva posicion, evitando desbordamiento
move = index + key # nueva posicion
move = get_index(move,length)
# debug
if debug:
print "move %d"%(move,)
crypted += alphabet[move] # agrega la letra al mensaje cifrado
#debug
if debug:
print "%s = %s" % (alphabet[index],alphabet[move])
return crypted
def decrypt(message = "", key = 0):
"""Decifra un mensaje usando sustitucion"""
decrypted = "" # mensaje decifrado
alphabet = get_alphabet() # alfabeto
length = len(alphabet) # longitud del alfabeto
index = 0
for letter in message:
try:
index = alphabet.index(letter) # indice dentro del alfabeto
except:
print "No existe %s en el alfabeto" % (letter,)
continue
move = index - key # nueva posicion
move = get_index(move,length)
# debug
if debug:
print "move %d"%(move,)
decrypted += alphabet[move] # agrega al mensaje decifrado
#debug
if debug:
print "%s = %s" % (alphabet[index],alphabet[move])
return decrypted
# inicio
print "Cifrado por sustitucion"
print "Mensaje:"
message = raw_input()
print "Llave:"
key = int(raw_input())
# mensaje cifrado
crypted = crypt(message,key)
print crypted
Ejemplos
# key = 1
auraham@machine:~/projects/python$ python -i cifrar_sustitucion.py
Cifrado por sustitucion
Mensaje:
hola
Llave:
1
ipmb
# key = 62, tiene el mismo efecto de key = 0, es decir, no cifra
auraham@machine:~/projects/python$ python -i cifrar_sustitucion.py
Cifrado por sustitucion
Mensaje:
hola
Llave:
62
hola
# key = 63, tiene el mismo efecto que key = 1
auraham@machine:~/projects/python$ python -i cifrar_sustitucion.py
Cifrado por sustitucion
Mensaje:
hola
Llave:
63
ipmb