使用iText 2.1.7或数字签名服务从pdf获取哈希

时间:2019-05-16 14:54:22

标签: pdf itext digital-signature

我正在将项目从iText 5迁移到iText 2 /或DSS(https://ec.europa.eu/cefdigital/wiki/display/CEFDIGITAL/eSignature。)

由于iText版本之间存在差异(DSS使用iText 2.17),因此无法获得正确的带符号哈希。

此处是从itex 5迁移的代码:

            // We get the self-signed certificate from the client
            CertificateFactory factory = CertificateFactory.getInstance("X.509");
            Certificate[] chain = new Certificate[1];
            chain[0] = factory.generateCertificate(new ByteArrayInputStream(decoded));

            // we create a reader and a stamper
            PdfReader reader = new PdfReader(hash.getInputFile());
            try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {

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

                // HERE WE HAD SOME DIFFERENCE                 
                PdfSignatureAppearance sap = stamper.getSignatureAppearance();

                sap.setVisibleSignature(new Rectangle(36, 748, 36, 748), 1, signField); //invisible

                // iText 5: 
                //sap.setCertificate(chain[0]);

                // iText 2.1.7: 
                sap.setCrypto(null,chain,null,PdfSignatureAppearance.SELF_SIGNED);


                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
                dic.setReason(sap.getReason());
                dic.setLocation(sap.getLocation());
                dic.setContact(sap.getContact());

                dic.setDate(new PdfDate(sap.getSignDate()));
                sap.setCryptoDictionary(dic);
                HashMap<PdfName,Integer> exc = new HashMap<>();
                exc.put(PdfName.CONTENTS, 8192 * 2 + 2);
                sap.preClose(exc);



                // iText 5: 
                /* 
                ExternalDigest externalDigest = hashAlgorithm ->
                        DigestAlgorithms.getMessageDigest(hashAlgorithm, null);

                ExternalDigest externalDigest = new ExternalDigest() {
                    public MessageDigest getMessageDigest(String hashAlgorithm)
                            throws GeneralSecurityException {
                        return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
                    }
                };

                PdfPKCS7 sgn = new PdfPKCS7(null,
                        chain,
                        "SHA256",
                        null,
                        externalDigest,
                        false);
                */
                // iText 2.1.7: 
                PdfPKCS7 sgn = new PdfPKCS7(null,chain,null, "SHA256",null,false);

                // WARNING SAP.getRange different response content!!!
                InputStream data = sap.getRangeStream();


                // iText 5:
                //byte[] hashArray = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));

                //iText 2
                MessageDigest md = MessageDigest.getInstance("SHA-256");
                byte[] hashArray = md.digest(IOUtils.toByteArray(data));


                byte[] ocsp = null;

                // iText 5:
                //byte[] sh = sgn.getAuthenticatedAttributeBytes(hashArray,
                //      null,
                //      null,
                //      MakeSignature.CryptoStandard.CMS);

                // iText 2:
                Calendar cal = Calendar.getInstance();
                byte[] sh = sgn.getAuthenticatedAttributeBytes(hashArray,cal,null);

                InputStream shInputStream = new ByteArrayInputStream(sh);

                // iText 5:
                //byte[] signedAttributesHash = DigestAlgorithms.digest(shInputStream,externalDigest.getMessageDigest("SHA256"));

                // iText 2:
                byte[] signedAttributesHash = md.digest(IOUtils.toByteArray(shInputStream));                


                hash.setOcsp(ocsp);                
                hash.setSgn(sgn);
                hash.setFilehash(hashArray);
                hash.setSap(sap);
                hash.setBaos(byteArrayOutputStream);

                hash.setSignedAttributesHashB64(new String(
                    org.bouncycastle.util.encoders.Base64.encode(signedAttributesHash),
                    Charsets.UTF_8)
                );

问题始于sap.getRangeStream();,输出却不同。 以下变量shsignedAttributesHash的内容有误。

有人成功做到了吗?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

使用pdfbox的临时方法。

我不知道如何在空签名中插入公共证书:/就像iText一样!我不知道是否可能。

public abstract class testtwostep
{

private static final String ID_PKCS7_DATA = "1.2.840.113549.1.7.1";
private static final String ID_PKCS7_SIGNED_DATA = "1.2.840.113549.1.7.2";
private static final String ID_MD5 = "1.2.840.113549.2.5";
private static final String ID_MD2 = "1.2.840.113549.2.2";
private static final String ID_SHA1 = "1.3.14.3.2.26";
private static final String ID_RSA = "1.2.840.113549.1.1.1";
private static final String ID_DSA = "1.2.840.10040.4.1";
private static final String ID_CONTENT_TYPE = "1.2.840.113549.1.9.3";
private static final String ID_MESSAGE_DIGEST = "1.2.840.113549.1.9.4";
private static final String ID_SIGNING_TIME = "1.2.840.113549.1.9.5";
private static final String ID_MD2RSA = "1.2.840.113549.1.1.2";
private static final String ID_MD5RSA = "1.2.840.113549.1.1.4";
private static final String ID_SHA1RSA = "1.2.840.113549.1.1.5";


public byte[] getAuthenticatedAttributeBytes(byte secondDigest[],Calendar signingTime) throws IOException {

    ASN1EncodableVector attribute = new ASN1EncodableVector();
    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(new DERObjectIdentifier(ID_CONTENT_TYPE));
    v.add(new DERSet(new DERObjectIdentifier(ID_PKCS7_DATA)));
    attribute.add(new DERSequence(v));
    v = new ASN1EncodableVector();
    v.add(new DERObjectIdentifier(ID_SIGNING_TIME));
    v.add(new DERSet(new DERUTCTime(signingTime.getTime())));
    attribute.add(new DERSequence(v));
    v = new ASN1EncodableVector();
    v.add(new DERObjectIdentifier(ID_MESSAGE_DIGEST));
    v.add(new DERSet(new DEROctetString(secondDigest)));
    attribute.add(new DERSequence(v));
    ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    ASN1OutputStream dout = new ASN1OutputStream(bOut);
    dout.writeObject(new DERSet(attribute));
    dout.close();
    return bOut.toByteArray();
}

public byte[] getHash() throws IOException, NoSuchAlgorithmException, CertificateException {
    String documentFile = "/home/gigio2k/dev/swap/tmp.pdf";
    String documentFileSigned = "/home/gigio2k/dev/swap/tmp_pdfbox.pdf";
    String certStr = "MII....GsNw==";
    byte[] certByte = org.apache.commons.codec.binary.Base64.decodeBase64(certStr.getBytes());

    PDDocument document = PDDocument.load(new File(documentFile));

    Calendar date = Calendar.getInstance();
    long SeedTS = date.getTimeInMillis();
    document.setDocumentId(SeedTS);


    PDSignature signature = new PDSignature();
    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
    //signature.setName("Example User");
    signature.setLocation("Los Angeles, CA");
    signature.setReason("Testing");
    signature.setSignDate(date);


    SignatureOptions opt = new SignatureOptions();
    opt.setPreferredSignatureSize(8192);

    document.addSignature(signature,opt);

    ExternalSigningSupport externalSigningSupport = document.saveIncrementalForExternalSigning(null);

    byte[] content = IOUtils.toByteArray(externalSigningSupport.getContent());
    MessageDigest md = MessageDigest.getInstance("SHA256", new BouncyCastleProvider());
    byte[] digest = md.digest(content); // this is sent to client


   //byte[] sh = sgn.getAuthenticatedAttributeBytes(hashArray,null,null,MakeSignature.CryptoStandard.CMS);

        byte[] sh = getAuthenticatedAttributeBytes(digest,date);
        InputStream shInputStream = new ByteArrayInputStream(sh);
        //byte[] signedAttributesHash = DigestAlgorithms.digest(shInputStream, externalDigest.getMessageDigest("SHA256"));
        byte[] signedAttributesHash = md.digest(sh);



        System.out.println("--------------------");
        System.out.println(new String(org.bouncycastle.util.encoders.Base64.encode(signedAttributesHash),Charsets.UTF_8));
    System.out.println(date.getTimeInMillis());
    System.out.println("--------------------");
    System.out.println("Enter b64 signed:");
    System.out.println("--------------------");

    Scanner in = new Scanner(System.in);
    String signedHashB64 = in.nextLine();
    byte[] encodedSignature = org.apache.commons.codec.binary.Base64.decodeBase64(signedHashB64.getBytes());

    PDDocument document2 = PDDocument.load(new File(documentFile));

    Calendar date2 = date;
    document2.setDocumentId(SeedTS);

    PDSignature signature2 = new PDSignature();
    signature2.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
    signature2.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
    //signature2.setName("Example User");
    signature2.setLocation("Los Angeles, CA");
    signature2.setReason("Testing");
    signature2.setSignDate(date2);

    SignatureOptions opt2 = new SignatureOptions();
    opt2.setPreferredSignatureSize(8192);

    document2.addSignature(signature2,opt2);

    File file = new File(documentFileSigned);
    FileOutputStream fos = new FileOutputStream(file);
    ExternalSigningSupport externalSigning = document2.saveIncrementalForExternalSigning(fos);
    externalSigning.setSignature(encodedSignature);

    System.out.println("--------------------");
    System.out.println("saved to: " + documentFileSigned);
    System.out.println("--------------------");
    return digest;
}

public static void main(String[] args) throws IOException, GeneralSecurityException
{
    testtwostep t2s = new testtwostep();
    t2s.getHash();
}
}

请注意:我没有编辑第一个问题,因为我会尝试更多方法,最后我会编辑原始问题