Интегрировать подписанный Ha sh в исходный PDF-файл - PullRequest
0 голосов
/ 09 июля 2020

Я интегрирую подписанный ha sh в исходный PDF-файл, но у меня все еще есть ошибка в отношении действительности подписи. это говорит о том, что PDF-файл был изменен после подписания.

ниже шагов: я вычисляю ha sh, затем отправляю его на подпись и, наконец, я получаю знак ha sh и перехожу к интеграции в оригинальном pdf

package com.example.hashdocument;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.security.*;
import com.lexpersona.commons.utils.ProcessLauncher;
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.*;


public class Test2 {

    private static final String SRC = "B:/Hash-et-Reconstitution/tmp/Doc_test.pdf";
    private static final String DST = "B:/Hash-et-Reconstitution/tmp/Doc_test_DST.pdf";
    private static final String HASH = "B:/Hash-et-Reconstitution/tmp/Doc_test_hashed.hash";
    
    private static final String PATH_BAT = "C:/Repo_LP7/lpcommand.bat";
    private static final String PIN = "123456";
    private static final String CERTIFICATE = "C:/lp7command/tools/certificate.p12";
    private static final String SIGNED_HASH = "B:/Hash-et-Reconstitution/tmp/doc_signed.hash";
    
    private static byte[] readFileToByteArray(File file){
        FileInputStream fis = null;
        byte[] bArray = new byte[(int) file.length()];
        try{
          fis = new FileInputStream(file);
          fis.read(bArray);
          fis.close();                   
        }catch(IOException ioExp){
          ioExp.printStackTrace();
        }
        return bArray;
      }
    public static File bytesToFile(byte[] fileByte,String pathFile)  {
        File file = new File(pathFile);
        try {
            OutputStream os = new FileOutputStream(file);
            os.write(fileByte);
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;
    }
    public static byte[] signDocument() throws IOException {
        
        
        ProcessLauncher p = new ProcessLauncher(System.out, System.err);
        int exec;
        exec = p.exec("cmd.exe /c "+PATH_BAT+" <nul "+ SIGNED_HASH +" "+ PIN+" "
                + HASH+" "+CERTIFICATE, null, null);

        byte[] signedHash = readFileToByteArray(new File(SIGNED_HASH));
        
        return signedHash;
    }
     
    
    public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
        
        PdfSignatureAppearance appearance = null;
        ByteArrayOutputStream  os = null;
        String hash_document = "";
        
        InputStream data = null;
        int contentEstimated = 8192;

        PdfReader reader = new PdfReader(SRC);

        reader.unethicalreading = true;
        reader.setAppendable(true);

        int pdfPagenumber = 1;

        pdfPagenumber = reader.getNumberOfPages(); // Sign on last page

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

        Calendar cal = Calendar.getInstance();        
        appearance = stamper.getSignatureAppearance();        
        appearance.setSignDate(cal);
        //appearance.setAcro6Layers(false);
        appearance.setReason("Signature de contrat");
        appearance.setLocation("MAROC");              
        appearance.setImage(null);
        appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);

        Rectangle rect = new Rectangle(300, 300, 20, 20);        
        appearance.setVisibleSignature(rect, pdfPagenumber, null);

        HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
        exc.put(PdfName.CONTENTS, new Integer(contentEstimated * 2 + 2));
        PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
        dic.setReason(appearance.getReason()); 
        dic.setLocation(appearance.getLocation());
        dic.setContact(appearance.getContact());
        dic.setDate(new PdfDate(appearance.getSignDate()));
        appearance.setCryptoDictionary(dic);

        appearance.preClose(exc);

        data = appearance.getRangeStream();    

        MessageDigest messageDigest;
        String provider = null;
        String hashAlgorithm = DigestAlgorithms.SHA256;
        if (provider == null){
            messageDigest = MessageDigest.getInstance(hashAlgorithm);
        }else {
            messageDigest = MessageDigest.getInstance(hashAlgorithm,provider);
        }


        int read = 0;
        byte[] buff = new byte[contentEstimated];

        while ((read = data.read(buff, 0, contentEstimated)) > 0)
        {
            messageDigest.update(buff,0,read);                      
        }
        byte[] hashDigest = messageDigest.digest();

        byte[] documentHash = org.bouncycastle.util.encoders.Hex.encode(hashDigest);

        //eSign Start        
        hash_document = new String(documentHash, "UTF-8");        
        System.out.println("Document Hash :"+hash_document);
        

        
        PrintStream out = new PrintStream(new FileOutputStream(HASH));
        out.print(hash_document);
        
        
        byte[] hashdocumentByte = signDocument();
        
        //////////////////// ADD SIGNED BYTES/HASH TO PDF DOCUMENT.      
        int contentEstimated2 = 8192;
        byte[] paddedSig = new byte[contentEstimated2];
        byte[] signedDocByte = hashdocumentByte;
        
        System.arraycopy(signedDocByte, 0, paddedSig, 0, signedDocByte.length);
        
        PdfDictionary dic2 = new PdfDictionary();
        dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));

        appearance.close(dic2);
        
        try(OutputStream outputStream = new FileOutputStream(DST)) {
            os.writeTo(outputStream);
        }

        os.close(); 
        
    }
}

Ответы [ 2 ]

0 голосов
/ 14 июля 2020

что вы думаете об этом коде: Сначала я вычисляю ha sh и отправляю на сервер A для подписи

    PdfReader reader = new PdfReader(SRC);
    FileOutputStream os = new FileOutputStream(TEMP);
    PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
    PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
    appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
    //appearance.setCertificate(chain[0]);
    ExternalSignatureContainer external = new 
    ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
    MakeSignature.signExternalContainer(appearance, external, 8192);

    InputStream inp = appearance.getRangeStream();  

    BouncyCastleDigest digest = new BouncyCastleDigest();


     byte[] hash = DigestAlgorithms.digest(inp, digest.getMessageDigest("SHA256"));
     System.out.println("hash to sign : "+ hash);
     bytesToFile(hash, HASH);
     byte[] hashdocumentByte = TEST.signed_hash(hash);
     
     PdfReader reader2 = new PdfReader(TEMP);
    FileOutputStream os2 = new FileOutputStream(DEST);
    ExternalSignatureContainer external2 = new 
    MyExternalSignatureContainer(hashdocumentByte,null);
    MakeSignature.signDeferred(reader2, "sig", os2, external2);

И на сервере B, где я подписываю ha sh:

        BouncyCastleProvider providerBC = new BouncyCastleProvider();
        Security.addProvider(providerBC);

        // we load our private key from the key store
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(CERTIFICATE), PIN);
        String alias = (String)ks.aliases().nextElement();
        Certificate[] chain = ks.getCertificateChain(alias);
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PIN);
        
        
     PrivateKeySignature signature = new PrivateKeySignature(pk, "SHA256", null);
       BouncyCastleDigest digest = new BouncyCastleDigest();
        Calendar cal = Calendar.getInstance();
        String hashAlgorithm = signature.getHashAlgorithm();
        System.out.println(hashAlgorithm);
        PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, digest, false);

        byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
        byte[] extSignature = signature.sign(sh);

        System.out.println(signature.getEncryptionAlgorithm());
        sgn.setExternalDigest(extSignature, null, signature.getEncryptionAlgorithm());
        return sgn.getEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
0 голосов
/ 10 июля 2020

Ваш метод signDocument, по-видимому, не принимает предварительно рассчитанное значение ha sh, но, похоже, вычисляет ha sh данных, которые вы ему даете, в вашем случае (нижний регистр) шестнадцатеричное представление ha sh значение, которое вы уже вычислили.

В вашем первом примере документа у вас есть эти значения (все хэши являются хешами SHA256):

  • Ha sh байта диапазоны для подписи:

    91A9F5EBC4F2ECEC819898824E00ECD9194C3E85E4410A3EFCF5193ED7739119
    
  • Ha sh из "91a9f5ebc4f2ecec819898824e00ecd9194c3e85e4410a3efcf5193ed7739119".getBytes():

    2F37FE82F4F71770C2B33FB8787DE29627D7319EE77C6B5C48152F6E420A3242
    
  • Ha sh значение, подписанное контейнер встроенной подписи:

    2F37FE82F4F71770C2B33FB8787DE29627D7319EE77C6B5C48152F6E420A3242
    

И в вашем первом примере документа у вас есть эти значения (все хэши также являются хешами SHA256):

  • Ha sh диапазонов байтов для подписи:

    79793C58489EB94A17C365445622B7F7945972A5A0BC4C93B6444BEDFFA5A5BB
    
  • Ha sh из "79793c58489eb94a17c365445622b7f7945972a5a0bc4c93b6444bedffa5a5bb".getBytes():

    A8BCBC6F9619ECB950864BFDF41D1B5B7CD33D035AF95570C426CF4B0405949B
    
  • Ha sh значение, подписанное встроенным контейнером подписи:

    A8BCBC6F9619ECB950864BFDF41D1B5B7CD33D035AF95570C426CF4B0405949B
    

Таким образом, вы должны исправить свой метод signDocument, чтобы правильно интерпретировать данные, или вам нужно gi это массив байтов, содержащий весь поток диапазона для обработки.

...