python - codigo - cifrado cesar
¿Cómo encriptar texto con una contraseña en python? (4)
- Si vas a utilizar la base de datos mencionada para autorizar a los usuarios, debes usar hashes o resúmenes de mensajes de contraseñas de usuario, en lugar de algoritmos de cifrado bidireccional, que harían que tus datos sean difíciles de usar incluso en caso de fugas de db.
- No puede usar el método anterior para proteger los datos que deben descifrarse en algún momento, pero incluso así puede usar una forma más segura que solo cifrar las contraseñas de los usuarios usando una tecla fija (que es el peor método). Eche un vistazo a la Hoja de referencia de almacenamiento de contraseñas de OWASP .
Al escribir "Quiero ser capaz de encriptar / descifrar el mensaje", adjunto una fuente de Python simple (probada en 2.7) para encr / decr usando Blowfish.
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import os
from Crypto.Cipher import Blowfish # pip install pycrypto
BS = 8
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-ord(s[-1])]
def doEncrypt(phrase, key):
c1 = Blowfish.new(key, Blowfish.MODE_ECB)
return c1.encrypt(pad(phrase))
def doDecrypt(phrase, key):
c1 = Blowfish.new(key, Blowfish.MODE_ECB)
return unpad(c1.decrypt(phrase))
def testing123(phrase, key):
encrypted = doEncrypt(phrase, key)
decrypted = doDecrypt(encrypted, key)
assert phrase == decrypted, "Blowfish ECB enc/dec verification failed"
print ("Blowfish ECB enc/dec verified ok")
print (''phrase/key(hex)/enc+dec: {}/{}/{}''.format(phrase, key.encode(''hex''), decrypted))
if __name__== "__main__":
phrase= ''Ala ma kota, a kot ma AIDS.''
key= os.urandom(32)
testing123(phrase, key)
Sorprendentemente difícil encontrar una respuesta directa a esto en Google.
Quiero recopilar un texto y un mensaje de un usuario como 1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDc
hello world
.
Entonces quiero poder cifrar / descifrar el mensaje con el texto de alguna manera para poder guardarlo en mi base de datos y no preocuparme por la exposición de los datos si mi sitio web es pirateado, encrypt(''1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDc'', ''hello world'')
decrypt(''1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDc'', <encrypted_text>)
¿Hay una manera simple de lograr esto con Python y por favor alguien puede proporcionarme / dirigirme a un ejemplo?
¿Tal vez un ejemplo de cómo crear pares de claves públicas / privadas usando una semilla como ''1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDc''
?
Muchas gracias de antemano :)
EDITAR: Para que quede claro, estoy buscando una manera de encriptar los datos de mis usuarios de una manera determinista para no ofuscar el mensaje.
Si eso significa que tengo que generar un par de claves pub / pri PGP / GPG sobre la marcha utilizando el texto 1PWP7a6xgoYx81VZocrDr5okEEcnqKkyDc
como una semilla, entonces eso está bien, pero ¿cuál es el método para hacerlo?
Aquí está mi solución para cualquiera que pueda estar interesado:
from Crypto.Cipher import AES # pip install pycrypto
import base64
def cypher_aes(secret_key, msg_text, encrypt=True):
# an AES key must be either 16, 24, or 32 bytes long
# in this case we make sure the key is 32 bytes long by adding padding and/or slicing if necessary
remainder = len(secret_key) % 16
modified_key = secret_key.ljust(len(secret_key) + (16 - remainder))[:32]
print(modified_key)
# input strings must be a multiple of 16 in length
# we achieve this by adding padding if necessary
remainder = len(msg_text) % 16
modified_text = msg_text.ljust(len(msg_text) + (16 - remainder))
print(modified_text)
cipher = AES.new(modified_key, AES.MODE_ECB) # use of ECB mode in enterprise environments is very much frowned upon
if encrypt:
return base64.b64encode(cipher.encrypt(modified_text)).strip()
return cipher.decrypt(base64.b64decode(modified_text)).strip()
encrypted = cypher_aes(b''secret_AES_key_string_to_encrypt/decrypt_with'', b''input_string_to_encrypt/decrypt'', encrypt=True)
print(encrypted)
print()
print(cypher_aes(b''secret_AES_key_string_to_encrypt/decrypt_with'', encrypted, encrypt=False))
Resultado:
b''secret_AES_key_string_to_encrypt''
b''input_string_to_encrypt/decrypt ''
b''+IFU4e4rFWEkUlOU6sd+y8JKyyRdRbPoT/FvDBCFeuY=''
b''secret_AES_key_string_to_encrypt''
b''+IFU4e4rFWEkUlOU6sd+y8JKyyRdRbPoT/FvDBCFeuY= ''
b''input_string_to_encrypt/decrypt''
Puede hacerlo utilizando dos de las funciones integradas en la biblioteca estándar de Python. El primero es la función ord () , que toma un carácter de cadena Unicode como parámetro de entrada única y lo convierte en su código Unicode correspondiente (un entero). Se proporcionan dos ejemplos simples del uso de esta función:
>>> ord(''a'')
97
>>> ord(''b'')
98
Entonces, también tiene la función inversa de ord (): chr () . Y como se puede imaginar, funciona en todos los sentidos: tiene un código Unicode como entrada (entero) y obtiene el carácter unicode correspondiente (cadena):
>>> chr(97)
''a''
>>> chr(98)
''b''
Luego puede hacer una inscripción simple agregando o restando por un entero arbitrario ... en este caso, el número 2:
NOTA: Tenga cuidado al no emitir valores muy grandes o obtendrá una identificación de error, por ejemplo, llegará a un valor negativo.
def encrypt(message):
newS=''''
for car in message:
newS=newS+chr(ord(car)+2)
return newS
print(encrypt(''hello world''))
Y obteniendo como resultado:
jgnnq"yqtnf
Ahora puede copiar y pasar la misma función y generar la función de descifrado. En este caso, requiere, obviamente, restar por 2:
def decrypt(message):
newS=''''
for car in message:
newS=newS+chr(ord(car)-2)
return newS
print(decrypt(''jgnnq"yqtnf''))
Y el resultado será el mensaje original nuevamente:
''hello world''
Esta sería una gran manera de encriptar mensajes a no programadores. Sin embargo, cualquiera con un poco de conocimiento de programación podría escribir un programa que variara el entero que usamos hasta que descubrieran que acabamos de agregar (2) a los caracteres Unicode para encriptar el código ...
Para evitar eso, propondría dos alternativas más complejas.
1. El primero es el más simple: consiste en aplicar un valor de suma diferente a la función chr según la posición del personaje (por ejemplo, sumar 2 a cada código Unicode cuando ocupa una posición pareja en la cadena y restar 3) cuando se sienta en una posición extraña).
2. El segundo generará la máxima seguridad. Consistirá en agregar o sustraer cada código Unicode a un número que se generará aleatoriamente para cada personaje. Se requerirá almacenar una matriz de valores para descifrar el mensaje. Asegúrese, entonces, que esta matriz de valores no esté disponible para terceros.
Ahí va una posible solución para 1 .
def encryptHard(message):
newS=''''
for i in range(len(message)):
if i%2==0:
newS=newS+chr(ord(message[i])+2)
else:
newS=newS+chr(ord(message[i])-3)
return newS
print(encryptHard(''hello world''))
Y el resultado sería:
jbniqyltif
Con la información aquí privilegiada, el guión de descifrado es obvio, por lo que no te molestaré para lidiar, pasar y cambiar dos valores.
Finalmente, veamos un análisis en profundidad de la segunda alternativa más compleja. Con esto podemos decir que la inscripción será casi indefinible. La idea es variar el valor que agregamos o sustraemos a cada código Unicode por un número aleatorio comprendido entre 0 y 255 (este es el rango de números que admite la función chr (), así que no intente jugar con otros números o lo hará Definitivamente obtener un error).
En este caso, mi propuesta también aleatoriza la operación (suma o resta) y evita que el número final sea un 0 (es decir, obtendríamos un carácter original). Finalmente, también devuelve una lista con los números a los que se ha restado, algo que necesitará para descifrar el mensaje.
Las posibilidades de que obtenga el mismo mensaje cifrado si llama dos veces a esta función usando el mismo mensaje de longitud n son algo así como 255 ^ n ... Así que no se preocupe (digo algo, ya que el algoritmo creado realmente generaría valores más repetidos en el rango de valores de gama baja o alta, por ejemplo, en caso de que los caracteres más frecuentes no estén centrados en este conjunto de caracubo de distribución de unicode (de 0 a 255), que es el caso. Sin embargo, el programa , aunque no es perfecto, funciona perfectamente y protege la información.
import random as r
def encryptSuperHard(message):
newS=''''
l_trans=[]
for car in message:
code=ord(car)
add_subtract=r.choice([True,False])
if add_subtract:
transpose=r.randint(0,code-1)
newS=newS+chr(code-transpose)
l_trans=l_trans+[-transpose]
else:
transpose=r.randint(code+1,255)
newS=newS+chr(code+transpose)
l_trans=l_trans+[transpose]
return newS, l_trans
print(encryptSuperHard(''hello world''))
En este caso, este script de encriptación aleatorio que he hecho ha devuelto esta tupla de dos valores, donde el primer valor es el mensaje encriptado y el segundo es el valor que ha "transpuesto" cada carácter en orden de apearance.
(''A0ŤłY/x10řG;,à'', [-39, -53, 248, 214, -22, -16, 226, -40, -55, -64, 124])
El descifrado, en este caso, necesitaría tomar el mensaje encriptado y la lista y proceder de la siguiente manera:
def decryptSuperHard(encriptedS,l):
newS=''''
for i in range(len(l)):
newS=newS+chr(ord(encriptedS[i])-l[i])
return newS
print(decryptSuperHard(''A0ŤłY/x10řG;,à'', [-39,-53,248,214,-22,-16,226,-40,-55,-64,124]))
Y los resultados se remontan a:
Hola Mundo
print(deccryptSuperHard(''A0ŤłY/x10řG;,à'', [-39, -53, 248, 214, -22, -16, 226, -40, -55, -64, 124])
A continuación, le mostramos cómo hacerlo correctamente en modo CBC, incluido el relleno PKCS # 7:
import base64
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
from Crypto import Random
def encrypt(key, source, encode=True):
key = SHA256.new(key).digest() # use SHA-256 over our key to get a proper-sized AES key
IV = Random.new().read(AES.block_size) # generate IV
encryptor = AES.new(key, AES.MODE_CBC, IV)
padding = AES.block_size - len(source) % AES.block_size # calculate needed padding
source += bytes([padding]) * padding # Python 2.x: source += chr(padding) * padding
data = IV + encryptor.encrypt(source) # store the IV at the beginning and encrypt
return base64.b64encode(data).decode("latin-1") if encode else data
def decrypt(key, source, decode=True):
if decode:
source = base64.b64decode(source.encode("latin-1"))
key = SHA256.new(key).digest() # use SHA-256 over our key to get a proper-sized AES key
IV = source[:AES.block_size] # extract the IV from the beginning
decryptor = AES.new(key, AES.MODE_CBC, IV)
data = decryptor.decrypt(source[AES.block_size:]) # decrypt
padding = data[-1] # pick the padding value from the end; Python 2.x: ord(data[-1])
if data[-padding:] != bytes([padding]) * padding: # Python 2.x: chr(padding) * padding
raise ValueError("Invalid padding...")
return data[:-padding] # remove the padding
Está configurado para trabajar con datos de bytes
, por lo que si desea encriptar cadenas o usar contraseñas de cadenas, asegúrese de encode()
con un códec adecuado antes de pasarlas a los métodos. Si deja el parámetro de encode
en True
el resultado de encrypt()
será string codificado en base64, y el origen de decrypt()
también será base64 string.
Ahora si lo prueba como:
my_password = b"secret_AES_key_string_to_encrypt/decrypt_with"
my_data = b"input_string_to_encrypt/decrypt"
print("key: {}".format(my_password))
print("data: {}".format(my_data))
encrypted = encrypt(my_password, my_data)
print("/nenc: {}".format(encrypted))
decrypted = decrypt(my_password, encrypted)
print("dec: {}".format(decrypted))
print("/ndata match: {}".format(my_data == decrypted))
print("/nSecond round....")
encrypted = encrypt(my_password, my_data)
print("/nenc: {}".format(encrypted))
decrypted = decrypt(my_password, encrypted)
print("dec: {}".format(decrypted))
print("/ndata match: {}".format(my_data == decrypted))
su salida sería similar a:
key: b''secret_AES_key_string_to_encrypt/decrypt_with''
data: b''input_string_to_encrypt/decrypt''
enc: 7roSO+P/4eYdyhCbZmraVfc305g5P8VhDBOUDGrXmHw8h5ISsS3aPTGfsTSqn9f5
dec: b''input_string_to_encrypt/decrypt''
data match: True
Second round....
enc: BQm8FeoPx1H+bztlZJYZH9foI+IKAorCXRsMjbiYQkqLWbGU3NU50OsR+L9Nuqm6
dec: b''input_string_to_encrypt/decrypt''
data match: True
Al probar que la misma clave y los mismos datos aún producen texto cifrado diferente cada vez.
Ahora, esto es mucho mejor que el BCE, pero ... si vas a utilizar esto para la comunicación, ¡no lo hagas! Esto es más para explicar cómo debería construirse, no para ser utilizado realmente en un entorno de producción y especialmente no para la comunicación, ya que le falta un ingrediente crucial: la autenticación del mensaje. Siéntete libre de jugar con él, pero no deberías lanzar tu propia criptografía, existen protocolos bien investigados que te ayudarán a evitar las trampas comunes y deberías usarlas.