, Таким образом, эта процедура также может быть запрещена как часть документа об исправлениях для спецификации.

лизовал цифровую подпись, используя iTextSharp Dll, чтобы подписывать файлы PDF одной подписью, создавая пустые поля подписи и обновляя поле подписи с помощью подписанного хеш-кода. Теперь я хочу разместить одну и ту же цифровую подпись на каждой странице PDF. Это мое требование к клиенту.

Я использую следующий код:

public class MyExternalSignatureContainer : IExternalSignatureContainer
{
    private readonly byte[] signedBytes;

    public MyExternalSignatureContainer(byte[] signedBytes)
    {
        this.signedBytes = signedBytes;
    }

    public byte[] Sign(Stream data)
    {
        return signedBytes;
    }

    public void ModifySigningDictionary(PdfDictionary signDic)
    {
    }
}

Ниже код, используемый в программе

PdfReader reader = new PdfReader(unsignedPdf);
FileStream os = File.OpenWrite(tempPdf);
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;

appearance.Reason = "Reason1";
appearance.Contact = "";
appearance.Location = "Location1";
appearance.Acro6Layers = false;
appearance.Image = null;
appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(36, 748, 144, 780), 1, null);
for (int i = 1; i < 8; i++)
{
    var signatureField = PdfFormField.CreateSignature(stamper.Writer);
    var signatureRect = new Rectangle(200, 200, 100, 100);
    signatureField.Put(PdfName.T, new PdfString("ClientSignature_"+i.ToString()));
    PdfIndirectReference PRef = stamper.Writer.PdfIndirectReference;
    signatureField.Put(PdfName.V, PRef);
    signatureField.Put(PdfName.F, new PdfNumber("132"));
    signatureField.SetWidget(signatureRect, null);
    signatureField.Put(PdfName.SUBTYPE, PdfName.WIDGET);

    PdfDictionary xobject1 = new PdfDictionary();
    PdfDictionary xobject2 = new PdfDictionary();
    xobject1.Put(PdfName.N, appearance.GetAppearance().IndirectReference);
    xobject2.Put(PdfName.AP, xobject1);
    signatureField.Put(PdfName.AP, xobject1);
    signatureField.SetPage();
    PdfDictionary xobject3 = new PdfDictionary();
    PdfDictionary xobject4 = new PdfDictionary();
    xobject4.Put(PdfName.FRM, appearance.GetAppearance().IndirectReference);
    xobject3.Put(PdfName.XOBJECT, xobject4);
    signatureField.Put(PdfName.DR, xobject3);

    stamper.AddAnnotation(signatureField, i);
}

IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.SignExternalContainer(appearance, external, 8192);
stamper.Close();

byte[] SignedHash =  DoEsign(SHA256Managed.Create().ComputeHash(appearance.GetRangeStream());
os.close();
reader.close();

reader = new PdfReader(tempPdf))
os = File.OpenWrite(signedPdf)

IExternalSignatureContainer external1 = new MyExternalSignatureContainer(SignedHash);
MakeSignature.SignDeferred(reader, signatureFieldName, os, external1);
os.close();
reader.close();

Пожалуйста, предложите мне выполнить задачу

 mkl29 нояб. 2017 г., 16:08
Тем не менее, вы показали свой код; ты уже запустил его? Это работает? Если нет, то в чем проблема? (Для меня ваше назначение новой косвенной ссылки для значения подписи выглядит ложным. Если вы хотите использовать одно и то же значение подписи во всех полях подписи, все эти поля должны использовать одну и ту же ссылку ...)
 mkl28 нояб. 2017 г., 09:45
«требование клиента» - сообщили ли вы своему клиенту о том, что текущая спецификация PDF ISO 32000-2 диктует: «Расположение подписи в документе может иметь отношение к его юридическому значению. По этой причине поля подписи никогда не должны ссылаться на более чем одна аннотация. " и «На данный словарь аннотаций следует ссылаться изAnnots массив только одной страницы. »Таким образом, эти требования делают PDF недействительным и позволяют отклонять его любому зрителю, либо сразу, либо во время проверки подписи.
 Balasubramaniyan Jayaraman29 нояб. 2017 г., 13:56
Я сделал то же самое, используя тот же код. пожалуйста, просмотрите это еще раз.
 mkl28 нояб. 2017 г., 09:50
Это было сказано,этот ответ показывает обзор опций (с комментариями до ISO 32000-2);другой ответ на этот же вопрос дает подсказку, как патчить iText 5.5.x для желаемого результата; Патч описан для версии Java, но его легко перенести на .Net.
 mkl29 нояб. 2017 г., 15:30
«Я сделал то же самое, используя тот же код» - Ну не совсем. Ваш подход пытается пойти еще одним путем, вы не пытаетесь ссылаться на одно поле подписи на многих страницах, как это делается там (или создавать несколько аннотаций виджетов для одного поля подписи, как это делается в другом месте), вы пытаетесь создать несколько полей подписи разделяя ту же ценность! Как такая интересная идея. Я не уверен, как зрители PDF отреагируют на это, если это будет реализовано должным образом, насколько я знаю, это еще явно не запрещено спецификациями, но и не ожидается ...

Ответы на вопрос(1)

охватывающее вновь созданный контейнер подписи, все они должны ссылаться на тот же косвенный объект, что и значение. К сожалению, iText создает косвенный объект только для значения подписипосле код приложения имел возможность добавить свои дополнительные поля, которые, в свою очередь, требуют ссылки на этот объект значения подписи. Таким образом, код приложения должен предвидеть номер объекта, который будет иметь косвенный объект.

Это предвидение или предсказание номера объекта очень деликатное, оно зависит от точно такого же варианта использования и может также стать неверным в результате незначительных изменений в библиотеке iTextSharp

Чтобы сделать это проще, код приложения должен добавлять эти поля подписи с их ссылками на значения подписи как можно позже, чтобы было как можно меньше новых косвенных объектов, создаваемых до тех пор, пока iText не создаст косвенный объект значения.

Как оказалось,ModifySigningDictionary методIExternalSignatureContainer это хорошая позиция для этого.

Как только кто-то добавляет туда свой код, всплывает другая проблема: нет средств для установки ожидаемого номера объекта вPdfIndirectReference экземпляр внешне. Один из способов обойти это - подражать такой ссылке, используяPdfLiteral, (Ну, наверное, для этого тоже можно использовать отражение.)

Кроме того, оказывается, что лучше всего создать потоки внешнего вида для использования всеми дополнительными полями подписи, прежде чем создаватьPdfLiteral подражаяPdfIndirectReference поскольку это упрощает вычисление номера объекта, который iText будет использовать для объекта фактического значения.

Имея это в виду, здесь доказательство концепции. Это доказательство концепции используетIExternalSignature экземпляр для собственно подписи. Это не является обязательным условием, можно также использоватьIExternalSignatureContainer вместо этого с несколькими изменениями, дажеExternalBlankSignatureContainer как в вопросе, чтобы позже завершить подпись с помощьюMakeSignature.SignDeferred.

Итак, данные параметры шифраcp (материал закрытого ключа, например,pk.Key дляOrg.BouncyCastle.Pkcs.AsymmetricKeyEntry pk) и цепочка сертификатовchainможно было бы использовать

PdfReader reader = new PdfReader(SRC);
FileStream os = new FileStream(DEST, FileMode.Create, FileAccess.Write);
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;

appearance.Reason = "Reason1";
appearance.Contact = "";
appearance.Location = "Location1";
appearance.Acro6Layers = false;
appearance.Image = null;
appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(10, 10, 100, 100), reader.NumberOfPages, null);

IExternalSignature externalSignature = new PrivateKeySignature(cp, "SHA-256");
AllPagesSignatureContainer allPagesContainer = new AllPagesSignatureContainer(appearance, externalSignature, chain);
MakeSignature.SignExternalContainer(appearance, allPagesContainer, 8192);

с этим классом контейнера внешней подписи

public class AllPagesSignatureContainer : IExternalSignatureContainer
{
    public AllPagesSignatureContainer(PdfSignatureAppearance appearance, IExternalSignature externalSignature, ICollection<X509Certificate> chain)
    {
        this.appearance = appearance;
        this.chain = chain;
        this.externalSignature = externalSignature;
    }

    public void ModifySigningDictionary(PdfDictionary signDic)
    {
        signDic.Put(PdfName.FILTER, PdfName.ADOBE_PPKMS);
        signDic.Put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_DETACHED);

        PdfStamper stamper = appearance.Stamper;
        PdfReader reader = stamper.Reader;
        PdfDictionary xobject1 = new PdfDictionary();
        PdfDictionary xobject2 = new PdfDictionary();
        xobject1.Put(PdfName.N, appearance.GetAppearance().IndirectReference);
        xobject2.Put(PdfName.AP, xobject1);

        PdfIndirectReference PRef = stamper.Writer.PdfIndirectReference;
        PdfLiteral PRefLiteral = new PdfLiteral((PRef.Number + 1 + 2*(reader.NumberOfPages - 1)) + " 0 R");

        for (int i = 1; i < reader.NumberOfPages; i++)
        {
            var signatureField = PdfFormField.CreateSignature(stamper.Writer);

            signatureField.Put(PdfName.T, new PdfString("ClientSignature_" + i.ToString()));
            signatureField.Put(PdfName.V, PRefLiteral);
            signatureField.Put(PdfName.F, new PdfNumber("132"));
            signatureField.SetWidget(appearance.Rect, null);
            signatureField.Put(PdfName.SUBTYPE, PdfName.WIDGET);

            signatureField.Put(PdfName.AP, xobject1);
            signatureField.SetPage();
            Console.WriteLine(signatureField);

            stamper.AddAnnotation(signatureField, i);
        }
    }

    public byte[] Sign(Stream data)
    {
        String hashAlgorithm = externalSignature.GetHashAlgorithm();
        PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
        IDigest messageDigest = DigestUtilities.GetDigest(hashAlgorithm);
        byte[] hash = DigestAlgorithms.Digest(data, hashAlgorithm);
        byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
        byte[] extSignature = externalSignature.Sign(sh);
        sgn.SetExternalDigest(extSignature, null, externalSignature.GetEncryptionAlgorithm());
        return sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
    }

    PdfSignatureAppearance appearance;
    ICollection<X509Certificate> chain;
    IExternalSignature externalSignature;
}

Прогнозируемый косвенный номер объекта значения подписи в строке

PdfLiteral PRefLiteral = new PdfLiteral((PRef.Number + 1 + 2*(reader.NumberOfPages - 1)) + " 0 R");

Строго зависит от того, какой вариант использования является «ровно одним полем подписи на странице». Для разных случаев использования оценка прогноз будет отличаться.

Я подчеркиваю это еще раз, потому что, например, ОП изэтот вопрос не принял это во внимание при попытке«разместить несколько подписей на одной странице».

Осторожно: пока эта процедура создает что-то, что не нарушаетписьмо спецификаций PDF (которые запрещают только те случаи, когда на один и тот же объект поля ссылаются с нескольких страниц, будь то с помощью одинаковых или с помощью отдельных виджетов), он явно нарушает егонамерение, егодух, Таким образом, эта процедура также может быть запрещена как часть документа об исправлениях для спецификации.

Ваш ответ на вопрос