Itext签名PDF哈希。代码错误0x2727

时间:2016-03-31 14:47:02

标签: java pdf hash cryptography itext

我在数字签名pdf哈希时遇到问题。这是我发现的实施和解决方案,它基于Bruno Lewagie的PDF文档数字签名。我们的想法是签署PDF哈希以避免将其带到客户端。 这是我提出的解决方案:

1。一个Applet Java,我用它来实例化一个令牌,获取它,然后访问它。

2。我用来获取我要签名的PDF的哈希的servlet java。我使用从applet获得的公钥来计算哈希值。获得此哈希后,我将其发送到applet(客户端)以使其签名。

小程序对生成的PDF哈希进行签名,然后将其返回到servlet,以插入到生成的PDF中并保存在给定目录中。 起初,它似乎可以正常工作,但在完成该过程并使用任何阅读器打开PDF后,我收到以下错误:“内部加密错误。错误代码:0x2727”。 值得一提的是,当我创建PDF并仅使用applet对其进行签名时,签名已正确验证。

代码: 与令牌交互并调用servlet - >

的Applet
public void clientCallServlet(Certificate[] chain, PrivateKey pk) {
// Send to servlet cert
  ObjectOutputStream out = new ObjectOutputStream(aConnection.getOutputStream());
  out.writeObject(chain[0]);
  out.flush();
  out.close();

  List<String> cookies = aConnection.getHeaderFields().get("Set-Cookie");
  // received hash pdf from servlet       
  InputStream is = aConnection.getInputStream();
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  byte[] data = new byte[256];
  int read;
  while ((read = is.read(data, 0, data.length)) != -1) {
    baos.write(data, 0, read);
  }
  is.close();
  // Sign bytes hash received
  Signature sig = Signature.getInstance("SHA1withRSA");
  sig.initSign(pk);
  sig.update(baos.toByteArray());
  data = sig.sign();
  // End to sign 

  // send signed hash to servlet (second step)
    ...
    ...
  // Write the signed bytes received from servlet  in a PDF 
  File someFile = new File("c:/test1.pdf");
  OutputStream fos = new FileOutputStream(someFile);
  ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
  byte[] data1 = new byte[256];
  int read1;
  while ((read1 = retornoFirmado.read(data1)) != -1) {
    baos1.write(data1, 0, read1);
  }
  retornoFirmado.close();
  byte[] firmado = baos1.toByteArray();

  fos.write(firmado);
  fos.flush();
  fos.close();

}

Servlet在收到证书的公钥后(由applet发送)读取PDF并计算其哈希值以将其返回给applet。

protected void doPost(HttpServletRequest request, HttpServletResponse response){
response.setContentType("application/octet-stream");
ObjectInputStream resultStream = null;
  resultStream = new ObjectInputStream(request.getInputStream());
  Certificate[] chain = new Certificate[1];
  chain[0] = (Certificate) resultStream.readObject();
  resultStream.close();

  PdfReader reader = new PdfReader("c:/test.pdf");
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');

  PdfSignatureAppearance sap = stamper.getSignatureAppearance();
  sap.setReason("Test");
  sap.setLocation("On a server!");
  sap.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
  sap.setCertificate(chain[0]);
  PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
  dic.setReason(sap.getReason());
  dic.setLocation(sap.getLocation());
  dic.setContact(sap.getContact());
  dic.setDate(new PdfDate(sap.getSignDate()));
  sap.setCryptoDictionary(dic);
  HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
  exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
  sap.preClose(exc);
  // ExternalDigest digest = new BouncyCastleDigest();

  ExternalDigest externalDigest = new ExternalDigest() {

    @Override
    public MessageDigest getMessageDigest(String hashAlgorithm) throws GeneralSecurityException {
      return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
    }
  };
  PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA1", null, externalDigest, false);
  InputStream data = sap.getRangeStream();
  byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("RSA"));
  Calendar cal = Calendar.getInstance();

  byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
  HttpSession session = request.getSession(true);
  session.setAttribute("sgn", sgn);
  session.setAttribute("hash", hash);
  session.setAttribute("cal", cal);
  session.setAttribute("sap", sap);
  session.setAttribute("baos", baos);
  OutputStream os = response.getOutputStream();
  os.write(sh, 0, sh.length);
  os.flush();
  os.close();   }

签署PDF后,再次从applet调用servlet,在生成的PDF - &gt;

中插入签名的哈希值
protected void doPost(HttpServletRequest request, HttpServletResponse response){
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setContentType("application/pdf");
HttpSession session = request.getSession(false);
PdfPKCS7 sgn = (PdfPKCS7) session.getAttribute("sgn");
byte[] hash = (byte[]) session.getAttribute("hash");
Calendar cal = (Calendar) session.getAttribute("cal");
PdfSignatureAppearance sap = (PdfSignatureAppearance) session.getAttribute("sap");
ByteArrayOutputStream os = (ByteArrayOutputStream) session.getAttribute("baos");
session.invalidate();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = request.getInputStream();
int read;
byte[] data = new byte[256];
while ((read = is.read(data, 0, data.length)) != -1) {
  baos.write(data, 0, read);
}
sgn.setExternalDigest(baos.toByteArray(), null, "RSA");
byte[] encodedSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
byte[] paddedSig = new byte[8192];
System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);
PdfDictionary dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
try {
  sap.close(dic2);
} catch (DocumentException e) {
  throw new IOException(e);
}
byte[] pdf = os.toByteArray();
//test save sign pdf
OutputStream out = new FileOutputStream("c:/out1.pdf");
out.write(pdf);
out.close();
OutputStream sos = response.getOutputStream();
sos.write(pdf, 0, pdf.length);
sos.flush();
sos.close();

这些是我使用的库的版本:

  • itextpdf - &gt; 5.5.6
  • bcprov.jdk15on.1.54
  • jdk1.7

0 个答案:

没有答案