首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >自签名被应用以来,单据已被更改或波纹,文本5.5.11

自签名被应用以来,单据已被更改或波纹,文本5.5.11
EN

Stack Overflow用户
提问于 2021-03-23 19:38:48
回答 2查看 372关注 0票数 3

基本上,我得到的错误文件已被修改或波纹,因为签名被应用,我遵循图文网站的例子,并适应我的情况。

  • 准备要签名的文档,添加附加模式,因为它可以是已签名的文档。
  • 调用webservice来签名散列。
  • 将签名散列添加到准备好的文档中

我的想法用完了,希望能得到一些帮助--以下是我的代码片段:

代码语言:javascript
复制
    public static final String src = "DynamicClient\sample.pdf";
    public static final String temp= "DynamicClient\sampleTEMP.pdf";
    public static final String dest= "DynamicClient\sampleFINAL.pdf";

    public static void emptySignatureSVC(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
            PdfReader reader = new PdfReader(src);
            reader.setAppendable(true);
            FileOutputStream os = new FileOutputStream(dest);
            PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0',null,true);
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
            appearance.setVisibleSignature(new Rectangle(0, 0, 0, 0), 1, fieldname);
            appearance.setCertificate(chain[0]);
            ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ETSI_CADES_DETACHED);
            MakeSignature.signExternalContainer(appearance, external, 8192);
            reader.close();
            
        }

    public static void createSignatureSVC(String src, String dest, String fieldname, byte[] sign, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
            
            PdfReader reader = new PdfReader(src);
            FileOutputStream os = new FileOutputStream(dest);
            ExternalSignatureContainer external = new MyExternalSignatureContainer(sign, chain);
            MakeSignature.signDeferred(reader, fieldname, os, external);
        }


    public static void main(String[] args) throws Exception {

                Certificate[] chain = signWS.getChain();//External WS to get chain
                emptySignatureSVC(src, temp, "signature", chain);               
                InputStream is = new FileInputStream(new File(temp));
                PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
                byte[] hash = DigestAlgorithms.digest(is, digest.getMessageDigest("SHA256"));
                byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CADES);
                
                byte[] extSignature = signWS(sh);//External WS to sign
                sgn.setExternalDigest(extSignature, null, "RSA");
    
                createSignatureSVC(temp, dest, "signature", sgn.getEncodedPKCS7(hash,null, null, null, CryptoStandard.CADES), chain);
}

以下是文件:原版 签署一份

编辑:忘记添加我使用的容器:

代码语言:javascript
复制
class MyExternalSignatureContainer implements ExternalSignatureContainer {
    protected byte[] sig;
    protected Certificate[] chain;
    public MyExternalSignatureContainer(byte[] sig,Certificate[] chain) {
        this.sig = sig;
        this.chain=chain;
    }
    public byte[] sign(InputStream is)throws GeneralSecurityException  {
        
        return sig;
        
    }

    @Override
    public void modifySigningDictionary(PdfDictionary signDic) {
        // TODO Auto-generated method stub
        
    }
}
EN

Stack Overflow用户

回答已采纳

发布于 2021-03-24 14:38:00

代码中有两个问题:

  • 你查错了数据
  • 你签的不对。

散列错误的数据

您正在散列所有准备好的PDF,如下所示:

代码语言:javascript
复制
InputStream is = new FileInputStream(new File(temp));
PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);
byte[] hash = DigestAlgorithms.digest(is, digest.getMessageDigest("SHA256"));

这不对。

签名的PDF实际上具有此结构(请阅读这里以获得更多详细信息):

(顺便说一下,草图不是100%正确的,因为签名值周围的角括号分隔符'<‘’和'>‘’也不能散列.)

您在temp准备的PDF格式具有相同的结构,只是“签名值”还不是实际的签名值,而是8192个十六进制编码的零字节的占位符(8192,因为这是您在MakeSignature.signExternalContainer中给出的数字)。

但是,正如您在草图中所看到的,签名值(或者在您的情况下,占位符)不能被散列以进行签名。

您可以使用PdfSignatureAppearance.getRangeStream他的回答中的@LkbhaiLr建议的MakeSignature.signExternalContainer之后返回的数据来计算哈希。

或者,您可以使用(而不是ExternalBlankSignatureContainer)一个自定义ExternalSignatureContainer实现,它在其sign方法中简单地散列其InputStream参数并提供该哈希。

我更喜欢后一种方法,但前一种方法也被广泛使用。

签名错误

您可以像这样检索裸露签名值:

代码语言:javascript
复制
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CADES);
byte[] extSignature = signWS(sh);//External WS to sign

也就是说,您将属性结构转发给您的签名服务,并期望它为它创建一个适当的签名值。

检查一下您的签名示例文件,很明显,签名服务没有达到您的期望:它只是使用SHA256withRSA和PKCS#1填充进行加密,而不是使用SHA256withRSA进行签名。因此,它希望您完成一半的签名,即使用SHA256进行散列并构建一个DigestInfo结构。

因此,在调用signWS之前,您必须对sgn.getAuthenticatedAttributeBytes返回的属性结构进行哈希,然后将得到的哈希值包装到DigestInfo对象中。

当你在其他地方计算散列时,这对你来说不应该是个问题。对于在DigestInfo中包装散列,RFC 8017节9.2附注1提供了一个捷径:

对于附录B.1中提到的九个哈希函数,DigestInfo值的DER编码T等于以下内容: ..。沙-256:(0x)30 31 30 d 06 09 60 86 48 01 65 03 04 02 01 05 00 00 00 04 20 x.

也就是说,您只需在哈希前面加上字节序列30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20

票数 4
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66770181

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档