Pdf подпись
Дополнительно требуется 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];
Gost3410CryptoServiceProvider cert_key;
if (args.Length > 2)
{
//set password.
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);
}
}
}
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());
CpSignedCms signedCms = new CpSignedCms(contentInfo, true);
CpCmsSigner cmsSigner = new CpCmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificate, cert_key);
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;
}
}
}