Статус: Участник
Группы: Участники
Зарегистрирован: 12.07.2022(UTC) Сообщений: 13 Сказал(а) «Спасибо»: 2 раз
|
Прошу помощи! Полученная подпись не действительна (ошибка значения хеша). Пытаюсь реализовать встроенную подпись в PDF. На сервере с помощью iTextSharp создаю тестовый pdf, добавляю в него пустой контейнер для подписи, сохраняю этот pdf как массив байт (pdfWithBlankSignatureContainer), а на клиент отправляю поток, который содержит последовательность, которую хочу подписывать в base64 (bytesToSign). Код:
public static byte[] CreatePdf()
{
using (MemoryStream ms = new MemoryStream())
{
Document document = new Document(PageSize.A4, 25, 25, 30, 30);
PdfWriter writer = PdfWriter.GetInstance(document, ms);
document.Open();
document.Add(new Paragraph("Hello World!"));
document.Close();
writer.Close();
return ms.ToArray();
}
}
public static byte[] GetPdfAndBytesToSign(byte[] unsignedPdf, string signatureFieldName, out byte[] pdfWithBlankSignatureContainer)
{
//unsignedPdf - массив байт исходного PDF файла
using (PdfReader reader = new PdfReader(unsignedPdf))
{
using (MemoryStream tempPdf = new MemoryStream())
{
//добавляем пустой контейнер для новой подписи
using (PdfStamper st = PdfStamper.CreateSignature(reader, tempPdf, '\0', null, true))
{
PdfSignatureAppearance appearance = st.SignatureAppearance;
appearance.SetVisibleSignature(new Rectangle(205, 700, 390, 800), reader.NumberOfPages, SignatureFieldName);
ExternalBlankSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.SignExternalContainer(appearance, external, BufferSize);
pdfWithBlankSignatureContainer = tempPdf.ToArray();
//получаем поток, который содержит последовательность, которую мы хотим подписывать
using (Stream contentStream = appearance.GetRangeStream())
{
MemoryStream memoryStream = new MemoryStream();
contentStream.CopyTo(memoryStream);
byte[] bytesToSign = memoryStream.ToArray();
return bytesToSign;
}
}
}
}
}
На клиенте получаю этот base64, используя плагин: выбираю сертификат, считаю сначала хеш, подписываю полученный хеш методом SignHash() и полученную подпись отдаю на сервер для встраивания в PDF. Код:
public SignHashAsync(dataToSign, thumbprint) {
return new Promise<string>(function(resolve, reject) {
cadesplugin.async_spawn(function*(arg) {
var oStore;
try {
oStore = yield cadesplugin.CreateObjectAsync("CAdESCOM.Store");
yield oStore.Open(cadesplugin.CAPICOM_CURRENT_USER_STORE, cadesplugin.CAPICOM_MY_STORE, cadesplugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED);
var allCertificates = yield oStore.Certificates;
var oCertificates = yield allCertificates.Find(cadesplugin.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, thumbprint);
var certificatesCount = yield oCertificates.Count;
if (certificatesCount === 0) {
return reject("Сертификат не найден в хранилище.");
}
var oCertificate = yield oCertificates.Item(1);
var oHashedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.HashedData");
yield oHashedData.propset_Algorithm(cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256);
yield oHashedData.propset_DataEncoding = cadesplugin.CADESCOM_BASE64_TO_BINARY;
yield oHashedData.Hash(dataToSign);
var oSigner = yield cadesplugin.CreateObjectAsync("CAdESCOM.CPSigner");
oSigner.propset_Certificate(oCertificate);
var oCadesSignedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
oCadesSignedData.propset_ContentEncoding(cadesplugin.CADESCOM_BASE64_TO_BINARY);
var signatureHex: string = yield oCadesSignedData.SignHash(oHashedData, oSigner, cadesplugin.CADESCOM_CADES_BES);
debugger;
return resolve(signatureHex);
} catch (err) {
return reject("Не удалось создать подпись. " + (err));
} finally {
if (oStore) {
yield oStore.Close();
}
}
});
});
}
На сервере получаю Эту подпись в base64, декодирую в массив байт и iTextSharp'ом встраиваю в PDF с пустым контейнером для подписи, созданный на сервере на первом этапе. Код:
public static byte[] GetSignedPdf(byte[] unsignedPdfWithContainer, byte[] signature)
{
using var pdfReader = new PdfReader(unsignedPdfWithContainer);
using var output = new MemoryStream();
var external = new MyExternalSignatureContainer(signature);
MakeSignature.SignDeferred(pdfReader, SignatureFieldName, output, external);
return output.ToArray();
}
private class MyExternalSignatureContainer : IExternalSignatureContainer
{
private readonly byte[] _signedBytes;
public MyExternalSignatureContainer(byte[] signedBytes)
{
this._signedBytes = signedBytes;
}
public byte[] Sign(Stream data)
{
return this._signedBytes;
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
throw new NotImplementedException();
}
}
Полученный PDF с встроенной подписью передаю на клиента в виде массива байт закодированный в base64, на клиенте сохраняю эту строку, конвертируя base64 в PDF. Когда проверяю подпись в PDF она не действительная! CryptExpert пишет что ошибка - неправильное значение хеша. Как надо подписывать хеш на клиенте и нужно ли считать хеш для встроенной подписи в PDF? Может надо подписывать сразу переданные данные без хеша? Что я делаю не так, подскажите, пожалуйста
|