Warto zadać sobie pytanie o dane, które dziś przetwarza Twoja aplikacja: jak długo pozostają one wrażliwe? Dokumentacja medyczna, umowa, plik płacowy, zestaw poświadczeń. Jeśli odpowiedź brzmi „więcej niż kilka lat”, to prawdziwym zagrożeniem nie jest atakujący, który złamie Twoje szyfrowanie już teraz. To atakujący, który nagrywa ruch sieciowy już teraz, przechowuje go i odszyfrowuje później, gdy narzędzia go dogonią. Ten schemat ma nazwę, harvest now, decrypt later (zbierz teraz, odszyfruj później), i nie wymaga, aby ktokolwiek zbudował komputer kwantowy już dziś. Wymaga jedynie, by ktoś w to wierzył.
Dlatego to standardy poszły pierwsze. NIST opublikował algorytmy w 2024 roku, przeglądarki i sieci CDN włączyły hybrydową wymianę kluczy w 2025 roku, a terminy wycofania RSA i uzgadniania kluczy na krzywych eliptycznych są już zapisane w publicznych wytycznych. sgcWebSockets 2026.10 wprowadza cały ten zestaw do Delphi, napisany w Object Pascal wewnątrz pakietu sgcCrypto, bez żadnej zewnętrznej biblioteki do zainstalowania czy wdrożenia.
Trzy algorytmy, jeden pakiet
Trzy standardy NIST pełnią różne funkcje, a zwykle będziesz korzystać z pierwszych dwóch:
- ML-KEM (FIPS 203) uzgadnia współdzielony sekret. Zastępuje zadanie, które dziś wykonuje Diffie-Hellman.
- ML-DSA (FIPS 204) podpisuje. Zastępuje podpisy RSA i ECDSA.
- SLH-DSA (FIPS 205) również podpisuje, oparty wyłącznie na funkcjach skrótu, na wypadek gdy potrzebujesz najbardziej konserwatywnego dostępnego założenia i możesz zaakceptować rozmiar podpisu.
Uzgadnianie klucza za pomocą ML-KEM
Mechanizm hermetyzacji klucza (key encapsulation) jest prostszy w użyciu niż Diffie-Hellman. Nadawca bierze klucz publiczny odbiorcy i tworzy dwie rzeczy: świeży współdzielony sekret oraz szyfrogram, który go przenosi. Odbiorca zamienia szyfrogram z powrotem w ten sam sekret.
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;
Zestawy parametrów to mlkem512, mlkem768 i mlkem1024. Sprawdzenia danych wejściowych wymagane przez FIPS 203 wykonywane są przed czymkolwiek innym, więc nieprawidłowy klucz publiczny zgłasza wyjątek zamiast po cichu tworzyć sekret, a szyfrogram, który się nie odszyfrowuje, zwraca pseudolosowy sekret zamiast błędu, co jest niejawnym odrzuceniem (implicit rejection) wymaganym przez standard.
X-Wing, gdy nie chcesz wybierać
Przyjęcie nowego algorytmu oznacza zaufanie mu. Konstrukcje hybrydowe usuwają tę decyzję: łączą algorytm klasyczny z postkwantowym, dzięki czemu wynik jest bezpieczny, dopóki którakolwiek z połówek pozostaje nienaruszona. X-Wing łączy X25519 z ML-KEM-768 i udostępnia pojedynczą parę kluczy.
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;
Podpisywanie za pomocą ML-DSA
Podpisywanie przyjmuje zestaw parametrów, klucz prywatny, wiadomość i ciąg kontekstu, który zwykle jest pusty:
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;
Zwróć uwagę na ziarno (seed). Klucz prywatny ML-DSA może być przechowywany jako 32 bajty, z których został wygenerowany, jako klucz rozwinięty, lub jako oba, a biblioteka odczytuje i zapisuje wszystkie trzy formy. Ziarno to forma, której chcesz używać w pliku konfiguracyjnym: jest mała, a klucz rozwinięty jest z niej wyprowadzany w sposób deterministyczny.
Klucze, które podróżują
Algorytm, z którym nikt nie może wymieniać kluczy, niewiele daje, dlatego kodowania są zgodne z opublikowanymi profilami: SubjectPublicKeyInfo i PKCS#8, w formacie DER lub PEM, zgodnie z RFC 9935 dla ML-KEM, RFC 9881 dla ML-DSA i RFC 9909 dla SLH-DSA.
var
vPublicPEM, vPrivatePEM: string;
begin
vPublicPEM := sgcMLDSA_ExportPublicKeyPEM(mldsa65, oPublicKey);
vPrivatePEM := sgcMLDSA_ExportPrivateKeyPEM(mldsa65, oSeed, nil);
end;
To zwykłe bloki BEGIN PUBLIC KEY i BEGIN PRIVATE KEY, które odczytują inne implementacje. Klucz prywatny jest sprawdzany podczas importu: połowa publiczna jest ponownie wyprowadzana i porównywana, więc klucz, który nie należy do swojego certyfikatu, jest odrzucany od razu, zamiast tworzyć podpisy, których nikt nie może zweryfikować.
Certyfikaty i postkwantowy urząd certyfikacji
Certyfikaty i żądania certyfikatów mogą przenosić klucze postkwantowe, a urząd certyfikacji również może taki klucz posiadać, dzięki czemu cały łańcuch może być postkwantowy:
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;
Zasady użycia klucza określone w profilach są egzekwowane, zanim cokolwiek zostanie podpisane, więc klucz postkwantowy, od którego oczekuje się szyfrowania klucza (key encipherment), zgłasza wyjątek zamiast tworzyć certyfikat naruszający własny profil. Walidacja łańcucha egzekwuje teraz również długość ścieżki i ograniczenia nazw deklarowane przez certyfikaty wystawiające.
Gdzie jest to już zintegrowane
Dwa miejsca w bibliotece wykorzystują to wszystko za Ciebie, bez konieczności pisania żadnej kryptografii:
- TLS. Natywny silnik TLS 1.3 negocjuje hybrydowe grupy wymiany kluczy z RFC 10024,
X25519MLKEM768,SecP256r1MLKEM768iSecP384r1MLKEM1024, a domyślna lista zaczyna się już od grupy hybrydowej. Zobacz Delphi TLS 1.3 bez bibliotek DLL OpenSSL. - JWT. Tokeny mogą być podpisywane i weryfikowane za pomocą ML-DSA zgodnie z RFC 9964. Zobacz Podpisywanie tokenu JWT za pomocą ML-DSA w Delphi.
Skąd wiemy, że to działa poprawnie
Implementacja standardu jest jedynie deklaracją, dopóki coś jej nie zweryfikuje. Wszystkie trzy algorytmy są walidowane względem wektorów testowych NIST (known answer vectors), a wektory te są dostarczane z biblioteką jako uruchamialny zestaw testów, a nie jako zdanie w karcie danych. Podpisywanie ML-DSA odbywa się w wariancie deterministycznym, więc ten sam klucz i ta sama wiadomość zawsze dają ten sam podpis, co sprawia, że opublikowane przykłady w dokumentach RFC są odtwarzalne bajt po bajcie.
Którego algorytmu użyć
Do uzgadniania kluczy używaj hybrydy: samego X-Wing lub hybrydowych grup TLS, jeśli ruch jest TLS. Nie tracisz przy tym prawie nic, a jesteś zabezpieczony niezależnie od tego, które założenie okaże się błędne. Do podpisów rozsądnym domyślnym wyborem jest ML-DSA-65, z ML-DSA-44, gdy liczy się rozmiar, i ML-DSA-87, gdy nie ma to znaczenia. Sięgnij po SLH-DSA, gdy podpis będzie weryfikowany za wiele lat przez coś, czego nie możesz zaktualizować, na przykład firmware, a rozmiar podpisu jest akceptowalny.
Aktualizacja
Wszystko to znajduje się w pakiecie sgcCrypto i nie dodaje żadnej zależności: bez OpenSSL, bez DLL, bez niczego do zainstalowania na maszynie, na której działa Twoja aplikacja. Istniejący kod pozostaje nietknięty, dopóki go nie wywołasz.
Czytaj dalej
- Delphi TLS 1.3 bez bibliotek DLL OpenSSL
- Podpisywanie tokenu JWT za pomocą ML-DSA w Delphi
- sgcWebSockets 2026.10, wszystko inne w tym wydaniu
Zobacz
Jest o tym krótki film na kanale eSeGeCe.
Masz pytania, uwagi lub potrzebujesz pomocy z migracją? Skontaktuj się z nami — odpowiedź otrzymasz od osób, które napisały ten kod.
