Criptografía con Python - Guía rápida
La criptografía es el arte de la comunicación entre dos usuarios mediante mensajes codificados. La ciencia de la criptografía surgió con el motivo básico de brindar seguridad a los mensajes confidenciales transferidos de una parte a otra.
La criptografía se define como el arte y la ciencia de ocultar el mensaje para introducir la privacidad y el secreto reconocidos en la seguridad de la información.
Terminologías de criptografía
Los términos de uso frecuente en criptografía se explican aquí:
Texto sin formato
El mensaje de texto sin formato es el texto que es legible y puede ser entendido por todos los usuarios. El texto sin formato es el mensaje que se somete a criptografía.
Texto cifrado
El texto cifrado es el mensaje que se obtiene después de aplicar la criptografía en texto plano.
Cifrado
El proceso de convertir texto sin formato en texto cifrado se denomina cifrado. También se denomina codificación.
Descifrado
El proceso de convertir texto cifrado en texto sin formato se llama descifrado. También se denomina decodificación.
El diagrama que se muestra a continuación muestra una ilustración del proceso completo de criptografía:
Características de la criptografía moderna
Las características básicas de la criptografía moderna son las siguientes:
Opera en secuencias de bits.
Utiliza algoritmos matemáticos para asegurar la información.
Requiere que las partes interesadas en un canal de comunicación seguro logren privacidad.
El cifrado de doble fuerza, también llamado cifrado múltiple, es el proceso de cifrar un texto ya cifrado una o más veces, ya sea con el mismo algoritmo o patrón o con uno diferente.
Los otros nombres para el cifrado de doble fuerza incluyen cifrado en cascada o cifrado en cascada.
Niveles de cifrado de doble fuerza
El cifrado de doble fuerza incluye varios niveles de cifrado que se explican a continuación:
Primera capa de cifrado
El texto cifrado se genera a partir del mensaje legible original utilizando algoritmos hash y claves simétricas. Las claves simétricas posteriores se cifran con la ayuda de claves asimétricas. La mejor ilustración para este patrón es combinar el resumen de hash del texto cifrado en una cápsula. El receptor calculará el resumen primero y luego descifrará el texto para verificar que el texto no esté alterado en el medio.
Segunda capa de cifrado
La segunda capa de cifrado es el proceso de agregar una capa más para cifrar el texto con el mismo o diferente algoritmo. Por lo general, se utiliza una contraseña simétrica de 32 bits de caracteres de longitud para lo mismo.
Tercera capa de cifrado
En este proceso, la cápsula cifrada se transmite a través de una conexión SSL / TLS al socio de comunicación.
El siguiente diagrama muestra gráficamente el proceso de doble cifrado:
Criptografía híbrida
La criptografía híbrida es el proceso de utilizar múltiples cifrados de diferentes tipos al incluir los beneficios de cada uno de los cifrados. Existe un enfoque común que generalmente se sigue para generar una clave secreta aleatoria para un cifrado simétrico y luego cifrar esta clave mediante criptografía de clave asimétrica.
Debido a este patrón, el mensaje original en sí se encripta usando el cifrado simétrico y luego usando la clave secreta. El receptor después de recibir el mensaje descifra el mensaje usando primero la clave secreta, usando su propia clave privada y luego usa la clave especificada para descifrar el mensaje.
Python es un lenguaje de programación de código abierto que es de alto nivel, interpretado, interactivo y orientado a objetos. Está diseñado para ser muy legible. La sintaxis del lenguaje Python es fácil de entender y utiliza palabras clave en inglés con frecuencia.
Características del lenguaje Python
Python proporciona las siguientes características principales:
Interpretado
Python se procesa en tiempo de ejecución mediante el intérprete. No es necesario compilar un programa antes de su ejecución. Es similar a PERL y PHP.
Orientado a objetos
Python sigue patrones de diseño y estilo orientados a objetos. Incluye definición de clase con varias características como encapsulación y polimorfismo.
Puntos clave del lenguaje Python
Los puntos clave del lenguaje de programación Python son los siguientes:
Incluye programación y métodos funcionales y estructurados, así como métodos de programación orientada a objetos.
Se puede utilizar como lenguaje de programación o como lenguaje de programación.
Incluye recolección automática de basura.
Incluye tipos de datos dinámicos de alto nivel y admite varias comprobaciones de tipos dinámicos.
Python incluye una función de integración con C, C ++ y lenguajes como Java.
El enlace de descarga para el lenguaje Python es el siguiente: www.python.org/downloads Incluye paquetes para varios sistemas operativos como distribuciones de Windows, MacOS y Linux.
Cadenas de Python
La declaración básica de cadenas se muestra a continuación:
str = 'Hello World!'
Listas de Python
Las listas de Python se pueden declarar como tipos de datos compuestos, separados por comas y encerrados entre corchetes ([]).
list = [ 'abcd', 786 , 2.23, 'john', 70.2 ]
tinylist = [123, 'john']
Tuplas de Python
Una tupla es un tipo de datos dinámico de Python que consta de un número de valores separados por comas. Las tuplas están entre paréntesis.
tinytuple = (123, 'john')
Diccionario de Python
El diccionario de Python es un tipo de tabla hash. Una clave de diccionario puede ser casi cualquier tipo de datos de Python, que suelen ser números o cadenas.
tinydict = {'name': 'omkar','code':6734, 'dept': 'sales'}
Paquetes de criptografía
Python incluye un paquete llamado criptografía que proporciona recetas y primitivas criptográficas. Es compatible con Python 2.7, Python 3.4+ y PyPy 5.3+. La instalación básica del paquete de criptografía se logra mediante el siguiente comando:
pip install cryptography
Hay varios paquetes con recetas de alto nivel e interfaces de bajo nivel para algoritmos criptográficos comunes como symmetric ciphers, message digests y key derivation functions.
A lo largo de este tutorial, utilizaremos varios paquetes de Python para la implementación de algoritmos criptográficos.
El capítulo anterior le dio una descripción general de la instalación de Python en su computadora local. En este capítulo, aprenderá en detalle sobre el cifrado inverso y su codificación.
Algoritmo de cifrado inverso
El algoritmo de cifrado inverso tiene las siguientes características:
Reverse Cipher utiliza un patrón de invertir la cadena de texto sin formato para convertir como texto cifrado.
El proceso de cifrado y descifrado es el mismo.
Para descifrar el texto cifrado, el usuario simplemente necesita invertir el texto cifrado para obtener el texto sin formato.
Retirarse
El principal inconveniente del cifrado inverso es que es muy débil. Un pirata informático puede romper fácilmente el texto cifrado para obtener el mensaje original. Por lo tanto, el cifrado inverso no se considera una buena opción para mantener un canal de comunicación seguro.
Ejemplo
Considere un ejemplo donde la declaración This is program to explain reverse cipherse implementará con un algoritmo de cifrado inverso. El siguiente código de Python usa el algoritmo para obtener el resultado.
message = 'This is program to explain reverse cipher.'
translated = '' #cipher text is stored in this variable
i = len(message) - 1
while i >= 0:
translated = translated + message[i]
i = i - 1
print(“The cipher text is : “, translated)
Salida
Puede ver el texto invertido, que es el resultado como se muestra en la siguiente imagen:
Explicación
El texto sin formato se almacena en el mensaje de la variable y la variable traducida se utiliza para almacenar el texto cifrado creado.
La longitud del texto sin formato se calcula utilizando for bucle y con la ayuda de index number. Los caracteres se almacenan en la variable de texto cifradotranslated que está impreso en la última línea.
En el último capítulo, nos ocupamos del cifrado inverso. Este capítulo habla sobre el cifrado César en detalle.
Algoritmo de cifrado César
El algoritmo del cifrado Caesar tiene las siguientes características:
La técnica de cifrado Caesar es un método sencillo y sencillo de técnica de cifrado.
Es un tipo simple de cifrado de sustitución.
Cada letra de texto sin formato se reemplaza por una letra con un número fijo de posiciones hacia abajo con el alfabeto.
El siguiente diagrama muestra el funcionamiento de la implementación del algoritmo de cifrado Caesar:
La implementación del programa del algoritmo de cifrado Caesar es la siguiente:
def encrypt(text,s):
result = ""
# transverse the plain text
for i in range(len(text)):
char = text[i]
# Encrypt uppercase characters in plain text
if (char.isupper()):
result += chr((ord(char) + s-65) % 26 + 65)
# Encrypt lowercase characters in plain text
else:
result += chr((ord(char) + s - 97) % 26 + 97)
return result
#check the above function
text = "CEASER CIPHER DEMO"
s = 4
print "Plain Text : " + text
print "Shift pattern : " + str(s)
print "Cipher: " + encrypt(text,s)
Salida
Puede ver el cifrado César, que es el resultado como se muestra en la siguiente imagen:
Explicación
El carácter de texto sin formato se recorre de uno en uno.
Para cada carácter en el texto sin formato dado, transforme el carácter dado según la regla según el procedimiento de cifrado y descifrado del texto.
Después de seguir los pasos, se genera una nueva cadena que se conoce como texto cifrado.
Hackeo del algoritmo de cifrado Caesar
El texto cifrado se puede piratear con varias posibilidades. Una de esas posibilidades esBrute Force Technique,que implica probar todas las claves de descifrado posibles. Esta técnica no requiere mucho esfuerzo y es relativamente simple para un pirata informático.
La implementación del programa para piratear el algoritmo de cifrado Caesar es la siguiente:
message = 'GIEWIVrGMTLIVrHIQS' #encrypted message
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for key in range(len(LETTERS)):
translated = ''
for symbol in message:
if symbol in LETTERS:
num = LETTERS.find(symbol)
num = num - key
if num < 0:
num = num + len(LETTERS)
translated = translated + LETTERS[num]
else:
translated = translated + symbol
print('Hacking key #%s: %s' % (key, translated))
Considere el texto cifrado encriptado en el ejemplo anterior. Luego, la salida con posibles métodos de piratería con la clave y el uso de la técnica de ataque de fuerza bruta es la siguiente:
Hasta ahora, ha aprendido sobre el cifrado inverso y los algoritmos de cifrado César. Ahora, analicemos el algoritmo ROT13 y su implementación.
Explicación del algoritmo ROT13
El cifrado ROT13 se refiere a la forma abreviada Rotate by 13 places. Es un caso especial de Caesar Cipher en el que el cambio es siempre 13. Cada letra se desplaza 13 lugares para cifrar o descifrar el mensaje.
Ejemplo
El siguiente diagrama explica gráficamente el proceso del algoritmo ROT13:
Código de programa
La implementación del programa del algoritmo ROT13 es la siguiente:
from string import maketrans
rot13trans = maketrans('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm')
# Function to translate plain text
def rot13(text):
return text.translate(rot13trans)
def main():
txt = "ROT13 Algorithm"
print rot13(txt)
if __name__ == "__main__":
main()
Puede ver la salida ROT13 como se muestra en la siguiente imagen:
Retirarse
El algoritmo ROT13 utiliza 13 turnos. Por lo tanto, es muy fácil cambiar los caracteres a la inversa para descifrar el texto cifrado.
Análisis del algoritmo ROT13
El algoritmo de cifrado ROT13 se considera un caso especial de Caesar Cipher. No es un algoritmo muy seguro y se puede romper fácilmente con el análisis de frecuencia o simplemente probando las posibles 25 teclas, mientras que ROT13 se puede romper cambiando 13 lugares. Por tanto, no incluye ningún uso práctico.
Transposition Cipher es un algoritmo criptográfico en el que el orden de los alfabetos en el texto sin formato se reorganiza para formar un texto cifrado. En este proceso, no se incluyen los alfabetos de texto sin formato reales.
Ejemplo
Un ejemplo simple de un cifrado de transposición es columnar transposition cipherdonde cada carácter en el texto sin formato se escribe horizontalmente con un ancho de alfabeto especificado. El cifrado se escribe verticalmente, lo que crea un texto cifrado completamente diferente.
Considere el texto plano hello world, y apliquemos la técnica de transposición columnar simple como se muestra a continuación
Los caracteres de texto plano se colocan horizontalmente y el texto cifrado se crea con formato vertical como : holewdlo lr. Ahora, el receptor tiene que usar la misma tabla para descifrar el texto cifrado a texto sin formato.
Código
El siguiente código de programa demuestra la implementación básica de la técnica de transposición en columnas:
def split_len(seq, length):
return [seq[i:i + length] for i in range(0, len(seq), length)]
def encode(key, plaintext):
order = {
int(val): num for num, val in enumerate(key)
}
ciphertext = ''
for index in sorted(order.keys()):
for part in split_len(plaintext, len(key)):
try:ciphertext += part[order[index]]
except IndexError:
continue
return ciphertext
print(encode('3214', 'HELLO'))
Explicación
Usando la función split_len(), podemos dividir los caracteres de texto sin formato, que se pueden colocar en formato de columna o de fila.
encode El método ayuda a crear texto cifrado con la clave que especifica el número de columnas e imprime el texto cifrado leyendo caracteres en cada columna.
Salida
El código del programa para la implementación básica de la técnica de transposición en columnas da el siguiente resultado:
Note- Los criptoanalistas observaron una mejora significativa en la seguridad criptográfica cuando se realiza la técnica de transposición. También señalaron que volver a cifrar el texto cifrado utilizando el mismo cifrado de transposición crea una mejor seguridad.
En el capítulo anterior, aprendimos sobre Transposition Cipher. En este capítulo, analicemos su cifrado.
Pyperclip
El uso principal de pyperclipEl complemento en el lenguaje de programación Python es realizar un módulo multiplataforma para copiar y pegar texto en el portapapeles. Puedes instalar Pythonpyperclip módulo usando el comando como se muestra
pip install pyperclip
Si el requisito ya existe en el sistema, puede ver el siguiente resultado:
Código
El código de Python para cifrar el cifrado de transposición en el que pyperclip es el módulo principal es el que se muestra a continuación:
import pyperclip
def main():
myMessage = 'Transposition Cipher'
myKey = 10
ciphertext = encryptMessage(myKey, myMessage)
print("Cipher Text is")
print(ciphertext + '|')
pyperclip.copy(ciphertext)
def encryptMessage(key, message):
ciphertext = [''] * key
for col in range(key):
position = col
while position < len(message):
ciphertext[col] += message[position]
position += key
return ''.join(ciphertext) #Cipher text
if __name__ == '__main__':
main()
Salida
El código del programa para cifrar el cifrado de transposición en el que pyperclip es el módulo principal da la siguiente salida:
Explicación
La función main() llama al encryptMessage() que incluye el procedimiento para dividir los caracteres usando len función e iterarlos en un formato columnar.
La función principal se inicializa al final para obtener la salida adecuada.
En este capítulo, aprenderá el procedimiento para descifrar el cifrado de transposición.
Código
Observe el siguiente código para comprender mejor cómo descifrar un cifrado de transposición. El texto cifrado del mensajeTransposition Cipher con llave como 6 se busca como Toners raiCntisippoh.
import math, pyperclip
def main():
myMessage= 'Toners raiCntisippoh'
myKey = 6
plaintext = decryptMessage(myKey, myMessage)
print("The plain text is")
print('Transposition Cipher')
def decryptMessage(key, message):
numOfColumns = math.ceil(len(message) / key)
numOfRows = key
numOfShadedBoxes = (numOfColumns * numOfRows) - len(message)
plaintext = float('') * numOfColumns
col = 0
row = 0
for symbol in message:
plaintext[col] += symbol
col += 1
if (col == numOfColumns) or (col == numOfColumns - 1 and row >= numOfRows - numOfShadedBoxes):
col = 0 row += 1 return ''.join(plaintext)
if __name__ == '__main__':
main()
Explicación
El texto cifrado y la clave mencionada son los dos valores que se toman como parámetros de entrada para decodificar o descifrar el texto cifrado en técnica inversa colocando caracteres en formato de columna y leyéndolos de manera horizontal.
Puede colocar letras en un formato de columna y luego combinarlas o concatenarlas usando el siguiente código:
for symbol in message:
plaintext[col] += symbol
col += 1
if (col == numOfColumns) or (col == numOfColumns - 1 and row >= numOfRows - numOfShadedBoxes):
col = 0
row += 1
return ''.join(plaintext)
Salida
El código del programa para descifrar el cifrado de transposición da la siguiente salida:
En Python, es posible cifrar y descifrar archivos antes de transmitirlos a un canal de comunicación. Para esto, tendrás que usar el complementoPyCrypto. Puede instalar este complemento usando el comando que se proporciona a continuación.
pip install pycrypto
Código
El código del programa para cifrar el archivo con protector de contraseña se menciona a continuación:
# =================Other Configuration================
# Usages :
usage = "usage: %prog [options] "
# Version
Version="%prog 0.0.1"
# ====================================================
# Import Modules
import optparse, sys,os
from toolkit import processor as ps
def main():
parser = optparse.OptionParser(usage = usage,version = Version)
parser.add_option(
'-i','--input',type = 'string',dest = 'inputfile',
help = "File Input Path For Encryption", default = None)
parser.add_option(
'-o','--output',type = "string",dest = 'outputfile',
help = "File Output Path For Saving Encrypter Cipher",default = ".")
parser.add_option(
'-p','--password',type = "string",dest = 'password',
help = "Provide Password For Encrypting File",default = None)
parser.add_option(
'-p','--password',type = "string",dest = 'password',
help = "Provide Password For Encrypting File",default = None)
(options, args)= parser.parse_args()
# Input Conditions Checkings
if not options.inputfile or not os.path.isfile(options.inputfile):
print " [Error] Please Specify Input File Path"
exit(0)
if not options.outputfile or not os.path.isdir(options.outputfile):
print " [Error] Please Specify Output Path"
exit(0)
if not options.password:
print " [Error] No Password Input"
exit(0)
inputfile = options.inputfile
outputfile = os.path.join(
options.outputfile,os.path.basename(options.inputfile).split('.')[0]+'.ssb')
password = options.password
base = os.path.basename(inputfile).split('.')[1]
work = "E"
ps.FileCipher(inputfile,outputfile,password,work)
return
if __name__ == '__main__':
main()
Puede usar el siguiente comando para ejecutar el proceso de cifrado junto con la contraseña:
python pyfilecipher-encrypt.py -i file_path_for_encryption -o output_path -p password
Salida
Puede observar la siguiente salida cuando ejecuta el código dado anteriormente:
Explicación
Las contraseñas se generan utilizando el algoritmo hash MD5 y los valores se almacenan en archivos de copia de seguridad simplemente seguros en el sistema Windows, que incluye los valores que se muestran a continuación:
En este capítulo, analicemos el descifrado de archivos en criptografía usando Python. Tenga en cuenta que para el proceso de descifrado, seguiremos el mismo procedimiento, pero en lugar de especificar la ruta de salida, nos centraremos en la ruta de entrada o el archivo necesario que está encriptado.
Código
El siguiente es un código de muestra para descifrar archivos en criptografía usando Python:
#!/usr/bin/python
# ---------------- READ ME ---------------------------------------------
# This Script is Created Only For Practise And Educational Purpose Only
# This Script Is Created For http://bitforestinfo.blogspot.in
# This Script is Written By
#
#
##################################################
######## Please Don't Remove Author Name #########
############### Thanks ###########################
##################################################
#
#
# =================Other Configuration================
# Usages :
usage = "usage: %prog [options] "
# Version
Version="%prog 0.0.1"
# ====================================================
# Import Modules
import optparse, sys,os
from toolkit import processor as ps
def main():
parser = optparse.OptionParser(usage = usage,version = Version)
parser.add_option(
'-i','--input',type = 'string',dest = 'inputfile',
help = "File Input Path For Encryption", default = None)
parser.add_option(
'-o','--output',type = "string",dest = 'outputfile',
help = "File Output Path For Saving Encrypter Cipher",default = ".")
parser.add_option(
'-p','--password',type = "string",dest = 'password',
help = "Provide Password For Encrypting File",default = None)
(options, args) = parser.parse_args()
# Input Conditions Checkings
if not options.inputfile or not os.path.isfile(options.inputfile):
print " [Error] Please Specify Input File Path"
exit(0)
if not options.outputfile or not os.path.isdir(options.outputfile):
print " [Error] Please Specify Output Path"
exit(0)
if not options.password:
print " [Error] No
exit(0)
inputfile = options.inputfile
outputfile = options.outputfile
password = options.password
work = "D"
ps.FileCipher(inputfile,outputfile,password,work)
return
if __name__ == '__main__':
main()
Puede usar el siguiente comando para ejecutar el código anterior:
python pyfilecipher-decrypt.py -i encrypted_file_path -p password
Salida
Puede observar el siguiente código cuando ejecuta el comando que se muestra arriba:
Note - La salida especifica los valores hash antes del cifrado y después del descifrado, lo que mantiene una nota de que el mismo archivo está cifrado y el proceso fue exitoso.
La codificación Base64 convierte los datos binarios en formato de texto, que se pasa a través del canal de comunicación donde un usuario puede manejar el texto de forma segura. Base64 también se llama comoPrivacy enhanced Electronic mail (PEM) y se utiliza principalmente en el proceso de cifrado de correo electrónico.
Python incluye un módulo llamado BASE64 que incluye dos funciones principales como se indica a continuación:
base64.decode(input, output) - Decodifica el parámetro de valor de entrada especificado y almacena la salida decodificada como un objeto.
Base64.encode(input, output) - Codifica el parámetro de valor de entrada especificado y almacena la salida decodificada como un objeto.
Programa de codificación
Puede utilizar el siguiente fragmento de código para realizar la codificación base64:
import base64
encoded_data = base64.b64encode("Encode this text")
print("Encoded text with base 64 is")
print(encoded_data)
Salida
El código para la codificación base64 le da el siguiente resultado:
Programa de decodificación
Puede usar el siguiente código para realizar la decodificación base64:
import base64
decoded_data = base64.b64decode("RW5jb2RlIHRoaXMgdGV4dA==")
print("decoded text is ")
print(decoded_data)
Salida
El código para la decodificación base64 le da el siguiente resultado:
Diferencia entre ASCII y base64
Puede observar las siguientes diferencias cuando trabaja en ASCII y base64 para codificar datos:
Cuando codifica texto en ASCII, comienza con una cadena de texto y la convierte en una secuencia de bytes.
Cuando codifica datos en Base64, comienza con una secuencia de bytes y la convierte en una cadena de texto.
Retirarse
El algoritmo Base64 se usa generalmente para almacenar contraseñas en la base de datos. El mayor inconveniente es que cada palabra decodificada se puede codificar fácilmente a través de cualquier herramienta en línea y los intrusos pueden obtener la información fácilmente.
En este capítulo, entendamos el proceso XOR junto con su codificación en Python.
Algoritmo
El algoritmo XOR de cifrado y descifrado convierte el texto plano en el formato de bytes ASCII y utiliza el procedimiento XOR para convertirlo en un byte especificado. Ofrece las siguientes ventajas a sus usuarios:
- Computación rápida
- No hay diferencia marcada en el lado izquierdo y derecho
- Fácil de entender y analizar
Código
Puede utilizar el siguiente fragmento de código para realizar el proceso XOR:
def xor_crypt_string(data, key = 'awesomepassword', encode = False, decode = False):
from itertools import izip, cycle
import base64
if decode:
data = base64.decodestring(data)
xored = ''.join(chr(ord(x) ^ ord(y)) for (x,y) in izip(data, cycle(key)))
if encode:
return base64.encodestring(xored).strip()
return xored
secret_data = "XOR procedure"
print("The cipher text is")
print xor_crypt_string(secret_data, encode = True)
print("The plain text fetched")
print xor_crypt_string(xor_crypt_string(secret_data, encode = True), decode = True)
Salida
El código para el proceso XOR le da el siguiente resultado:
Explicación
La función xor_crypt_string() incluye un parámetro para especificar el modo de codificación y decodificación y también el valor de la cadena.
Las funciones básicas se toman con módulos base64 que siguen el procedimiento / operación XOR para cifrar o descifrar el texto sin formato / cifrado.
Note - El cifrado XOR se utiliza para cifrar datos y es difícil de descifrar mediante el método de fuerza bruta, es decir, generando claves de cifrado aleatorias para que coincidan con el texto cifrado correcto.
Mientras se utiliza la técnica de cifrado César, cifrar y descifrar símbolos implica convertir los valores en números con un procedimiento básico simple de suma o resta.
Si se utiliza la multiplicación para convertir a texto cifrado, se denomina wrap-aroundsituación. Considere las letras y los números asociados que se utilizarán como se muestra a continuación:
Los números se utilizarán para el procedimiento de multiplicación y la clave asociada es 7. La fórmula básica que se utilizará en tal escenario para generar un cifrado multiplicativo es la siguiente:
(Alphabet Number * key)mod(total number of alphabets)
El número obtenido a través de la salida se asigna en la tabla mencionada anteriormente y la letra correspondiente se toma como la letra cifrada.
La función de modulación básica de un cifrado multiplicativo en Python es la siguiente:
def unshift(key, ch):
offset = ord(ch) - ASC_A
return chr(((key[0] * (offset + key[1])) % WIDTH) + ASC_A)
Note- La ventaja de un cifrado multiplicativo es que puede funcionar con claves muy grandes como 8,953,851. Una computadora tardaría bastante tiempo en utilizar la fuerza bruta a través de una mayoría de nueve millones de claves.
Affine Cipher es la combinación del algoritmo Multiplicative Cipher y Caesar Cipher. La implementación básica del cifrado afín es como se muestra en la imagen a continuación:
En este capítulo, implementaremos el cifrado afín creando su clase correspondiente que incluye dos funciones básicas para el cifrado y el descifrado.
Código
Puede usar el siguiente código para implementar un cifrado afín:
class Affine(object):
DIE = 128
KEY = (7, 3, 55)
def __init__(self):
pass
def encryptChar(self, char):
K1, K2, kI = self.KEY
return chr((K1 * ord(char) + K2) % self.DIE)
def encrypt(self, string):
return "".join(map(self.encryptChar, string))
def decryptChar(self, char):
K1, K2, KI = self.KEY
return chr(KI * (ord(char) - K2) % self.DIE)
def decrypt(self, string):
return "".join(map(self.decryptChar, string))
affine = Affine()
print affine.encrypt('Affine Cipher')
print affine.decrypt('*18?FMT')
Salida
Puede observar el siguiente resultado cuando implementa un cifrado afín:
La salida muestra el mensaje cifrado para el mensaje de texto sin formato. Affine Cipher y mensaje descifrado para el mensaje enviado como entrada abcdefg.
En este capítulo, aprenderá sobre el cifrado monoalfabético y su pirateo con Python.
Cifrado monoalfabético
Un cifrado monoalfabético utiliza una sustitución fija para cifrar todo el mensaje. Aquí se muestra un cifrado monoalfabético que utiliza un diccionario Python con objetos JSON:
monoalpha_cipher = {
'a': 'm',
'b': 'n',
'c': 'b',
'd': 'v',
'e': 'c',
'f': 'x',
'g': 'z',
'h': 'a',
'i': 's',
'j': 'd',
'k': 'f',
'l': 'g',
'm': 'h',
'n': 'j',
'o': 'k',
'p': 'l',
'q': 'p',
'r': 'o',
's': 'i',
't': 'u',
'u': 'y',
'v': 't',
'w': 'r',
'x': 'e',
'y': 'w',
'z': 'q',
' ': ' ',
}
Con la ayuda de este diccionario, podemos cifrar las letras con las letras asociadas como valores en el objeto JSON. El siguiente programa crea un programa monoalfabético como una representación de clase que incluye todas las funciones de cifrado y descifrado.
from string import letters, digits
from random import shuffle
def random_monoalpha_cipher(pool = None):
if pool is None:
pool = letters + digits
original_pool = list(pool)
shuffled_pool = list(pool)
shuffle(shuffled_pool)
return dict(zip(original_pool, shuffled_pool))
def inverse_monoalpha_cipher(monoalpha_cipher):
inverse_monoalpha = {}
for key, value in monoalpha_cipher.iteritems():
inverse_monoalpha[value] = key
return inverse_monoalpha
def encrypt_with_monoalpha(message, monoalpha_cipher):
encrypted_message = []
for letter in message:
encrypted_message.append(monoalpha_cipher.get(letter, letter))
return ''.join(encrypted_message)
def decrypt_with_monoalpha(encrypted_message, monoalpha_cipher):
return encrypt_with_monoalpha(
encrypted_message,
inverse_monoalpha_cipher(monoalpha_cipher)
)
Este archivo se llama más tarde para implementar el proceso de cifrado y descifrado del cifrado monoalfabético que se menciona a continuación:
import monoalphabeticCipher as mc
cipher = mc.random_monoalpha_cipher()
print(cipher)
encrypted = mc.encrypt_with_monoalpha('Hello all you hackers out there!', cipher)
decrypted = mc.decrypt_with_monoalpha('sXGGt SGG Nt0 HSrLXFC t0U UHXFX!', cipher)
print(encrypted)
print(decrypted)
Salida
Puede observar el siguiente resultado cuando implementa el código dado anteriormente:
Por lo tanto, puede piratear un cifrado monoalfabético con un par de clave-valor especificado que convierte el texto cifrado en texto sin formato real.
El cifrado de sustitución simple es el cifrado más comúnmente utilizado e incluye un algoritmo de sustitución de cada carácter de texto plano por cada carácter de texto cifrado. En este proceso, los alfabetos se mezclan en comparación con el algoritmo de cifrado de Caesar.
Ejemplo
Las claves para un cifrado de sustitución simple generalmente constan de 26 letras. Un ejemplo de clave es:
plain alphabet : abcdefghijklmnopqrstuvwxyz
cipher alphabet: phqgiumeaylnofdxjkrcvstzwb
Un ejemplo de cifrado que utiliza la clave anterior es:
plaintext : defend the east wall of the castle
ciphertext: giuifg cei iprc tpnn du cei qprcni
El siguiente código muestra un programa para implementar cifrado de sustitución simple:
import random, sys
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def main():
message = ''
if len(sys.argv) > 1:
with open(sys.argv[1], 'r') as f:
message = f.read()
else:
message = raw_input("Enter your message: ")
mode = raw_input("E for Encrypt, D for Decrypt: ")
key = ''
while checkKey(key) is False:
key = raw_input("Enter 26 ALPHA key (leave blank for random key): ")
if key == '':
key = getRandomKey()
if checkKey(key) is False:
print('There is an error in the key or symbol set.')
translated = translateMessage(message, key, mode)
print('Using key: %s' % (key))
if len(sys.argv) > 1:
fileOut = 'enc.' + sys.argv[1]
with open(fileOut, 'w') as f:
f.write(translated)
print('Success! File written to: %s' % (fileOut))
else: print('Result: ' + translated)
# Store the key into list, sort it, convert back, compare to alphabet.
def checkKey(key):
keyString = ''.join(sorted(list(key)))
return keyString == LETTERS
def translateMessage(message, key, mode):
translated = ''
charsA = LETTERS
charsB = key
# If decrypt mode is detected, swap A and B
if mode == 'D':
charsA, charsB = charsB, charsA
for symbol in message:
if symbol.upper() in charsA:
symIndex = charsA.find(symbol.upper())
if symbol.isupper():
translated += charsB[symIndex].upper()
else:
translated += charsB[symIndex].lower()
else:
translated += symbol
return translated
def getRandomKey():
randomList = list(LETTERS)
random.shuffle(randomList)
return ''.join(randomList)
if __name__ == '__main__':
main()
Salida
Puede observar el siguiente resultado cuando implementa el código dado anteriormente:
En este capítulo, nos centraremos en probar el cifrado de sustitución utilizando varios métodos, lo que ayuda a generar cadenas aleatorias como se indica a continuación:
import random, string, substitution
def main():
for i in range(1000):
key = substitution.getRandomKey()
message = random_string()
print('Test %s: String: "%s.."' % (i + 1, message[:50]))
print("Key: " + key)
encrypted = substitution.translateMessage(message, key, 'E')
decrypted = substitution.translateMessage(encrypted, key, 'D')
if decrypted != message:
print('ERROR: Decrypted: "%s" Key: %s' % (decrypted, key))
sys.exit()
print('Substutition test passed!')
def random_string(size = 5000, chars = string.ascii_letters + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
if __name__ == '__main__':
main()
Salida
Puede observar la salida como cadenas generadas aleatoriamente que ayudan a generar mensajes de texto sin formato aleatorios, como se muestra a continuación:
Una vez que la prueba se completa con éxito, podemos observar el mensaje de salida Substitution test passed!.
Por lo tanto, puede piratear un cifrado de sustitución de manera sistemática.
En este capítulo, puede aprender acerca de la implementación simple del cifrado de sustitución que muestra el mensaje cifrado y descifrado según la lógica utilizada en la técnica de cifrado de sustitución simple. Esto puede considerarse como un enfoque alternativo de codificación.
Código
Puede utilizar el siguiente código para realizar el descifrado utilizando un cifrado de sustitución simple:
import random
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \
'abcdefghijklmnopqrstuvwxyz' + \
'0123456789' + \
':.;,?!@#$%&()+=-*/_<> []{}`~^"\'\\'
def generate_key():
"""Generate an key for our cipher"""
shuffled = sorted(chars, key=lambda k: random.random())
return dict(zip(chars, shuffled))
def encrypt(key, plaintext):
"""Encrypt the string and return the ciphertext"""
return ''.join(key[l] for l in plaintext)
def decrypt(key, ciphertext):
"""Decrypt the string and return the plaintext"""
flipped = {v: k for k, v in key.items()}
return ''.join(flipped[l] for l in ciphertext)
def show_result(plaintext):
"""Generate a resulting cipher with elements shown"""
key = generate_key()
encrypted = encrypt(key, plaintext)
decrypted = decrypt(key, encrypted)
print 'Key: %s' % key
print 'Plaintext: %s' % plaintext
print 'Encrypted: %s' % encrypted
print 'Decrypted: %s' % decrypted
show_result('Hello World. This is demo of substitution cipher')
Salida
El código anterior le da el resultado como se muestra aquí:
En este capítulo, aprenderá en detalle sobre varios módulos de criptografía en Python.
Módulo de criptografía
Incluye todas las recetas y primitivas, y proporciona una interfaz de codificación de alto nivel en Python. Puede instalar el módulo de criptografía usando el siguiente comando:
pip install cryptography
Código
Puede utilizar el siguiente código para implementar el módulo de criptografía:
from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher_suite = Fernet(key)
cipher_text = cipher_suite.encrypt("This example is used to demonstrate cryptography module")
plain_text = cipher_suite.decrypt(cipher_text)
Salida
El código dado arriba produce el siguiente resultado:
El código proporcionado aquí se utiliza para verificar la contraseña y crear su hash. También incluye lógica para verificar la contraseña con fines de autenticación.
import uuid
import hashlib
def hash_password(password):
# uuid is used to generate a random number of the specified password
salt = uuid.uuid4().hex
return hashlib.sha256(salt.encode() + password.encode()).hexdigest() + ':' + salt
def check_password(hashed_password, user_password):
password, salt = hashed_password.split(':')
return password == hashlib.sha256(salt.encode() + user_password.encode()).hexdigest()
new_pass = input('Please enter a password: ')
hashed_password = hash_password(new_pass)
print('The string to store in the db is: ' + hashed_password)
old_pass = input('Now please enter the password again to check: ')
if check_password(hashed_password, old_pass):
print('You entered the right password')
else:
print('Passwords do not match')
Salida
Scenario 1 - Si ha introducido una contraseña correcta, puede encontrar el siguiente resultado:
Scenario 2 - Si ingresamos una contraseña incorrecta, puede encontrar el siguiente resultado -
Explicación
HashlibEl paquete se utiliza para almacenar contraseñas en una base de datos. En este programa,salt se usa, lo que agrega una secuencia aleatoria a la cadena de contraseña antes de implementar la función hash.
Vignere Cipher incluye un giro con el algoritmo Caesar Cipher utilizado para el cifrado y descifrado. Vignere Cipher funciona de manera similar al algoritmo Caesar Cipher con solo una distinción importante: Caesar Cipher incluye un algoritmo para cambio de un carácter, mientras que Vignere Cipher incluye clave con cambio de varios alfabetos.
Ecuación matemática
Para el cifrado, la ecuación matemática es la siguiente:
$$ E_ {k} \ left (M {_ {i {}}} \ right) = \ left (M_ {i} + K_ {i} \ right) \; \; \; modificación \;\; 26 $$
Para el descifrado, la ecuación matemática es la siguiente:
$$ D_ {k} \ left (C {_ {i {}}} \ right) = \ left (C_ {i} -K_ {i} \ right) \; \; \; modificación \;\; 26 $$
El cifrado de Vignere utiliza más de un conjunto de sustituciones y, por lo tanto, también se denomina polyalphabetic cipher. Vignere Cipher utilizará una clave de letra en lugar de una representación de clave numérica: la letra A se utilizará para la clave 0, la letra B para la clave 1, etc. Los números de las letras antes y después del proceso de cifrado se muestran a continuación:
La posible combinación de la cantidad de claves posibles basadas en la longitud de la clave Vignere se da de la siguiente manera, lo que da el resultado de cuán seguro es el algoritmo de cifrado de Vignere:
Vignere Tableau
El cuadro utilizado para el cifrado Vignere se muestra a continuación:
En este capítulo, entendamos cómo implementar el cifrado Vignere. Considere el textoThis is basic implementation of Vignere Cipher se va a codificar y la clave utilizada es PIZZA.
Código
Puede usar el siguiente código para implementar un cifrado Vignere en Python:
import pyperclip
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def main():
myMessage = "This is basic implementation of Vignere Cipher"
myKey = 'PIZZA'
myMode = 'encrypt'
if myMode == 'encrypt':
translated = encryptMessage(myKey, myMessage)
elif myMode == 'decrypt':
translated = decryptMessage(myKey, myMessage)
print('%sed message:' % (myMode.title()))
print(translated)
print()
def encryptMessage(key, message):
return translateMessage(key, message, 'encrypt')
def decryptMessage(key, message):
return translateMessage(key, message, 'decrypt')
def translateMessage(key, message, mode):
translated = [] # stores the encrypted/decrypted message string
keyIndex = 0
key = key.upper()
for symbol in message:
num = LETTERS.find(symbol.upper())
if num != -1:
if mode == 'encrypt':
num += LETTERS.find(key[keyIndex])
elif mode == 'decrypt':
num -= LETTERS.find(key[keyIndex])
num %= len(LETTERS)
if symbol.isupper():
translated.append(LETTERS[num])
elif symbol.islower():
translated.append(LETTERS[num].lower())
keyIndex += 1
if keyIndex == len(key):
keyIndex = 0
else:
translated.append(symbol)
return ''.join(translated)
if __name__ == '__main__':
main()
Salida
Puede observar el siguiente resultado cuando implementa el código dado anteriormente:
Las posibles combinaciones de piratear el cifrado de Vignere son casi imposibles. Por lo tanto, se considera un modo de cifrado seguro.
El cifrado de almohadilla de un solo uso es un tipo de cifrado de Vignere que incluye las siguientes características:
Es una cifra indescifrable.
La clave es exactamente la misma que la longitud del mensaje cifrado.
La clave está formada por símbolos aleatorios.
Como sugiere el nombre, la clave se utiliza una sola vez y nunca se vuelve a utilizar para cifrar ningún otro mensaje.
Debido a esto, el mensaje cifrado será vulnerable al ataque de un criptoanalista. La clave utilizada para un cifrado de almohadilla de una sola vez se llamapad, ya que está impreso en blocs de papel.
¿Por qué es irrompible?
La llave es irrompible debido a las siguientes características:
La clave es tan larga como el mensaje dado.
La clave es verdaderamente aleatoria y especialmente generada automáticamente.
Texto sin formato y clave calculado como módulo 10/26/2.
Cada clave debe usarse una vez y ser destruida tanto por el remitente como por el receptor.
Debe haber dos copias de la clave: una con el remitente y otra con el receptor.
Cifrado
Para cifrar una carta, un usuario debe escribir una clave debajo del texto sin formato. La letra de texto plano se coloca en la parte superior y la letra clave a la izquierda. La sección transversal lograda entre dos letras es el texto sin formato. Se describe en el siguiente ejemplo:
Descifrado
Para descifrar una letra, el usuario toma la letra clave de la izquierda y encuentra la letra de texto cifrada en esa fila. La letra de texto sin formato se coloca en la parte superior de la columna donde el usuario puede encontrar la letra de texto cifrado.
Python incluye un módulo de implementación hacky para one-time-padimplementación de cifrado. El nombre del paquete se llama One-Time-Pad que incluye una herramienta de cifrado de línea de comandos que utiliza un mecanismo de cifrado similar al algoritmo de cifrado de un solo uso.
Instalación
Puede usar el siguiente comando para instalar este módulo:
pip install onetimepad
Si desea usarlo desde la línea de comandos, ejecute el siguiente comando:
onetimepad
Código
El siguiente código ayuda a generar un cifrado de almohadilla de una sola vez:
import onetimepad
cipher = onetimepad.encrypt('One Time Cipher', 'random')
print("Cipher text is ")
print(cipher)
print("Plain text is ")
msg = onetimepad.decrypt(cipher, 'random')
print(msg)
Salida
Puede observar el siguiente resultado cuando ejecuta el código dado anteriormente:
Note - El mensaje cifrado es muy fácil de descifrar si la longitud de la clave es menor que la longitud del mensaje (texto sin formato).
En cualquier caso, la clave no es necesariamente aleatoria, lo que hace que el cifrado de un solo uso sea una herramienta útil.
En este capítulo, analicemos en detalle acerca de la criptografía simétrica y asimétrica.
Criptografía simétrica
En este tipo, el proceso de cifrado y descifrado utiliza la misma clave. También se llama comosecret key cryptography. Las principales características de la criptografía simétrica son las siguientes:
- Es más sencillo y rápido.
- Las dos partes intercambian la clave de forma segura.
Retirarse
El principal inconveniente de la criptografía simétrica es que si la clave se filtra al intruso, el mensaje se puede cambiar fácilmente y esto se considera un factor de riesgo.
Estándar de cifrado de datos (DES)
El algoritmo de clave simétrica más popular es el Estándar de cifrado de datos (DES) y Python incluye un paquete que incluye la lógica detrás del algoritmo DES.
Instalación
El comando para la instalación del paquete DES pyDES en Python es -
pip install pyDES
La implementación del programa simple del algoritmo DES es la siguiente:
import pyDes
data = "DES Algorithm Implementation"
k = pyDes.des("DESCRYPT", pyDes.CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=pyDes.PAD_PKCS5)
d = k.encrypt(data)
print "Encrypted: %r" % d
print "Decrypted: %r" % k.decrypt(d)
assert k.decrypt(d) == data
Requiere la variable padmode que obtiene todos los paquetes según la implementación del algoritmo DES y sigue el cifrado y descifrado de una manera específica.
Salida
Puede ver el siguiente resultado como resultado del código proporcionado anteriormente:
Criptografía asimétrica
También se llama como public key cryptography.Funciona a la inversa de la criptografía simétrica. Esto implica que requiere dos claves: una para el cifrado y otra para el descifrado. La clave pública se utiliza para cifrar y la clave privada se utiliza para descifrar.
Retirarse
- Debido a su longitud de clave, contribuye a una menor velocidad de cifrado.
- La gestión de claves es fundamental.
El siguiente código de programa en Python ilustra el funcionamiento de la criptografía asimétrica utilizando el algoritmo RSA y su implementación:
from Crypto import Random
from Crypto.PublicKey import RSA
import base64
def generate_keys():
# key length must be a multiple of 256 and >= 1024
modulus_length = 256*4
privatekey = RSA.generate(modulus_length, Random.new().read)
publickey = privatekey.publickey()
return privatekey, publickey
def encrypt_message(a_message , publickey):
encrypted_msg = publickey.encrypt(a_message, 32)[0]
encoded_encrypted_msg = base64.b64encode(encrypted_msg)
return encoded_encrypted_msg
def decrypt_message(encoded_encrypted_msg, privatekey):
decoded_encrypted_msg = base64.b64decode(encoded_encrypted_msg)
decoded_decrypted_msg = privatekey.decrypt(decoded_encrypted_msg)
return decoded_decrypted_msg
a_message = "This is the illustration of RSA algorithm of asymmetric cryptography"
privatekey , publickey = generate_keys()
encrypted_msg = encrypt_message(a_message , publickey)
decrypted_msg = decrypt_message(encrypted_msg, privatekey)
print "%s - (%d)" % (privatekey.exportKey() , len(privatekey.exportKey()))
print "%s - (%d)" % (publickey.exportKey() , len(publickey.exportKey()))
print " Original content: %s - (%d)" % (a_message, len(a_message))
print "Encrypted message: %s - (%d)" % (encrypted_msg, len(encrypted_msg))
print "Decrypted message: %s - (%d)" % (decrypted_msg, len(decrypted_msg))
Salida
Puede encontrar la siguiente salida cuando ejecuta el código dado anteriormente:
El algoritmo RSA es una técnica de cifrado de clave pública y se considera la forma más segura de cifrado. Fue inventado por Rivest, Shamir y Adleman en el año 1978 y de ahí el nombreRSA algoritmo.
Algoritmo
El algoritmo RSA tiene las siguientes características:
El algoritmo RSA es una exponenciación popular en un campo finito sobre enteros, incluidos números primos.
Los números enteros utilizados por este método son lo suficientemente grandes, lo que dificulta su resolución.
Hay dos conjuntos de claves en este algoritmo: clave privada y clave pública.
Deberá seguir los siguientes pasos para trabajar en el algoritmo RSA:
Paso 1: generar el módulo RSA
El procedimiento inicial comienza con la selección de dos números primos, a saber, pyq, y luego calcula su producto N, como se muestra:
N=p*q
Aquí, sea N el gran número especificado.
Paso 2: Número derivado (e)
Considere el número e como un número derivado que debe ser mayor que 1 y menor que (p-1) y (q-1). La condición principal será que no debe haber un factor común de (p-1) y (q-1) excepto 1
Paso 3: clave pública
El par de números especificado n y e forma la clave pública RSA y se hace pública.
Paso 4: clave privada
Llave privada dse calcula a partir de los números p, qye. La relación matemática entre los números es la siguiente:
ed = 1 mod (p-1) (q-1)
La fórmula anterior es la fórmula básica para el algoritmo euclidiano extendido, que toma p y q como parámetros de entrada.
Fórmula de cifrado
Considere un remitente que envía el mensaje de texto sin formato a alguien cuya clave pública es (n,e). Para cifrar el mensaje de texto sin formato en el escenario dado, use la siguiente sintaxis:
C = Pe mod n
Fórmula de descifrado
El proceso de descifrado es muy sencillo e incluye análisis para el cálculo en un enfoque sistemático. Considerando receptor C tiene la clave privada d, el módulo de resultado se calculará como -
Plaintext = Cd mod n
En este capítulo, nos centraremos en la implementación paso a paso del algoritmo RSA utilizando Python.
Generando claves RSA
Los siguientes pasos están involucrados en la generación de claves RSA:
Crea dos números primos grandes a saber p y q. El producto de estos números se llamarán, dónde n= p*q
Genere un número aleatorio que sea primo relativo con (p-1) y (q-1). Dejemos que el número se llame como e.
Calcule el inverso modular de e. El inverso calculado se llamará comod.
Algoritmos para generar claves RSA
Necesitamos dos algoritmos principales para generar claves RSA usando Python: Cryptomath module y Rabin Miller module.
Módulo Cryptomath
El código fuente del módulo cryptomath que sigue toda la implementación básica del algoritmo RSA es el siguiente:
def gcd(a, b):
while a != 0:
a, b = b % a, a
return b
def findModInverse(a, m):
if gcd(a, m) != 1:
return None
u1, u2, u3 = 1, 0, a
v1, v2, v3 = 0, 1, m
while v3 != 0:
q = u3 // v3
v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3
return u1 % m
Módulo RabinMiller
El código fuente del módulo RabinMiller que sigue toda la implementación básica del algoritmo RSA es el siguiente:
import random
def rabinMiller(num):
s = num - 1
t = 0
while s % 2 == 0:
s = s // 2
t += 1
for trials in range(5):
a = random.randrange(2, num - 1)
v = pow(a, s, num)
if v != 1:
i = 0
while v != (num - 1):
if i == t - 1:
return False
else:
i = i + 1
v = (v ** 2) % num
return True
def isPrime(num):
if (num 7< 2):
return False
lowPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241,
251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449,
457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569,
571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661,
673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787,
797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907,
911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
if num in lowPrimes:
return True
for prime in lowPrimes:
if (num % prime == 0):
return False
return rabinMiller(num)
def generateLargePrime(keysize = 1024):
while True:
num = random.randrange(2**(keysize-1), 2**(keysize))
if isPrime(num):
return num
El código completo para generar claves RSA es el siguiente:
import random, sys, os, rabinMiller, cryptomath
def main():
makeKeyFiles('RSA_demo', 1024)
def generateKey(keySize):
# Step 1: Create two prime numbers, p and q. Calculate n = p * q.
print('Generating p prime...')
p = rabinMiller.generateLargePrime(keySize)
print('Generating q prime...')
q = rabinMiller.generateLargePrime(keySize)
n = p * q
# Step 2: Create a number e that is relatively prime to (p-1)*(q-1).
print('Generating e that is relatively prime to (p-1)*(q-1)...')
while True:
e = random.randrange(2 ** (keySize - 1), 2 ** (keySize))
if cryptomath.gcd(e, (p - 1) * (q - 1)) == 1:
break
# Step 3: Calculate d, the mod inverse of e.
print('Calculating d that is mod inverse of e...')
d = cryptomath.findModInverse(e, (p - 1) * (q - 1))
publicKey = (n, e)
privateKey = (n, d)
print('Public key:', publicKey)
print('Private key:', privateKey)
return (publicKey, privateKey)
def makeKeyFiles(name, keySize):
# Creates two files 'x_pubkey.txt' and 'x_privkey.txt'
(where x is the value in name) with the the n,e and d,e integers written in them,
# delimited by a comma.
if os.path.exists('%s_pubkey.txt' % (name)) or os.path.exists('%s_privkey.txt' % (name)):
sys.exit('WARNING: The file %s_pubkey.txt or %s_privkey.txt already exists! Use a different name or delete these files and re-run this program.' % (name, name))
publicKey, privateKey = generateKey(keySize)
print()
print('The public key is a %s and a %s digit number.' % (len(str(publicKey[0])), len(str(publicKey[1]))))
print('Writing public key to file %s_pubkey.txt...' % (name))
fo = open('%s_pubkey.txt' % (name), 'w')
fo.write('%s,%s,%s' % (keySize, publicKey[0], publicKey[1]))
fo.close()
print()
print('The private key is a %s and a %s digit number.' % (len(str(publicKey[0])), len(str(publicKey[1]))))
print('Writing private key to file %s_privkey.txt...' % (name))
fo = open('%s_privkey.txt' % (name), 'w')
fo.write('%s,%s,%s' % (keySize, privateKey[0], privateKey[1]))
fo.close()
# If makeRsaKeys.py is run (instead of imported as a module) call
# the main() function.
if __name__ == '__main__':
main()
Salida
La clave pública y las claves privadas se generan y guardan en los archivos respectivos como se muestra en el siguiente resultado.
En este capítulo, nos centraremos en diferentes implementaciones del cifrado de cifrado RSA y las funciones involucradas para el mismo. Puede consultar o incluir este archivo de Python para implementar la implementación del algoritmo de cifrado RSA.
Los módulos incluidos para el algoritmo de cifrado son los siguientes:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode
hash = "SHA-256"
Hemos inicializado el valor hash como SHA-256 para mejorar la seguridad. Usaremos una función para generar nuevas claves o un par de clave pública y privada usando el siguiente código.
def newkeys(keysize):
random_generator = Random.new().read
key = RSA.generate(keysize, random_generator)
private, public = key, key.publickey()
return public, private
def importKey(externKey):
return RSA.importKey(externKey)
Para el cifrado, se utiliza la siguiente función que sigue el algoritmo RSA:
def encrypt(message, pub_key):
cipher = PKCS1_OAEP.new(pub_key)
return cipher.encrypt(message)
Dos parámetros son obligatorios: message y pub_keyque se refiere a la clave pública. Se utiliza una clave pública para el cifrado y una clave privada para el descifrado.
El programa completo para el procedimiento de cifrado se menciona a continuación:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode
hash = "SHA-256"
def newkeys(keysize):
random_generator = Random.new().read
key = RSA.generate(keysize, random_generator)
private, public = key, key.publickey()
return public, private
def importKey(externKey):
return RSA.importKey(externKey)
def getpublickey(priv_key):
return priv_key.publickey()
def encrypt(message, pub_key):
cipher = PKCS1_OAEP.new(pub_key)
return cipher.encrypt(message)
Este capítulo es una continuación del capítulo anterior donde seguimos la implementación paso a paso del cifrado utilizando el algoritmo RSA y lo analiza en detalle.
La función utilizada para descifrar el texto cifrado es la siguiente:
def decrypt(ciphertext, priv_key):
cipher = PKCS1_OAEP.new(priv_key)
return cipher.decrypt(ciphertext)
Para la criptografía de clave pública o la criptografía de clave asimétrica, es importante mantener dos características importantes: Authentication y Authorization.
Autorización
La autorización es el proceso para confirmar que el remitente es el único que ha transmitido el mensaje. El siguiente código explica esto:
def sign(message, priv_key, hashAlg="SHA-256"):
global hash
hash = hashAlg
signer = PKCS1_v1_5.new(priv_key)
if (hash == "SHA-512"):
digest = SHA512.new()
elif (hash == "SHA-384"):
digest = SHA384.new()
elif (hash == "SHA-256"):
digest = SHA256.new()
elif (hash == "SHA-1"):
digest = SHA.new()
else:
digest = MD5.new()
digest.update(message)
return signer.sign(digest)
Autenticación
La autenticación es posible mediante el método de verificación que se explica a continuación:
def verify(message, signature, pub_key):
signer = PKCS1_v1_5.new(pub_key)
if (hash == "SHA-512"):
digest = SHA512.new()
elif (hash == "SHA-384"):
digest = SHA384.new()
elif (hash == "SHA-256"):
digest = SHA256.new()
elif (hash == "SHA-1"):
digest = SHA.new()
else:
digest = MD5.new()
digest.update(message)
return signer.verify(digest, signature)
La firma digital se verifica junto con los datos del remitente y el destinatario. Esto agrega más edad de peso por razones de seguridad.
Descifrado de cifrado RSA
Puede utilizar el siguiente código para el descifrado de cifrado RSA:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode
hash = "SHA-256"
def newkeys(keysize):
random_generator = Random.new().read
key = RSA.generate(keysize, random_generator)
private, public = key, key.publickey()
return public, private
def importKey(externKey):
return RSA.importKey(externKey)
def getpublickey(priv_key):
return priv_key.publickey()
def encrypt(message, pub_key):
cipher = PKCS1_OAEP.new(pub_key)
return cipher.encrypt(message)
def decrypt(ciphertext, priv_key):
cipher = PKCS1_OAEP.new(priv_key)
return cipher.decrypt(ciphertext)
def sign(message, priv_key, hashAlg = "SHA-256"):
global hash
hash = hashAlg
signer = PKCS1_v1_5.new(priv_key)
if (hash == "SHA-512"):
digest = SHA512.new()
elif (hash == "SHA-384"):
digest = SHA384.new()
elif (hash == "SHA-256"):
digest = SHA256.new()
elif (hash == "SHA-1"):
digest = SHA.new()
else:
digest = MD5.new()
digest.update(message)
return signer.sign(digest)
def verify(message, signature, pub_key):
signer = PKCS1_v1_5.new(pub_key)
if (hash == "SHA-512"):
digest = SHA512.new()
elif (hash == "SHA-384"):
digest = SHA384.new()
elif (hash == "SHA-256"):
digest = SHA256.new()
elif (hash == "SHA-1"):
digest = SHA.new()
else:
digest = MD5.new()
digest.update(message)
return signer.verify(digest, signature)
Hackear el cifrado RSA es posible con números primos pequeños, pero se considera imposible si se usa con números grandes. Las razones que especifican por qué es difícil piratear el cifrado RSA son las siguientes:
El ataque de fuerza bruta no funcionaría ya que hay demasiadas claves posibles para trabajar. Además, esto consume mucho tiempo.
El ataque de diccionario no funcionará en el algoritmo RSA ya que las claves son numéricas y no incluyen ningún carácter.
El análisis de frecuencia de los caracteres es muy difícil de seguir, ya que un solo bloque cifrado representa varios caracteres.
No hay trucos matemáticos específicos para piratear el cifrado RSA.
La ecuación de descifrado de RSA es:
M = C^d mod n
Con la ayuda de pequeños números primos, podemos intentar piratear el cifrado RSA y el código de muestra para el mismo se menciona a continuación:
def p_and_q(n):
data = []
for i in range(2, n):
if n % i == 0:
data.append(i)
return tuple(data)
def euler(p, q):
return (p - 1) * (q - 1)
def private_index(e, euler_v):
for i in range(2, euler_v):
if i * e % euler_v == 1:
return i
def decipher(d, n, c):
return c ** d % n
def main():
e = int(input("input e: "))
n = int(input("input n: "))
c = int(input("input c: "))
# t = 123
# private key = (103, 143)
p_and_q_v = p_and_q(n)
# print("[p_and_q]: ", p_and_q_v)
euler_v = euler(p_and_q_v[0], p_and_q_v[1])
# print("[euler]: ", euler_v)
d = private_index(e, euler_v)
plain = decipher(d, n, c)
print("plain: ", plain)
if __name__ == "__main__":
main()
Salida
El código anterior produce la siguiente salida: