生成电子签工具类

具体代码
一共分为重要的几个工具类

**1.这个是对字节数组字符串进行Base64解码并生成图片
前端生成签名 ,应该是base64的需要转换成图片 **

package com.hegao.pdos.pdf_update;

import sun.misc.BASE64Decoder;

import java.io.FileOutputStream;
import java.io.OutputStream;

/**
 * Created by huasheng on 2020/8/30.
 */
public class Base64Transformation {
    public static boolean GenerateImage(String imgStr, String imgFilePath) {// 对字节数组字符串进行Base64解码并生成图片
        if (imgStr == null) // 图像数据为空
            return false;
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            // Base64解码
            byte[] bytes = decoder.decodeBuffer(imgStr);
            for (int i = 0; i < bytes.length; ++i) {
                if (bytes[i] < 0) {// 调整异常数据
                    bytes[i] += 256;
                }
            }
            // 生成jpeg图片
            OutputStream out = new FileOutputStream(imgFilePath);
            out.write(bytes);
            out.flush();
            out.close();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static void main(String[] args) {
        // 测试从Base64编码转换为图片文件
        String strImge = "";
        GenerateImage("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", "11.jpg");
        // 测试从图片文件转换为Base64编码
        // System.out.println(GetImageStr("d:\\11.jpg"));
    }
}

**2. 电子签章的pom **


<!--        电子签章-->
        <!--<dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.56</version>
        </dependency>-->
        <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.57</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcmail-jdk16 -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcmail-jdk15on</artifactId>
            <version>1.56</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13.1</version>
        </dependency>

3.

package com.hegao.pdos.pdf_update;

public class Extension {
    private String oid;

    private boolean critical;

    private byte[] value;

    public String getOid() {
        return oid;
    }

    public byte[] getValue() {
        return value;
    }
    public boolean isCritical() {
        return critical;
    }

}

4. 模板生成的pdf 和之后加完数据,生成的新的pdf 路径

package com.hegao.pdos.pdf_update;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.AcroFields.Item;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;

public class PDFUtils {


    /**
     * @param fields
     * @param data
     * @throws IOException
     * @throws DocumentException
     */
    private static void fillData(AcroFields fields, Map<String, String> data) throws IOException, DocumentException {
        List<String> keys = new ArrayList<String>();
        Map<String, Item> formFields = fields.getFields();
        for (String key : data.keySet()) {
            if(formFields.containsKey(key)){
                String value = data.get(key);
                fields.setField(key, value); // 为字段赋值,注意字段名称是区分大小写的
                keys.add(key);
            }
        }
        Iterator<String> itemsKey = formFields.keySet().iterator();
        while(itemsKey.hasNext()){
            String itemKey = itemsKey.next();
            if(!keys.contains(itemKey)){
                fields.setField(itemKey, " ");
            }
        }
    }

    /**
     * @param templatePdfPath
     *            模板pdf路径
     * @param generatePdfPath
     *            生成pdf路径
     * @param data
     *            数据
     */
    public static String generatePDF(String templatePdfPath, String generatePdfPath, Map<String, String> data) {
        OutputStream fos = null;
        ByteArrayOutputStream bos = null;
        try {
            PdfReader reader = new PdfReader(templatePdfPath);
            bos = new ByteArrayOutputStream();
            /* 将要生成的目标PDF文件名称 */
            PdfStamper ps = new PdfStamper(reader, bos);
            /* 使用中文字体 */
            BaseFont bf =BaseFont.createFont("C:/WINDOWS/Fonts/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            ArrayList<BaseFont> fontList = new ArrayList<BaseFont>();
            fontList.add(bf);
            /* 取出报表模板中的所有字段 */
            AcroFields fields = ps.getAcroFields();
            fields.setSubstitutionFonts(fontList);
            fillData(fields, data);
            /* 必须要调用这个,否则文档不会生成的  如果为false那么生成的PDF文件还能编辑,一定要设为true*/
            ps.setFormFlattening(true);
            ps.close();
            fos = new FileOutputStream(generatePdfPath);
            fos.write(bos.toByteArray());
            fos.flush();
            return generatePdfPath;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static void main(String[] args) {
        Map<String, String> data = new HashMap<String, String>();
        //key为pdf模板的form表单的名字,value为需要填充的值
        data.put("test123", "尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方,尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方,尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方\r\n尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方,尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方,尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方\r\n" +
                "尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方,尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方,尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方\r\n" +
                "尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方,尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方,尽量呆在通风较好的地方,保持空气流通,有利于病情康复。尽量呆在通风较好的地方");
        generatePDF("D:\\company\\seeDoctor\\pdos-admin\\target\\pdos-admin\\\\upload\\TEST.pdf",
                "D:\\company\\seeDoctor\\pdos-admin\\target\\pdos-admin\\\\upload\\TEST1.pdf", data );

//
//        generatePDF("C:/Users/huasheng/Desktop/脑血栓合同050脑血栓合同577.pdf",
//                "C:/Users/huasheng/Desktop/999.pdf", data );
    }
}

5.生成证书接口

package com.hegao.pdos.pdf_update;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

public class Pkcs {

    private static KeyPair getKey() throws NoSuchAlgorithmException {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA",
                new BouncyCastleProvider());
        generator.initialize(1024);
        // 证书中的密钥 公钥和私钥
        KeyPair keyPair = generator.generateKeyPair();
        return keyPair;
    }

    /**
     * @param password
     *            密码
     * @param issuerStr 颁发机构信息
     *
     * @param subjectStr 使用者信息
     *
     * @param certificateCRL 颁发地址
     *
     * @return
     */
    public static Map<String, byte[]> createCert(String password,
                                                 String issuerStr, String subjectStr, String certificateCRL) {
        Map<String, byte[]> result = new HashMap<String, byte[]>();
        ByteArrayOutputStream out = null;
        try {
            // 生成JKS证书
            // KeyStore keyStore = KeyStore.getInstance("JKS");
            // 标志生成PKCS12证书
            KeyStore keyStore = KeyStore.getInstance("PKCS12",
                    new BouncyCastleProvider());
            keyStore.load(null, null);
            KeyPair keyPair = getKey();
            // issuer与 subject相同的证书就是CA证书
            Certificate cert = generateCertificateV3(issuerStr, subjectStr,
                    keyPair, result, certificateCRL, null);
            // cretkey随便写,标识别名
            keyStore.setKeyEntry("cretkey", keyPair.getPrivate(),
                    password.toCharArray(), new Certificate[] { cert });
            out = new ByteArrayOutputStream();
            cert.verify(keyPair.getPublic());
            keyStore.store(out, password.toCharArray());
            byte[] keyStoreData = out.toByteArray();
            result.put("keyStoreData", keyStoreData);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }
        }
        return result;
    }

    /**
     * @param issuerStr
     * @param subjectStr
     * @param keyPair
     * @param result
     * @param certificateCRL
     * @param extensions
     * @return
     */
    public static Certificate generateCertificateV3(String issuerStr,
                                                    String subjectStr, KeyPair keyPair, Map<String, byte[]> result,
                                                    String certificateCRL, List<Extension> extensions) {
        ByteArrayInputStream bout = null;
        X509Certificate cert = null;
        try {
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();
            Date notBefore = new Date();
            Calendar rightNow = Calendar.getInstance();
            rightNow.setTime(notBefore);
            // 日期加1年
            rightNow.add(Calendar.YEAR, 1);
            Date notAfter = rightNow.getTime();
            // 证书序列号
            BigInteger serial = BigInteger.probablePrime(256, new Random());
            X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
                    new X500Name(issuerStr), serial, notBefore, notAfter,
                    new X500Name(subjectStr), publicKey);
            JcaContentSignerBuilder jBuilder = new JcaContentSignerBuilder(
                    "SHA1withRSA");
            SecureRandom secureRandom = new SecureRandom();
            jBuilder.setSecureRandom(secureRandom);
            ContentSigner singer = jBuilder.setProvider(
                    new BouncyCastleProvider()).build(privateKey);
            // 分发点
            ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier(
                    "2.5.29.31");
            GeneralName generalName = new GeneralName(
                    GeneralName.uniformResourceIdentifier, certificateCRL);
            GeneralNames seneralNames = new GeneralNames(generalName);
            DistributionPointName distributionPoint = new DistributionPointName(
                    seneralNames);
            DistributionPoint[] points = new DistributionPoint[1];
            points[0] = new DistributionPoint(distributionPoint, null, null);
            CRLDistPoint cRLDistPoint = new CRLDistPoint(points);
            builder.addExtension(cRLDistributionPoints, true, cRLDistPoint);
            // 用途
            ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier(
                    "2.5.29.15");
            // | KeyUsage.nonRepudiation | KeyUsage.keyCertSign
            builder.addExtension(keyUsage, true, new KeyUsage(
                    KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
            // 基本限制 X509Extension.java
            ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier(
                    "2.5.29.19");
            builder.addExtension(basicConstraints, true, new BasicConstraints(
                    true));
            // privKey:使用自己的私钥进行签名,CA证书
            if (extensions != null)
                for (Extension ext : extensions) {
                    builder.addExtension(
                            new ASN1ObjectIdentifier(ext.getOid()),
                            ext.isCritical(),
                            ASN1Primitive.fromByteArray(ext.getValue()));
                }
            X509CertificateHolder holder = builder.build(singer);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            bout = new ByteArrayInputStream(holder.toASN1Structure()
                    .getEncoded());
            cert = (X509Certificate) cf.generateCertificate(bout);
            byte[] certBuf = holder.getEncoded();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            // 证书数据
            result.put("certificateData", certBuf);
            //公钥
            result.put("publicKey", publicKey.getEncoded());
            //私钥
            result.put("privateKey", privateKey.getEncoded());
            //证书有效开始时间
            result.put("notBefore", format.format(notBefore).getBytes("utf-8"));
            //证书有效结束时间
            result.put("notAfter", format.format(notAfter).getBytes("utf-8"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bout != null) {
                try {
                    bout.close();
                } catch (IOException e) {
                }
            }
        }
        return cert;
    }

    public static void main(String[] args) throws Exception{
        // CN: 名字与姓氏    OU : 组织单位名称
        // O :组织名称  L : 城市或区域名称  E : 电子邮件
        // ST: 州或省份名称  C: 单位的两字母国家代码
        String issuerStr = "CN=在线医院,OU=gitbook研发部,O=gitbook有限公司,C=CN,E=gitbook@sina.com,L=北京,ST=北京";
        String subjectStr = "CN=huangjinjin,OU=gitbook研发部,O=gitbook有限公司,C=CN,E=huangjinjin@sina.com,L=北京,ST=北京";
        String certificateCRL  = "https://gitbook.cn";
        Map<String, byte[]> result = createCert("123456", issuerStr, subjectStr, certificateCRL);

        FileOutputStream outPutStream = new FileOutputStream("C:/Users/Administrator/Desktop/keystore.p12"); // ca.jks
        outPutStream.write(result.get("keyStoreData"));
        outPutStream.close();
        FileOutputStream fos = new FileOutputStream(new File("C:/Users/Administrator/Desktop/keystore.cer"));
        fos.write(result.get("certificateData"));
        fos.flush();
        fos.close();
    }
}

6对已经签章的signed.pdf文件再次签章,这次是高清签章

package com.hegao.pdos.pdf_update;

import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.itextpdf.awt.AsianFontMapper;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfStream;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PrivateKeySignature;


public class SignHighPdf {

    /**
     * @param password
     *            秘钥密码
     * @param keyStorePath
     *            秘钥文件路径
     * @param signPdfSrc
     *            签名的PDF文件
     * @param x
     *
     * @param y
     * @return
     */
    public static byte[] sign(String password, String keyStorePath, String signPdfSrc,
                              float x, float y,
                              String signText) {
        File signPdfSrcFile = new File(signPdfSrc);
        PdfReader reader = null;
        ByteArrayOutputStream signPDFData = null;
        PdfStamper stp = null;
        FileInputStream fos = null;
        try {
            BouncyCastleProvider provider = new BouncyCastleProvider();
            Security.addProvider(provider);
            KeyStore ks = KeyStore.getInstance("PKCS12", new BouncyCastleProvider());
            fos = new FileInputStream(keyStorePath);
            ks.load(fos, password.toCharArray()); // 私钥密码
            String alias = (String) ks.aliases().nextElement();
            PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
            Certificate[] chain = ks.getCertificateChain(alias);
            reader = new PdfReader(signPdfSrc);
            signPDFData = new ByteArrayOutputStream();
            // 临时pdf文件
            File temp = new File(signPdfSrcFile.getParent(), System.currentTimeMillis() + ".pdf");
            stp = PdfStamper.createSignature(reader, signPDFData, '\0', temp, true);
            PdfSignatureAppearance sap = stp.getSignatureAppearance();
            sap.setReason("数字签名,不可改变");
            // 是对应x轴和y轴坐标
            sap.setVisibleSignature(new Rectangle(x, y, x + 150, y + 65), 1,
                    "sr"+String.valueOf(System.nanoTime()));
            //layer 0 Creating the appearance for layer 0
            PdfTemplate n0 = sap.getLayer(0);
            n0.reset();
            float lx = n0.getBoundingBox().getLeft();
            float by = n0.getBoundingBox().getBottom();
            float width = n0.getBoundingBox().getWidth();
            float height = n0.getBoundingBox().getHeight();
            n0.setRGBColorFill(255, 0, 0);
            n0.rectangle(lx, by, 5, height);
            n0.rectangle(lx, by, width, 5);
            n0.rectangle(lx, by+height-5, width, 5);
            n0.rectangle(lx+width-5, by, 5, height);
            n0.fill();
            ///layer 2
            PdfTemplate n2 = sap.getLayer(2);
            n2.setCharacterSpacing(0.0f);
            ColumnText ct = new ColumnText(n2);
            ct.setSimpleColumn(n2.getBoundingBox());
            n2.setRGBColorFill(255, 0, 0);
            //做一个占位的动作
            Paragraph p1 = new Paragraph(" ");
            BaseFont bf = BaseFont.createFont(AsianFontMapper.ChineseSimplifiedFont, AsianFontMapper.ChineseSimplifiedEncoding_H,
                    BaseFont.NOT_EMBEDDED);
            Font font1 = new Font(bf, 5, Font.BOLD, BaseColor.RED);
            Font font2 = new Font(bf, 13, Font.BOLD, BaseColor.RED);
            p1.setFont(font1);
            ct.addElement(p1);
            Paragraph p = new Paragraph(signText);
            p.setAlignment(Element.ALIGN_CENTER);
            p.setFont(font2);
            ct.addElement(p);
            ct.go();
            stp.getWriter().setCompressionLevel(PdfStream.BEST_COMPRESSION);
            ExternalDigest digest = new BouncyCastleDigest();
            ExternalSignature signature = new PrivateKeySignature(key, DigestAlgorithms.SHA512, provider.getName());
            MakeSignature.signDetached(sap, digest, signature, chain, null, null, null, 0, CryptoStandard.CADES);
            stp.close();
            reader.close();
            return signPDFData.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (signPDFData != null) {
                try {
                    signPDFData.close();
                } catch (IOException e) {
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        //对已经签章的signed.pdf文件再次签章,这次是高清签章
        byte[] fileData = sign("123456", "C:\\Users\\zhilin\\Desktop\\chat\\keystore.p12",//
                "C:\\Users\\zhilin\\Desktop\\chat\\signed.pdf", 350, 290, "华佗\n2017-12-20");
        FileOutputStream f = new FileOutputStream(new File("C:\\Users\\zhilin\\Desktop\\chat\\signed2.pdf"));
        f.write(fileData);
        f.close();
    }

}

7把签名当到PDF中

package com.hegao.pdos.pdf_update;

import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.UUID;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PrivateKeySignature;


public class SignPdf {
    /**
     * @param password
     *            秘钥密码
     * @param keyStorePath
     *            秘钥文件路径
     * @param signPdfSrc
     *            签名的PDF文件
     * @param signImage
     *            签名图片文件
     * @param x
     *            x坐标
     * @param y
     *            y坐标
     * @return
     */
    public static byte[] sign(String password, String keyStorePath, String signPdfSrc, String signImage,
                              float x, float y) {
        File signPdfSrcFile = new File(signPdfSrc);
        PdfReader reader = null;
        ByteArrayOutputStream signPDFData = null;
        PdfStamper stp = null;
        FileInputStream fos = null;
        try {
            BouncyCastleProvider provider = new BouncyCastleProvider();
            Security.addProvider(provider);
            KeyStore ks = KeyStore.getInstance("PKCS12", new BouncyCastleProvider());
            fos = new FileInputStream(keyStorePath);
            // 私钥密码 为Pkcs生成证书是的私钥密码 123456
            ks.load(fos, password.toCharArray());
            String alias = (String) ks.aliases().nextElement();
            PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
            Certificate[] chain = ks.getCertificateChain(alias);
            reader = new PdfReader(signPdfSrc);
            signPDFData = new ByteArrayOutputStream();
            // 临时pdf文件
            File temp = new File(signPdfSrcFile.getParent(), System.currentTimeMillis() + ".pdf");
            stp = PdfStamper.createSignature(reader, signPDFData, '\0', temp, true);
            stp.setFullCompression();
            PdfSignatureAppearance sap = stp.getSignatureAppearance();
            sap.setReason("数字签名,不可改变");
            // 使用png格式透明图片
            Image image = Image.getInstance(signImage);
            sap.setImageScale(0);
            sap.setSignatureGraphic(image);
            sap.setRenderingMode(RenderingMode.GRAPHIC);
            // 是对应x轴和y轴坐标
            sap.setVisibleSignature(new Rectangle(x, y, x + 185, y + 68), 1,
                    UUID.randomUUID().toString().replaceAll("-", ""));
            stp.getWriter().setCompressionLevel(5);
            ExternalDigest digest = new BouncyCastleDigest();
            ExternalSignature signature = new PrivateKeySignature(key, DigestAlgorithms.SHA512, provider.getName());
            MakeSignature.signDetached(sap, digest, signature, chain, null, null, null, 0, CryptoStandard.CADES);
            stp.close();
            reader.close();
            return signPDFData.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (signPDFData != null) {
                try {
                    signPDFData.close();
                } catch (IOException e) {
                }
            }

            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        byte[] fileData = sign("123456", "C:/Users/Administrator/Desktop/keystore.p12", //
                "D:\\company\\seeDoctor\\pdos-admin\\target\\pdos-admin\\upload\\2020\\9\\1\\049.pdf",
                "D:\\company\\seeDoctor\\pdos-admin\\target\\pdos-admin\\upload\\脑血栓合同049.jpg", 200, 290);
        FileOutputStream f = new FileOutputStream(new File("C:/Users/Administrator/Desktop/脑血栓合同571.pdf"));
        f.write(fileData);
        f.close();
    }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值