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 податлив (malleable) вполне конкретными, хорошо изученными способами: злоумышленник, способный переворачивать биты в шифротексте, вызывает предсказуемые изменения в открытом тексте следующего блока, и ничто в формате этого не замечает
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