Itext 5.5 + Hwcrypto.js添加签名“文档自签名后已被更改或损坏”

时间:2016-05-19 14:05:14

标签: java struts2 itext digital-signature signature

我正在尝试通过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();
    }

最后生成了sig

        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();
        }

有谁能请我指出我做错了什么?

1 个答案:

答案 0 :(得分:1)

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