iTextSharp签署在MemoryStream中创建的PDF

时间:2014-11-19 14:22:50

标签: c# pdf itextsharp digital-signature

我需要动态创建PDF文件,因此我使用MemoryStream和iTextSharp来编辑PDF。但我想在将PDF文件发送到浏览器之前对其进行数字签名。我在一个示例项目中看到iTextSharp有一个PDFSigner类,它主要完成所有工作。但正如我所见,它的工作原理如下:

PDFSigner signer = new PDFSigner(inputFileName, outputFileName, certificate, metaData);
signer.Sign(......)

但是使用MemoryStream,我也无法为输入或输出提供物理文件名。我的代码如下:

MemoryStream memoryStream = new MemoryStream();
var document = new Document(iTextSharp.text.PageSize.LETTER, 40, 40, 60, 40);
PdfWriter.GetInstance(document, memoryStream).CloseStream = false;

document.Open();
PopulatePDF(document, someId);
document.Close();

byte[] byteArray = memoryStream.ToArray();

memoryStream.Write(byteArray, 0, byteArray.Length);
memoryStream.Position = 0;

return new FileStreamResult(memoryStream, "application/pdf");

我的问题是如何使用PDFSigner对象对文档进行签名,使PDFSigner只接受字符串 - 文件名作为参数。

1 个答案:

答案 0 :(得分:2)

正如Chris Haas所解释的那样,iText中没有名为PdfSigner的类。您可能正在使用iText的非官方版本,在这种情况下,您需要确保正确应用数字签名。

您可以在我撰写的关于digital signatures的书中阅读有关正确数字签名的更多信息。

基本上,这就是你使用PKCS#12密钥库签名的方式:

Pkcs12Store store = new Pkcs12Store(new FileStream(KEYSTORE, FileMode.Open), PASSWORD);
String alias = "";
ICollection<X509Certificate> chain = new List<X509Certificate>();
// searching for private key
foreach (string al in store.Aliases)
    if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate) {
        alias = al;
        break;
    }
AsymmetricKeyEntry pk = store.GetKey(alias);
foreach (X509CertificateEntry c in store.GetCertificateChain(alias))
    chain.Add(c.Certificate);
RsaPrivateCrtKeyParameters parameters = pk.Key as RsaPrivateCrtKeyParameters;

PdfReader reader = new PdfReader(src);
FileStream os = new FileStream(dest, FileMode.Create);
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Reason = "My reason for signing";
appearance.Location = "The middle of nowhere";
appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
IExternalSignature pks = new PrivateKeySignature(parameters, DigestAlgorithms.SHA256);
MakeSignature.SignDetached(appearance, pks, chain, null, null, null, 0, CryptoStandard.CMS);

显然,您希望将null值替换为获取吊销信息的实现,甚至可以允许时间戳,但这不是您的问题。

您的问题是:我可以提供仅存在于内存中的PDF吗?答案是肯定的:创建src实例时PdfReader参数可以是磁盘上文件的路径,但它也可以是byte[]从{{1}获得的}}