💡 Pełny działający przykład dostępny na GitHubie:
sign-word-with-ml-dsa-certificates-dotnet

Stara metoda była planem projektu

Zapytaj, co jest potrzebne, aby uczynić podpisywanie dokumentów odpornym na komputery kwantowe, a otrzymasz plan działania: ocenić algorytmy, wybrać bibliotekę, napisać warstwę abstrakcji nad kodem podpisu, zaplanować okres podwójnego podpisywania, przydzielić budżet na kwartał.

Większość z tego nadal dotyczy części organizacyjnej – pozyskiwania certyfikatów, polityki, wsparcia walidatorów. Część kodowa okazała się mniejsza niż sugeruje plan, co warto wiedzieć, zanim ktoś przydzieli na to kwartał budżetu.

Podpisywanie ML-DSA jest funkcją GroupDocs.Signature dla .NET, która podpisuje dokumenty Word certyfikatami opartymi na FIPS 204, standardzie podpisów post‑kwantowych NIST. Pojawiło się w wersji 26.9 i z perspektywy wywołującego kodu jest to inny plik PFX.

Istnieje lepszy sposób

Here is the whole of the code change:

using var signature = new Signature(sourcePath);

var options = new DigitalSignOptions(pfxPath)
{
    Password = certificatePassword
};

SignResult result = signature.Sign(outputPath, options);

To jest to samo wywołanie używane dla certyfikatu RSA. Algorytm jest właściwością certyfikatu, więc nie ma opcji go wybierającej, nie jest potrzebna warstwa abstrakcji i nie pojawia się druga ścieżka kodu na okres przejściowy. Wskaż DigitalSignOptions na plik PFX ML-DSA, a wynik będzie podpisem ML-DSA.

Odczytanie certyfikatu z wyniku jest warte wykonania, gdy w grze jest kilka certyfikatów:

var created = result.Succeeded.OfType<DigitalSignature>().FirstOrDefault();
return created?.Certificate?.Subject ?? "(no certificate returned)";

Wybór poziomu, z liczbami zamiast opinii

ML-DSA występuje w trzech zestawach parametrów, odpowiadających kategoriom bezpieczeństwa NIST 2, 3 i 5. Silniejszy oznacza większy – zarówno klucz, jak i podpis – a rozsądny sposób podjęcia decyzji to podpisanie własnego dokumentu trzykrotnie i obserwacja:

var levels = new Dictionary<string, string>
{
    ["ML-DSA-44"] = MlDsa44Pfx,
    ["ML-DSA-65"] = MlDsa65Pfx,
    ["ML-DSA-87"] = MlDsa87Pfx
};

Przykład zapisuje jedną podpisaną kopię dla każdego poziomu i rejestruje jej rozmiar, więc kompromis jest pomiarem, a nie tabelą ze specyfikacji. Dla pojedynczego kontraktu różnica jest nieistotna; dla archiwum kilku milionów podpisanych dokumentów jest to kwestia pojemności, którą warto rozważyć przed standaryzacją na najwyższym poziomie.

ML-DSA-65 jest rozsądnym domyślnym wyborem, gdy żadna polityka nie określa innego. Profile takie jak CNSA 2.0 wymieniają wyraźnie ML-DSA-87, a ML-DSA-44 ma sens tylko wtedy, gdy rozmiar jest ważniejszy niż margines.

Weryfikacja wymaga tylko publicznego certyfikatu

Historia dystrybucji nie zmieniła się w porównaniu do RSA, co jest drugą dobrą wiadomością:

var options = new DigitalVerifyOptions(certificatePath);
if (password != null)
{
    options.Password = password;
}

VerificationResult result = signature.Verify(options);

Odbiorca potrzebuje jedynie pliku .cer podpisującego i nic więcej. Wynik jest ważny tylko wtedy, gdy podpis zgadza się z treścią, a certyfikat pasuje pod numerem seryjnym i odciskiem palca, więc dokument podpisany przez inną stronę nie przejdzie weryfikacji – co przykład udowadnia, uruchamiając weryfikację dwukrotnie, raz z prawidłowym certyfikatem i raz z certyfikatem innej osoby.

Obok siebie: Oczekiwane vs. Rzeczywiste

Co zakłada plan migracji Co wymaga rzeczywiście 26.9
Zmiana kodu warstwa abstrakcji nad podpisywaniem inny ścieżka PFX
Powierzchnia API nowe metody post‑kwantowe DigitalSignOptions, niezmienione
Wybór poziomu konfiguracja biblioteki który certyfikat załadujesz
Weryfikacja nowe narzędzia dla odbiorców publiczny .cer podpisującego
Praca platformowa obsługa kluczy per system operacyjny brak – biblioteka wewnętrznie przełącza się
Obsługa formatów wszystkie formaty tylko formaty Word, na razie

Ostatni wiersz jest tym, który ogranicza planowanie i prowadzi do szczerej części tego artykułu.

Co jeszcze nie działa

Dwa ograniczenia, które warto znać, zanim cokolwiek obiecasz.

Obsługa formatów w wersji 26.9 obejmuje tylko Word – DOCX, DOC, ODT i pozostałe formaty rodziny Word. PDF, arkusze kalkulacyjne i prezentacje nie mogą być podpisane przy użyciu ML-DSA. Dla pipeline’u skoncentrowanego na PDF ta wersja jest przeznaczona do prototypowania i pomiarów, a nie migracji.

Wsparcie walidatorów to drugie ograniczenie. Nie istnieje jeszcze standardowy identyfikator XML‑DSig dla ML-DSA, więc Microsoft Word może nie zgłaszać podpisu jako ważnego, mimo że jest kryptograficznie poprawny i weryfikuje się prawidłowo przez API. To luka w standardach, a nie wada, i oznacza, że weryfikacja powinna znajdować się w Twoim kodzie, a nie w recenzencie otwierającym plik i patrzącym na baner.

Istnieje także szczegół platformowy, który nie wymaga działania: .NET nie może odczytać kluczy ML-DSA wszędzie, w tym na Linuksie w .NET 8. Tam, gdzie nie może, GroupDocs.Signature odczytuje certyfikat przez silnik Word, więc ta sama kompilacja działa na laptopie dewelopera i w kontenerze Linux bez kodu warunkowego.

Czy warto to zrobić teraz, biorąc pod uwagę te ograniczenia?

Tak, z dwóch powodów niezwiązanych z kodem. Pozyskiwanie certyfikatów jest wolne – publiczne CA wciąż wprowadzają wydawanie ML-DSA – więc prace po stronie organizacji zyskują na wczesnym rozpoczęciu. A pytanie „czy możemy dziś wygenerować podpis post‑kwantowy” jest zadawane coraz częściej przez zespoły ds. zgodności; możliwość odpowiedzi podpisanym dokumentem zamiast planem jest warta popołudnia potrzebnego na to.

Co próbka faktycznie udowadnia

Cztery metody, uruchamiane kolejno, z kodem wyjścia powiązanym z wynikiem. Podpisuje kontrakt przy użyciu ML-DSA-65 i wypisuje temat użytego certyfikatu. Podpisuje ten sam kontrakt na wszystkich trzech poziomach i wypisuje uzyskane rozmiary. Weryfikuje podpisany plik dwukrotnie – raz z publicznym certyfikatem podpisującego, oczekując sukcesu, i raz z certyfikatem innego podpisującego, oczekując niepowodzenia. Następnie wymienia cyfrowe podpisy znalezione w wyniku.

Druga weryfikacja jest tą, którą warto skopiować. Procedura, której jedynie podano prawidłowe dane wejściowe, nie mówi nic o tym, czy odrzuci nieprawidłowe, a w przypadku podpisów to jest cała kwestia.

Przykład z rzeczywistości: Trzydziestoletni kontrakt

Archiwa o długim okresie przechowywania to miejsce, w którym przestaje to być teoretyczne. Kontrakt podpisany dziś i przechowywany przez trzydzieści lat musi pozostać weryfikowalny, niezależnie od zmian w kryptografii w tym okresie, a „zbieraj teraz, odszyfruj później” jest udokumentowanym modelem zagrożenia dla takiego materiału.

Dla takiego archiwum praktycznym działaniem już dziś jest podwójna ścieżka: zachować RSA dla formatów, które ML-DSA jeszcze nie obsługuje, rozpocząć podpisywanie wyjścia Word przy użyciu ML-DSA-65 lub 87 oraz rejestrować, który algorytm został użyty dla każdego dokumentu, aby przyszły audyt mógł je odróżnić bez otwierania plików.

Jedna rzecz do naprawienia w próbce przed jej skopiowaniem

Repozytorium dostarcza samopodpisane certyfikaty ML-DSA, więc demonstracja działa od razu, co oznacza cztery pliki PFX i zakodowane na stałe hasło w documents/. Dla jednorazowego certyfikatu testowego ważnego tylko w ramach tego przykładu jest to w porządku.

Nie jest to wzorzec, który powinno się przenosić do własnego repozytorium. Zamiast tego generuj certyfikaty testowe w czasie wykonywania, tak jak robi to przykład certyfikat‑validity GroupDocs, lub trzymaj je całkowicie poza kontrolą wersji. Zatwierdzony klucz jest trudny do odwołania i ma tendencję do przetrwania demonstracji, dla której został napisany.

Wnioski

Drogi elementy migracji post‑kwantowej to certyfikaty, polityka i walidatory. Kod, przynajmniej dla dokumentów Word w .NET, to inny plik PFX i to samo wywołanie DigitalSignOptions. Sklonuj przykład, skieruj go na jeden ze swoich kontraktów i w ciągu kilku minut będziesz mieć trzy podpisane pliki, dwa wyniki weryfikacji oraz porównanie rozmiarów – co stanowi lepszą podstawę planu migracji niż szacunek.

Dodatkowe zasoby