Saltar al contenido

Encriptar y desencriptar usando PyCrypto AES 256

Ya no busques más por otras páginas porque llegaste al sitio adecuado, tenemos la solución que quieres recibir pero sin problemas.

Solución:

Aquí está mi implementación y funciona para mí con algunas correcciones y mejora la alineación de la key y frase secreta con 32 bytes y iv a 16 bytes:

import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES

class AESCipher(object):

    def __init__(self, key): 
        self.bs = AES.block_size
        self.key = hashlib.sha256(key.encode()).digest()

    def encrypt(self, raw):
        raw = self._pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw.encode()))

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')

    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)

    @staticmethod
    def _unpad(s):
        return s[:-ord(s[len(s)-1:])]

Es posible que necesite las siguientes dos funciones: pad– para rellenar (al hacer cifrado) y unpad– para unpad (al realizar el descifrado) cuando la longitud de la entrada no es un múltiplo de BLOCK_SIZE.

BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) 
unpad = lambda s : s[:-ord(s[len(s)-1:])]

Entonces estás preguntando la longitud de key? Puede utilizar el md5sum del key en lugar de usarlo directamente.

Además, de acuerdo con mi pequeña experiencia en el uso de PyCrypto, el IV se usa para mezclar la salida de un cifrado cuando la entrada es la misma, por lo que el IV se elige como aleatorio. stringy utilícelo como parte de la salida de cifrado y, a continuación, utilícelo para descifrar el mensaje.

Y aquí está mi implementación, espero que te sea útil:

import base64
from Crypto.Cipher import AES
from Crypto import Random

class AESCipher:
    def __init__( self, key ):
        self.key = key

    def encrypt( self, raw ):
        raw = pad(raw)
        iv = Random.new().read( AES.block_size )
        cipher = AES.new( self.key, AES.MODE_CBC, iv )
        return base64.b64encode( iv + cipher.encrypt( raw ) ) 

    def decrypt( self, enc ):
        enc = base64.b64decode(enc)
        iv = enc[:16]
        cipher = AES.new(self.key, AES.MODE_CBC, iv )
        return unpad(cipher.decrypt( enc[16:] ))

Permítame abordar su pregunta sobre los “modos”. AES256 es una especie de cifrado de bloque. Toma como entrada 32 bytes key y un 16 bytes string, llamó al cuadra y produce un bloque. Usamos AES en un modo de operación para encriptar. Las soluciones anteriores sugieren el uso de CBC, que es un ejemplo. Otro se llama CTR y es algo más fácil de usar:

from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto import Random

# AES supports multiple key sizes: 16 (AES128), 24 (AES192), or 32 (AES256).
key_bytes = 32

# Takes as input a 32-byte key and an arbitrary-length plaintext and returns a
# pair (iv, ciphtertext). "iv" stands for initialization vector.
def encrypt(key, plaintext):
    assert len(key) == key_bytes

    # Choose a random, 16-byte IV.
    iv = Random.new().read(AES.block_size)

    # Convert the IV to a Python integer.
    iv_int = int(binascii.hexlify(iv), 16) 

    # Create a new Counter object with IV = iv_int.
    ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)

    # Create AES-CTR cipher.
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)

    # Encrypt and return IV and ciphertext.
    ciphertext = aes.encrypt(plaintext)
    return (iv, ciphertext)

# Takes as input a 32-byte key, a 16-byte IV, and a ciphertext, and outputs the
# corresponding plaintext.
def decrypt(key, iv, ciphertext):
    assert len(key) == key_bytes

    # Initialize counter for decryption. iv should be the same as the output of
    # encrypt().
    iv_int = int(iv.encode('hex'), 16) 
    ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)

    # Create AES-CTR cipher.
    aes = AES.new(key, AES.MODE_CTR, counter=ctr)

    # Decrypt and return the plaintext.
    plaintext = aes.decrypt(ciphertext)
    return plaintext

(iv, ciphertext) = encrypt(key, 'hella')
print decrypt(key, iv, ciphertext)

Esto a menudo se conoce como AES-CTR. Aconsejaría precaución al usar AES-CBC con PyCrypto. La razón es que requiere que especifique el esquema de relleno, como lo ejemplifican las otras soluciones dadas. En general, si no lo eres muy cuidado con el acolchado, ¡Hay ataques que rompen completamente el cifrado!

Ahora bien, es importante tener en cuenta que key debe ser un aleatorio, 32 bytes string; una contraseña no satisfacer. Normalmente, el key se genera así:

# Nominal way to generate a fresh key. This calls the system's random number
# generator (RNG).
key1 = Random.new().read(key_bytes)

A key quizás derivado de una contraseña, también:

# It's also possible to derive a key from a password, but it's important that
# the password have high entropy, meaning difficult to predict.
password = "This is a rather weak password."

# For added # security, we add a "salt", which increases the entropy.
#
# In this example, we use the same RNG to produce the salt that we used to
# produce key1.
salt_bytes = 8 
salt = Random.new().read(salt_bytes)

# Stands for "Password-based key derivation function 2"
key2 = PBKDF2(password, salt, key_bytes)

Algunas soluciones anteriores sugieren usar SHA256 para derivar el key, pero esto generalmente se considera una mala práctica criptográfica. Consulte wikipedia para obtener más información sobre los modos de funcionamiento.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *