Это моя форма -

enter image description here

Ниже приведен код -

private void btnSign_Click(object sender, EventArgs e)
{   
    string sbase64 = richTextBox2.Text;
    byte[] bytes = System.Convert.FromBase64String(sbase64);
    PdfReader reader = new PdfReader("F:\\test1.pdf"); 
    FileStream os = new FileStream("F:\\output.pdf", FileMode.Create);
    IExternalSignatureContainer external1 = new MyExternalSignatureContainer(bytes);
    MakeSignature.SignDeferred(reader, "Signature1", os, external1);
    reader.Close();
    os.Close(); 
}

private class MyExternalSignatureContainer : IExternalSignatureContainer
{
    protected byte[] sig;
    public MyExternalSignatureContainer(byte[] sig)
    {
        this.sig = sig;
    }
    public byte[] Sign(Stream s)
    {
        var certificate = new X509Certificate2();
        certificate.Import("F:\\180332.cer");
        Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
        Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { cp.ReadCertificate(certificate.RawData) };
        string hashAlgorithm = "SHA-256";
        PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
        byte[] hash = DigestAlgorithms.Digest(s, hashAlgorithm);
        byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
        string messageDigest = sha256_hash(sh);
        byte[] signatureAsByte = sig;
        sgn.SetExternalDigest(signatureAsByte, null, "RSA");
        return sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
    }
    public void ModifySigningDictionary(PdfDictionary signDic) { }
}

private void btnPreparePDF_Click(object sender, EventArgs e)
{
    //Prepare file .cer
    var certificate = new X509Certificate2();
    certificate.Import("F:\\base64.cer");
    Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
    Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { cp.ReadCertificate(certificate.RawData) };

    //Create area sign
    PdfReader reader = new PdfReader("F:\\test.pdf");
    FileStream os = new FileStream("F:\\test1.pdf", FileMode.Create);
    PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
    PdfSignatureAppearance appearance = stamper.SignatureAppearance;
    appearance.Certificate = chain[0];
    appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(36, 748, 250, 400), 1, "Signature1");
    IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
    MakeSignature.SignExternalContainer(appearance, external, 8192);
    string hashAlgorithm = "SHA-256";
    PdfPKCS7 sgn = new PdfPKCS7(null, chain , hashAlgorithm, false);
    PdfSignatureAppearance appearance2 = stamper.SignatureAppearance;
    Stream stream = appearance2.GetRangeStream();
    byte[] hash = DigestAlgorithms.Digest(stream, hashAlgorithm);
    byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);

    //Export chain to sign
    string abc = sha256_hash(sh);
    richtextbox1.Text = abc;
}

private static String sha256_hash(Byte[] value)
{
    using (SHA256 hash = SHA256.Create())
    {
        return String.Concat(hash.ComputeHash(value).Select(item => item.ToString("x2"))).ToUpper();
    }
}

Сначала я готовлю PDF-файл (test.pdf) для создания подписанной области в PDF-файле. Затем выведите файл test1.pdf и строку SHA-256.

Затем я использую строку SHA-1, которая загружается на сервер для подписи. Сервер возвращает строку base64.

Я копирую этот base64 и вставляю его в richtextbox2, чтобы подписать и экспортировать файл output.pdf.

Затем я проверяю этот файл "output.pdf" в Foxit Reader (версия 10.0), подпись ДЕЙСТВИТЕЛЬНА.

Но когда я проверяю этот файл в Adobe Reader или Adobe Acrobat, подпись НЕДЕЙСТВИТЕЛЬНА.

Даже на Foxit Reader (последняя версия 10.1) подпись недействительна. Что случилось???

Я не очень хорошо говорю по-английски. Извиняюсь!

ОБНОВЛЕНИЕ - ОШИБКА !!!

Когда я проверял Foxit Reader 10.0, это файл output.pdf (он действителен) -

enter image description here

И это когда я проверяю Adobe Acrobat (он недействителен) -

enter image description here

ОБНОВЛЕНИЕ ... Есть ли ошибки ?? PKCS # 1 или PKCS # 7

0
Duc Nhan Do 17 Окт 2020 в 10:37

1 ответ

Лучший ответ

В вашем примере PDF есть как минимум две проблемы, и они вызваны не столько кодом, связанным с iText, сколько вашей службой подписи или тем, как вы ее решаете.

Проблемы

Используемые смешанные алгоритмы дайджеста

Вы используете SHA-256 для вычисления дайджеста диапазонов байтов подписанного PDF-файла. Таким образом, алгоритм хеширования, хранящийся в SignerInfo, - это SHA-256. В качестве алгоритма подписи / шифрования он относится только к RSA. Но в байтах подписи явно используется SHA-1.

Это ошибка, согласно RFC 5652 этот алгоритм хеширования должен использоваться как для хеширования сообщения. данные и подписанные атрибуты.

Это дамп объекта SignerInfo

. . . . SEQUENCE {
. . . . . INTEGER 1
. . . . . [...SID...]
. . . . . SEQUENCE {
. . . . . . OBJECT IDENTIFIER sha-256 (2 16 840 1 101 3 4 2 1)
. . . . . . . (NIST Algorithm)
. . . . . . NULL
. . . . . . }
. . . . . [0] {
. . . . . . SEQUENCE {
. . . . . . . OBJECT IDENTIFIER contentType (1 2 840 113549 1 9 3)
. . . . . . . . (PKCS #9)
. . . . . . . SET {
. . . . . . . . OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
. . . . . . . . . (PKCS #7)
. . . . . . . . }
. . . . . . . }
. . . . . . SEQUENCE {
. . . . . . . OBJECT IDENTIFIER messageDigest (1 2 840 113549 1 9 4)
. . . . . . . . (PKCS #9)
. . . . . . . SET {
. . . . . . . . OCTET STRING    
. . . . . . . . . 2F AA 90 5F A3 3B 2E 74    /.._.;.t
. . . . . . . . . 3F 78 7A C1 85 F8 EF B7    ?xz.....
. . . . . . . . . 20 AE 73 2B F4 2F B2 80     .s+./..
. . . . . . . . . 87 3C 24 50 F9 A8 3F 8B                            
. . . . . . . . }
. . . . . . . }
. . . . . . }
. . . . . SEQUENCE {
. . . . . . OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
. . . . . . . (PKCS #1)
. . . . . . NULL
. . . . . . }
. . . . . OCTET STRING    
. . . . . . [...Signature Bytes...]
. . . . . }
. . . . }

Вы можете легко распознать SHA-256 и RSA OID; они были добавлены классом iText PdfPKCS7 на основе ваших входных данных.

А это дамп расшифрованного объекта DigestInfo в байтах вашей подписи:

SEQUENCE (2 elem) {
. SEQUENCE (2 elem) {
. . OBJECT IDENTIFIER 1.3.14.3.2.26 sha1 (OIW)
. . NULL
. . }
. OCTET STRING (20 byte) AD002EA501871117250DE3BF42D51B4FD2B1C5A0
. }

Вы можете ясно видеть SHA-1 OID; кроме того, 20-байтовое хеш-значение является возможным хешем SHA-1, но не хешем SHA-256.

Очевидно, служба подписи создала подпись SHA1withRSA в ответ на ваш запрос.

Неверное значение хэша со знаком

Как видно из расшифрованного дампа объекта DigestInfo выше, хеш-значение со знаком

AD002EA501871117250DE3BF42D51B4FD2B1C5A0

Но даже если одно предполагаемое использование смешанного алгоритма, как упомянуто выше, в порядке, это значение неверно, правильное значение хэша SHA-1 для подписанных атрибутов в вашем SignerInfo равно

851AD7BF24D159C02A705FD4ABB20EBA9DE2AD2B

Это несоответствие на самом деле неудивительно, учитывая, что вы отправили в службу подписи только дайджест SHA-256. Вероятно, служба использовала только 20-байтовую часть вашего 32-байтового значения дайджеста SHA-256 или использовала ваш ввод в качестве простых данных для подписи и хеширования.

Последующие действия

В ответ LBMinh спросил

1 / Могу ли я изменить свои алгоритмы дайджеста на SHA1 и отправить их на сервер подписи?

2 / Если сервер подписи использовал мои входные данные как простые данные, могу ли я отправить ему необработанные данные (без хеша)?

3 / Почему, когда я проверяю выходной PDF-файл с помощью Foxit reader (10.0), он говорит, что он действителен, но в новейших версиях Foxit или Adobe он говорит, что он недействителен.

Изменение алгоритмов

1 / Могу ли я изменить свои алгоритмы дайджеста на SHA1 и отправить их на сервер подписи?

Конечно, вы можете использовать SHA-1 вместо варианта SHA-2, просто переключите строки имени алгоритма в своем коде.

Но вы не должны . Было показано, что SHA-1 в контексте подписи PDF не работает, см. shattered.io, и, как следствие, в международном масштабе считается устаревшим. Поэтому, если вы не подписываете только те документы, которые ни для чего не требуют подписи, переход на SHA-1 - плохая идея. Никто в здравом уме не будет доверять документу, подписанному с помощью хеширования SHA-1, если только он не является крайне несущественным.

Вместо этого вам следует изучить, как запрашивать подписи на основе хеширования SHA-2 из вашей службы подписи или переключиться на другую службу.

Отправка сырых данных

2 / Если сервер подписи использовал мои входные данные как простые данные, могу ли я отправить ему необработанные данные (без хеша)?

Если он использует ваш ввод как еще не хешированные данные для подписи, вполне вероятно, что это хороший вариант для исследования. В btnPreparePDF_Click просто не переваривайте byte[] sh, а используйте его содержимое как есть.

Почему Foxit 10 говорит, что это действительно так?

3 / Почему, когда я проверяю выходной PDF-файл с помощью Foxit reader (10.0), он говорит, что он действителен, но в новейших версиях Foxit или Adobe он говорит, что он недействителен.

Как я показал выше в разделе «Проблемы», подпись не работает. Таким образом, если какой-то валидатор говорит, что подпись действительна, вы являетесь свидетелем серьезной ошибки безопасности в ней.

Судя по всему, Foxit уже распознала эту ошибку и исправила ее в своей последней версии.


Боковые примечания

Есть ли ошибки ?? PKCS # 1 или PKCS # 7

С комментарием «Я обнаружил несколько ошибок» вы добавили к своему вопросу следующее изображение.

RSA with PKCS#1 v.1.5

Нет, это не ошибка, «RSA с PKCS # 1 v.1.5» - это сокращение от «RSASSA с PKCS # 1 v1.5 padding», также известного как RSASSA-PKCS1-v1_5.

По сути, существуют две соответствующие схемы подписи, основанные на алгоритме RSA: RSASSA-PKCS1-v1_5 и RSASSA-PSS.

RSASSA-PKCS1-v1_5 - это старая схема, которая очень проста и имеет некоторые сомнительные свойства безопасности.

RSASSA-PSS - это более новая схема, более сложная и не имеющая этих сомнительных свойств безопасности.

Поэтому перспективное программное обеспечение, основанное на алгоритме RSA, должно использовать RSASSA-PSS.

Подробнее об этих схемах подписи см. RFC 8017.

2
mkl 19 Окт 2020 в 13:16