Перейти к содержимому
getnextpdf.com

Как цифровая подпись доказывает, кто подписал

Spec: RFC 5652Spec: RFC 5280, §6Spec: RFC 3161, §1

Цифровая подпись делает три вещи, и их стоит разделять с самого начала: она доказывает, что байты не были изменены, доказывает, кто их подписал, и — с небольшой помощью — доказывает, когда. Эта страница выстраивает эту идею с нуля, чтобы криптография перестала быть чёрным ящиком.

«Подписано» — это слово, на котором люди строят решения. Договор, счёт, примечание к релизу программного обеспечения, которое кто-то запустит. Если вы знаете только, что инструмент напечатал зелёную галочку, вы на самом деле не знаете, что было доказано. У вас может быть доказательство, что байты целы, но никакого понятия о том, чей ключ их подписал. У вас может быть настоящий подписант, но сертификат, истёкший годы назад. Понимание частей — это то, что позволяет вам сказать, точно, что означает действительная подпись — и, что не менее полезно, чего она не означает.

Представьте конверт с защитой от вскрытия и личной печатью, вдавленной в клапан.

  • Печать уникальна для одного человека и практически невозможна для подделки. Узнать её может любой; изготовить — только её владелец. Это и есть пара ключей: закрытый ключ, который держите только вы, и открытый ключ, который видит каждый.
  • Вы не вдавливаете печать поверх всего документа. Вы вдавливаете её поверх крошечной, неподделываемой сводки документа — хеша. Измените один байт документа, и сводка полностью изменится, так что печать больше не подойдёт.
  • Подписание — это создание подписи над документом вашим закрытым ключом — над хешем для RSA и ECDSA или над самим содержимым для EdDSA, который выполняет собственное хеширование внутри. Проверка — это запуск проверки алгоритма с вашим открытым ключом, подписью и тем же содержимым (как хешем или напрямую) — она возвращает «действительна» или «недействительна». Эти два связывает математика, а не доверие.
  • Сертификат — это часть, которая говорит, чья это печать. Без него вы доказали, что ключ подписал байты, но не то, что ключ принадлежит кому-то конкретно.
  • Метка времени — это часть, которая говорит, когда. Собственные часы подписанта — это всего лишь утверждение; доверенное время приходит от внешнего удостоверяющего центра.

Начните с хеша, потому что всё остальное стоит на нём. Криптографическая хеш-функция читает любой объём данных и производит короткий отпечаток фиксированной длины — для подписи PDF, как правило, 256-битное значение. Два свойства делают его полезным: один и тот же вход всегда даёт один и тот же отпечаток, и невозможно на практике найти другой вход с тем же отпечатком. Так что хеш — это верный заместитель документа. Если два хеша совпадают, совпадают и байты.

Теперь пара ключей. Закрытый ключ и открытый ключ математически связаны, но вы не можете вывести один из другого за сколь-нибудь практичное время. Только закрытый ключ может произвести действительную подпись, и только соответствующий открытый ключ может её проверить. Подписание использует эту асимметрию: подписант применяет операцию с закрытым ключом к входу, который определяет выбранный алгоритм — хешу содержимого для RSA и ECDSA или содержимому напрямую для EdDSA, который хеширует внутренне. Результат — это значение подписи. Поскольку только держатель закрытого ключа мог его произвести и поскольку оно привязано именно к этому содержимому, оно доказывает сразу две вещи — что держатель подписал и что байты не сдвигались с тех пор.

Проверка зеркалит эту логику. Проверяющий восстанавливает тот же вход — хешируя документ для RSA и ECDSA или беря содержимое напрямую для EdDSA — затем запускает операцию проверки алгоритма подписи над открытым ключом, значением подписи и этим входом. Операция возвращает «действительна» или «недействительна» — и это одна и та же форма независимо от того, RSA это, ECDSA или EdDSA, даже несмотря на то что только RSA можно представить как буквальное «восстановление» хеша. «Действительна» означает «цело и подлинно». «Недействительна» означает, что что-то изменилось или был использован неверный ключ, и честный ответ — недействительна.

  1. Prepare the inputRSA and ECDSA hash the document to a short, fixed-length fingerprint; EdDSA signs the content directly and hashes it internally. Either way, any change to the bytes changes what is signed.
  2. Sign with the private keyThe signer applies a private-key operation to that input — the hash for RSA and ECDSA, the content for EdDSA. The output is the signature value; only the private-key holder could have produced it.
  3. Reconstruct the inputThe verifier independently rebuilds the same input from the content — a recomputed hash for RSA and ECDSA, the content itself for EdDSA. This is what the verify operation checks against.
  4. Verify with the public keyThe verifier runs the algorithm's verify operation on the public key, the signature value, and that input. The same shape works for RSA, ECDSA, and EdDSA.
  5. Accept or rejectThe verify operation returns valid or invalid. Valid means the bytes are intact and the private-key holder signed them. Otherwise the result is invalid — no guessing.
How a digital signature is produced and then checked, from first principles. The signer produces a signature over the content with their private key — over a hash for RSA and ECDSA, or over the content directly for EdDSA; the verifier reconstructs the same input, then runs the algorithm's verify operation on the public key, the signature, and that input. A valid result proves the bytes are intact and that the private-key holder signed them.

В реальном PDF NextPDF не вдавливает печать поверх видимой страницы — он вдавливает её поверх объявленного диапазона байтов и упаковывает подпись как отделённый объект CMS (Spec: RFC 5652), помещённый внутрь файла (Spec: ISO 32000-2, §12.8). Один нюанс важен: подписант не подписывает сырой хеш содержимого напрямую. Он подписывает небольшой набор подписанных атрибутов, которые включают хеш содержимого, так что время, тип содержимого и идентификатор сертификата подписанта запечатаны вместе. Где живут эти байты и почему диапазон имеет именно такую форму — тема страницы Как подписи располагаются в PDF.

Пока что математика доказывает, что некий ключ подписал эти байты. Она ничего не говорит о том, чей ключ. Именно этот пробел и заполняет сертификат. Сертификат — это сам по себе подписанное утверждение — от удостоверяющего центра, — что этот открытый ключ принадлежит этому именованному субъекту. Доверять ему — значит следовать по цепочке от сертификата подписанта вверх до центра, которому вы решили доверять, проверяя действительность каждого звена по пути (Spec: RFC 5280, §6). Без этой цепочки «подписано» анонимно. С ней «подписано» имеет имя.

Последняя часть — это когда. Подпись может встроить собственное заявленное подписантом время, но часы, которыми вы не управляете, — это утверждение, а не доказательство. Метка времени от удостоверяющего центра меток времени (TSA) привязывает хеш подписи к моменту, заверенный стороной, не заинтересованной в документе (Spec: RFC 3161, §1). Это то, что позволяет подписи оставаться значимой после истечения срока действия сертификата подписанта: вы можете показать, что подпись существовала, пока сертификат был ещё действителен. Более глубокое рассмотрение — в Метки времени и доверенное время.

Формы ниже — это концептуальные операции, записанные просто. Суть не в вызове API — она в том, чтобы увидеть, что подписание и проверка — зеркальные отражения друг друга и что изменённый байт ломает совпадение по построению.

<?php
declare(strict_types=1);
// SIGN — the holder of the private key seals the content.
// RSA and ECDSA sign a hash; EdDSA signs the content directly (hashing inside).
$signingInput = sign_input($content); // a digest for RSA/ECDSA, the content for EdDSA
$signatureValue = private_key_transform( // only the key holder can do this
privateKey: $signerPrivateKey,
input: $signingInput,
);
// VERIFY — anyone with the public key runs the algorithm's check.
$recomputedInput = sign_input($content); // verifier rebuilds the same input
$intactAndAuthentic = signature_verify( // RSA, ECDSA, EdDSA — same shape
publicKey: $signerPublicKey, // taken from the certificate
signatureValue: $signatureValue,
input: $recomputedInput, // the freshly reconstructed input
);
// true -> bytes unchanged AND signed by the private-key holder
// false -> a byte changed, or the wrong key — the honest answer is "invalid"
// The certificate answers a SEPARATE question: whose public key is this?
// The timestamp answers ANOTHER: when did this signature exist?
// "intact + authentic" alone proves neither identity nor time.

Подделать изменение, которое всё ещё проходит проверку, вычислительно неосуществимо. Хеш верно несёт содержимое, так что изменение содержимого изменяет хеш, и операция проверки его отвергает — за исключением нахождения коллизии хеша, что выбранная функция спроектирована делать непрактичным.

Частая ошибка — читать «действительная подпись» как «заслуживающий доверия документ». Это не одно и то же предложение. Криптография доказывает, что байты целы и что их подписал держатель закрытого ключа — и ничего больше. Документ, подписанный ключом, о котором вы никогда не слышали, заверенный никаким центром, который вы признаёте, может быть безупречно «действительным» и ничего не стоить. Идентичность приходит от сертификата и его цепочки; время приходит от доверенной метки времени. Зелёная галочка, которая незаметно сворачивает всё это в один булев флаг, решила за вас, какие вопросы имели значение. Знание частей — это то, что позволяет вам задать остальные.

Эта страница объясняет идею цифровой подписи, а не полную процедуру проверки. Математика здесь доказывает целостность и подлинность. Сама по себе она не говорит вам, был ли подписывающий сертификат выдан тому, кому вы думаете, был ли он действителен в момент подписания и не был ли он позднее отозван — это вопросы пути сертификата и отзыва, и корректная проверка прогоняет их все. Полный набор проверок — в Правильная проверка подписи.

NextPDF строит структуру подписи и выполняет криптографические проверки. Он не выбирает за вас якоря доверия, не ручается ни за какой удостоверяющий центр и не решает юридический эффект подписи — это зависит от вашего развёртывания, сертификата и юрисдикции. Движок доказывает механизм; решения о доверии поверх него — ваши.

То, что движок поставляет, по уровням, надстраивается наружу от этого фундамента:

Digital signature: integrity, identity, and trusted time — edition availability
EditionAvailability
Core

PAdES B-B: the hash-and-sign mechanism described here, packaged as a detached CMS SignedData object, plus certificate-path validation against a trust anchor you supply.

Pro

Adds PAdES B-T — a verified RFC 3161 trusted timestamp on the signature value, so the “when” is attested rather than self-claimed.

Enterprise

Adds the long-term profiles (B-LT, B-LTA): embedded validation material and document timestamps that keep the identity and time proofs answerable for years.

  • Хеш (дайджест) — короткий отпечаток данных фиксированной длины от криптографической хеш-функции; любое изменение данных меняет его полностью.
  • Пара ключей — связанные закрытый ключ (которым владеет только подписант) и открытый ключ (распространяемый свободно); только закрытый ключ может подписывать, и только соответствующий открытый ключ может проверять.
  • Подписание — применение операции с закрытым ключом к входу, который определяет алгоритм: хешу содержимого для RSA и ECDSA или содержимому напрямую для EdDSA (который хеширует внутренне). В PDF этим содержимым являются подписанные атрибуты, включающие хеш документа. Результат — это значение подписи.
  • Проверка — восстановление того же входа (пересчитанного хеша или содержимого напрямую для EdDSA), затем запуск операции проверки алгоритма над открытым ключом, значением подписи и этим входом, чтобы получить ответ «действительна или недействительна».
  • Значение подписи — байты, которые производит операция с закрытым ключом; то, что проверяющий сверяет с заново восстановленным входом алгоритма (дайджестом для RSA и ECDSA, самим содержимым для EdDSA).
  • Сертификат — подписанное утверждение, связывающее открытый ключ с именованной идентичностью; доверенное за счёт сцепления с центром, который вы признаёте (RFC 5280 §6).
  • Якорь доверия (trust anchor) — удостоверяющий центр, которому вы решили доверять; корень приемлемой цепочки сертификатов.
  • Метка времени (RFC 3161) — подписанный токен от удостоверяющего центра меток времени, привязывающий хеш к значению времени, обеспечивающий доверенное доказательство того, когда.
  • CMS SignedData — структура Cryptographic Message Syntax (RFC 5652), которая несёт значение подписи и сертификат подписанта.
  • PAdES — PDF Advanced Electronic Signatures: семейство профилей ETSI для подписания PDF. Подробно рассмотрено на страницах о подписании.