Entrada destacada

Como usar enums en Android, kotlin

Decifrar por fuerza bruta cifrado César en pyhton

En una entrada anterior de este blog vimos como programar el Cifrado César, pero ahora veremos como hacerlo de una manera un tanto más complejo, ya que en este ejemplo no solo cifraremos texto, también se verá como descifrar un código, y como hacerlo con un método de fuerza bruta.


En el ejemplo antes mencionado usabamos listas para almacenar las letras del abecedario, pero en esta ocasión usaremos el correspondiente código ASCII del caracter o también llamado valor ordinal entero.
Empecemos creando un menú, que pida al usuario elegir entre Cifrar o Descifrar.

def menuPrincipal():
 while True:
  print("================================== ")
  print("========= CIFRADO CESAR ========== ")
  print("================================== ")
  print("== a) Cifrar                    == ")
  print("== b) Decifrar                  == ")
  print("== c) Decifrar por fuerza bruta == ")
  print("== x) Salir                     == ")
  print("================================== ")
  opcion = input().lower();
  if opcion in "a,b,c,x".split(','):
   return opcion
La entrada que se obtiene siempre se convierte a minúsculas, así no importara si las mayúsculas están activadas. Se valida que la letra introducida sea una opción valida y entonces si es una opción valida retorna el string de entrada.

Si la opción introducida es a) o b) se solicita es texto que se va cifrar o descifrar.
def obtenerMensaje():
 print('Ingresa tu mensaje:')
 return input()

La siguiente función solicita al usuario cuando posiciones se moverá en el alfabeto, suponiendo que el mensaje introducido sea "abc" y seleccionamos cifrar y como clave elegimos 2 el resultado sería "cde".
def obtenerClave():
    clave = 0
    while True:
     print('Ingresa el número de clave (1-%s)' % (TAM_MAX_CLAVE))
     clave = int(input())
     if(clave >= 1 and clave <= TAM_MAX_CLAVE):
      return clave
Usamos un while para repetir el mensaje en caso que la clave introducida no este dentro del rango. TAM_MAX_CLAVE fue inicializada con un valor de 26 que son el número de caracteres entre a y z, si el valor introducido es un posición valida sale del ciclo y devuelve el valor.


Para cifrar y descifrar usamos la siguiente función, la cual recibe como parámetros:
  • la opcion (sea a o b),  
  • el mensaje y
  • la clave 
Comprobamos si la opción es 'b' (descifrar) pasamos a negativo el valor de la clave de lo contrario la clave queda tal cual. Con la ayuda de un for recorremos el mensaje como si de una lista se tratara, símbolo contendrá cada letra del mensaje por cada iteración. En cada ciclo comprobamos si el caracter pertenece al alfabeto (o sea que no sea numérico o caracteres especiales) de lo contrario simplemente se deja pasar con su valor original. Con la función ord obtenemos el valor ordinal del caracter, que es un valor numérico.

Por ejemplo A = 65 y si la clave es 2 la suma valor será 67.
Con chr hacemos lo inverso, mediante un valor ordinal obtenemos su correspondiente caracter 67 = C.

Las comprobaciones simbolo.isupper y simbolo.islower comprueban si el símbolo es mayúscula o minúscula, para cualquiera de los dos casos se verifica si el valor ordinal obtenido está fuera del alfabeto, si lo estuviera tendríamos que volver al inicio y contar aparir de ahí.
Suponiendo que el mensaje introducido sea 'Z' = 90 y la clave seleccionada sea 2 la suma seria 92 el cual corresponde a '\'. Entonces lo que hacemos es restar a esa suma el número de caracteres existentes en el alfabeto 92 - 26 = 66 el cual corresponde a 'B' lo mismo pasa si se trata de descifrar y el valor obtenido es menor al valor ordinal de A o a.
def traducirMensaje(opcion, mensaje, clave):
 if opcion == 'b':
  clave = -clave
 traduccion = ''

 for simbolo in mensaje:
  if simbolo.isalpha():
   num = ord(simbolo)
   num += clave

   if simbolo.isupper():
    if num > ord('Z'):
     num -= 26
    elif num < ord('A'):
     num += 26
   elif simbolo.islower():
    if num > ord('z'):
     num -= 26
    elif num < ord('a'):
     num += 26
   traduccion += chr(num)
  else:
   traduccion += simbolo
 return traduccion


Finalmente ejecutamos las funciones según sea la selección de opciones del usuario, como vemos para hacer el descifrado por fuerza bruta es probar con todas las claves posibles y mostrar todas las traducciones.
def main():
 while True:
  opcion = menuPrincipal()
  if opcion == 'x':
   break
  mensaje = obtenerMensaje()
  if opcion == 'c':
   print('Tu texto traducido es:')
   for clave in range(1, TAM_MAX_CLAVE):
    print(clave, traducirMensaje(opcion, mensaje, clave));
  else:
   clave = obtenerClave()
   print('Tu texto traducido es:')
   print(traducirMensaje(opcion, mensaje, clave));

Código fuente completo de CifradoCesar.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
TAM_MAX_CLAVE = 26

def menuPrincipal():
 while True:
  print("================================== ")
  print("========= CIFRADO CESAR ========== ")
  print("================================== ")
  print("== a) Cifrar                    == ")
  print("== b) Decifrar                  == ")
  print("== c) Decifrar por fuerza bruta == ")
  print("== x) Salir                     == ")
  print("================================== ")
  opcion = input().lower();
  if opcion in "a,b,c,x".split(','):
   return opcion

def obtenerMensaje():
 print('Ingresa tu mensaje:')
 return input()

def obtenerClave():
    clave = 0
    while True:
     print('Ingresa el número de clave (1-%s)' % (TAM_MAX_CLAVE))
     clave = int(input())
     if(clave >= 1 and clave <= TAM_MAX_CLAVE):
      return clave

def traducirMensaje(opcion, mensaje, clave):
 if opcion == 'b':
  clave = -clave
 traduccion = ''

 for simbolo in mensaje:
  if simbolo.isalpha():
   num = ord(simbolo)
   num += clave

   if simbolo.isupper():
    if num > ord('Z'):
     num -= 26
    elif num < ord('A'):
     num += 26
   elif simbolo.islower():
    if num > ord('z'):
     num -= 26
    elif num < ord('a'):
     num += 26
   traduccion += chr(num)
  else:
   traduccion += simbolo
 return traduccion

def main():
 while True:
  opcion = menuPrincipal()
  if opcion == 'x':
   break
  mensaje = obtenerMensaje()
  if opcion == 'c':
   print('Tu texto traducido es:')
   for clave in range(1, TAM_MAX_CLAVE):
    print(clave, traducirMensaje(opcion, mensaje, clave));
  else:
   clave = obtenerClave()
   print('Tu texto traducido es:')
   print(traducirMensaje(opcion, mensaje, clave));

if __name__ == "__main__":
 main()

Comenta tus dudas en la sección de comentarios.


Comentarios