자바 를 이용 하여 PDF 파일 에 전자 서명 을 하 는 실전 과정

38807 단어 자바pdf전자 서명
개술
인장 은 우리 나라 특유 의 역사 문화 산물 로 고대 에는 주로 신분증 과 직권 을 행사 하 는 도구 로 사용 되 었 다.그것 의 기원 은 사회 생활 의 실제 수요 때문이다.일찍이 상주 시대 에 인장 이 이미 생 겼 다.오늘날 의 인장 은 이미 독특 하고 실용성 과 예술성 을 하나 로 융합 시 킨 예술 보물 이 되 었 다.전통 적 인 인장 은 나 쁜 사람,소인 에 게 개인 적 으로 새 겨 지기 쉽다.어떤 개인 공인 이 국가 재산 을 착복 했다 는 보 도 는 드 물 었 다.컴퓨터 기술,암호 화 기술 과 영상 처리 기술 의 발전 에 따라 전자 서명 이 나 타 났 다.전자 서명 은 전자 서명 의 표현 형식 으로 이미지 처리 기술,디지털 암호 화 기술 을 이용 하여 전자 서명 작업 을 종이 파일 날인 작업 과 같은 시각 적 효과 로 전환 시 키 는 동시에 전자 서명 기술 을 이용 하여 전자 정보의 진실성 과 완전 성,서명 인의 부인 할 수 없 는 성 을 보장 한다.
전자 서명 은 디지털 인증서 와 마찬가지 로 인증 의 한 수단 으로 전자 형식 으로 존재 하고 전자 문서 에 의존 하 며 논리 적 으로 관련 되 며 전자 문서 서명 자의 신분 을 식별 하고 문서 의 완전 성 을 확보 하 며 서명 자가 전자 문서 가 진술 한 사실 에 동의 하 는 내용 을 말한다.일반적으로 전자 서명 에 대한 인정 은 기술적 인 측면 에서 볼 수 있다.특정 기술 방안 을 통 해 당사자 의 신분 을 감별 하고 전자 자료 내용 이 변조 되 지 않도록 하 는 안전 보장 조 치 를 말한다.전자 서명 은 항상 안전 이메일 발송,안전 사이트 방문,인터넷 입찰 입찰 입찰,인터넷 계약,안전 인터넷 공문 전송,회사 계약,전자 처방 용지 등 을 보낸다.
전자 서명 은 매우 복잡 한 문제 로 관련 전자 서명 시스템 이 있 을 정도 로 크다.전자 처방전 의 PDF 파일 에 전자 서명 을 적용 하 는 방법 을 공유 합 니 다.
2.기술 선택
현재 주류 처리 PDF 파일 두 jar 패 키 지 는 다음 과 같 습 니 다.
  • 아파 치 의 PDFBox,홈 페이지 오픈 소스https://pdfbox.apache.org/
  • 유명한 adobe 회사 의 iText,홈 페이지https://itextpdf.com/tags/adobe그 중에서 iText 는 iText 5 와 iText 7 로 나 뉜 다.
  • 어떻게 PDFBox,iText 5 와 iText 7 에서 자신의 프로젝트 에 적합 한 기술 을 선택 합 니까?
    PDFBox,iText 5,iText 7 세 가 지 를 비교 합 니 다.
  • PDFBox 의 기능 이 상대 적 으로 약 하고 iText 5 와 iText 7 의 기능 이 매우 강하 다.
  • iText 5 의 자료 인터넷 이 상대 적 으로 많 기 때문에 문제 가 발생 하면 해결 방안 을 찾기 쉽다.PDFBox 와 iText 7 의 인터넷 자료 가 상대 적 으로 적 고 문제 가 발생 하면 관련 해결 방안 을 찾기 어렵다.
  • PDFBox 코드 를 읽 고 현재 PDFBox 는 사용자 정의 서명 과 관련 된 인 터 페 이 스 를 제공 하지 않 았 습 니 다.iText 5 와 iText 7 은 사용자 정의 서명 처리 와 관련 된 실현 을 제공 합 니 다.
  • PDFBox 는 서명 사진 을 PDF 파일 에 추가 할 수 있 습 니 다.iText 5 와 iText 7 은 서명 사진 을 PDF 파일 에 추가 할 수 있 을 뿐만 아니 라 직접 서명 을 그 려 서 서명 에 파일 을 그 릴 수 있 습 니 다.
  • PDFBox 와 iText 5/iText 7 이 사용 하 는 프로 토 콜 이 다 릅 니 다.PDFBox 는 APACHE LICENSE VERSION 2.0(https://www.apache.org/licenses/);iText 5/iText 7 은 AGPL(https://itextpdf.com/agpl)。PDFBox 무료 사용,AGPL 상용 요금
  • 본 공유 JAVA 가 PDF 파일 에 전자 서명 을 할 때 실현 해 야 할 기능:
  • 인증서 생 성.PDFBox,iText 5,iText 7 기술 과 무관
  • 템 플 릿 에 따라 PDF 파일 을 출력 합 니 다:PDFBox,iText 5,iText 7 은 모두 완성 할 수 있 지만,PDFBox 는 중국어 코드 가 까다 로 운 문제 에 부 딪 힐 수 있 습 니 다
  • PDF 파일 에서 사인 사진 을 PDF 파일 에 추가 하 는 것 을 실현 합 니 다:PDFBox,iText 5 와 iText 7 은 모두 실현 할 수 있 습 니 다.많은 차이 가 없습니다
  • PDF 파일 에 서명 을 그립 니 다:iText 5 와 iText 7 모두 가능 합 니 다.PDFBox 는 현재 지원 되 지 않 습 니 다
  • PDF 파일 에 고 화질 서명 생 성:iText 5 와 iText 7 모두 가능 합 니 다.PDFBox 는 현재 지원 되 지 않 습 니 다
  • PDF 파일 에 여러 번 서명:PDFBox,iText 5,iText 7 을 모두 완성 할 수 있 습 니 다.다 름 없습니다.
  • 관련 기술 분석 과 실현 하고 자 하 는 기능 분석 을 통 해 iText 5 를 이용 하여 개발 하 는데 유일한 유감 은 iText 상용 요금 이다.하지만 이 건 기술 에 관심 이 필요 한 게 아니 야!!iText 5 를 선택 한 이유:
  • iText 5 를 사용 하면 모든 기능 을 실현 할 수 있 습 니 다
  • 어떻게 개발 과정 에서 관련 문제 에 부 딪 히 면 해당 하 는 해결 방안 을 쉽게 찾 을 수 있 습 니까?
  • 3.그림 사인 생 성
    1.다음 그림 과 같은 사인 사진 생 성

    2.관련 코드
    
        import java.awt.Color;
        import java.awt.Font;
        import java.awt.FontMetrics;
        import java.awt.Graphics2D;
        import java.awt.RenderingHints;
        import java.awt.image.BufferedImage;
        import java.io.FileOutputStream;
        import java.io.IOException;
        import sun.font.FontDesignMetrics;
     
        import com.sun.image.codec.jpeg.JPEGCodec;
        import com.sun.image.codec.jpeg.JPEGEncodeParam;
        import com.sun.image.codec.jpeg.JPEGImageEncoder;
     
        public class SignImage {
     
        /**
         * @param doctorName
         *            String     
         * @param hospitalName
         *            String     
         * @param date
         *            String     
         *                
         * @param jpgname
         *            String jpg   
         * @return
         */
        public static boolean createSignTextImg(
                String doctorName, //
                String hospitalName, //
                String date, 
                String jpgname) {
            int width = 255;
            int height = 100;
            FileOutputStream out = null;
            //   
            Color bgcolor = Color.WHITE;
            //  
            Color fontcolor = Color.RED;
            Font doctorNameFont = new Font(null, Font.BOLD, 20);
            Font othorTextFont = new Font(null, Font.BOLD, 18);
            try { //      
                BufferedImage bimage = new BufferedImage(width, height,
                        BufferedImage.TYPE_INT_RGB);
                Graphics2D g = bimage.createGraphics();
                g.setColor(bgcolor); //    
                g.fillRect(0, 0, width, height); //      
                g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON); //     (           ,     )
     
                g.setColor(Color.RED);
                g.fillRect(0, 0, 8, height);
                g.fillRect(0, 0, width, 8);
                g.fillRect(0, height - 8, width, height);
                g.fillRect(width - 8, 0, width, height);
     
                g.setColor(fontcolor); //     
                g.setFont(doctorNameFont); //       
                FontMetrics fm = FontDesignMetrics.getMetrics(doctorNameFont);
                int font1_Hight = fm.getHeight();
                int strWidth = fm.stringWidth(doctorName);
                int y = 35;
                int x = (width - strWidth) / 2;
                g.drawString(doctorName, x, y); //           
     
                g.setFont(othorTextFont); //       
     
                fm = FontDesignMetrics.getMetrics(othorTextFont);
                int font2_Hight = fm.getHeight();
                strWidth = fm.stringWidth(hospitalName);
                x = (width - strWidth) / 2;
                g.drawString(hospitalName, x, y + font1_Hight); //           
     
                strWidth = fm.stringWidth(date);
                x = (width - strWidth) / 2;
                g.drawString(date, x, y + font1_Hight + font2_Hight); //           
     
                g.dispose();
                out = new FileOutputStream(jpgname); //       
                JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
                JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage);
                param.setQuality(50f, true);
                encoder.encode(bimage, param); //   
                out.flush();
                return true;
            } catch (Exception e) {
                return false;
            }finally{
                if(out!=null){
                    try {
                        out.close();
                    } catch (IOException e) {
                    }
                }
            }
        }
        public static void main(String[] args) {
            createSignTextImg("  ", "    ", "2018.01.01",   "sign.jpg");
        }
    }
    4.어떻게 템 플 릿 에 따라 PDF 파일 을 생 성 합 니까?
    1.PDF 템 플 릿 만 들 기
    현재 PDF 템 플 릿 도 구 는 다른 것 이 없어 위대 한 Adobe 회사 가 제공 하 는 Adobe Acrobatpro DC 소프트웨어 로 만 제작 할 수 있다.이 소프트웨어 를 어떻게 사용 하 는 지 는 더 이상 말 하지 않 겠 습 니 다.사용 중 에 어떤 것 이 있 으 면 따로 문의 하 셔 도 됩 니 다.
    2.다음 그림 과 같은 PDF 템 플 릿 을 만 듭 니 다.이 템 플 릿 은 PDF 가 있 는 폼 필드 입 니 다.

    5.PKCS 12 인증 서 를 어떻게 생 성 합 니까?
    1.PKCS 의 간단 한 소개
    PKCS:The Public-Key Cryptography Standards(PKCS 로 약칭)는 미국 RSA 데이터 보안 회사 와 합작 파트너 가 제정 한 공개 키 암호 학 기준 으로 인증서 신청,인증서 업데이트,인증서 폐기 표 발표,확장 인증서 내용 과 디지털 서명,디지털 봉투 의 형식 등 일련의 관련 협 의 를 포함한다.
    1999 년 말 까지 PKCS 는 다음 과 같은 기준 을 발표 했다.
  • PKCS\#1:RSA 공개 키 알고리즘 암호 화 및 서명 메커니즘 을 정의 합 니 다.주로 PKCS\#7 에서 설명 한 디지털 서명 과 디지털 봉 투 를 구성 하 는 데 사 용 됩 니 다[22].
  • PKCS\#3:Diffie-Hellman 키 교환 프로 토 콜 을 정의 합 니 다[23].
  • PKCS\#5:암호 에서 파생 된 보안 키 암호 화 문자열 을 사용 하 는 방법 을 설명 합 니 다.MD2 나 MD5 를 사용 하여 암호 에서 키 를 파생 시 키 고 DES-CBC 모드 로 암호 화 합 니 다.주로 한 컴퓨터 에서 다른 컴퓨터 로 전송 되 는 개인 키 를 암호 화 하 는 데 사용 되 며,메 시 지 를 암호 화 하 는 데 사용 할 수 없습니다[24].
  • PKCS\#6:공개 키 인증서 의 표준 문법 을 설명 합 니 다.주로 X.509 인증서 의 확장 형식 을 설명 합 니 다[25].
  • PKCS\#7:디지털 서명 과 암호 화 등 강화 에 사용 되 는 암호 화 메커니즘 을 포함 하여 통용 되 는 메시지 문법 을 정의 합 니 다.PKCS\#7 은 PEM 과 호 환 되 기 때문에 다른 암호 조작 없 이 암호 화 된 메 시 지 를 PEM 메시지 로 변환 할 수 있 습 니 다[26].
  • PKCS\#8:개인 키 정보 형식 을 설명 합 니 다.이 정 보 는 공개 키 알고리즘 의 개인 키 와 선택 가능 한 속성 집합 등 을 포함 합 니 다[27].
  • PKCS\#9:PKCS\#6 인증서 확장,PKCS\#7 디지털 서명 과 PKCS\#8 비밀 키 암호 화 정보 에 사용 할 속성 유형 을 정의 합 니 다[28].
  • PKCS\#10:인증서 요청 문법 설명[29].
  • PKCS\#11:Cyptoki 라 고 부 르 며 기술 에 독립 된 프로 그래 밍 인 터 페 이 스 를 정의 하여 스마트 카드 와 PCMCIA 카드 같은 암호 화 장치[30]에 사용 합 니 다.
  • PKCS\#12:개인 정보 교환 문법 기준 을 설명 합 니 다.사용자 공개 키,비밀 키,인증서 및 기타 관련 정 보 를 포장 하 는 문법[31]을 설명 합 니 다.
  • PKCS\#13:타원 곡선 암호 시스템 표준[32].
  • PKCS\#14:위조 난수 생 성 기준.
  • PKCS\#15:암호 토 큰 정보 형식 표준[33].
  • PKCS 12 는 상기 기준의 PKCS\#12 로 주로 개인 신분 정 보 를 묘사 하 는 데 사용 된다.이번 공유 에서 사인 작업 을 해 야 할 사람 은 의사 와 약사 이다.그들 은 개인 주체 이 고 PKCS 12 의 증 서 를 나 누 어 주 는 것 은 그들 에 게 도장 을 찍 을 도장 을 나 누 어 주 는 것 과 같다.
    2.JAVA 를 사용 하여 PKCS 12 인증 서 를 생 성하 고 저장 합 니 다.관련 분석 은 코드 설명 참조.
    
        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;
            }
        }
     
     
        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,[email protected],L=  ,ST=  ";
            String subjectStr = "CN=huangjinjin,OU=gitbook   ,O=gitbook    ,C=CN,[email protected],L=  ,ST=  ";
            String certificateCRL  = "https://gitbook.cn";
            Map<String, byte[]> result = createCert("123456", issuerStr, subjectStr, certificateCRL);
     
            FileOutputStream outPutStream = new FileOutputStream("c:/keystore.p12"); // ca.jks
            outPutStream.write(result.get("keyStoreData"));
            outPutStream.close();
            FileOutputStream fos = new FileOutputStream(new File("c:/keystore.cer"));
            fos.write(result.get("certificateData"));
            fos.flush();
            fos.close();
        }
        }
    6.어떻게 높 고 뚜렷 한 사인 을 만 듭 니까?
    1.PDF 템 플 릿 에서 PDF 파일 을 생 성 합 니 다.코드 설명 참조
    
        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("STSong-Light", "UniGB-UCS2-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("title", "    ");
            data.put("case", "123456789");
            data.put("date", "2018.12.07");
            data.put("name", "gitbook");
            data.put("sex", " ");
            data.put("age", "29");
            data.put("phone", "13711645814");
            data.put("office", "  ");
            data.put("cert", "    ");
            data.put("drug", "1、                     0.25g10 ×2  ");
            data.put("dose", "×2 ");
            data.put("cons", "    :          2 ");
            data.put("tips", "    ");
            data.put("desc", "           ,      ,       。           ");
            generatePDF("C:\\Users\\zhilin\\Desktop\\chat\\tpl.pdf", 
                    "C:\\Users\\zhilin\\Desktop\\chat\\filled.pdf", data );
        }
        }

    2.PDF 파일 에 서명
    위의 코드 를 통 해 sign.jpg 라 는 서명 그림 을 만 들 고 keystore.p12 인증서 파일 을 만 들 수 있 으 며 템 플 릿 을 통 해 폼 을 채 운 filled.pdf 라 는 pdf 파일 도 있 습 니 다.아래 는 위 자 료 를 통 해 서명 한 PDF 파일 을 만 들 수 있 습 니 다.
    
        import java.io.File;
        import java.io.FileInputStream;
        import java.io.FileOutputStream;
        import java.io.IOException;
        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\\zhilin\\Desktop\\chat\\keystore.p12", //
                    "C:\\Users\\zhilin\\Desktop\\chat\\filled.pdf",//
                    "C:\\Users\\zhilin\\Desktop\\chat\\sign.jpg", 100, 290);
            FileOutputStream f = new FileOutputStream(new File("C:\\Users\\zhilin\\Desktop\\chat\\signed.pdf"));
            f.write(fileData);
            f.close();
        }
        }

    3.고 화질 사인
    고 화질 사인 은 iText 의 그리 기 기능 을 통 해 이 루어 집 니 다.주로 PDF 파일 에 직접 서명 을 그립 니 다.코드 는 다음 과 같 습 니 다.
    
        import java.io.File;
        import java.io.FileInputStream;
        import java.io.FileOutputStream;
        import java.io.IOException;
        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, "  
    2017-12-20"); FileOutputStream f = new FileOutputStream(new File("C:\\Users\\zhilin\\Desktop\\chat\\signed2.pdf")); f.write(fileData); f.close(); } }
    아래 두 개의 서명 의 차 이 를 분석 해 보면 왼쪽 의 서명 이 매우 모호 하고 오른쪽 이 매우 뚜렷 하 다 는 것 을 발견 할 수 있다.

    7.어떻게 여러 번 PDF 서명 을 진행 합 니까?
    여러 개의 서명 중점 코드 를 생 성하 여 SignPdf.자바 류 에 레이 블 설명 을 했 습 니 다.여러 번 서명 을 하려 면 이미 서명 한 PDF 파일 에 다시 sign 방법 을 호출 하여 다시 서명 하면 됩 니 다(여섯 번 째 시 에 그림 이 있 으 면 두 개의 서명 이 있 습 니 다.이것 이 바로 여러 번 서명 한 결과 입 니 다).
    
    PdfStamper.createSignature(reader, signPDFData, '\0', temp, true);
    
    8.총화
    공유 중인 sign.jpg 파일 의 흰색 배경 을 투명 하 게 처리 해 야 정확 한 전자 서명 효 과 를 얻 을 수 있 습 니 다.SignPdf.자바 와 SignHighPdf.자바 를 문자 가 있 는 PDF 에 서명 하여 효 과 를 볼 수 있 습 니 다).
    모두 가 본 회사 의 공인 은 모두 원형 이다.이것 도 할 수 있 습 니 다.여러분 은 동 그 란 그림 사인 을 어떻게 만 드 는 지 생각해 보 세 요.그리고 전자 서명 을 합 니 다.여 기 는 주로 코드 실현 을 설명 하 는데 모든 코드 가 매우 많다.모두 돌아 가서 코드 를 잘 연구 해라.진정한 전자 서명 은 CA 인증 회 사 를 통 해 이 루어 져 야 합 니 다.저 는 참고 방안 을 제공 하여 여러분 에 게 공부 하 게 할 뿐 입 니 다.
    자 바 를 이용 하여 PDF 파일 에 대한 전자 서명 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 가 PDF 파일 에 대한 전자 서명 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기