【问题标题】:Itext 5.5 + Hwcrypto.js on adding signature "Document has been altered or corrupted since it was signed"Itext 5.5 + Hwcrypto.js 关于添加签名“文档自签名以来已被更改或损坏”
【发布时间】:2016-09-16 11:30:17
【问题描述】:

我正在尝试通过 HWCryto - https://github.com/open-eid/hwcrypto.js/wiki/ModernAPI - 在 Struts2 应用程序中添加对数字签名的支持。 首先尝试遵循 Bruno Lowagie 的书,我创建了一个空签名

    CertificateFactory certFactory;
    try {
        certFactory = CertificateFactory.getInstance("X.509");
        ByteArrayInputStream in = new ByteArrayInputStream(certDecoded);
        cert = (X509Certificate) certFactory.generateCertificate(in);
    } catch (CertificateException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    Calendar cal = Calendar.getInstance();

    int estimatedSize = 8192;

    PdfSignatureAppearance sap = pdfStamper.getSignatureAppearance();

    sap.setVisibleSignature("sig");
    sap.setCertificate(cert);
    sap.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
    sap.setSignDate(cal);
    ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE,
            PdfName.ADBE_PKCS7_DETACHED);

    try {
        MakeSignature.signExternalContainer(sap, external, 8192);
        pdfStamper.close();
        pdfReader.close();
    } catch (GeneralSecurityException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (DocumentException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

之后我得到 pdf 输出并创建一个新的哈希,我将发送到智能卡

byte [] alteredPDF=output.toByteArray();


    ExternalDigest externalDigest = new ExternalDigest() {
        @Override
        public MessageDigest getMessageDigest(String hashAlgorithm) throws GeneralSecurityException {
            return DigestAlgorithms.getMessageDigest(hashAlgorithm, "BC");
        }
    };
    PdfSignatureAppearance sapFinal = null;
    try {
        ByteArrayOutputStream outputFinal = new ByteArrayOutputStream();
        pdfReader = new PdfReader(new ByteArrayInputStream(alteredPDF));
        pdfStamper = PdfStamper.createSignature(pdfReader, outputFinal, '\0');
        sapFinal = pdfStamper.getSignatureAppearance();
        sapFinal.setVisibleSignature("sig");
        sapFinal.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
        sapFinal.setCertificate(cert);
        sapFinal.setSignDate(cal);

        PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
        dic.setReason(sap.getReason());
        dic.setLocation(sap.getLocation());
        String certInfo = cert.getSubjectX500Principal().getName();
        dic.setName(certInfo.substring(certInfo.indexOf("CN=") + 3,
                certInfo.indexOf(",OU", certInfo.indexOf("CN=") + 3)));
        dic.setSignatureCreator(sap.getSignatureCreator());
        dic.setContact(sap.getContact());
        dic.setCert(certDecoded);
        dic.setDate(new PdfDate(sap.getSignDate()));
        sapFinal.setCryptoDictionary(dic);

        HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
        exc.put(PdfName.CONTENTS, new Integer(estimatedSize * 2 + 2));
        sapFinal.preClose(exc);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (DocumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }catch(Exception e){
        e.printStackTrace();
    }


    byte[] sh = null;
    byte[] hashVal = null;
    PdfPKCS7 sgn = null;



    try {
        sgn = new PdfPKCS7(null, new Certificate[] { cert }, "SHA256", null, externalDigest, false);

        InputStream data = sapFinal.getRangeStream();
        hashVal = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
        sh = sgn.getAuthenticatedAttributeBytes(hashVal, cal, null, null, CryptoStandard.CMS);
        sh = MessageDigest.getInstance("SHA256", "BC").digest(sh);

    } catch (IOException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchProviderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (GeneralSecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

终于有了生成的签名

        sgn.setExternalDigest(sig, null, "RSA");
        byte[] encodedSign = null;

        try {
            System.out.println(Arrays.toString(Hex.decodeHex(hash.toCharArray())));
            encodedSign = sgn.getEncodedPKCS7(Hex.decodeHex(hash.toCharArray()), cal, null, null, null,
                    CryptoStandard.CMS);
        } catch (DecoderException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        try {
            MakeSignature.signDeferred(pdfReader, "sig", output,
                    new MyExternalSignatureContainer(encodedSign));
        } catch (DocumentException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (GeneralSecurityException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        System.out.println("called sign pdf");

        try {
            FileOutputStream outputStream = new FileOutputStream("d:\\debug.pdf");
            output.writeTo(outputStream);
            output.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

谁能指出我做错了什么?

【问题讨论】:

  • 这些代码是如何交互的?特别是,哪些PdfStamper 输出用作PdfReaders 的输入?流程不清楚。
  • 首先感谢您的意见。有两个 pdfStampers 。第一个用于创建空签名,然后我根据包含空签名的新 pdf 创建一个新签名。第一个阅读器将原始 pdf 的字节作为参数,第二个阅读器将“alteredPDF”的字节作为参数。

标签: java struts2 itext digital-signature signature


【解决方案1】:

终于解决了我的问题。将空签名存储到 PDF 中并重新创建输出流是罪魁祸首。设法从头到尾使用相同的输出流并且它有效。 这个链接 - https://github.com/sueastside/BEIDSign/blob/master/beidsign-service/src/main/java/be/redtree/beid/services/SignatureServiceImpl.java -肯定帮助了我。 感谢 mkl 抽出宝贵时间。

【讨论】:

    猜你喜欢
    • 2021-06-20
    • 1970-01-01
    • 2023-04-03
    • 2018-12-04
    • 1970-01-01
    • 2021-05-11
    • 2021-11-06
    • 1970-01-01
    • 2021-02-22
    相关资源
    最近更新 更多