Há uma pergunta que vale a pena fazer sobre os dados que sua aplicação movimenta hoje: por quanto tempo eles permanecem sensíveis? Um prontuário médico, um contrato, um arquivo de folha de pagamento, um conjunto de credenciais. Se a resposta for mais de alguns anos, então a ameaça interessante não é um atacante que quebra sua criptografia agora. É um atacante que grava o tráfego agora, armazena e decifra depois, quando as ferramentas tiverem evoluído o suficiente. Essa prática tem um nome, colher agora, decifrar depois, e ela não exige que ninguém construa um computador quântico hoje. Basta que acreditem que alguém vai construir.
É por isso que os padrões se moveram primeiro. O NIST publicou os algoritmos em 2024, navegadores e CDNs ativaram a troca de chaves híbrida ao longo de 2025, e os prazos para aposentar o RSA e a troca de chaves por curvas elípticas já estão escritos em recomendações públicas. O sgcWebSockets 2026.10 traz todo esse conjunto para o Delphi, escrito em Object Pascal dentro do pacote sgcCrypto, sem nenhuma biblioteca externa para instalar ou implantar.
Três algoritmos, um só pacote
Os três padrões do NIST cumprem funções diferentes, e normalmente você usará os dois primeiros:
- ML-KEM (FIPS 203) combina um segredo compartilhado. Substitui a função que o Diffie-Hellman cumpre hoje.
- ML-DSA (FIPS 204) assina. Substitui as assinaturas RSA e ECDSA.
- SLH-DSA (FIPS 205) também assina, construído apenas sobre funções de hash, para o caso em que você quer a premissa mais conservadora disponível e pode arcar com o tamanho da assinatura.
Combinando uma chave com ML-KEM
Um mecanismo de encapsulamento de chave é mais simples de usar do que o Diffie-Hellman. O remetente pega a chave pública do destinatário e produz duas coisas: um novo segredo compartilhado e um texto cifrado que o entrega. O destinatário transforma o texto cifrado de volta no mesmo segredo.
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;
Os conjuntos de parâmetros são mlkem512, mlkem768 e mlkem1024. As verificações de entrada exigidas pela FIPS 203 são executadas antes de qualquer outra coisa, de modo que uma chave pública malformada gera uma exceção em vez de produzir silenciosamente um segredo, e um texto cifrado que não decifra resulta em um segredo pseudoaleatório em vez de um erro, que é a rejeição implícita exigida pelo padrão.
X-Wing, quando você não quer escolher
Adotar um novo algoritmo significa confiar nele. As construções híbridas eliminam essa decisão: combinam um algoritmo clássico com um pós-quântico, de modo que o resultado é seguro enquanto qualquer uma das duas metades se mantiver. O X-Wing combina o X25519 com o ML-KEM-768 e expõe um único par de chaves.
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;
Assinando com ML-DSA
A assinatura recebe o conjunto de parâmetros, a chave privada, a mensagem e uma string de contexto, que normalmente é vazia:
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;
Observe a semente (seed). Uma chave privada ML-DSA pode ser armazenada como os 32 bytes a partir dos quais foi gerada, como a chave expandida, ou como ambas, e a biblioteca lê e grava as três formas. A semente é a forma indicada para um arquivo de configuração: é pequena, e a chave expandida é derivada dela de maneira determinística.
Chaves que viajam
Um algoritmo com o qual ninguém consegue trocar chaves não tem muita utilidade, então as codificações seguem os perfis publicados: SubjectPublicKeyInfo e PKCS#8, em DER ou PEM, conforme a RFC 9935 para ML-KEM, a RFC 9881 para ML-DSA e a RFC 9909 para SLH-DSA.
var
vPublicPEM, vPrivatePEM: string;
begin
vPublicPEM := sgcMLDSA_ExportPublicKeyPEM(mldsa65, oPublicKey);
vPrivatePEM := sgcMLDSA_ExportPrivateKeyPEM(mldsa65, oSeed, nil);
end;
Esses são blocos comuns BEGIN PUBLIC KEY e BEGIN PRIVATE KEY, que outras implementações sabem ler. Uma chave privada é verificada no momento da importação: a metade pública é derivada novamente e comparada, de modo que uma chave que não pertence ao seu certificado é recusada ali mesmo, em vez de produzir assinaturas que ninguém consegue verificar.
Certificados e uma AC pós-quântica
Certificados e solicitações de certificado podem carregar chaves pós-quânticas, e uma autoridade certificadora também pode ter uma, de modo que uma cadeia inteira pode ser pós-quâ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;
As regras de uso de chave dos perfis são aplicadas antes de qualquer assinatura, de modo que uma chave pós-quântica solicitada para cifrar chave lança uma exceção em vez de produzir um certificado que viola seu próprio perfil. A validação de cadeia agora também aplica o comprimento do caminho e as restrições de nome declaradas pelos certificados emissores.
Onde já está integrado
Dois pontos da biblioteca já usam tudo isso para você, sem que seja preciso escrever nenhuma criptografia:
- TLS. O mecanismo nativo de TLS 1.3 negocia os grupos de troca de chaves híbridos da RFC 10024,
X25519MLKEM768,SecP256r1MLKEM768eSecP384r1MLKEM1024, e a lista padrão já começa com um grupo híbrido. Veja Delphi TLS 1.3 sem DLLs OpenSSL. - JWT. Os tokens podem ser assinados e verificados com ML-DSA conforme a RFC 9964. Veja Assinar um JWT com ML-DSA em Delphi.
Como sabemos que está correto
A implementação de um padrão é só uma afirmação até que algo a verifique. Os três algoritmos são validados em relação aos vetores de teste conhecidos do NIST, e esses vetores são distribuídos com a biblioteca como um conjunto de testes executável, e não apenas como uma frase em uma ficha técnica. O assinador ML-DSA é a variante determinística, de modo que a mesma chave e a mesma mensagem sempre produzem a mesma assinatura, o que torna os exemplos publicados nas RFCs reproduzíveis byte a byte.
Qual usar
Para a combinação de chaves, use um híbrido: X-Wing sozinho, ou os grupos TLS híbridos se o tráfego for TLS. Você não abre mão de quase nada e fica coberto seja qual for a premissa que se revelar errada. Para assinaturas, ML-DSA-65 é o padrão sensato, com ML-DSA-44 quando o tamanho importa e ML-DSA-87 quando não importa. Recorra ao SLH-DSA quando a assinatura for verificada muitos anos depois por algo que você não pode atualizar, como um firmware, e o tamanho da assinatura for aceitável.
Atualizando
Tudo isso está no pacote sgcCrypto e não adiciona nenhuma dependência: sem OpenSSL, sem DLL, nada para instalar na máquina que executa sua aplicação. O código existente permanece intocado até que você o chame.
Leia também
- Delphi TLS 1.3 sem DLLs OpenSSL
- Assinar um JWT com ML-DSA em Delphi
- sgcWebSockets 2026.10, tudo o mais nesta versão
Assista
Há um vídeo curto sobre isso no canal eSeGeCe.
Perguntas, feedback ou ajuda com a migração? Entre em contato — você receberá uma resposta das pessoas que escreveram o código.
