💡 Повний робочий приклад доступний на GitHub:
sign-word-with-ml-dsa-certificates-dotnet

Старий підхід був планом проекту

Запитайте, що потрібно, щоб зробити підписання документів постквантовим, і ви отримаєте дорожню карту: оцінити алгоритми, вибрати бібліотеку, написати шар абстракції над кодом підписання, спланувати період подвійного підписання, виділити бюджет на квартал.

Більшість цього досі актуально для організаційної частини — закупівля сертифікатів, політики, підтримка валідаторів. Частина коду виявилася меншою, ніж передбачає дорожня карта, і це варто знати, перш ніж хтось плануватиме бюджет на квартал.

Підписання ML‑DSA — це можливість GroupDocs.Signature для .NET, яка підписує Word‑документи сертифікатами на основі FIPS 204, постквантового стандарту підпису NIST. Воно з’явилося у версії 26.9, і з точки зору коду виклику це інший PFX‑файл.

Є кращий спосіб

Ось весь кодовий зміни:

using var signature = new Signature(sourcePath);

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

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

Це той самий виклик, який використовується для RSA‑сертифіката. Алгоритм є властивістю сертифіката, тому жодна опція його не вибирає, шар абстракції не потрібен і не з’являється другий кодовий шлях для періоду переходу. Вкажіть DigitalSignOptions на ML‑DSA PFX — і вихід буде підписом ML‑DSA.

Читання сертифіката з результату варте того, коли використовується кілька сертифікатів:

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

Вибір рівня, з числами замість думок

ML‑DSA постачається в трьох наборах параметрів, що відповідають категоріям безпеки NIST 2, 3 і 5. Сильніший — більший, і це стосується і ключа, і підпису. Розумний спосіб визначитися — підписати власний документ тричі і подивитися:

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

Приклад записує одну підписану копію для кожного рівня і фіксує розмір, тому компроміс — вимір, а не таблиця зі специфікації. Для одного контракту різниця непомітна; для архіву з кількома мільйонами підписаних документів це питання місткості, яке варто задати перед стандартизацією на найвищому рівні.

ML‑DSA‑65 є розумним значенням за замовчуванням, коли політика не вказує інше. Профілі типу CNSA 2.0 явно називають ML‑DSA‑87, а ML‑DSA‑44 має сенс лише тоді, коли розмір важливіший за запас безпеки.

Для перевірки потрібен лише публічний сертифікат

Історія розповсюдження не змінилася порівняно з RSA, що є другою хорошою новиною:

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

VerificationResult result = signature.Verify(options);

Отримувачеві потрібен лише .cer підписанта і нічого більше. Результат є дійсним лише тоді, коли підпис відповідає вмісту, а сертифікат збігається за серійним номером і відбитком, тому документ, підписаний іншою стороною, не проходить перевірку — що демонструється прикладом, який запускає верифікацію двічі: один раз з правильним сертифікатом і один раз з чужим.

Порівняння: Очікуване проти Фактичного

Що передбачає план міграції Що насправді вимагає 26.9
Зміна коду шар абстракції над підписанням інший шлях до PFX
API-інтерфейс нові постквантові методи DigitalSignOptions, без змін
Вибір рівня конфігурація бібліотеки який сертифікат ви завантажуєте
Перевірка нові інструменти для отримувачів публічний .cer підписанта
Робота платформи обробка ключів per‑OS нічого — бібліотека автоматично підбирає
Покриття форматів всі формати лише формати Word, наразі

Останній рядок обмежує планування і веде до чесної частини статті.

Що ще не працює

Два обмеження, які варто знати, перш ніж щось обіцяти.

Покриття форматів у 26.9 — лише Word (DOCX, DOC, ODT та інші формати сімейства Word). PDF, електронні таблиці та презентації не можна підписати за допомогою ML‑DSA. Для конвеєра, орієнтованого на PDF, цей реліз підходить більше для прототипування та вимірювань, а не для міграції.

Підтримка валідаторів — це інше. Стандартного ідентифікатора XML‑DSig для ML‑DSA ще немає, тому Microsoft Word може не вважати підпис дійсним, хоча криптографічно він коректний і успішно перевіряється через API. Це прогалина в стандартах, а не дефект, і означає, що верифікація має виконуватись у вашому коді, а не у рецензенті, який відкриває файл і дивиться на банер.

Є ще деталь платформи, яка не потребує дій: .NET не може читати ML‑DSA‑ключі скрізь, зокрема у Linux на .NET 8. Там, де це неможливо, GroupDocs.Signature читає сертифікат через Word‑двигун, тому одна і та сама збірка працює і на ноутбуці розробника, і в Linux‑контейнері без умовного коду.

Чи варто робити це зараз, враховуючи ці обмеження?

Так, з двох причин, які не стосуються коду. Закупівля сертифікатів йде повільно — публічні CA все ще впроваджують випуск ML‑DSA — тому організаційна робота виграє від раннього старту. І питання «чи можемо ми сьогодні створити постквантовий підпис» вже ставлять команди з комплаєнсу; можливість відповісти підписаним документом, а не планом, варта витраченого післяобіднього часу.

Що насправді доводить приклад

Чотири методи, що виконуються послідовно, з кодом виходу, прив’язаним до результату. Він підписує контракт ML‑DSA‑65 і виводить subject використаного сертифіката. Підписує той самий контракт на всіх трьох рівнях і виводить отримані розміри. Перевіряє підписаний файл двічі — один раз з публічним сертифікатом підписанта (очікується успіх), і один раз з іншим сертифікатом (очікується провал). Потім перелічує цифрові підписи, знайдені у вихідному файлі.

Друга верифікація — це та, яку варто копіювати. Рутинна функція, яка була показана лише з валідними вхідними даними, нічого не каже про те, чи вона відхилить неправильні, а для підписів це саме й є питанням.

Реальний приклад: Тридцятирічний контракт

Архіви довготривалого зберігання — це місце, де теорія стає практикою. Контракт, підписаний сьогодні і збережений тридцять років, має залишатися верифікованим незалежно від того, що станеться з криптографією за цей період, а модель загрози «збирати зараз, розшифровувати пізніше» саме для такого матеріалу задокументована.

Для такого архіву практичний крок сьогодні — подвійний шлях: залишити RSA для форматів, які ще не підтримує ML‑DSA, почати підписувати Word‑вивід ML‑DSA‑65 або 87 і фіксувати, який алгоритм використано для кожного документа, щоб майбутній аудит міг їх розрізнити без відкриття файлів.

Одна річ, яку треба виправити в прикладі перед копіюванням

Репозиторій постачається з самопідписаними ML‑DSA‑сертифікатами, тому демонстрація працює «з коробки», що означає чотири PFX‑файли і жорстко закодований пароль у documents/. Для одноразового тестового сертифіката, дійсного лише в межах цього прикладу, це прийнятно.

Проте це не шаблон, який варто переносити у власний репозиторій. Генеруйте тестові сертифікати під час виконання, як це робить приклад GroupDocs «certificate‑validity», або тримайте їх поза системою контролю версій. Закомічений ключ важко відкликати і, як правило, переживає демо‑версію, для якої був створений.

Висновок

Дорогі частини постквантової міграції — сертифікати, політики та валідатори. Код, принаймні для Word‑документів у .NET, це інший PFX і той самий виклик DigitalSignOptions. Клонуйте приклад, вкажіть один зі своїх контрактів, і ви отримаєте три підписані файли, два результати верифікації та порівняння розмірів за кілька хвилин — це краща база для плану міграції, ніж оцінка.

Додаткові ресурси