💡 Volledig werkend voorbeeld beschikbaar op GitHub:
onderteken-woord-met-ml-dsa-certificaten-dotnet

De oude manier was een projectplan

Vraag wat er nodig is om documentondertekening post‑kwantum te maken en je krijgt een routekaart: algoritmen evalueren, een bibliotheek kiezen, een abstractielaag over de ondertekeningscode schrijven, een dual‑signing‑periode plannen, een kwartaal budgetteren.

Het grootste deel daarvan blijft waar voor de organisatorische kant – certificaat‑aankoop, beleid, validatorondersteuning. Het code‑deel bleek kleiner dan de routekaart suggereert, en dat is het waard om te weten voordat iemand een kwartaal budgetteert.

ML‑DSA‑ondertekening is een GroupDocs.Signature‑functionaliteit voor .NET die Word‑documenten ondertekent met certificaten gebaseerd op FIPS 204, de NIST‑post‑kwantum‑handtekeningstandaard. Het kwam in versie 26.9, en vanuit het perspectief van de aanroepende code is het een ander PFX‑bestand.

Er is een betere manier

Hier is de volledige codewijziging:

using var signature = new Signature(sourcePath);

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

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

Dat is dezelfde aanroep die wordt gebruikt voor een RSA‑certificaat. Het algoritme is een eigenschap van het certificaat, dus er is geen optie die het selecteert, er is geen abstractielaag nodig, en er verschijnt geen tweede codepad voor de overgangsperiode. Wijs DigitalSignOptions naar een ML‑DSA‑PFX en de output is een ML‑DSA‑handtekening.

Het uitlezen van het certificaat uit het resultaat is de moeite waard terwijl er meerdere certificaten in gebruik zijn:

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

Een niveau kiezen, met cijfers in plaats van meningen

ML‑DSA komt in drie parametersets, die overeenkomen met NIST‑beveiligingscategorieën 2, 3 en 5. Sterker betekent groter – zowel de sleutel als de handtekening – en de verstandige manier om te beslissen is je eigen document drie keer te ondertekenen en te kijken:

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

Het voorbeeld schrijft één ondertekende kopie per niveau en registreert elke grootte, dus de afweging is een meting in plaats van een tabel uit een specificatie. Voor één enkel contract is het verschil onopvallend; voor een archief van enkele miljoenen ondertekende documenten is het een capaciteitsvraag die je moet stellen voordat je standaardiseert op het hoogste niveau.

ML‑DSA‑65 is de redelijke standaard wanneer geen beleid er een voorschrijft. Profielen zoals CNSA 2.0 noemen expliciet ML‑DSA‑87, en ML‑DSA‑44 heeft alleen zin wanneer grootte belangrijker is dan marge.

Verificatie heeft alleen het openbare certificaat nodig

Het distributieverhaal is ongewijzigd ten opzichte van RSA, wat het tweede goede nieuws is:

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

VerificationResult result = signature.Verify(options);

Een ontvanger heeft alleen het .cer‑bestand van de ondertekenaar nodig en niets anders. Het resultaat is alleen geldig wanneer de handtekening overeenkomt met de inhoud en het certificaat overeenkomt op serienummer en vingerafdruk, dus een document ondertekend door een andere partij faalt de controle – wat het voorbeeld bewijst door de verificatie twee keer uit te voeren, eenmaal met het juiste certificaat en eenmaal met dat van iemand anders.

Zij-aan-zij: Verwacht vs. Werkelijk

Wat een migratieplan veronderstelt Wat 26.9 daadwerkelijk vereist
Codewijziging abstractielaag over ondertekening een ander PFX-pad
API‑oppervlak nieuwe post‑kwantum methoden DigitalSignOptions, ongewijzigd
Niveauselectie bibliotheekconfiguratie welk certificaat je laadt
Verificatie nieuwe tooling voor ontvangers het openbare .cer van de ondertekenaar
Platformwerk sleutelafhandeling per OS geen – de bibliotheek valt intern terug
Formaatdekking alle formaten alleen Word-formaten, voorlopig

De laatste rij is degene die de planning beperkt, en die leidt tot het eerlijke deel van dit artikel.

Wat werkt nog niet

Twee beperkingen, beide de moeite waard om te kennen voordat je iets belooft.

Formaatdekking is in 26.9 alleen Word – DOCX, DOC, ODT en de rest van de Word‑familie. PDF, spreadsheets en presentaties kunnen niet met ML‑DSA worden ondertekend. Voor een PDF‑first‑pipeline is deze release bedoeld voor prototyping en meting in plaats van migratie.

Validatorondersteuning is de andere. Er bestaat nog geen standaard XML‑DSig‑identifier voor ML‑DSA, dus Microsoft Word meldt de handtekening mogelijk niet als geldig, ook al is deze cryptografisch correct en verifieert via de API. Dat is een standaarden‑gat in plaats van een defect, en het betekent dat verificatie in je eigen code moet plaatsvinden in plaats van in een reviewer die het bestand opent en naar de banner kijkt.

Er is ook een platformdetail dat geen actie vereist: .NET kan ML‑DSA‑sleutels niet overal lezen, inclusief Linux op .NET 8. Waar dat niet kan, leest GroupDocs.Signature het certificaat via de Word‑engine, zodat dezelfde build op een ontwikkelaars‑laptop en een Linux‑container draait zonder conditionele code.

Is het de moeite waard om nu te doen, gezien die beperkingen?

Ja, om twee redenen die niets met de code te maken hebben. Certificaat‑aankoop is traag – publieke CAs rollen nog steeds ML‑DSA‑uitgifte uit – dus het organisatorische werk profiteert van een vroege start. En “kunnen we vandaag een post‑kwantum‑handtekening produceren” is een vraag die compliance‑teams steeds vaker stellen; kunnen antwoorden met een ondertekend document in plaats van een plan is de middag die het kost waard.

Wat het voorbeeld daadwerkelijk bewijst

Vier methoden, uitgevoerd in volgorde, met de exit‑code gekoppeld aan het resultaat. Het ondertekent het contract met ML‑DSA‑65 en print het onderwerp van het gebruikte certificaat. Het ondertekent hetzelfde contract op alle drie de niveaus en print de resulterende groottes. Het verifieert het ondertekende bestand twee keer – eenmaal met het openbare certificaat van de ondertekenaar (verwacht succes) en eenmaal met een ander ondertekenaar‑certificaat (verwacht falen). Daarna lijst het de digitale handtekeningen op die in de output zijn gevonden.

De tweede verificatie is degene die je moet kopiëren. Een routine die alleen ooit met geldige invoer is getoond, vertelt je niets over of hij een ongeldige zou afwijzen, en voor handtekeningen is dat de volledige vraag.

Praktijkvoorbeeld: Het dertigjarige contract

Archieven met lange retentie zijn waar dit niet meer theoretisch blijft. Een contract dat vandaag wordt ondertekend en dertig jaar wordt bewaard, moet verifieerbaar blijven ongeacht wat er met cryptografie gebeurt in dat venster, en “nu oogsten, later ontsleutelen” is een gedocumenteerd dreigingsmodel voor precies dat soort materiaal.

Voor zo’n archief is de praktische stap vandaag een dual‑track‑aanpak: houd RSA voor de formaten die ML‑DSA nog niet dekt, begin Word‑output te ondertekenen met ML‑DSA‑65 of 87, en registreer per document welk algoritme is gebruikt zodat een toekomstige audit ze kan onderscheiden zonder bestanden te openen.

Eén ding om te corrigeren in het voorbeeld voordat je het kopieert

De repository levert zelf‑ondertekende ML‑DSA‑certificaten zodat de demonstratie direct werkt, wat betekent dat er vier PFX‑bestanden en een hard‑coded wachtwoord in documents/ staan. Voor een wegwerpcertificaat dat alleen binnen dat voorbeeld geldig is, is dat prima.

Het is echter geen patroon om in je eigen repository over te nemen. Genereer testcertificaten tijdens runtime, zoals het certificate‑validity‑voorbeeld van GroupDocs doet, of houd ze volledig buiten versie‑controle. Een gecommitte sleutel is lastig te intrekken en overleeft vaak de demo waarvoor hij is geschreven.

Conclusie

De dure onderdelen van post‑kwantum‑migratie zijn certificaten, beleid en validators. De code, althans voor Word‑documenten in .NET, is een ander PFX‑bestand en dezelfde DigitalSignOptions‑aanroep. Clone het voorbeeld, wijs het naar een van je eigen contracten, en je hebt drie ondertekende bestanden, twee verificatieresultaten en een grootte‑vergelijking binnen enkele minuten – wat een betere basis is voor een migratieplan dan een ruwe schatting.

Aanvullende bronnen