Criptografía post-cuántica fácil con Python

Introducción a la criptografía post-cuántica

Cómo decía Daniel Bernstein, el día que alguien consiga construir un computador cuántico funcional, se acabó la criptografía tal y como la conocemos. Todos los algoritmos de clave pública usados actualmente para proteger nuestros datos y comunicaciones serán vulnerables. Pero que esta máquina consiga romper algoritmos como RSA, DSA o ECDSA no implica que la criptografía y la privacidad hayan llegado a su fin. Nace de este modo la criptografía post-cuántica, el inicio de una nueva generación de algoritmos que resistan el impacto de la computación cuántica.

Criptografía post-cuántica con Kyber y Dilithium: seguridad frente a ordenadores cuánticos.

Imagen 1. Visualización de la transición de RSA hacia algoritmos de criptografía post-cuántica como Kyber y Dilithium, base de la nueva generación de seguridad digital.

La criptografía post-cuántica surge precisamente para anticiparse a este escenario. Los candidatos post-cuánticos se basan en problemas para los cuales no se conocen algoritmos cuánticos capaces de resolverlos de forma práctica. De ahí que organismos como el NIST estén estandarizando esquemas como Kyber (para cifrado e intercambio de claves) y Dilithium (para firmas digitales).

En esta entrada vamos a ver cómo trabajar con algoritmos post-cuánticos, concretamente los dos más famosos, Kyber y Dilithium. Aprenderemos a clonar e instalar PQcrypt, una sencilla herramienta en Python que nos permitirá generar pares de claves, cifrar y descifrar ficheros, así como firmar y verificar documentos a través de una interfaz muy fácil de usar.

Preparación del entorno

Como se ha mencionado, para adentrarnos en la criptografía post-cuántica vamos a utilizar la herramienta PQcrypt. En principio, necesitaremos un ordenador con sistema operativo Linux y al menos 4GB de memoria RAM. Yo he usado una máquina virtual con 8 cores y 4GB de RAM y el proceso de creación de claves, así como otras operaciones, ha sido bastante rápido.

Lo primero que hacemos es actualizar la lista de repositorios y los paquetes.

$ sudo apt-get update && sudo apt-get upgrade -y

Después, tenemos que clonar el repositorio. Para ello, es posible que haya que instalar el paquete git con sus dependencias, aunque lo más probable es que ya lo tengamos en el sistema.

$ git clone https://github.com/Anish-M-code/pqcrypt.git

Por último, compilamos el repositorio:

$ cd pqcrypt && source check_deps.sh

¡Con esto ya tenemos el entorno preparado! Ha sido fácil, ¿verdad?

Utilizando PQcrypt

La herramienta de criptografía post-cuántica se ejecuta desde la raiz de su directorio. Al realizar la compilación mediante el script anterior, nos ha cambiado el path, por lo que tendremos que volver a la carpeta «pqcrypt«, que es la del repositorio clonado de git. El comando es el siguiente (y muestra un menú):

$ source run.sh                                                                                                                                                                                                  

 --- PQcrypt : Post Quantum Cryptography Toolkit --- 


 Menu:-

 1) Encrypt/Decrypt Data
 2) Digitally Sign/Verify Data
 3) Check Fingerprint of Public key
 4) Export/Extract Public key from Private key
 5) Update Dependencies
 6) About

Enter choice:

La herramienta nos ofrece varios algoritmos de cifrado, todos ellos son:

  • Algoritmos de cifrado de clave pública y establecimiento de claves que fueron seleccionados en la 3ª ronda del proceso de estandarización del NIST.
  • Algoritmos de firma digital que también fueron seleccionados para estandarización en esa ronda.
  • Además, se consideran algoritmos que están siendo evaluados para una posible 4ª ronda de análisis (es decir, candidatos avanzados, pero aún no estandarizados).

Cifrado y descifrado de datos con criptografía post-cuántica

Para cifrar datos lo primero que necesitamos es un fichero que queramos ofuscar. Yo he creado el fichero hello.txt, que contiene el texto «Hello World» como ejemplo. A continuación vamos a cifrarlo con el algoritmo Kyber.

Generar una pareja de claves

Lo primero que tenemos que hacer es lo mismo que en la criptografía tradicional, generar una pareja de claves. Podremos verlas en el mismo directorio en el que estamos trabajando. Posteriormente le decimos que queremos cifrar un fichero. Nos preguntará cuál es la pública, si queremos protegerlo con contraseña y cuál es el nombre del fichero a cifrar. Aquí debajo dejo una captura del log:

 --- PQcrypt : Post Quantum Cryptography Toolkit --- 

 Menu:-

 1) Encrypt/Decrypt Data
 2) Digitally Sign/Verify Data
 3) Check Fingerprint of Public key
 4) Export/Extract Public key from Private key
 5) Update Dependencies
 6) About

Enter choice:1

 --- Encryption/Decryption Mode ---

 1) Generate key pair
 2) Encrypt data
 3) Decrypt Data

Enter choice:1

--- Supported Ciphers ---

 1) Kyber1024 [ Recommended ]
 2) HQC-256
 3) Classic-McEliece-6688128
...

Enter choice:1

<--- Task Started --->

Enter Password to protect secret key:
Do you need ASCII armoured public key?(Y/N):N

<--- Task Completed --->

 --- Encryption/Decryption Mode ---

 1) Generate key pair
 2) Encrypt data
 3) Decrypt Data

Enter choice:2

<--- Task Started --->

Enter Public key:82ab1c3def1c65b4639cb87b0904538b.pub

Enter file:hello.txt

<--- Task Completed --->

Do you need ASCII armoured Encrypted Message ?(Y/N):N

Después de esto, si listamos el directorio actual, aparecerán dos nuevos ficheros con extensión .sec y .pub, los cuales se corresponden con las claves privada y pública.

$ ls -l | awk '{print $1, $3, $5, $9}'                                                                                                                                                                      
-rw-r--r-- osboxes 8192 82ab1c3def1c65b4639cb87b0904538b.pub
-rw-r--r-- osboxes 12288 82ab1c3def1c65b4639cb87b0904538b.sec

Cifrar el mensaje con la clave pública

La lógica que sigue la criptografía post-cuántica es la misma que la tradicional. Usaremos la clave pública para cifrar y la privada para descifrar. Para ello seleccionamos desde el menú principal la opción 1, “Encrypt/Decrypt Data”.

--- Encryption/Decryption Mode ---

 1) Generate key pair
 2) Encrypt data
 3) Decrypt Data

Enter choice:2

<--- Task Started --->

Enter Public key:82ab1c3def1c65b4639cb87b0904538b.pub

Enter file:hello.txt

<--- Task Completed --->

Hemos seleccionado la opción de cifrar y hemos seguido los pasos proporcionando la información que nos solicita. Con esto, ya se ha generado de forma automática el fichero “hello.txt.cry”. Si lo abrimos, veremos que contiene símbolos y caracteres ilegibles.

Descifrar el mensaje con la clave privada

Para realizar la operación contraria, desde el mismo menú, tendremos que seleccionar la opción 3, «Decrypt Data«.

Enter choice:3

<--- Task Started --->

Enter Private key:82ab1c3def1c65b4639cb87b0904538b.sec

Enter Encrypted file:hello.txt.cry
Enter Password to unlock secret key:
Enter Name of output file:hola.txt

<--- Task Completed --->

Podemos confirmar que el fichero original y que el nuevo fichero generado a partir del cifrado tienen el mismo contenido:

$ cat hello.txt
Hello World
$ cat hola.txt 
Hello World

Firma digital con criptografía post-cuántica

Una firma digital es un mecanismo criptográfico que garantiza la autenticidad, integridad y no repudio de un mensaje o documento. Funciona mediante un par de claves: la privada (que solo el firmante conoce) y la pública (que cualquiera puede usar para verificar la firma).

Test: Todos los algoritmos no sirven para firmar

Ahora bien, no todas las claves privadas sirven para firmar. En el siguiente ejemplo he intentado firmar un archivo con una clave Kyber y, como era de esperar, he obtenido el siguiente error:

--- Sign/Verify Data ---

 1) Generate key pair
 2) Digitally Sign Data
 3) Verify Digital Signature

Enter choice:2

<--- Task Started --->

Enter Private key:82ab1c3def1c65b4639cb87b0904538b.sec

Enter file which will be signed:hello.txt
Enter Password to unlock secret key:
Kyber1024

<--- Task Failed --->

Esto ocurre porque Kyber está diseñado para cifrado e intercambio de claves, no para firmas digitales. En la criptografía tradicional pasa algo parecido: algoritmos como RSA permiten tanto cifrar como firmar, aunque se recomienda no usar la misma clave para ambas funciones. En el caso de las curvas elípticas (ECC), directamente hay que elegir el algoritmo adecuado para cada tarea: ECDH para intercambio de claves y ECDSA o EdDSA para firmas.

Generar una pareja de claves para firmar con criptografía post-cuántica

Tras comprobar que con Kyber no podemos firmar, vamos a dar el paso lógico: generar un par de claves Dilithium, un esquema diseñado específicamente para firmas digitales. Desde el mismo menú de pqcrypt seleccionamos la opción de generar una nueva clave y elegimos Dilithium5 (la opción recomendada):

--- Supported Algorithms ---
 1) Dilithium5 [ Recommended ]
 2) Falcon-1024
 3) SPHINCS+-Haraka-256f-robust
 ...
Enter choice:1

<--- Task Started --->

Enter Password to protect secret key:
Do you need ASCII armoured public key?(Y/N):N

<--- Task Completed --->

Firma del mensaje con la clave privada

Con la clave ya creada, podemos firmar nuestro fichero hello.txt introduciendo la clave privada correspondiente:

Enter Private key:20b477338f583c838b1c21162a8df413.ssec
Enter file which will be signed:hello.txt
Enter Password to unlock secret key:
Do you need ascii armoured digital signature?(Y/n):n

<--- Task Completed --->

Comprobación de la firma con la clave pública

La firma se generó correctamente y quedó guardada como hello.txt.qsig. Ahora, si compartimos el fichero con su firma, el receptor podría verificar la firma usando nuestra clave pública:

Enter Public key:20b477338f583c838b1c21162a8df413.spub
Enter file which has to be verified:hello.txt
Enter Digital Signature File Location:hello.txt.qsig

Good Signature , Data signed on 2025-09-19 11:38:42.785343

Digital Signature made using key with fingerprint:-
  186ee88836e6abde77552448fd5fc63965e728a394490b0dc8834536cf24b119 
  3cc829e227f7c1268aff29f40a1d6a29d976e6b70d4803a202948a921ed2d1fd

Como vemos, la firma es válida y nos confirma que el documento no ha sido modificado desde el momento en que se firmó.

Poniendo a prueba la integridad del mensaje

Para comprobar la robustez del sistema, editamos el archivo original añadiendo una línea más:

$ echo "modification" >> hello.txt
$ cat hello.txt
Hello World
modification

Si volvemos a verificar la firma, el resultado cambia:

Enter Public key:20b477338f583c838b1c21162a8df413.spub
Enter file which has to be verified:hello.txt
Enter Digital Signature File Location:hello.txt.qsig

<--- Task Completed --->

En este caso ya no se muestra el mensaje de Good Signature, lo que indica que el documento fue alterado y, por tanto, la firma ya no es válida. Este ejemplo demuestra claramente la función principal de una firma digital: garantizar la integridad y autenticidad de la información.

Criptografía híbrida

La criptografía asimétrica tiene un inconveniente, y es que no puede cifrar grandes volúmenes de información. Por el contrario, la criptografía simétrica, con algoritmos como AES o ChaCha20, sí es capaz de resolver este problema, sin embargo, si alguien intercepta la clave los datos quedan comprometidos.

Para resolver estos problemas, la solución está en combinar lo mejor de ambos mundos, la criptografía híbrida, empleada en sistemas como PGP. Este enfoque consiste en cifrar los datos con una clave simétrica aleatoria, y protegerla a su vez cifrando esa clave con un algoritmo asimétrico, como RSA, ECC o Kyber.

Este enfoque sigue siendo válido para criptografía post-cuántica, ya que algoritmos simétricos como AES siguen siendo seguros frente a ordenadores cuánticos. La única precaución es usar claves de 256 bits o más, ya que el ataque de Grover permite reducir a la mitad la seguridad efectiva de las claves simétricas. A diferencia de RSA o ECC, AES no se ve afectado por el algoritmo de Shor.

Generar una clave AES aleatoria

Este paso vamos a darlo con el framework de OpenSSL. Para ello, es necesario que tanto la clave como el vector de inicialización (VI) estén en formato hexadecimal:

$ openssl rand -hex 32 > aes.key
$ openssl rand -hex 16 > aes.iv

Cifrar el mensaje con la clave AES

El siguiente paso es usar la clave privada con su vector de inicialización para cifrar el mensaje hello.txt. El resultado de este cifrado se guarda como hello.enc.

$ openssl enc -aes-256-cbc -in hello.txt -out hello.enc -K $(cat aes.key) -iv $(cat aes.iv)

Utilizar criptografía post-cuántica para cifrar la clave privada

El siguiente paso es cifrar, tal y como hemos visto antes, la clave simétrica aes.key con la clave pública de Kyber. Los ficheros que enviaríamos al destinatario serían los siguientes:

  1. hello.enc – fichero cifrado con AES
  2. aes.key.cry – clave AES cifrada con Kyber
  3. aes.iv – IV en claro (no es secreto)

Para descifrar el mensaje, el receptor tendrá que usar su clave privada para obtener la clave simétrica AES, y utilizar esta clave para descifrar el mensaje hello.enc.

Mejorando la criptografía híbrida con la firma digital

Hasta ahora hemos visto cómo cifrar un archivo con una clave simétrica AES y cómo proteger esa clave con un algoritmo post-cuántico como Kyber. Con este enfoque garantizamos la confidencialidad de la información. Sin embargo, todavía queda una cuestión importante por resolver: ¿cómo puede el receptor estar seguro de que el mensaje no ha sido manipulado y que procede realmente del emisor?

Aquí es donde entra en juego la firma digital. Al añadir una firma a nuestro esquema híbrido, conseguimos no solo cifrar el contenido, sino también validar su integridad y autenticidad. De este modo, aunque un atacante intercepte o modifique los datos, la firma fallará en la verificación.

Firmar antes o después de cifrar

Existen dos formas de combinar cifrado y firma digital:

  • Firmar antes de cifrar (sign-then-encrypt): se genera la firma del archivo original y después se cifra tanto el archivo como su firma. Esto es lo más común en sistemas como PGP, ya que protege también la propia firma.
  • Firmar después de cifrar (encrypt-then-sign): primero se cifra el archivo y después se firma el fichero resultante. La ventaja es que el receptor puede comprobar la validez de la firma incluso antes de descifrar.

En ambos casos, la idea es la misma: la firma digital, generada con Dilithium u otro algoritmo post-cuántico, añade una capa de seguridad que el cifrado híbrido por sí solo no ofrece.

Ejemplo de flujo completo

Siguiendo nuestro ejemplo, el proceso quedaría así:

  1. Generamos una clave AES y ciframos el archivo hello.txt → obtenemos hello.enc.
  2. Ciframos la clave AES con Kyber → obtenemos aes.key.cry y compartimos también el aes.iv.
  3. Firmamos el archivo original o bien el cifrado (según el enfoque elegido) con Dilithium → obtenemos hello.txt.qsig o hello.enc.qsig.
  4. El receptor descifra la clave AES con su clave privada Kyber, descifra el archivo con AES y, finalmente, verifica la firma con la clave pública Dilithium.

De este modo combinamos lo mejor de cada enfoque: confidencialidad gracias al cifrado híbrido y integridad, autenticidad y no repudio gracias a la firma digital. Este esquema es el que se utiliza en sistemas modernos de comunicación segura y es, en esencia, la base sobre la que se construye la criptografía post-cuántica aplicada.

Fin de la guía

Con esto terminamos: has visto cómo generar claves post-cuánticas, cifrar y firmar ficheros con pqcrypt, y cómo encajar ese trabajo en un esquema híbrido (Kyber + AES/ChaCha20 + Dilithium) para lograr confidencialidad y autenticidad. Si te ha gustado, pruébalo en tu entorno y, si surge alguna duda, no dudes en dejar un comentario y lo revisamos juntos.

Si te interesa la ciberseguridad, puedes continuar leyendo esta lecturas relacionada: Pentesting (VulnHub): escalada y persistencia.

Deja una respuesta

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