我需要对代码从itext5到itext8进行一些更改.这是一个两步签名,创建散列和在CA API签名,然后嵌入回pdf.一切正常,使用一些参考文献here.但是,它在验证文档时返回错误.我已经使用相同的PdfPkcs7实现了,但它仍然返回错误.签名的pdf可以从here下载.请帮我解释一下已经花了几个晚上的时间了.我使用的是iText 8.0.2.

public class PDF_prepareHash {
    //global variable
    static Logger logger = LogManager.getLogger(PDF_prepareHash.class.getName());
    static Timestamp timestamp = new Timestamp(System.currentTimeMillis());
    static Instant instant = timestamp.toInstant();
    static String txId=Long.toString(instant.toEpochMilli());
    
    static String ORI="D:\\pdf"+File.separator+"files"+File.separator+txId+".pdf";
    static String TEMP="D:\\pdf"+File.separator+"files"+File.separator+txId+"-TEMP.pdf";
    static String DEST="D:\\pdf"+File.separator+"files"+File.separator+txId+"-SIGNED.pdf";
    public static PdfPKCS7 sgn;
    
    //variable for get sign hash
    private static String signature=null;
    
    //function for prepare hash
    public static String prepareHash(String certx509,SignatureDetails sd,String name, String userId)
    {
        JSONObject obj = new JSONObject();
        try{
            BouncyCastleProvider providerBC = new BouncyCastleProvider();
            Security.addProvider(providerBC);
            String x509b64 = certx509;
            String certString="-----BEGIN CERTIFICATE-----\n" +x509b64+"\n-----END CERTIFICATE-----";
            byte[] certinByte= certString.getBytes();
            X509Certificate x509 = fromByteArrayToX509Certificate(certinByte);
            Certificate cert = loadCertificate(certinByte);
            Certificate[] chain = new Certificate[1];
            chain[0] = cert;
            
            FileBase64Converter fileB64 = new FileBase64Converter();
            fileB64.base64ToFile(sd.getPdfb64(), ORI);
            PDF_prepareHash app = new PDF_prepareHash();
            String json_hh = emptySignature_hash(chain, sd.getVisibility(), sd.getPage(), sd.getX1(), sd.getY1(), sd.getX2(), sd.getY2(), name, userId);
            if(!json_hh.isEmpty()){
                obj.put("StatusCode", "000");
                obj.put("StatusMsg", "Successfully prepare hash");
                obj.put("Data", json_hh);
                logger.info("prepareHash: Status Code: 000");
                logger.info("prepareHash: Status Msg: Successfully prepare hash");
                return obj.toString();
            }
        }catch(GeneralSecurityException e){
            logger.fatal("GeneralSecurityException");
            logger.fatal("GeneralSecurityException: " + e.getMessage());
        }catch(JSONException e){
            logger.fatal("JSONException");
            logger.fatal("JSONException: " + e.getMessage());
        }
        return null;
    }
    
    public static String emptySignature_hash(Certificate[] chain, Boolean visibility, Integer page, Integer x1, Integer y1, Integer x2, Integer y2,String name,String userId)
    {
        
        try {
            JSONObject obj = new JSONObject();
            PdfReader reader = new PdfReader(ORI);
            FileOutputStream os = new FileOutputStream(TEMP);
            PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
            
            String timeStamp = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss z").format(new Timestamp(System.currentTimeMillis()));
            
            Rectangle rect = new Rectangle(36, 748, 200, 100);
            PdfSignatureAppearance sap = signer.getSignatureAppearance();
            sap
                .setLayer2Text("Digitally signed by\n"+name+", "+userId+"\nDate: "+timeStamp)
                .setReuseAppearance(false)
                .setPageRect(rect)
                .setPageNumber(page)
                .setCertificate(chain[0]);
            signer.setFieldName("signature"); // this field already exists
            BouncyCastleDigest digest = new BouncyCastleDigest();
            sgn = new PdfPKCS7(null, chain, Digest算法rithms.SHA256, null, digest,false);
            //IExternalSignatureContainer like BlankContainer
            PreSignatureContainer external = new PreSignatureContainer(PdfName.Adobe_PPKLite,PdfName.Adbe_pkcs7_detached) {};
            signer.signExternalContainer( external, 8192);
            byte[] hash=external.getHash();
            byte[] sh = sgn.getAuthenticatedAttributeBytes(hash,PdfSigner.CryptoStandard.CMS, null, null);
            
            MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
            messageDigest.update(sh);
            byte[] hash_byte = messageDigest.digest();
            
            obj.put("digest", Base64.getEncoder().encodeToString(hash));
            obj.put("hash", Base64.getEncoder().encodeToString(hash_byte));
            os.close();
            reader.close();
            
            return obj.toString();
        } catch (IOException ex) {
            logger.fatal("IOException");
            logger.fatal("IOException: " + ex.getMessage());
        } catch (InvalidKeyException ex) {
            logger.fatal("InvalidKeyException");
            logger.fatal("InvalidKeyException: " + ex.getMessage());
        } catch (NoSuchProviderException ex) {
            logger.fatal("NoSuchProviderException");
            logger.fatal("NoSuchProviderException: " + ex.getMessage());
        } catch (NoSuch算法rithmException ex) {
            logger.fatal("NoSuch算法rithmException");
            logger.fatal("NoSuch算法rithmException: " + ex.getMessage());
        } catch (GeneralSecurityException ex) {
            logger.fatal("GeneralSecurityException");
            logger.fatal("GeneralSecurityException: " + ex.getMessage());
        }
        return null;
    }
    
    //function for get sign hash
    public static String serveSigning(String userId, String hash,String digest,String x509b64)
    {
        JSONObject obj = new JSONObject();

        Scanner myObj = new Scanner(System.in);  // Create a Scanner object
        System.out.println("Enter signature");

        String casignature = myObj.nextLine();  // Read user input

        signature=casignature;
        byte[] extSignature = Base64.getDecoder().decode(signature);
        Certificate[] chain = null;

        try {
            String certString="-----BEGIN CERTIFICATE-----\n" +x509b64+"\n-----END CERTIFICATE-----";
            byte[] certinByte= certString.getBytes();
            X509Certificate x509 = fromByteArrayToX509Certificate(certinByte);
            Certificate cert = loadCertificate(certinByte);
            chain = new Certificate[1];
            chain[0] = cert;
        } catch (CertificateException e) {
            logger.fatal("IOException");
            logger.fatal("IOException: " + e.getMessage());
            return null;
        }

        //embed signature
        String extSignature_b64 = Base64.getEncoder().encodeToString(extSignature);
        PDF_prepareHash.createSignature(digest, extSignature_b64, chain);
        obj.put("StatusCode", "000");
        obj.put("StatusMsg", "Embed signature succesfully ");
        logger.info("[GetSignHash] Successfully embed prepared hash");

        return obj.toString();
    }
    
    //function for embed signature
    public static void createSignature(String hash, String extSignature, Certificate[] chain)
    {
        try {
//            BouncyCastleDigest digest = new BouncyCastleDigest();
//            PdfPKCS7 sgn = new PdfPKCS7(null, chain, Digest算法rithms.SHA256, null, digest, false);
            sgn.setExternalSignatureValue(Base64.getDecoder().decode(extSignature), null, "ECDSA");
            ITSAClient tsc = null;
            Security.addProvider(new BouncyCastleProvider());
            String TSA_URL="http://timestamp.entrust.net/TSS/RFC3161sha2TS";
            String TSA_ACCNT=null;
            String TSA_PASSW=null;

            try {
                tsc = new TSAClientBouncyCastle(TSA_URL, TSA_ACCNT, TSA_PASSW);
            } catch(Exception e) {
                logger.error("Error timestamping services: "+e.toString());
            }
            byte[] hh_sign = sgn.getEncodedPKCS7(Base64.getDecoder().decode(hash), PdfSigner.CryptoStandard.CMS, tsc, null, null);

            PdfReader reader = new PdfReader(TEMP);
            FileOutputStream os = new FileOutputStream(DEST);
            PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
            MyExternalSignatureContainer external = new MyExternalSignatureContainer(hh_sign,chain);

            PdfSigner.signDeferred(signer.getDocument(), "signature", os, external);
            //close pdf files
            os.close();
            reader.close();
        } catch(IOException ex) {
            logger.fatal("IOException");
            logger.fatal("IOException: " + ex.getMessage());
        } catch (GeneralSecurityException ex) { 
            logger.fatal("GeneralSecurityException");
            logger.fatal("GeneralSecurityException: " + ex.getMessage());
        } 
   }
    
    //global function
    public static X509Certificate fromByteArrayToX509Certificate(byte[] bytes) throws CertificateException 
    {
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(bytes);
        X509Certificate x509cert = (X509Certificate)certFactory.generateCertificate(in);
        return x509cert;
    }
    
    public static Certificate loadCertificate(byte[] bytes) throws CertificateException 
    {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream in = new ByteArrayInputStream(bytes);
        Certificate c=null;
        
        try {
            c =(Certificate)cf.generateCertificate(in);
            //c.checkValidity();
        }
        catch (CertificateException ex) {
            logger.error("[PDF_prepareHash.java] Certificate loadCertificate: "+ex.getMessage());
        }
        finally {
            try {
                in.close();
            } catch (IOException ex) {
                logger.error("[PDF_prepareHash.java] Certificate loadCertificate: "+ex.getMessage());
            }
        }
        
        try {
            in.close();
        } catch (IOException ex) {
            logger.error("[PDF_prepareHash.java] Certificate loadCertificate: "+ex.getMessage());
        }
        return c;
    }
}

推荐答案

在示例文件中,一个主要问题变得显而易见:您希望您的签名是ECDSA签名:

sgn.setExternalSignatureValue(Base64.getDecoder().decode(extSignature), null, "ECDSA");

但是证书中的公钥(以及您的私钥)是RSA密钥,所以您的签名是RSA签名.这当然完全不匹配.


一个小问题是,为了注入生成的签名容器,您需要初始化两个对象以写入相同的输出:

PdfReader reader = new PdfReader(TEMP);
FileOutputStream os = new FileOutputStream(DEST);
PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
MyExternalSignatureContainer external = new MyExternalSignatureContainer(hh_sign,chain);

PdfSigner.signDeferred(signer.getDocument(), "signature", os, external);
//close pdf files
os.close();
reader.close();

PdfSigner signer和静态方法PdfSigner.signDeferred都可以写入相同的输出流,这可能导致相当混乱.不过,显然signer没有在您的代码中编写任何内容,因此不会发生混淆.

PdfSigner.signDeferred仅使用第一个参数中的PdfDocument进行读取.因此,无需创建PdfSigner并检索其内部PdfDocument,您只需为PdfReader创建PdfDocument即可.

Java相关问答推荐

ActivityCompat.请求收件箱自动拒绝权限

日食IDE 2024-03在Ubuntu下崩溃,导致hr_err_pid.log

伪类focus-in不适用于PFA中的选项卡

查找最大子数组的和

Java在模块化jar文件中找不到类,但是javap可以

方法没有用正确的值填充数组—而是将数组保留为null,'

为什么BasicComboBoxRenderer在文本不存在或文本为空的情况下设置两次文本?

有关手动创建的包的问题

连接Quarkus中的两个异步操作

蒙蒂霍尔比赛结果不正确

使用Spring和ActiveMQ的侦听器方法引发属性名称不能重复为空警告

当构造函数创建一个新实例时,Java为什么需要&new";

将关闭拍卖的TimerService

泛型与泛型问题的完美解决方案?

在打开搜索结果时,如何让Eclipse打开整个文件?

在Java中将对象&转换为&q;HashMap(&Q)

我无法在我的Spring Boot应用程序中导入CSV依赖项

如何使用带有可选参数的类生成器?

Java 8 中 ByteBuffer 和 BitSet 的奇怪行为

Xml Reader 将 BMP 外部的字符解析为代理项对,这会导致无效的 xml