当前位置: 首页 > 知识库问答 >
问题:

使用iText 5对已签名的文档进行数字签名

房学文
2023-03-14

您好,我可以使用iText 5对PDF文档进行数字签名。我需要再次签署PDF,而在验证PDF时,它表明初始签名无效。您可以在此处查看再次签名的文件。

请参见下面用于标记的代码,

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
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.PrivateKeySignature;

public class Test {

    

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

        PdfReader reader = null;
        PrivateKey pk = null; 
        String alias = "PRASANTH KARUNAKARAN NAIR"; 

        KeyStore ks = null; 
        try { 
            ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI"); 
        } 
        catch (KeyStoreException|java.security.NoSuchProviderException e4){ 
            e4.printStackTrace(); 
        }  
        try { 
            ks.load(null, null); 
        } 
        catch (NoSuchAlgorithmException|java.security.cert.CertificateException|IOException e4){ 
            e4.printStackTrace(); 
        } 

        try { 
            pk = (PrivateKey)ks.getKey(alias, "abcd".toCharArray()); 
        } 

        catch (UnrecoverableKeyException|KeyStoreException|NoSuchAlgorithmException e3){ 
            e3.printStackTrace(); 
        }  
        Certificate[] chain = null; 
        try { 
            chain = ks.getCertificateChain(alias); 
        } 
        catch (KeyStoreException e3){ 
            e3.printStackTrace(); 
        }  

        
        try {
            reader = new PdfReader("D:///signedSample.pdf"); 
        } 
        catch (IOException e5){ 
            e5.printStackTrace(); 
        }  
        String signedFileNameWithPath = "D:///signedsignedSample.pdf"; 
        FileOutputStream os = null; 
        try { 
            os = new FileOutputStream(signedFileNameWithPath); 
        } 
        catch (FileNotFoundException e5){ 
            e5.printStackTrace();
        }
        PdfStamper stamper = null; 
        
        
        try {
            stamper = PdfStamper.createSignature(reader, os,'\0');
        } 
        catch (DocumentException|IOException e5) {
            e5.printStackTrace(); 
        } 
        
        
        PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
        Integer pageNumber = 2; 
        Rectangle rect=new Rectangle(50,100,220,140);
        appearance.setAcro6Layers(false);
        appearance.setLayer4Text(PdfSignatureAppearance.questionMark);
        appearance.setVisibleSignature(rect,pageNumber, "sig2");

        PrivateKeySignature privateKeySignature=null;
        try {
            privateKeySignature= new PrivateKeySignature(pk, "SHA-256", ks.getProvider().getName()); 
        }
        catch (NullPointerException e) {
        }
        if(privateKeySignature!=null) {
            BouncyCastleDigest bouncyCastleDigest = new BouncyCastleDigest(); 
            try { 
                MakeSignature.signDetached(appearance, (ExternalDigest)bouncyCastleDigest, (ExternalSignature)privateKeySignature, chain, null, null, null, 0, MakeSignature.CryptoStandard.CMS);
            } 
            catch (IOException e1){
                e1.printStackTrace(); 
            }
            catch (DocumentException e1){
                e1.printStackTrace(); 
            } 
            catch (SignatureException e1) {
                e1.printStackTrace(); 
            } 
            catch (GeneralSecurityException e1){ 
                e1.printStackTrace(); 
            }  
        }
        
    }

}

请让我知道出了什么问题。

共有1个答案

茹正祥
2023-03-14

如果您想向已经签名的PDF添加另一个签名,您显然必须小心不要更改任何签名字节。换句话说,添加和更改必须作为增量更新附加到现有文件中。

例如,具有三个签名的PDF的示意图必须与以下内容类似:

(有关背景,请阅读此答案及其引用的文档。)

不过,默认情况下,iText PdfStamper不使用增量更新,而是使用原始文件中的各个对象以可能完全更改的顺序创建一个全新的文件,并删除新版本中不再需要的对象。这当然会导致第一个签名无效。

要创建使用增量更新的PdfStamper,必须使用不同的PdfStamper。createSignature重载。请更换

stamper = PdfStamper.createSignature(reader, os,'\0');

通过

stamper = PdfStamper.createSignature(reader, os, '\0', null, true);

额外的参数在JavaDocs方法中记录如下:

/* @param reader the original document
 * @param os the output stream or <CODE>null</CODE> to keep the document in the temporary file
 * @param pdfVersion the new pdf version or '\0' to keep the same version as the original
 * document
 * @param tempFile location of the temporary file. If it's a directory a temporary file will be created there.
 *     If it's a file it will be used directly. The file will be deleted on exit unless <CODE>os</CODE> is null.
 *     In that case the document can be retrieved directly from the temporary file. If it's <CODE>null</CODE>
 *     no temporary file will be created and memory will be used
 * @param append if <CODE>true</CODE> the signature and all the other content will be added as a
 * new revision thus not invalidating existing signatures
 类似资料:
  • 有没有办法使用openssl对x509证书或任何文档进行数字签名?

  • 我正在尝试用DSS签署PDF文档,我的问题是我无法在服务器a中计算文档的哈希值,然后在服务器B中签署它。 知道服务器A包含PDF文档,我们在服务器B中检索用于签名的证书 我的问题是如何在不需要证书的情况下计算服务器a中文档的哈希值。然后在服务器B上发送签名? 更新: ******散列的准备和计算******** ******散列签名******** ********PDF错误:*********

  • 下面是我想做的: 用户创建文档(html) 编辑->在服务器上保存PDF 询问用户是否要签署文档 (是)这是问题 (否)无问题 所以现在我面临的问题是如何在步骤3中做到这一点(是的)。如果签名在服务器上没有问题,我有一些HTML->PHP->PDF类可以用数字签名进行签名,但签名必须作为文件在服务器上。问题是,我怎么能直接在服务器上做。用户选择是,签名被读取(从他的计算机上的阅读器)并发送到服务器

  • 我希望我们拥有iPhone的员工能够让公众对一份文件进行数字签名,该文件最初是基于Spring的网络表单。 此表格仅在我们的内部网上,仅由我们的员工填写。 到目前为止,我的研究考虑了一些可能的解决方案: 手机屏幕上的电子湿墨水签名 目的是证明某个人签署了一份文件。 1从技术上讲是可能的,但并不重要,因为它很容易被复制。 是否可以在iOS设备上通过浏览器和javascript捕获指纹? 3能适应这种

  • 我一直在网络和java教程中寻找这一点。但我没有澄清如何为文档生成数字签名。java教程对此进行了解释,但我真正想要的是 用户附带一个文件和一个字符串密钥 使用该密钥,文件被数字签名 相应的公钥,该标志与该文档一起发布 那么,如何转换给定的String私钥来做到这一点。在尝试java教程和web中给出的示例(带有将字节从字符串而不是文件中放置的一些变体)时,我遇到了如下异常

  • 请原谅我!我在爪哇很穷。 我错在哪里请指正,差在哪里请改进! 我正尝试使用PDFBox对动态创建的pdf进行数字签名,并使用以下程序: 程序中的任务: (i)创建模板PDF (ii)更新ByteRange、xref、startxref (iii)构造用于签名创建的原始文档 (iv)创建分离式信封数字签名 (v)通过连接原始文档第一部分、分离式签名和原始PDF第二部分来构造数字签名的PDF文档 观察