Статус: Новичок
Группы: Участники
Зарегистрирован: 18.05.2023(UTC) Сообщений: 7
Сказал(а) «Спасибо»: 2 раз
|
Добрый день! Имеется десктопное приложение, написанное на wpf .net core 7.0, которое формирует pdf документ. Требуется подписать pdf документы с помощью крипто про сертификатом с типом шифрования Crypto-Pro GOST R 34.10. Варианты, которые предложены в сети(например использование corefx и тд) актуальны для более ранних версий .net core. Подскажите, пожалуйста, актуальные пути решения данной задачи с помощью ваших или сторонних утилит/библиотек. Отредактировано пользователем 19 мая 2023 г. 12:34:00(UTC)
| Причина: Не указана
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 20.02.2017(UTC) Сообщений: 217
Сказал(а) «Спасибо»: 4 раз Поблагодарили: 63 раз в 59 постах
|
Добрый день. Для 6.0 есть libcore - https://github.com/CryptoPro/libcoreПример формирования подписи примерно такой (требует BouncyCastle и iTextSharp) Код:namespace Simple35.Pdf
{
using iTextSharp.text.pdf;
using System.IO;
using Org.BouncyCastle.X509;
using System.Security.Cryptography.Pkcs;
using CryptoPro.Sharpei;
using iTextSharp.text.pdf.security;
/// <summary>
/// По мотивам http://www.cryptopro.ru/forum2/Default.aspx?g=posts&t=2846
/// Для сборки примера необходимо установить последнюю версию iTextSharp и определить переменную PDF_SIGNATURE_ENABLED
/// </summary>
public class Sign
{
[STAThread]
public static int Main(string[] args)
{
// Разбираем аргументы
if (args.Length < 2)
{
Console.WriteLine("Pdf.Sign <document> <certificate-dn> [<key-container-password>]");
return 1;
}
string document = args[0];
string certificate_dn = args[1];
// Находим секретный ключ по сертификату в хранилище MY
X509Store store = new X509Store("My", StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
X509Certificate2Collection found = store.Certificates.Find(
X509FindType.FindBySubjectName, certificate_dn, true);
if (found.Count == 0)
{
Console.WriteLine("Секретный ключ не найден.");
return 1;
}
if (found.Count > 1)
{
Console.WriteLine("Найдено более одного секретного ключа.");
return 1;
}
X509Certificate2 certificate = found[0];
if (args.Length > 2)
{
//set password.
Gost3410CryptoServiceProvider cert_key = certificate.PrivateKey as Gost3410CryptoServiceProvider;
if (null != cert_key)
{
var cspParameters = new CspParameters();
//копируем параметры csp из исходного контекста сертификата
cspParameters.KeyContainerName = cert_key.CspKeyContainerInfo.KeyContainerName;
cspParameters.ProviderType = cert_key.CspKeyContainerInfo.ProviderType;
cspParameters.ProviderName = cert_key.CspKeyContainerInfo.ProviderName;
cspParameters.Flags = cert_key.CspKeyContainerInfo.MachineKeyStore
? (CspProviderFlags.UseExistingKey|CspProviderFlags.UseMachineKeyStore)
: (CspProviderFlags.UseExistingKey);
cspParameters.KeyPassword = new SecureString();
foreach (var c in args[2])
{
cspParameters.KeyPassword.AppendChar(c);
}
//создаем новый контекст сертификат, поскольку исходный открыт readonly
certificate = new X509Certificate2(certificate.RawData);
//задаем криптопровайдер с установленным паролем
certificate.PrivateKey = new Gost3410CryptoServiceProvider(cspParameters);
}
}
PdfReader reader = new PdfReader(document);
PdfStamper st = PdfStamper.CreateSignature(reader, new FileStream(document + "_signed.pdf", FileMode.Create, FileAccess.Write), '\0');
PdfSignatureAppearance sap = st.SignatureAppearance;
// Загружаем сертификат в объект iTextSharp
X509CertificateParser parser = new X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] {
parser.ReadCertificate(certificate.RawData)
};
sap.Certificate = parser.ReadCertificate(certificate.RawData);
sap.Reason = "I like to sign";
sap.Location = "Universe";
sap.Acro6Layers = true;
//sap.Render = PdfSignatureAppearance.SignatureRender.NameAndDescription;
sap.SignDate = DateTime.Now;
// Выбираем подходящий тип фильтра
PdfName filterName = new PdfName("CryptoPro PDF");
// Создаем подпись
PdfSignature dic = new PdfSignature(filterName, PdfName.ADBE_PKCS7_DETACHED);
dic.Date = new PdfDate(sap.SignDate);
dic.Name = "PdfPKCS7 signature";
if (sap.Reason != null)
dic.Reason = sap.Reason;
if (sap.Location != null)
dic.Location = sap.Location;
sap.CryptoDictionary = dic;
int intCSize = 4000;
Dictionary<PdfName, int> hashtable = new Dictionary<PdfName, int>();
hashtable[PdfName.CONTENTS] = intCSize * 2 + 2;
sap.PreClose(hashtable);
Stream s = sap.GetRangeStream();
MemoryStream ss = new MemoryStream();
int read = 0;
byte[] buff = new byte[8192];
while ((read = s.Read(buff, 0, 8192)) > 0)
{
ss.Write(buff, 0, read);
}
// Вычисляем подпись
ContentInfo contentInfo = new ContentInfo(ss.ToArray());
SignedCms signedCms = new SignedCms(contentInfo, true);
CmsSigner cmsSigner = new CmsSigner(certificate);
signedCms.ComputeSignature(cmsSigner, false);
byte[] pk = signedCms.Encode();
// Помещаем подпись в документ
byte[] outc = new byte[intCSize];
PdfDictionary dic2 = new PdfDictionary();
Array.Copy(pk, 0, outc, 0, pk.Length);
dic2.Put(PdfName.CONTENTS, new PdfString(outc).SetHexWriting(true));
sap.Close(dic2);
Console.WriteLine("Документ {0} успешно подписан на ключе {1} => {2}.",
document, certificate.Subject, document + "_signed.pdf");
return 0;
}
}
}
|
|
2 пользователей поблагодарили Артём Макаров за этот пост.
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 18.05.2023(UTC) Сообщений: 7
Сказал(а) «Спасибо»: 2 раз
|
А планируется поддержка 7.0 ?
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 20.02.2017(UTC) Сообщений: 217
Сказал(а) «Спасибо»: 4 раз Поблагодарили: 63 раз в 59 постах
|
Автор: Дмитрий007007 А планируется поддержка 7.0 ? 7.0 поддерживать не будем, поддерживаем только LTS релизы (т.е. следующая поддерживаемая версия будет 8.0). |
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 18.05.2023(UTC) Сообщений: 7
Сказал(а) «Спасибо»: 2 раз
|
Подскажите, а если необходимо подписать несколькими сертификатами? Есть подобный пример? Просто у меня только последняя подпись корректна, а остальные ошибочны. Отредактировано пользователем 31 мая 2023 г. 17:25:49(UTC)
| Причина: Не указана
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 14.10.2011(UTC) Сообщений: 144 Поблагодарили: 31 раз в 30 постах
|
Добрый день!
Покажите Ваш вариант, мы попробуем найти в нём ошибку. |
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 18.05.2023(UTC) Сообщений: 7
Сказал(а) «Спасибо»: 2 раз
|
Добрый день // Метод формирования подписи Код: public byte[] Sign(string thumbprint, byte[] bytes, int signatureFieldNumber)
{
var certCollection = _store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (!certCollection.Any())
throw new CryptoProException($"Не найден сертификат {thumbprint}");
var cert = certCollection[0];
if (cert is null)
throw new CryptoProException($"Не найден сертификат {thumbprint}");
using (MemoryStream output = new())
{
using (var reader = new PdfReader(bytes))
{
PdfStamper st = PdfStamper.CreateSignature(reader, output, '\0');
PdfSignatureAppearance sap = st.SignatureAppearance;
// Формируем штампик
X509CertificateParser parser = new X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] {
parser.ReadCertificate(cert.RawData)
};
sap.Certificate = parser.ReadCertificate(cert.RawData);
sap.Layer2Text = GetSignText(cert);
sap.Layer2Font = GetFont();
sap.Image = GetImage();
sap.SetVisibleSignature(GetRectangle(signatureFieldNumber), reader.NumberOfPages,
signatureFieldNumber.ToString());
// Создаем подпись
PdfSignature dic = new(new PdfName("CryptoPro PDF"), PdfName.ADBE_PKCS7_DETACHED)
{
Date = new PdfDate(sap.SignDate),
Name = signatureFieldNumber.ToString()
};
if (sap.Reason != null)
dic.Reason = sap.Reason;
if (sap.Location != null)
dic.Location = sap.Location;
sap.CryptoDictionary = dic;
int intCSize = 8000;
Dictionary<PdfName, int> hashtable = new()
{
[PdfName.CONTENTS] = intCSize * 2 + 2
};
sap.PreClose(hashtable);
Stream s = sap.GetRangeStream();
MemoryStream ss = new();
int read;
byte[] buff = new byte[8192];
while ((read = s.Read(buff, 0, 8192)) > 0)
{
ss.Write(buff, 0, read);
}
// Вычисляем подпись
ContentInfo contentInfo = new(ss.ToArray());
SignedCms signedCms = new(contentInfo, true);
CmsSigner cmsSigner = new(cert);
signedCms.ComputeSignature(cmsSigner, true);
byte[] pk = signedCms.Encode();
byte[] outc = new byte[intCSize];
PdfDictionary dic2 = new();
Array.Copy(pk, 0, outc, 0, pk.Length);
dic2.Put(PdfName.CONTENTS, new PdfString(outc).SetHexWriting(true));
sap.Close(dic2);
return output.ToArray();
}
}
}
// Как используем: ... Код: foreach (var cert in certificates)
{
Log.Write(LogEventLevel.Information, "Подписываем документ сертификатом {Certificate}", cert.Thumbprint);
signedPdf = _signService.Sign(cert.Thumbprint, signedPdf, signNumber);
if (signedPdf.Any())
Log.Write(LogEventLevel.Information, "Документ был подписан сертификатом {Certificate}", cert.Thumbprint);
signNumber++;
}
После того как подписали всеми сертификатами, signedPdf сохраняем в файл документ сохраняет и в нем 2 подписи, но первая дефектная, подскажите пожалуйста, что я делаю не так. errr.png (60kb) загружен 31 раз(а).Отредактировано пользователем 2 июня 2023 г. 15:01:49(UTC)
| Причина: Не указана
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 18.05.2023(UTC) Сообщений: 7
Сказал(а) «Спасибо»: 2 раз
|
rrrr.png (71kb) загружен 17 раз(а).
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 18.05.2023(UTC) Сообщений: 7
Сказал(а) «Спасибо»: 2 раз
|
Проблема решилась следующим образом: строчку PdfStamper st = PdfStamper.CreateSignature(reader, output, '\0'); меняем на PdfStamper st = PdfStamper.CreateSignature(reader, output, '\0', null, true); 4 параметр в метод отвечает за то, что подпись присоединяется в режиме добавления
|
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close