Hay una pregunta que merece la pena hacerse sobre los datos que hoy mueve su aplicación: ¿cuánto tiempo siguen siendo sensibles? Un historial médico, un contrato, una nómina, un conjunto de credenciales. Si la respuesta es más de unos pocos años, entonces la amenaza interesante no es un atacante que rompe su cifrado ahora. Es un atacante que graba el tráfico ahora, lo almacena y lo descifra más tarde, cuando las herramientas se hayan puesto al día. Esta costumbre tiene un nombre, harvest now, decrypt later (capturar ahora, descifrar después), y no requiere que nadie construya hoy un ordenador cuántico. Solo requiere que alguien crea que lo hará.
Por eso los estándares se movieron primero. NIST publicó los algoritmos en 2024, los navegadores y las CDN activaron el intercambio de claves híbrido durante 2025, y los plazos para retirar el acuerdo de claves con RSA y curva elíptica ya están escritos en las guías públicas. sgcWebSockets 2026.10 trae todo el conjunto a Delphi, escrito en Object Pascal dentro del paquete sgcCrypto, sin ninguna biblioteca externa que instalar ni distribuir.
Tres algoritmos, un paquete
Los tres estándares de NIST hacen trabajos distintos, y normalmente usará los dos primeros:
- ML-KEM (FIPS 203) acuerda un secreto compartido. Sustituye el trabajo que hoy hace Diffie-Hellman.
- ML-DSA (FIPS 204) firma. Sustituye las firmas RSA y ECDSA.
- SLH-DSA (FIPS 205) también firma, construido únicamente sobre funciones hash, para el caso en que quiera la suposición más conservadora disponible y pueda permitirse el tamaño de la firma.
Acordar una clave con ML-KEM
Un mecanismo de encapsulado de claves es más sencillo de usar que Diffie-Hellman. El emisor toma la clave pública del destinatario y produce dos cosas: un secreto compartido nuevo y un texto cifrado que lo transporta. El destinatario convierte ese texto cifrado de nuevo en el mismo secreto.
uses
sgcCrypto_MLKEM;
var
oPublicKey, oPrivateKey, oCiphertext, oSecret, oSame: TBytes;
begin
sgcMLKEM_GenerateKeyPair(mlkem768, oPublicKey, oPrivateKey);
// the sender, who only ever sees the public key
sgcMLKEM_Encapsulate(mlkem768, oPublicKey, oCiphertext, oSecret);
// the recipient, who holds the private key, gets the same 32 bytes
oSame := sgcMLKEM_Decapsulate(mlkem768, oPrivateKey, oCiphertext);
end;
Los conjuntos de parámetros son mlkem512, mlkem768 y mlkem1024. Las comprobaciones de entrada que exige FIPS 203 se ejecutan antes que cualquier otra cosa, de modo que una clave pública mal formada genera una excepción en lugar de producir un secreto en silencio, y un texto cifrado que no descifra correctamente da como resultado un secreto pseudoaleatorio en lugar de un error, que es el rechazo implícito que pide el estándar.
X-Wing, cuando no quiere elegir
Adoptar un algoritmo nuevo significa confiar en él. Las construcciones híbridas eliminan esa decisión: combinan un algoritmo clásico con uno poscuántico, de modo que el resultado es seguro mientras cualquiera de las dos mitades se mantenga firme. X-Wing combina X25519 con ML-KEM-768 y expone un único par de claves.
uses
sgcCrypto_MLKEM_Hybrid;
var
oPublicKey, oPrivateKey, oCiphertext, oSecret: TBytes;
begin
sgcXWing_GenerateKeyPair(oPublicKey, oPrivateKey);
sgcXWing_Encapsulate(oPublicKey, oCiphertext, oSecret);
oSecret := sgcXWing_Decapsulate(oPrivateKey, oCiphertext);
end;
Firmar con ML-DSA
Firmar recibe el conjunto de parámetros, la clave privada, el mensaje y una cadena de contexto, que normalmente está vacía:
uses
sgcCrypto_MLDSA;
var
oSeed, oPublicKey, oPrivateKey, oSignature: TBytes;
begin
sgcMLDSA_GenerateKeyPairAndSeed(mldsa65, oSeed, oPublicKey, oPrivateKey);
oSignature := sgcMLDSA_Sign(mldsa65, oPrivateKey, aMessage, nil);
if sgcMLDSA_Verify(mldsa65, oPublicKey, aMessage, oSignature, nil) then
ShowMessage('signature is valid');
end;
Fíjese en la semilla (seed). Una clave privada ML-DSA puede almacenarse como los 32 bytes de los que se generó, como la clave expandida, o como ambas cosas, y la biblioteca lee y escribe las tres formas. La semilla es la forma que interesa en un archivo de configuración: es pequeña, y la clave expandida se deriva de ella de forma determinista.
Claves que viajan
Un algoritmo con el que nadie puede intercambiar claves no sirve de mucho, así que las codificaciones siguen los perfiles publicados: SubjectPublicKeyInfo y PKCS#8, en DER o PEM, según RFC 9935 para ML-KEM, RFC 9881 para ML-DSA y RFC 9909 para SLH-DSA.
var
vPublicPEM, vPrivatePEM: string;
begin
vPublicPEM := sgcMLDSA_ExportPublicKeyPEM(mldsa65, oPublicKey);
vPrivatePEM := sgcMLDSA_ExportPrivateKeyPEM(mldsa65, oSeed, nil);
end;
Son bloques BEGIN PUBLIC KEY y BEGIN PRIVATE KEY corrientes, que otras implementaciones saben leer. Una clave privada se comprueba al importarla: la mitad pública se vuelve a derivar y se compara, de modo que una clave que no pertenece a su certificado se rechaza en el acto, en lugar de producir firmas que nadie puede verificar.
Certificados y una CA poscuántica
Los certificados y las solicitudes de certificado pueden llevar claves poscuánticas, y una autoridad de certificación también puede tener una, de modo que toda una cadena puede ser poscuántica:
var
vKey: TsgcX509SignKey;
vOptions: TsgcX509Options;
oCertDER: TBytes;
begin
vKey := sgcX509_MLDSAKey(mldsa65, oPrivateKey, oPublicKey);
vOptions.Subject.CommonName := 'My Post-Quantum CA';
vOptions.KeyUsage := [kuKeyCertSign, kuCRLSign];
oCertDER := sgcX509_CreateSelfSignedEx(vKey, vOptions);
end;
Las reglas de uso de clave de los perfiles se aplican antes de firmar nada, de modo que una clave poscuántica a la que se le pide cifrado de claves genera una excepción en lugar de producir un certificado que viola su propio perfil. La validación de la cadena ahora también aplica la longitud de ruta y las restricciones de nombre que declaran los certificados emisores.
Dónde ya está integrado
Hay dos lugares de la biblioteca que usan todo esto por usted, sin que tenga que escribir criptografía:
- TLS. El motor nativo de TLS 1.3 negocia los grupos híbridos de intercambio de claves de RFC 10024,
X25519MLKEM768,SecP256r1MLKEM768ySecP384r1MLKEM1024, y la lista predeterminada ya empieza por uno híbrido. Vea Delphi TLS 1.3 sin DLLs de OpenSSL. - JWT. Los tokens se pueden firmar y verificar con ML-DSA según RFC 9964. Vea Firmar un JWT con ML-DSA en Delphi.
Cómo sabemos que es correcto
La implementación de un estándar es solo una afirmación hasta que algo la comprueba. Los tres algoritmos se validan contra los vectores de respuesta conocida de NIST, y esos vectores se distribuyen con la biblioteca como un conjunto de pruebas ejecutable, no como una frase en una ficha técnica. El firmante ML-DSA es la variante determinista, de modo que la misma clave y el mismo mensaje dan siempre la misma firma, que es lo que hace que los ejemplos publicados en los RFC sean reproducibles byte a byte.
Cuál debería usar
Para el acuerdo de claves, use un híbrido: X-Wing por sí solo, o los grupos híbridos de TLS si el tráfico es TLS. No renuncia prácticamente a nada y queda cubierto sea cual sea la suposición que resulte equivocada. Para las firmas, ML-DSA-65 es la opción sensata por defecto, con ML-DSA-44 cuando el tamaño importa y ML-DSA-87 cuando no. Recurra a SLH-DSA cuando la firma vaya a verificarse muchos años después con algo que no puede actualizar, como firmware, y el tamaño de la firma sea asumible.
Actualizar
Todo esto vive en el paquete sgcCrypto y no añade ninguna dependencia: ni OpenSSL, ni DLL, nada que instalar en la máquina que ejecuta su aplicación. El código existente no se toca hasta que usted lo llama.
Siga leyendo
- Delphi TLS 1.3 sin DLLs de OpenSSL
- Firmar un JWT con ML-DSA en Delphi
- sgcWebSockets 2026.10, todo lo demás de esta versión
Míralo
Hay un vídeo corto sobre esto en el canal de eSeGeCe.
¿Preguntas, comentarios o ayuda con la migración? Póngase en contacto — recibirá respuesta de las personas que escribieron el código.
