Мне нужно реализовать двухэтапный процесс подписания PDF, используя ITEXT в C#.
Поток выглядит следующим образом: < /p>
Подготовьте PDF для подписания-встройте пустое поле подписи, рассчитайте хэш и верните модифицированный документ и HASH (в базе 64). /> Внешняя компания (компания A) подписывает хэш и возвращает подпись.public PrepareDocumentSignResponseDto PrepareDocumentSign(byte[] documentBytes,
AlgorithmSignature algorithmSignature, byte[] certificateBytes)
{
ArgumentNullException.ThrowIfNull(documentBytes);
ArgumentNullException.ThrowIfNull(algorithmSignature);
ArgumentNullException.ThrowIfNull(certificateBytes);
// Step 1: Draw a rectangle for the signature
Rectangle signatureRectangle;
int signaturePageNumber;
using var readerStream = new MemoryStream(documentBytes);
using var outputStream = new MemoryStream();
using var reader = new PdfReader(readerStream);
using var writer = new PdfWriter(outputStream);
using (var pdfDoc = new PdfDocument(reader, writer))
{
signatureRectangle = pdfDoc.AddRectangleSignature();
var signaturePage = pdfDoc.GetLastPage();
signaturePageNumber = pdfDoc.GetPageNumber(signaturePage);
signaturePage.AddTitle(signatureRectangle);
signaturePage.AddCertificateInfo(signatureRectangle, certificateBytes);
}
var pdfBytes = outputStream.ToArray();
// Step 2: Add an empty signature
using var finalOutput = new MemoryStream();
var hashBytes = PdfSignatureHelper.AddEmptySignature(
pdfBytes,
finalOutput,
signatureRectangle,
signaturePageNumber,
algorithmSignature);
var finalPdfBytes = finalOutput.ToArray();
return new PrepareDocumentSignResponseDto(
Convert.ToBase64String(finalPdfBytes),
Convert.ToBase64String(hashBytes));
}
public static byte[] AddEmptySignature(byte[] documentBytes, Stream outputStream, Rectangle rectangle, int pageNumber, AlgorithmSignature algorithmSignature)
{
ArgumentNullException.ThrowIfNull(documentBytes);
ArgumentNullException.ThrowIfNull(outputStream);
ArgumentNullException.ThrowIfNull(rectangle);
ArgumentOutOfRangeException.ThrowIfNegative(pageNumber);
using var readerStream = new MemoryStream(documentBytes);
using var reader = new PdfReader(readerStream);
var signerProperties = new SignerProperties();
var fieldName = PdfConstants.SignatureName(documentBytes.SignaturesCount() + 1);
signerProperties.SetSignatureAppearance(new SignatureFieldAppearance(Guid.NewGuid().ToString()));
signerProperties.SetFieldName(fieldName);
signerProperties.SetPageRect(rectangle); // Устанавливает границы подписи
signerProperties.SetPageNumber(pageNumber);
var signer = new PdfSigner(reader, outputStream, new StampingProperties());
signer.SetSignerProperties(signerProperties);
var external = new PrepareSignatureContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached, algorithmSignature);
signer.SignExternalContainer(external, PdfConstants.MaxSignatureSize);
return external.GetHash();
}
< /code>
Пользовательский контейнер для подписи, используемый во время расчета хэша: < /p>
public sealed class PrepareSignatureContainer : IExternalSignatureContainer
{
private readonly PdfDictionary _sigDic = new();
private readonly AlgorithmSignature _algorithmSignature;
private byte[] _hash;
public PrepareSignatureContainer(PdfName filter, PdfName subFilter, AlgorithmSignature algorithmSignature)
{
_algorithmSignature = algorithmSignature;
_sigDic.Put(PdfName.Filter, filter);
_sigDic.Put(PdfName.SubFilter, subFilter);
}
public byte[] GetHash() => _hash;
///
/// This method is called by iText to "sign" the document.
/// In this implementation, we only compute the hash and return an empty byte array.
/// The actual signing is performed externally.
///
public byte[] Sign(Stream data)
{
_hash = new AlgorithmSignatureFactory()
.Create(_algorithmSignature)
.ComputeHash(data);
return [];
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
signDic.PutAll(_sigDic);
}
}
< /code>
Затем я прикрепляю полученную подпись: < /p>
public AttachDocumentSignResponseDto AttachDocumentSign(byte[] documentBytes, byte[] signatureBytes)
{
ArgumentNullException.ThrowIfNull(documentBytes);
ArgumentNullException.ThrowIfNull(signatureBytes);
CheckSignature(signatureBytes);
using var readerStream = new MemoryStream(documentBytes);
using var outputStream = new MemoryStream();
using var pdfReader = new PdfReader(readerStream);
IExternalSignatureContainer external = new PredefinedExternalSignatureContainer(signatureBytes);
var fieldName = PdfConstants.SignatureName(documentBytes.SignaturesCount());
PdfSigner.SignDeferred(
pdfReader,
fieldName,
outputStream,
external);
var signedPdfBytes = outputStream.ToArray();
return new AttachDocumentSignResponseDto(Convert.ToBase64String(signedPdfBytes));
}
< /code>
и пользовательский контейнер для вставки предопределенной подписи: < /p>
public sealed class PredefinedExternalSignatureContainer : IExternalSignatureContainer
{
private readonly byte[] _signatureBytes;
///
/// Constructor to initialize the signature container.
///
///
Byte array of the digital signature.
public PredefinedExternalSignatureContainer(byte[] signatureBytes)
{
_signatureBytes = signatureBytes ?? throw new ArgumentNullException(nameof(signatureBytes));
}
///
/// Method to sign the data. Returns the precomputed signature.
///
/// The stream of data to be signed.
/// The digital signature as a byte array.
public byte[] Sign(Stream data)
{
return _signatureBytes; // Returns the predefined signature. Assumes the signature was generated externally.
}
///
/// Method to modify the signature dictionary in the PDF document.
///
/// The signature dictionary to modify.
public void ModifySigningDictionary(PdfDictionary signDic)
{
signDic.Put(PdfName.Filter, PdfName.Adobe_PPKLite);
signDic.Put(PdfName.SubFilter, PdfName.Adbe_pkcs7_detached);
}
}
< /code>
Все, кажется, работает, и подпись вводится без исключений. Но Adobe Acrobat Reader сообщает о подписи как недействительной.
Вот что показывает UI:
Перевод с перевода с экрана. />
Подпись недопустима. Документ был изменен или
с момента его подписания. Последняя проверка: 2025.04.11
12:58:57 +03'00 Поле: Signature_1 на стр. 2 < /p>
< /blockquote>
Подробнее здесь: https://stackoverflow.com/questions/795 ... -signature
Как правильно подписать PDF в двух шагах, используя ITEXT7 и внешнюю подпись? ⇐ C#
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение