iText signing PDF using external signature with PKI SIM

蹲街弑〆低调 提交于 2020-01-14 06:18:04

问题


I am trying to use mobile signature service provider (MSSP) to sign the pdf file.

I used some code below to do. But the signature is invalid with the message "The document has been altered or corrupted since the signatures was applied."

Encode in "APWebService.sign(phoneNumber, messageDisplay, encode)" only accept 44 charracter.

Anyone can help me?

public class MyExternalSignatureContainer implements ExternalSignatureContainer {

    protected byte[] sig;
    protected Certificate[] chain;

    public static final String SRC = "/media/thanhpx1/MEDIA/FileCongVan.pdf";
    public static final String TEMP = "/media/thanhpx1/MEDIA/hello_changed.pdf";
    public static final String DEST_SIGN = "/media/thanhpx1/MEDIA/signed.pdf";

    public MyExternalSignatureContainer(byte[] sig, Certificate[] chain) {
        this.sig = sig;
        this.chain = chain;
    }

    public MyExternalSignatureContainer(Certificate[] chain) {
        this.chain = chain;
    }

    public byte[] sign(InputStream is) throws GeneralSecurityException {
        return sig;
    }

    public byte[] emptySignature_hash(String src, String dest, String fieldname, Certificate[] chain)
            throws IOException, DocumentException, GeneralSecurityException, java.io.IOException {
        PdfReader reader = new PdfReader(src);
        FileOutputStream os = new FileOutputStream(dest);
        PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
        PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
        appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, fieldname);
        appearance.setCertificate(chain[0]);
        ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
        MakeSignature.signExternalContainer(appearance, external, 8192);

        InputStream inp = appearance.getRangeStream();

        BouncyCastleDigest digest = new BouncyCastleDigest();

        byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
        return hash;
    }

    public byte[] signed_hash(byte[] hash, Certificate[] chain) throws GeneralSecurityException, MalformedURLException, java.io.IOException {
        BouncyCastleDigest digest = new BouncyCastleDigest();
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

        PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
        //hash.length=32
        byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);       
        //sh.length=77
        InputStream shInputStream = new ByteArrayInputStream(sh);
        byte[] signedAttributesHash = DigestAlgorithms.digest(shInputStream, digest.getMessageDigest("SHA256"));
        //signedAttributesHash.length=32
        String encode = com.itextpdf.io.codec.Base64.encodeBytes(signedAttributesHash);
        //encode have 44 characters
        String phoneNumber = "xxxxxxxxx";
        String messageDisplay = "Please sign this document";

        //Send to Application Provider WS
        String resultSign = APWebService.sign(phoneNumber, messageDisplay, encode);
        //resultSign = W5srXKNmRdXNd7uX/QsYhBPet8DOdO9A6F/Ku5ey5JoTatYEJVaEvXB7MjZ3w2W2tEetpZVfc0eFSmMwp/z3TZVX7JvjiN0uCjXgFtCCRr7ffm+jcbp2MEK4hJCCNoHawpjvVV1Qykcg1gerHQDaSSQhtrfJsxOVd0KUIgfIJeBmGMZMGerdz+snH9pe74fMlX+IuEp5Hhk0R6xuwL9vKFxvCVPyv/U6eRmlQmG/wIzr6IBIWET0JDNNgWjmq+jKL70hxZLakZU9Hqu1zKzpkS5jB+0UXMayjBldBuPF1rofgRJKsT8BJttQ8a/YYZr6Sw0X8m8Ah+yPCGTWunRUhA==

        byte[] signedHashValue = com.itextpdf.io.codec.Base64.decode(resultSign);
        sgn.setExternalDigest(signedHashValue, null, "RSA");
        return sgn.getEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);

    }

    public void createSignature(String src, String dest, String fieldname, byte[] hash,
            Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException, java.io.IOException {

        PdfReader reader = new PdfReader(src);
        FileOutputStream os = new FileOutputStream(dest);
        ExternalSignatureContainer external = new MyExternalSignatureContainer(hash, chain);
        MakeSignature.signDeferred(reader, fieldname, os, external);
    }

    public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException, java.io.IOException {

        String phoneNumber = "xxxxxxxx";

        //Call from Application Provider WS to get certificate
        GetCertDto certDto = APWebService.getCertInfo(phoneNumber);     
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        ByteArrayInputStream bytes = new ByteArrayInputStream(Base64.decodeBase64(certDto.getValue()));
        X509Certificate cert = (X509Certificate)certFactory.generateCertificate(bytes);     
        X509Certificate[] certArr = new X509Certificate[1];
        certArr[0] = cert;

        MyExternalSignatureContainer app = new MyExternalSignatureContainer(certArr);
        byte[] hh = app.emptySignature_hash(SRC, TEMP, "sig1", certArr);
        byte[] hh_sign = (app.signed_hash(hh, certArr));
        app.createSignature(TEMP, DEST_SIGN, "sig1", hh_sign, certArr);
        System.out.println("done");
    }

    @Override
    public void modifySigningDictionary(PdfDictionary signDic) {

    }
}

来源:https://stackoverflow.com/questions/59497941/itext-signing-pdf-using-external-signature-with-pki-sim

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!