首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iTextSharp -如何获取PDF内容以供签名,然后在稍后时间进行签名

iTextSharp -如何获取PDF内容以供签名,然后在稍后时间进行签名
EN

Stack Overflow用户
提问于 2016-09-13 15:01:56
回答 1查看 9.5K关注 0票数 3

我正在开发一个客户端服务器应用程序,客户端必须使用他们的签名签署PDF文档并将它们上传到服务器。由于客户端没有将签名嵌入到PDF中的方法,客户端只能读取原始字节并以原始字节的形式生成签名,这使得任务变得更加复杂。

我正在尝试实现以下工作流:

  1. 客户端将未签名的PDF上载到服务器。
  2. 服务器打开PDF,提取客户机需要签名的字节,并将这些字节发回。
  3. 客户端接收这些字节,使用客户端证书对它们签名,并将签名发送到服务器。
  4. 服务器将接收到的签名嵌入到它先前收到的PDF中。

我发现了一些提取字节的代码示例来对签名字节进行签名并将签名字节嵌入到PDF (这是我使用的主要示例)中。

问题是,这个示例在一个程序中执行所有步骤,它在不关闭PdfStamper的情况下获得文档哈希后立即嵌入签名。我需要的是在添加签名字段和获取sha.Hash之后保存文档,然后在稍后的某个时间(当服务器接收到计算的签名时)打开文档并将签名值嵌入到PDF中。

您能建议一种方法来修改这段代码,以便步骤(2)和(4)可以独立,并且不需要PdfReaderPdfStamper的共享实例。

EN

回答 1

Stack Overflow用户

发布于 2016-09-14 08:04:48

下面的答案摘自我们关于数字签名的白皮书,第4章4.3.3节使用在客户端上创建的签名在服务器上签名。代码示例这里

所需的工作流可看作是三个主要步骤:

  1. 预告牌: 要求: pdf,证书链 服务器端,设置签名基础结构,提取消息摘要并将摘要作为字节数组发送到客户端。
  2. 签名: 必需:消息摘要作为字节数组,私钥 客户端,将加密算法应用于消息摘要以从散列生成签名摘要,并将此签名发送到服务器。
  3. 邮戳:必需:签名摘要作为字节数组,pdf服务器端将签名摘要插入准备好的签名中,将签名插入pdf文档中

代码示例,iText5和C#:

预签名(服务器)

代码语言:javascript
复制
//hello : 
//location of the pdf on the server
//or
//bytestream variable with teh pdf loaded in
//chain: certificate chain
// we create a reader and a stamper
PdfReader reader = new PdfReader(hello);
Stream baos = new MemoryStream();
PdfStamper stamper = PdfStamper.CreateSignature(reader,  baos., '\0');
// we create the signature appearance
PdfSignatureAppearance sap = stamper.SignatureAppearance;
sap.Reason = "Test";
sap.Location = "On a server!";
sap.SetVisibleSignature ( new Rectangle(36, 748, 144, 780), 1, "sig");
sap.Certificate = chain[0];
// we create the signature infrastructure
PdfSignature dic = new PdfSignature(
PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.Reason = sap.Reason;
dic.Location = sap.Location;
dic.Contact = sap.Contact;
dic.Date = new PdfDate(sap.SignDate);
sap.CryptoDictionary = dic;
Dictionary<PdfName, int> exc = new Dictionary<PdfName, int>();
exc.Add(PdfName.CONTENTS, (int)(8192 * 2 + 2));
sap.PreClose(exc);
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", false);
//Extract the bytes that need to be signed
Stream data = sap.GetRangeStream();
byte[] hash = DigestAlgorithms.Digest(data,"SHA256");
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash,null, null, CryptoStandard.CMS);
//Store sgn, hash,sap and baos on the server
//...
//Send sh to client

签名(客户端)

代码语言:javascript
复制
// we receive a hash that needs to be signed
Stream istream = response.GetResponseStream();
MemoryStream baos = new MemoryStream();
data = new byte[0x100];
while ((read = istream.Read(data, 0, data.Length)) != 0)  
    baos.Write(data, 0, read);  
istream.Close();
byte[] hash = baos.ToArray();

// we load our private key from the key store
Pkcs12Store store = new Pkcs12Store(new FileStream(KEYSTORE, FileMode.Open), PASSWORD);
String alias = "";
// 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);

// we sign the hash received from the server
ISigner sig = SignerUtilities.GetSigner("SHA256withRSA");
sig.Init(true, pk.Key);
sig.BlockUpdate(hash, 0, hash.Length);
data = sig.GenerateSignature();

// we make a connection to the PostSign Servlet
request = (HttpWebRequest)WebRequest.Create(POST);
request.Headers.Add(HttpRequestHeader.Cookie,cookies.Split(";".ToCharArray(), 2)[0]);
request.Method = "POST";
// we upload the signed bytes
os = request.GetRequestStream();
os.Write(data, 0, data.Length);
os.Flush();
os.Close();

邮戳(服务器)

代码语言:javascript
复制
// we read the signed bytes
MemoryStream baos = new MemoryStream();
Stream InputStream iStream = req.GetInputStream();
int read;
byte[] data = new byte[256];
while ((read = iStream.read(data, 0, data.Length)) != -1) {
    baos.Write(data, 0, read);
}
// we complete the PDF signing process
sgn.SetExternalDigest(baos.ToArray(), null, "RSA");
byte[] encodedSig = sgn.getEncodedPKCS7(hash, cal, null,
null, null, CryptoStandard.CMS);
byte[] paddedSig = new byte[8192];
paddedSig.
encodedSig.CopyTo(paddedSig, 0);
PdfDictionary dic2 = new PdfDictionary();
dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true));
try
{
    sap.close(dic2);
}
catch (DocumentException e)
{
    throw new IOException(e);
}

我省略了大多数客户端-服务器通信代码,并将重点放在签名逻辑上。我也没有对这些代码片段进行彻底的测试,因为我必须从java代码中转换它们,而且我目前还没有一个客户端服务器设置来测试它们,所以复制并运行都是您自己的风险。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39473244

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档