Технічна стаття

AES-GCM шифрування PDF 2.0 у Delphi: ISO/TS 32003

PDFiumPas записує шифрування ISO/TS 32003 через SaveAsEncrypted: встановіть Revision у erR7, і кожен рядок та потік захищаються AES-256 у режимі GCM — автентифікованому шифрі, який PDF 2.0 отримав у 2023 році. Встановіть також EnableIntegrityProtection, і документ додатково нестиме окремий токен PDF MAC, який ValidatePdfMac перевіряє на боці читання

Це два різні механізми захисту, які люди регулярно плутають. GCM автентифікує кожне зашифроване значення. MAC автентифікує документ як єдине ціле. Вам потрібні обидва, з різних причин

Що додає GCM, чого ніколи не давав CBC?

Автентифікацію шифротексту. AES-256 у режимі CBC, схема AESV3 з ISO 32000-2, тримає вміст конфіденційним і нічого не каже про те, чи прибув він незміненим. CBC піддатливий до модифікації конкретними, добре вивченими способами: атакуюча сторона, що може перевернути біти в шифротексті, спричиняє передбачувані зміни у відкритому тексті наступного блоку, і ніщо у форматі цього не помічає

GCM закриває цю прогалину. Кожне зашифроване значення несе 16-байтовий тег автентифікації, серіалізований повністю, як вимагає ISO/TS 32003, і розшифрування завершується невдачею, а не повертає змінений відкритий текст, коли тег не збігається. У термінах PDF, підроблений рядок чи потік у документі AESV4 — це жорстка помилка в точці використання, а не дивне значення, що поширюється у ваш застосунок. Словник Encrypt позначає це через /CFM /AESV4 та V 6 / R 7, поряд із записом розширень, що декларує /ExtensionLevel 32003 і /ExtensionRevision (:2023)

Три ревізії, три екосистеми

TPdfEncryptionRevision пропонує erR5, erR6 і erR7, і вибір — це радше рішення про сумісність, ніж криптографічне. R5 — оригінальна схема AES-256, опублікована як розширення PDF 1.7, з одинарним хешем пароля SHA-256, і вона відкривається практично будь-чим за останні п'ятнадцять років. R6 — це посилене виведення ключа, стандартизоване в ISO 32000-2, з використанням ітеративної конструкції SHA-256/384/512 алгоритму 2.B, і саме цього очікує сучасний робочий процес PDF 2.0 чи PDF/A-4. R7 — це ISO/TS 32003, що використовує те саме виведення 2.B з AES-GCM як шифром

Підтримка з боку переглядачів іде саме в цьому порядку, і підтримка R7 досі рідкісна поза межами сучасних основних переглядачів. Це той самий компроміс, що керує будь-якою функцією PDF 2.0: найновіша опція — це найкраща інженерія й найвужча аудиторія. Вирішуйте, виходячи з того, хто має відкривати файл, і якщо відповідь — «система обліку записів, яку ніхто не оновлював з 2019 року», відповідь — R5, незалежно від того, що воліє політика безпеки

uses
  PDFium, FPdfEncrypt;

var
  Pdf: TPdf;
  Opts: TPdfEncryptOptions;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'quarterly-report.pdf';
    Pdf.LoadDocument;

    Opts := TPdfEncryptOptions.Default;
    Opts.UserPassword := 'open-secret';
    Opts.OwnerPassword := 'admin-secret';
    Opts.EncryptMetadata := True;
    Opts.Revision := erR7;                    // ISO/TS 32003 AESV4-GCM
    Opts.EnableIntegrityProtection := True;   // окремий токен PDF MAC

    if not Pdf.SaveAsEncrypted('quarterly-report.enc.pdf', Opts) then
      raise Exception.Create('Encrypted save failed');
  finally
    Pdf.Free;
  end;
end;

Навіщо MAC документа поверх автентифікованого шифру?

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

Окремий токен PDF MAC покриває саме цей шар. PDFiumPas виводить його з ключа шифрування файлу за допомогою окремої 32-байтової /KDFSalt, записаної у словнику Encrypt, тож саме володіння паролем дозволяє читачеві підтвердити токен. Результат — одна відповідь на одне питання: чи є цей документ, у цілому, тим самим документом, що був записаний

var
  Pdf: TPdf;
  Mac: TPdfMacValidationResult;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.Password := 'open-secret';
    Pdf.FileName := 'quarterly-report.enc.pdf';
    Pdf.LoadDocument;

    Mac := Pdf.ValidatePdfMac('open-secret');
    case Mac.Status of
      pmvsValid:       ProcessDocument(Pdf);
      pmvsNotPresent:  ProcessWithWarning(Pdf);       // у цьому файлі немає токена
      pmvsInvalid:     Quarantine(Mac.MessageText);   // підроблено або обрізано
      pmvsUnsupported: RouteForManualReview(Mac.MessageText);
    end;
  finally
    Pdf.Free;
  end;
end;

Чотири значення статусу вимагають чотирьох різних реакцій, і згортання їх у булеве значення втрачає розрізнення, яке має значення. pmvsNotPresent означає, що файл просто не має токена, що описує майже кожен зашифрований PDF, написаний до 2024 року, і не є доказом чогось узагалі. pmvsInvalid означає, що токен присутній, але не проходить перевірку, — це справжня знахідка, і обробку слід зупинити. pmvsUnsupported означає, що токен існує у формі, яку ця збірка не реалізує, — це прогалина сумісності, а не атака. Розгляд «відсутнього» як «недійсного» відправив би в карантин весь ваш архів документів уже в перший день

Чого шифрування досі не робить

Прапорці дозволів залишаються тим, чим завжди й були: запитом до сумлінного програмного забезпечення, а не контролем. Біти /P з таблиці 22 ISO 32000-1, що забороняють друк чи вилучення, шануються добре поведеними переглядачами й ігноруються всім іншим, а будь-хто, хто володіє паролем користувача, уже володіє розшифрованим вмістом. Шифрування — це межа; дозволи описують намір усередині неї

Варто спланувати дві операційні деталі. По-перше, шифрування та подальша модифікація взаємодіють: додавання інкрементного оновлення до зашифрованого документа має власні правила, розглянуті в статті про інкрементні оновлення зашифрованих PDF, і токен MAC — це твердження на рівні документа, яке необережне дописування зробить недійсним. По-друге, конструкція GCM використовує детермінований лічильник IV, і PDFiumPas викликає виняток, а не повторно використовує значення лічильника, якби цей простір колись вичерпався, бо повторне використання nonce в GCM катастрофічне саме так, як тихе переповнення приховало б

Практичний вибір між трьома ревізіями

Спершу запишіть, хто відкриватиме файл, а потім обирайте. Для внутрішнього розповсюдження, де кожен читач — це сучасний переглядач під вашим контролем, R7 з захистом цілісності — найсильніша доступна опція, і немає причини її не використовувати. Для документів, що покидають організацію, R6 — обґрунтований вибір за замовчуванням: він стандартизований у ISO 32000-2, а не в технічній специфікації поверх нього, і має широку підтримку. Для архівів і застарілих споживачів R5 — єдиний варіант, що надійно відкривається, і варто зафіксувати причину там само, де ви фіксуєте решту вашої політики зберігання

Незалежно від того, що ви оберете, перевіряйте результат, а не довіряйте тому, що виклик просто завершився успішно. Повторно відкрийте зашифрований файл, перевірте ValidatePdfMac і підтвердьте, що заявлена версія відповідає очікуваній, використовуючи перевірки відповідності версії зі статті про точну відповідність версії PDF. Ширший контрольний список приймання для недовірених документів — у статті про аудит ризиків безпеки PDF

PDFiumPas — це компонент для Delphi та Lazarus навколо рушія PDFium зі стеком шифрування PDF 2.0, реалізованим нативно на Pascal, тож AES-256, GCM і токен MAC не потребують жодної зовнішньої крипто-DLL. API шифрування задокументовано на сторінці PDFium Delphi component