Cómo realizar la encriptación y desencriptación AES con Python

Python es un lenguaje de programación flexible que permite implementar fácilmente algoritmos de encriptación poderosos como el AES (Advanced Encryption Standard). En este artículo, explicaremos paso a paso los conceptos básicos de la encriptación AES y proporcionaremos ejemplos prácticos de código. Si desea aprender a fortalecer la seguridad de los datos y proteger la información confidencial, este artículo le guiará a través del conocimiento necesario. Al final, adquirirá las habilidades para construir un sistema práctico de encriptación y desencriptación.

Índice

Conceptos básicos de la encriptación AES


AES (Advanced Encryption Standard) es un algoritmo de cifrado por bloques establecido por el Instituto Nacional de Estándares y Tecnología de los EE. UU. (NIST), que ofrece alta seguridad y eficiencia. Divide los datos en bloques de tamaño fijo (generalmente 128 bits) y realiza la encriptación. AES es un algoritmo de cifrado simétrico, lo que significa que utiliza la misma clave tanto para la encriptación como para la desencriptación.

Modos de operación de AES


AES ofrece varios modos de operación, que se pueden elegir según las necesidades específicas. Algunos de los modos más comunes incluyen:

  • ECB (Electronic Codebook): Un modo simple, pero con baja seguridad, ya que puede exponer patrones en los datos encriptados.
  • CBC (Cipher Block Chaining): Mejora la seguridad al añadir el resultado de la encriptación del bloque anterior a cada bloque de datos.
  • CFB (Cipher Feedback): Utiliza los resultados de la encriptación de forma continua, lo que lo hace adecuado para su uso como un cifrado de flujo.
  • GCM (Galois/Counter Mode): Proporciona no solo encriptación, sino también una verificación de la integridad de los datos.

Tamaños de clave de AES


AES soporta tres tamaños de clave:

  • 128 bits (16 bytes): El tamaño más común, proporciona seguridad estándar.
  • 192 bits (24 bytes): Se utiliza cuando se requiere una mayor seguridad.
  • 256 bits (32 bytes): Adecuado cuando se requiere una seguridad extremadamente alta.

El tamaño de la clave se elige según los requisitos de seguridad. Para la mayoría de las aplicaciones, una clave de 128 bits es suficiente, pero para niveles de seguridad más estrictos, se recomienda usar una clave de 256 bits.

Características de AES


AES es uno de los algoritmos de encriptación más utilizados actualmente por las siguientes razones:

  • Eficiencia: Funciona rápidamente tanto en hardware como en software.
  • Robustez: Su fiabilidad ha sido probada durante años de uso.
  • Flexibilidad: Ofrece modos de operación que pueden adaptarse a una amplia variedad de aplicaciones.

Gracias a su facilidad de implementación, AES se utiliza ampliamente en proyectos de encriptación, incluso con Python.

Instalación de las bibliotecas de Python necesarias


Para implementar la encriptación y desencriptación AES en Python, se debe utilizar una biblioteca especializada en criptografía. Una de las más recomendadas es PyCryptodome, una poderosa y fácil de usar biblioteca que extiende el módulo “Crypto” de la biblioteca estándar de Python.

Instalación de PyCryptodome


Para instalar PyCryptodome, use el siguiente comando:

pip install pycryptodome

Verificación de la instalación


Para verificar que la instalación fue exitosa, inicie el intérprete de Python e ingrese el siguiente comando:

from Crypto.Cipher import AES
print("¡PyCryptodome se ha instalado correctamente!")

Si no se muestra ningún error, la instalación ha sido exitosa.

Características principales de PyCryptodome


PyCryptodome ofrece las siguientes funciones de encriptación:

  • Cifrado de clave simétrica (AES, DES, etc.)
  • Cifrado de clave asimétrica (RSA, ECC, etc.)
  • Códigos de autenticación de mensajes (HMAC, etc.)
  • Funciones de hash (SHA256, SHA3, etc.)

En este caso de encriptación y desencriptación AES, utilizaremos el módulo Crypto.Cipher.AES de esta biblioteca.

Otras alternativas


Existen otras bibliotecas que también pueden ser utilizadas para encriptación AES:

  • cryptography: Ofrece operaciones criptográficas de alto nivel. El comando de instalación es pip install cryptography.
  • m2crypto: Una biblioteca de Python que envuelve la biblioteca C de OpenSSL.

Sin embargo, PyCryptodome es una opción fácil de usar, especialmente para principiantes, y es ideal para aprender e implementar encriptación AES. En este artículo, nos centraremos en los pasos utilizando PyCryptodome.

Preparativos para la encriptación


Para realizar encriptación AES, se deben preparar algunos elementos esenciales. En particular, la clave de encriptación (key) y el vector de inicialización (IV) son fundamentales. Si no se configuran correctamente, tanto la encriptación como la desencriptación no funcionarán correctamente.

Generación de la clave de encriptación


La clave es crucial para la encriptación AES. Su longitud debe ser de 128 bits (16 bytes), 192 bits (24 bytes), o 256 bits (32 bytes). Aquí hay un ejemplo de cómo generar una clave en Python:

from Crypto.Random import get_random_bytes

# Generar una clave de 256 bits (32 bytes)
key = get_random_bytes(32)  
print("Clave generada:", key)

Este código genera una clave aleatoria segura que se puede usar para la encriptación.

Generación del vector de inicialización (IV)


El vector de inicialización (IV) es utilizado para hacer única cada sesión de encriptación. Es especialmente necesario cuando se usa el modo de operación CBC en AES. La longitud del IV debe coincidir con el tamaño del bloque de AES (generalmente 16 bytes). A continuación, mostramos un ejemplo de cómo generar un IV con PyCryptodome:

# Generar un IV de 16 bytes
iv = get_random_bytes(16)  
print("IV generado:", iv)

Almacenamiento de la clave y el IV


La clave y el IV generados deben almacenarse de manera segura, ya que son necesarios tanto para la encriptación como para la desencriptación. Asegúrese de guardarlos en un lugar seguro, siguiendo estas recomendaciones:

  1. Ubicación segura de almacenamiento: Almacene la clave encriptada en un sistema de archivos o base de datos o utilice un módulo de seguridad de hardware (HSM).
  2. No compartir: Evite compartir la clave con terceros, ya que esto podría hacer que los datos encriptados sean fácilmente descifrables.
  3. Evitar regeneración: La misma clave y IV deben usarse para la encriptación y desencriptación de los mismos datos.

Una vez que todo esté listo


Ahora que tiene la clave y el IV generados, puede proceder a implementar la encriptación AES en el siguiente paso.

Implementación de la encriptación AES en Python


Para implementar la encriptación AES en Python, utilizamos el módulo Crypto.Cipher.AES. En esta sección, explicaremos cómo encriptar datos utilizando la clave y el IV preparados.

Proceso de encriptación


A continuación se muestra un ejemplo de código para encriptar datos usando PyCryptodome:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes

# Generar clave y IV para encriptación
key = get_random_bytes(32)  # Clave de 256 bits
iv = get_random_bytes(16)   # IV de tamaño de bloque de AES

# Datos a encriptar
data = "Este es el mensaje a encriptar"
# Convertir los datos a formato de bytes
data_bytes = data.encode('utf-8')

# Preparar la encriptación
cipher = AES.new(key, AES.MODE_CBC, iv)  # Usar el modo CBC
# Ajustar los datos al tamaño del bloque
encrypted_data = cipher.encrypt(pad(data_bytes, AES.block_size))

# Imprimir los resultados
print("Datos encriptados:", encrypted_data)
print("Clave:", key)
print("IV:", iv)

Explicación detallada del código

  1. Generación de la clave y el IV
  • Se genera una clave y un IV aleatorios usando get_random_bytes.
  • El tamaño de la clave se establece en 256 bits (32 bytes), pero puede ajustarse según sea necesario.
  1. Preparación de los datos
  • Los datos a encriptar se preparan como una cadena de texto, y se convierten a formato de bytes usando encode('utf-8').
  1. Configuración de AES
  • Se configura AES con AES.new y se especifica el modo CBC usando AES.MODE_CBC.
  1. Relleno de datos
  • Dado que AES utiliza bloques de tamaño fijo (16 bytes), se utiliza la función pad para ajustar el tamaño de los datos.
  1. Ejecutando la encriptación
  • Se encriptan los datos usando cipher.encrypt.

Manejo de los resultados de encriptación


Los datos encriptados se producen en forma de una secuencia de bytes. Para transferirlos o almacenarlos de forma eficiente, puede ser útil codificarlos en Base64:

import base64

# Codificar los datos encriptados en Base64
encoded_data = base64.b64encode(encrypted_data).decode('utf-8')
print("Datos encriptados en Base64:", encoded_data)

De esta manera, puede encriptar los datos de forma segura utilizando AES. En la siguiente sección, veremos cómo desencriptar los datos encriptados.

Implementación de la desencriptación AES en Python


Para desencriptar los datos encriptados, se debe utilizar la misma clave y el mismo IV que se usaron en la encriptación. En esta sección, mostraremos cómo implementar la desencriptación AES usando PyCryptodome.

Proceso de desencriptación


A continuación, se muestra un ejemplo de código para desencriptar los datos encriptados generados con AES:

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

# Datos encriptados (en formato codificado en Base64)
encrypted_data_base64 = "Aquí se encuentra el dato encriptado codificado en Base64"
encrypted_data = base64.b64decode(encrypted_data_base64)  # Decodificar Base64

# Clave y IV necesarios para la desencriptación (los mismos que se usaron para encriptar)
key = b"Aquí va la clave usada en la encriptación"  # Clave de 32 bytes (ejemplo: b'key12345678901234567890123456789')
iv = b"Aquí va el IV usado en la encriptación"   # IV de 16 bytes

# Realizar la desencriptación
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)

# Convertir los datos desencriptados a formato de texto y mostrarlos
print("Datos desencriptados:", decrypted_data.decode('utf-8'))

Explicación detallada del código

  1. Ingreso de los datos encriptados
  • Si los datos encriptados están en formato Base64, primero se decodifican con base64.b64decode.
  • Si los datos están en formato de bytes directamente, no es necesario este paso.
  1. Especificación de la clave y el IV
  • Para desencriptar, debe especificar la misma clave y el mismo IV que se usaron en la encriptación. Si no coinciden, la desencriptación fallará.
  1. Configuración del proceso de desencriptación
  • Se configura AES en modo CBC utilizando AES.new y se especifican la clave y el IV.
  1. Ejecutar la desencriptación
  • Se desencriptan los datos utilizando cipher.decrypt.
  • Como la desencriptación puede incluir relleno, se debe usar unpad para restaurar el tamaño original de los datos.
  1. Salida de los datos desencriptados
  • Los datos desencriptados se presentan en formato de texto tras convertirlos de bytes a cadena con decode('utf-8').

Ejemplo de desencriptación usando datos de muestra


Este es un ejemplo de desencriptación usando datos directamente en el código:

# Datos de ejemplo
encrypted_data = b"\x93\x4e\x8b\x12\xab..."  # Datos encriptados (ejemplo)
key = b"key12345678901234567890123456789"  # Clave de 32 bytes
iv = b"iv12345678901234"  # IV de 16 bytes

# Desencriptar
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
print("Resultado de la desencriptación:", decrypted_data.decode('utf-8'))

Errores comunes durante la desencriptación


Durante el proceso de desencriptación, pueden ocurrir algunos errores comunes, como los siguientes:

  • ValueError: Padding is incorrect.
  • Este error ocurre cuando la clave o el IV no coinciden con los utilizados para encriptar los datos.
  • También puede ocurrir si los datos han sido alterados.
  • TypeError: Object type cannot be passed to the function.
  • Este error ocurre si el formato de los datos (bytes o cadena) es incorrecto.

Ahora ha aprendido cómo realizar la implementación básica de encriptación y desencriptación AES, así como cómo solucionar los errores comunes que pueden surgir durante el proceso.

Manejo de errores y resolución de problemas


Al implementar la encriptación y desencriptación AES, pueden surgir errores y problemas específicos. En esta sección, abordaremos los errores más comunes y sus soluciones.

Errores comunes

1. `ValueError: Padding is incorrect.`


Causa

  • Este error ocurre cuando no se puede deshacer el relleno correctamente durante la desencriptación.
  • Generalmente ocurre en los siguientes casos:
  • La clave o el IV utilizados no coinciden con los de la encriptación.
  • Los datos encriptados han sido alterados.

Solución

  • Verifique que está utilizando la misma clave y IV tanto para encriptar como para desencriptar.
  • Verifique que los datos encriptados se hayan recibido correctamente (asegúrese de no cometer errores durante la codificación/decodificación Base64).
  • Si está utilizando un método personalizado para el relleno, implemente un método adecuado para quitar el relleno.

2. `ValueError: Incorrect AES key length.`


Causa

  • Este error ocurre cuando la longitud de la clave utilizada para AES no es de 16, 24 o 32 bytes.

Solución

  • Asegúrese de que la longitud de la clave sea correcta.
  from Crypto.Random import get_random_bytes
  key = get_random_bytes(32)  # Generar una clave de 256 bits

3. `TypeError: Object type cannot be passed to the function.`


Causa

  • Este error ocurre cuando los datos utilizados para encriptar o desencriptar no están en formato de bytes.

Solución

  • Convierta los datos de texto a formato de bytes antes de la encriptación o desencriptación:
  data_bytes = data.encode('utf-8')  # Convertir texto a bytes

4. Error relacionado con el tamaño de los datos (no múltiplo de 16 bytes)


Causa

  • AES requiere que los datos tengan un tamaño múltiplo de 16 bytes (el tamaño del bloque).

Solución

  • Utilice la función Crypto.Util.Padding.pad para agregar el relleno necesario:
  from Crypto.Util.Padding import pad
  padded_data = pad(data_bytes, AES.block_size)

Consejos de depuración

Revisar los registros de claves e IV

  • Revise los registros para asegurarse de que la clave y el IV utilizados para encriptar y desencriptar coincidan (en entornos de producción, evite imprimir estos registros).

Verificar la integridad de los datos encriptados

  • Asegúrese de que los datos no se hayan dañado durante la transferencia, la codificación/decodificación de Base64 o las operaciones de almacenamiento.

Revisar la versión de la biblioteca

  • Verifique que está utilizando la versión más reciente de PyCryptodome:
  pip show pycryptodome
  pip install --upgrade pycryptodome

Proceso de resolución de problemas

  1. Verificar clave, IV y datos
  • Asegúrese de que los datos correctos se estén utilizando tanto para la encriptación como para la desencriptación.
  1. Verificar el formato de los datos
  • Revise que los datos encriptados estén siendo procesados correctamente en formato de bytes.
  1. Revisar los procedimientos de encriptación y desencriptación
  • Verifique el manejo del relleno y la configuración del modo AES.

Siguiendo estos consejos, podrá depurar de manera eficaz los problemas comunes que pueden surgir durante la implementación de la encriptación y desencriptación AES. En la siguiente sección, discutiremos cómo aplicar estos conceptos a la encriptación y desencriptación de archivos.

Ejemplo práctico: Encriptación de archivos


El uso de AES para encriptar archivos completos, no solo datos de texto, es una forma excelente de proteger información sensible. En esta sección, le mostraremos cómo encriptar y desencriptar archivos utilizando AES.

Pasos para la encriptación de archivos


A continuación, un ejemplo de código para encriptar un archivo en Python:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes

# Ruta del archivo a encriptar
input_file_path = 'input.txt'  # Archivo a encriptar
encrypted_file_path = 'encrypted.bin'  # Archivo encriptado

# Generar clave y IV
key = get_random_bytes(32)  # Clave de 256 bits
iv = get_random_bytes(16)   # IV

# Leer el archivo y encriptar
with open(input_file_path, 'rb') as input_file:
    file_data = input_file.read()
    cipher = AES.new(key, AES.MODE_CBC, iv)
    encrypted_data = cipher.encrypt(pad(file_data, AES.block_size))

# Guardar los datos encriptados
with open(encrypted_file_path, 'wb') as encrypted_file:
    encrypted_file.write(iv + encrypted_data)

print(f"El archivo '{input_file_path}' ha sido encriptado y guardado como '{encrypted_file_path}'.")

Pasos para desencriptar archivos


A continuación, un ejemplo de código para desencriptar un archivo encriptado:

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

# Ruta del archivo encriptado
encrypted_file_path = 'encrypted.bin'  # Archivo encriptado
decrypted_file_path = 'decrypted.txt'  # Archivo desencriptado

# Clave (la misma que se utilizó para la encriptación)
key = b"Aquí va la clave usada para encriptar"  # Clave de 32 bytes

# Leer el archivo encriptado y desencriptar
with open(encrypted_file_path, 'rb') as encrypted_file:
    file_data = encrypted_file.read()
    iv = file_data[:16]  # Extraer el IV
    encrypted_data = file_data[16:]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)

# Guardar los datos desencriptados
with open(decrypted_file_path, 'wb') as decrypted_file:
    decrypted_file.write(decrypted_data)

print(f"El archivo '{encrypted_file_path}' ha sido desencriptado y guardado como '{decrypted_file_path}'.")

Puntos importantes del código

  1. Almacenamiento de la clave y el IV
  • En el código de ejemplo, hemos omitido detalles sobre cómo manejar de forma segura la clave y el IV. Si se incluyen en el archivo encriptado, se debe tener mucho cuidado de no compartir estos datos.
  1. Manejo del tamaño del bloque
  • Los datos del archivo generalmente no son un múltiplo del tamaño del bloque, por lo que se utiliza la función pad para ajustarlos.
  1. Guardado separado de la clave y el IV
  • Por razones de seguridad, es recomendable almacenar la clave y el IV en archivos separados o en almacenamiento seguro.

Ejemplo práctico: Manejo separado de la clave y el IV


A continuación, se muestra un ejemplo de cómo almacenar por separado la clave y el IV:

# Almacenar la clave y el IV
with open('key.bin', 'wb') as key_file:
    key_file.write(key)
with open('iv.bin', 'wb') as iv_file:
    iv_file.write(iv)

Y cómo leerlos durante la desencriptación:

# Leer la clave y el IV
with open('key.bin', 'rb') as key_file:
    key = key_file.read()
with open('iv.bin', 'rb') as iv_file:
    iv = iv_file.read()

Encriptación de archivos con seguridad en mente


La encriptación de archivos es útil para proteger información personal o confidencial. Sin embargo, es importante manejar adecuadamente las claves, implementar funciones de detección de alteraciones (como HMAC) y adoptar buenas prácticas de seguridad.

Con esto, ahora puede encriptar y desencriptar archivos. En la siguiente sección, discutiremos los puntos clave de seguridad al implementar estos procesos.

Puntos de seguridad a tener en cuenta


Para operar la encriptación y desencriptación AES de forma segura, es necesario considerar varios puntos de seguridad. Si no se implementan adecuadamente, los datos encriptados pueden ser vulnerables a ataques. En esta sección, abordaremos las principales consideraciones de seguridad.

1. Manejo seguro de las claves


El manejo adecuado de las claves es la base de cualquier sistema de encriptación seguro. La fuga o manejo incorrecto de claves puede invalidar el cifrado.

  • Elegir una ubicación segura de almacenamiento
  • No almacene claves en texto plano en el sistema de archivos; guárdelas en forma encriptada o en un almacenamiento seguro.
  • Recomendación: utilice un módulo de seguridad de hardware (HSM) o servicios de gestión de claves en la nube como AWS KMS o Azure Key Vault.
  • Rotación regular de claves
  • Cambie las claves de manera periódica para reducir riesgos de seguridad a largo plazo.

2. Gestión del vector de inicialización (IV)


La gestión adecuada de IV mejora la seguridad de AES.

  • Asegurar la unicidad del IV
  • No reutilice el mismo IV en múltiples operaciones de encriptación.
  • Recomendación: genere un IV aleatorio para cada operación de encriptación y guárdelo de manera segura junto con los datos encriptados.
  • Gestionar IV por separado de la clave
  • Guardar clave e IV juntos facilita que un atacante consiga ambos y pueda comprometer el sistema.

3. Selección del modo de operación


Existen varios modos de operación en AES, y es importante elegir uno que ofrezca la mejor seguridad.

  • Modo recomendado: GCM
  • El modo GCM (Galois/Counter Mode) no solo encripta, sino que también proporciona verificación de integridad de los datos.
  • Si utiliza CBC, agregue funciones de detección de alteraciones, como HMAC.

4. Resistencia a los ataques


Para minimizar el riesgo de que los datos encriptados sean analizados, se recomienda lo siguiente:

  • Prevenir ataques de tiempo
  • Implemente operaciones criptográficas que se ejecuten en un tiempo constante.
  • Hacer que la longitud de los datos encriptados sea constante
  • Evite que el análisis de la longitud de los datos permita la deducción de su contenido. Asegúrese de que los datos estén rellenos a un tamaño fijo.

5. Verificación de la integridad de los datos


Aunque la encriptación oculta los datos, no proporciona protección contra alteraciones. Es importante agregar verificación de integridad:

  • Agregar HMAC
  • Utilice HMAC (Código de Autenticación de Mensaje basado en Hash) para verificar que los datos no han sido alterados.
  • Ejemplo de HMAC en PyCryptodome:
    python from Crypto.Hash import HMAC, SHA256 h = HMAC.new(key, digestmod=SHA256) h.update(encrypted_data) mac = h.hexdigest()

6. Generación de claves a partir de contraseñas


Si genera claves a partir de una contraseña, asegúrese de utilizar un algoritmo adecuado.

  • Algoritmo recomendado: PBKDF2
  • PBKDF2 utiliza sal y repeticiones para generar claves de forma segura.
  • Ejemplo en PyCryptodome:
    python from Crypto.Protocol.KDF import PBKDF2 salt = get_random_bytes(16) key = PBKDF2("password", salt, dkLen=32, count=100000)

7. Actualización de bibliotecas


Las bibliotecas de criptografía pueden contener vulnerabilidades. Siempre asegúrese de usar la versión más reciente:

pip install --upgrade pycryptodome

8. Eliminación segura de datos encriptados


Elimine los archivos de datos encriptados o las claves de manera segura utilizando métodos de sobrescritura, evitando que puedan ser recuperados.

Resumen


La seguridad de un sistema AES depende de su implementación. Preste especial atención a la gestión de claves y IV, prevención de accesos no autorizados y verificación de la integridad de los datos. Con estas prácticas, puede construir un sistema de encriptación práctico y seguro.

Resumen


Este artículo cubre cómo implementar encriptación y desencriptación AES en Python. Desde los conceptos básicos de AES hasta las bibliotecas necesarias, los pasos de encriptación y desencriptación de datos y archivos, así como las precauciones de seguridad.

Al gestionar adecuadamente las claves y los vectores de inicialización (IV), implementar mecanismos de verificación de integridad y adoptar buenas prácticas de operación, puede aprovechar al máximo las capacidades de encriptación AES para proteger los datos importantes.

Índice