Kryptografia postkwantowa w Delphi

· Komponenty
Kryptografia postkwantowa w Delphi

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:

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:

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

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.