首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从PKCS#7整合中获取PKCS#1

如何从PKCS#7整合中获取PKCS#1
EN

Stack Overflow用户
提问于 2022-03-24 04:26:51
回答 3查看 295关注 0票数 1

我正在集成CSC2QR热情id集成。在这里,我发送Base64 URL编码的SHA256哈希签名,作为响应,我得到了PKCS#1原始签名。我无法理解如何使用这些信息对文档进行数字签名。我正在使用itext7。

代码语言:javascript
复制
"signatures": [
    "uXPiaQOEToyju50OIMrNe5gTstUQhnufmlcxmI9mG5tPCCMDYdfEV4Y+gKkixdzD\r\nZqni1+QAfy8cabRzpq13Puz31qUJ5spDRLfY/VLgBvLZLWTDK0KnJPsPWb36vMY5\r\n8CAn3DSbB02QkOoAafJkcOL3StnXc/JnAszk0lICwIM4lC3IW/pv3tWetrIn6pAJ\r\n7XBSX/zw2tfW9czFFrBaLm7hSe2NlQ1JsMgyLWEBauvFHeyFLdf9rLMM+aCoagRU\r\nD7T4Z31LrxmHFKVelS5dRvZuj8GTYJ78lfYfigSiVMsD8NEY3+YDthAsw2Lmgqs5\r\nMgVmRaQrjSdUMNeDZduFR1IeC/DLmQoBa8oXmeVqgxM0nIplq9gze1FklbPgiZ7G\r\n5zmdD8lnAP9BLawu9P+hC2GZNkeqVep3QzmoO149Iyu0jK8nrhYmxcEEqzaZiklc\r\nIKK7t03Ypst93Kps0OLc0s09A2g2wU+KzuuM+s29VKaE/gua9DKHNtf1iIZDmLtv\r\nRUoQxV9odJvRZwa+UMPsRTVejKb9pbgodiUtieyLq8Kr/NjJl+wnuH8CIiXYWxpe\r\nFoQ+J1teMOok/`sbO2X90SNqg5jvsyFTCBrGSgGWSob1TFghgWgRNiDBienXWWY09`\r\noaii058RhlJDm5l1KhMurBUZsyAre9rs74qj5tntMyQ="
  ]

我还将获得签名证书作为响应响应-:

代码语言:javascript
复制
{
  "authMode": "oauth2code",
  "cert": {},
  "key": {
    "algo": [
      "1.2.840.113549.1.1.11"
    ],
    "len": 4096,
    "status": "enabled"
  },
  "lang": "en-US",
  "multisign": 1
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-03-24 15:24:11

我不知道CSC2QRAPI,更不用说已经完成了解决它的代码。因此,在这个答案中,我将显示一个框架来集成一个任意的远程签名API。

将远程签名服务与iText 7签名API集成的最简单方法是相应地实现IExternalSignature。这可能如下所示(特定于由伪代码表示的CSC2QRAPI的代码):

代码语言:javascript
复制
public class CSC2QRSignature implements IExternalSignature {

    Certificate[] chain;
    String hashAlgorithm = "SHA256";
    String encryptionAlgorithm = "RSA";

    public CSC2QRSignature([... parameters you need for CSC 2QR communication ...]) {
        [... request your CSC 2QR Credentials Info and initialize      ...]
        [... chain, hashAlgorithm, and encryptionAlgorithm accordingly ...]
    }

    @Override
    public String getEncryptionAlgorithm() {
        return encryptionAlgorithm;
    }

    @Override
    public String getHashAlgorithm() {
        return hashAlgorithm;
    }

    public Certificate[] getChain() {
        return chain;
    }

    @Override
    public byte[] sign(byte[] message) throws GeneralSecurityException {
        byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(message);
        [... call CSC 2QR Sign Hash for the base64 encoded digest ...]
        [... and return the base64 decoded signature from the response ...]
    }
}

使用该类,您可以签署如下PDF文件:

代码语言:javascript
复制
PdfReader reader = new PdfReader(SOURCE_PDF);
OutputStream os = new FileOutputStream(RESULT_PDF);

CSC2QRSignature signature = new CSC2QRSignature(...);
IExternalDigest digest = new BouncyCastleDigest();

PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
signer.signDetached(digest, signature, signature.getChain() , null, null, null, 0, CryptoStandard.CMS);
票数 0
EN

Stack Overflow用户

发布于 2022-08-04 21:17:05

在注释中,很明显,您没有考虑在sign实现的IExternalSignature方法中执行所有与签名服务相关的内容(正如我在另一个答案中所建议的那样)。相反,您更愿意使用延迟签名。

在尝试延迟签名时,您创建了CMS签名容器,以最简单的形式嵌入到PDF中。但是,由于您希望创建PAdES签名,这种简单的格式是无效的,因此需要一个更复杂的CMS容器配置文件。详情见ETSI EN 319 142-1。

因此,这个答案的重点是为延迟签名用例的第一步中确定的字节范围的哈希创建一个PAdES基线兼容的CMS签名容器。在第二步中,这个签名容器可以嵌入到准备好的PDF中。

有两个主要选项,一个可以尝试提取iText为此使用的代码,另一个可以直接使用某些安全库(例如BouncyCastle )的CMS构建器代码。我们这里使用的是第一种方法。

因此,让我们对signer.signDetached进行剖析,并了解它如何为另一个答案中准备好的PDF的已签名字节范围的散列创建一个CMS签名容器。

该方法中的相关代码是

代码语言:javascript
复制
PdfPKCS7 sgn = new PdfPKCS7((PrivateKey) null, chain, hashAlgorithm, null, externalDigest, false);
if (signaturePolicy != null) {
    sgn.setSignaturePolicy(signaturePolicy);
}
InputStream data = getRangeStream();
byte[] hash = DigestAlgorithms.digest(data, SignUtils.getMessageDigest(hashAlgorithm, externalDigest));
List<byte[]> ocspList = new ArrayList<>();
if (chain.length > 1 && ocspClient != null) {
    for (int j = 0; j < chain.length - 1; ++j) {
        byte[] ocsp = ocspClient.getEncoded((X509Certificate) chain[j], (X509Certificate) chain[j + 1], null);
        if (ocsp != null) {
            ocspList.add(ocsp);
        }
    }
}
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, sigtype, ocspList, crlBytes);
byte[] extSignature = externalSignature.sign(sh);
sgn.setExternalDigest(extSignature, null, externalSignature.getEncryptionAlgorithm());

byte[] encodedSig = sgn.getEncodedPKCS7(hash, sigtype, tsaClient, ocspList, crlBytes);

对于PAdES基线签名,CRL和OCSP响应不会添加到签名容器中。对于基线-B我们甚至不需要一个TSA客户端

因此,在您的情况下,您可以这样进行:

代码语言:javascript
复制
try (
    InputStream resource = ...;
    ByteArrayOutputStream preparedArrayStream = new ByteArrayOutputStream()
) {
    IExternalDigest externalDigest = new BouncyCastleDigest();
    String digestAlgorithm = "SHA256";

    // deferred signing, step one
    String base64DocumentHash = prepareSignature(resource, preparedArrayStream);
    // prepare PdfPKCS7 with document hash
    byte[] hash = Base64.decodeBase64(base64DocumentHash);
    PdfPKCS7 sgn = new PdfPKCS7((PrivateKey) null, chain, digestAlgorithm, null, externalDigest, false);
    byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, CryptoStandard.CADES, null, null);
    // retrieve signature bytes:
    // * calculate hash of sh, 
    // * prepare ZealId signature request for hash of sh (QR code etc)
    // * request signature value for hash of sh
    byte[] extSignature = ... signature value for hash of sh ...;
    // finalize PdfPKCS7 with signature bytes
    sgn.setExternalDigest(extSignature, null, "RSA");
    byte[] encodedSig = sgn.getEncodedPKCS7(hash, CryptoStandard.CADES, null, null, null);
    // deferred signing, step two
    try (ByteArrayInputStream preparedInputStream = new ByteArrayInputStream(preparedArrayStream.toByteArray())) {
        createSignature(preparedInputStream , Base64.encodeBase64String(encodedSig));
    }
}

当然,您必须从您的PdfPKCS7中删除ExternalPrecalculatedSignatureContainer代码,因此它会被刻录为

代码语言:javascript
复制
class ExternalPrecalculatedSignatureContainer extends ExternalBlankSignatureContainer
{
    byte[] cmsSignatureContents;

    public ExternalPrecalculatedSignatureContainer(byte[] cmsSignatureContents) {
        super(new PdfDictionary());
        this.cmsSignatureContents = cmsSignatureContents;
    }

    @Override
    public  byte[] sign(InputStream data) throws CertificateException, InvalidKeyException, NoSuchProviderException, NoSuchAlgorithmException {
        return cmsSignatureContents;
    }
}
票数 1
EN

Stack Overflow用户

发布于 2022-08-03 09:16:04

这是我的代码,在得到热诚签名后。签名是有效的,但仍然显示PDF-不是ETSI。

代码语言:javascript
复制
public static  String  prepareSignature(InputStream in, ByteArrayOutputStream preparedArrayStream ) throws FileNotFoundException, IOException,GeneralSecurityException {
            PdfReader reader = new PdfReader(in);
             Rectangle rect = new Rectangle(36, 648, 200, 100);
            PdfSigner signer = new PdfSigner(reader, preparedArrayStream,  new StampingProperties().useAppendMode());
                
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
                appearance.setPageRect(rect)
                .setPageNumber(1)
                .setLocation("EU")
                .setReason("Test");
               signer.setFieldName("testing");
                
                PreSignatureContainer external = new PreSignatureContainer(PdfName.Adobe_PPKLite,
                        PdfName.ETSI_CAdES_DETACHED);
                
                signer.signExternalContainer(external, 8192);
                String hash = Base64.encodeBase64String(external.getHash());
                return hash;
               // byte[] preSignedBytes = os.toByteArray();
              //  outputStream.close();
                
            
            //return outputStream;
        }
        static class PreSignatureContainer  implements IExternalSignatureContainer 
        {
            private PdfDictionary sigDic;
            private byte hash[];
    
            public PreSignatureContainer(PdfName filter, PdfName subFilter) {
                sigDic = new PdfDictionary();
                sigDic.put(PdfName.Filter, filter);
                sigDic.put(PdfName.SubFilter, subFilter);
            }
    
            @Override
            public byte[] sign(InputStream data) throws GeneralSecurityException {
                String hashAlgorithm = "SHA256";
                BouncyCastleDigest digest = new BouncyCastleDigest();
    
                try {
                    this.hash = DigestAlgorithms.digest(data, digest.getMessageDigest(hashAlgorithm));
                } catch (IOException e) {
                    throw new GeneralSecurityException("PreSignatureContainer signing exception", e);
                }
    
                return new byte[0];
            }
    
            @Override
            public void modifySigningDictionary(PdfDictionary signDic) {
                signDic.putAll(sigDic);
            }
    
            public byte[] getHash() {
                return hash;
            }
        }
    
    public static void createSignature(InputStream in, String signatures) throws Exception {
             byte[] decodeSignature = Base64.decodeBase64(signatures);
             PdfReader reader =  null;
                reader = new PdfReader(in);
                FileOutputStream outputStream = new FileOutputStream(new File("D:\\zealid\\test\\newZeal.pdf"));
                 PdfSigner signer = new PdfSigner(reader, outputStream,  new StampingProperties().useAppendMode());
                 signer.signDeferred(signer.getDocument(), "testing", outputStream, new ExternalPrecalculatedSignatureContainer(decodeSignature));
                
                
                    outputStream.close();
        }
    
    class ExternalPrecalculatedSignatureContainer extends ExternalBlankSignatureContainer
        {
            byte[] cmsSignatureContents;
            public ExternalPrecalculatedSignatureContainer(byte[] cmsSignatureContents) 
            {
                super(new PdfDictionary());
                this.cmsSignatureContents = cmsSignatureContents;
            }
            
            
            @Override
            public  byte[] sign(InputStream data) throws CertificateException, InvalidKeyException, NoSuchProviderException, NoSuchAlgorithmException
            {
              BouncyCastleDigest digest = new BouncyCastleDigest();
             PdfPKCS7 sgn = new PdfPKCS7(null, chain, DigestAlgorithms.SHA256, null, digest, false);
             sgn.setExternalDigest(cmsSignatureContents, null,"RSA");
             cmsSignatureContents = sgn.getEncodedPKCS7();
             
                return cmsSignatureContents;
            }
    
          
    
        
        }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71597066

复制
相关文章

相似问题

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