iText - 仅加密嵌入式文件

时间:2016-09-30 10:58:10

标签: pdf encryption itext itext7

我想创建一个未加密的pdf文件,其中包含带有iText的加密嵌入文件,如PDF 32000-1:2008第7.6.1节所述:

  

从PDF 1.5开始,嵌入式文件可以加密   否则未加密的文件

但是,以下示例(iText 7.0.1)生成一个PDF文件,其中包含未加密的嵌入式文件流(关闭压缩以更好地分析生成的PDF文件):

             /* cf. 7.6.3.1: Documents in which only file attachments are 
                encrypted shall use the same password as the user and owner password.*/
PdfWriter writer = new PdfWriter(fileName, new WriterProperties()
                         .setStandardEncryption("secret".getBytes(),
                         "secret".getBytes(), EncryptionConstants.ALLOW_PRINTING |
                         EncryptionConstants.ALLOW_MODIFY_ANNOTATIONS,
                         EncryptionConstants.ENCRYPTION_AES_128 |
                         EncryptionConstants.DO_NOT_ENCRYPT_METADATA |
                         EncryptionConstants.EMBEDDED_FILES_ONLY)
                         .setCompressionLevel(CompressionConstants.NO_COMPRESSION));

PdfDocument pdf = new PdfDocument(writer);  

PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(pdf,"attached file".getBytes(),
                         null,"attachment.txt",null,null,null,true);
pdf.addFileAttachment("attachment.txt", fs);

try (Document doc = new Document(pdf)) {
        doc.add(new Paragraph("main file"));
}

此结果似乎与规范说明相反:

  

如果流的内容嵌入在PDF文件中(请参阅   7.11.4,"嵌入式文件流"),它们应像文件中的任何其他流一样加密

上面示例生成的pdf文件包含CF字典中加密嵌入文件流的正确条目:

<</CF<</StdCF<</AuthEvent/EFOpen/CFM/AESV2/Length 16>>>>/EFF/StdCF

规范表20中的表格:

  

在加密嵌入时,符合编写者应尊重此值   文件,除了具有自己的crypt的嵌入式文件流   过滤器说明符。

我们案例中的流没有自己的CF说明符,因此应使用AESV2进行加密。但是,在我们的示例中,流未加密:

4 0 obj
<</Length 13/Params<</ModDate(D:20160930101501+02'00')/Size 13>>/Subtype    /application#2foctet-stream/Type/EmbeddedFile>>stream
attached file
endstream
endobj

这导致以下问题:

  1. 这是iText中的错误还是我误解了PDF规范?
  2. 如何使用加密的嵌入文件创建未加密的pdf文件 用iText?
  3. 如果还没有,还有其他免费的库或命令 行工具吗?
  4. PS:Acrobat Reader DC和PDF-XChange Viewer 2.5要求输入密码才能打开附件,而(不符合要求)的读者如evince打开附件时没有任何问题。但这不是我的问题。我的问题不是关于读者行为和可能的道德问题,而是关于pdf文件本身及其对规范的遵守情况。

1 个答案:

答案 0 :(得分:1)

由于我没有得到任何答案,我使用iText 5.5.9和iText 7.0.1进行了更多测试,并得出结论不用override func viewDidLoad() { super.viewDidLoad() myImageView.image = newphoto } 加密嵌入式文件流新版iText 7中的错误。它仅适用于iText 5和EMBEDDED_FILES_ONLY,但Acrobat reader会发出警告,指出此页面上存在错误,并且可能无法正确显示页面。有关详细信息,请参阅下表:

Summary of test results

以下是使用iText 5.5.9生成上表中使用的pdf文件的最小,完整和可验证示例的代码...

ENCRYPTION_AES_256

...和iText 7.0.1:

package pdfencryptef_itext5;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfFileSpecification;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class PDFEncryptEF_iText5 {

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

        new PDFEncryptEF_iText5().createPDF("iText5_STD128.pdf", PdfWriter.STANDARD_ENCRYPTION_128);
        new PDFEncryptEF_iText5().createPDF("iText5_AES128.pdf", PdfWriter.ENCRYPTION_AES_128);
        new PDFEncryptEF_iText5().createPDF("iText5_AES256.pdf", PdfWriter.ENCRYPTION_AES_256);

        Security.addProvider(new BouncyCastleProvider());
        new PDFEncryptEF_iText5().createPDF("iText5_AES128C.pdf", -PdfWriter.ENCRYPTION_AES_128);
        new PDFEncryptEF_iText5().createPDF("iText5_AES256C.pdf", -PdfWriter.ENCRYPTION_AES_256);

    }

    public void createPDF(String fileName, int encryption  ) throws FileNotFoundException, DocumentException, IOException, CertificateException {

        Document document = new Document();
        Document.compress = false;

        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(fileName));

        if( encryption >= 0 ){
            writer.setEncryption("secret".getBytes(),"secret".getBytes(), 0,
                   encryption | PdfWriter.EMBEDDED_FILES_ONLY);
        } else {
            Certificate cert = getPublicCertificate("MyCert.cer" );
            writer.setEncryption( new Certificate[] {cert}, new int[] {0}, -encryption  | PdfWriter.EMBEDDED_FILES_ONLY);
        }
        writer.setPdfVersion(PdfWriter.VERSION_1_6);

        document.open();

        PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(writer, null, "attachment.txt", "attached file".getBytes(), 0);
        writer.addFileAttachment( fs );

        document.add(new Paragraph("main file"));
        document.close(); 

    }

     public Certificate getPublicCertificate(String path) throws IOException, CertificateException {
        FileInputStream is = new FileInputStream(path);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
        return cert;
    }

}

我必须承认,我对iText人员至少在我的三个问题中的第一个问题没有反馈感到有点失望,但希望未来版本的iText 7能够正确处理package pdfencryptef_itext7; import com.itextpdf.kernel.pdf.CompressionConstants; import com.itextpdf.kernel.pdf.EncryptionConstants; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfVersion; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.kernel.pdf.WriterProperties; import com.itextpdf.kernel.pdf.filespec.PdfFileSpec; import com.itextpdf.layout.Document; import com.itextpdf.layout.element.Paragraph; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.Security; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import org.bouncycastle.jce.provider.BouncyCastleProvider; public class PDFEncryptEF_iText7 { public static void main(String[] args) throws Exception { new PDFEncryptEF_iText7().createPDF("iText7_STD128.pdf", EncryptionConstants.STANDARD_ENCRYPTION_128); new PDFEncryptEF_iText7().createPDF("iText7_AES128.pdf", EncryptionConstants.ENCRYPTION_AES_128); new PDFEncryptEF_iText7().createPDF("iText7_AES256.pdf", EncryptionConstants.ENCRYPTION_AES_256); Security.addProvider(new BouncyCastleProvider()); new PDFEncryptEF_iText7().createPDF("iText7_AES128C.pdf", -EncryptionConstants.ENCRYPTION_AES_128); new PDFEncryptEF_iText7().createPDF("iText7_AES256C.pdf", -EncryptionConstants.ENCRYPTION_AES_256); } public void createPDF(String fileName, int encryption ) throws FileNotFoundException, IOException, CertificateException{ PdfWriter writer; if( encryption >= 0 ){ writer = new PdfWriter(fileName, new WriterProperties().setStandardEncryption("secret".getBytes(),"secret".getBytes(), 0, encryption | EncryptionConstants.EMBEDDED_FILES_ONLY) .setPdfVersion(PdfVersion.PDF_1_6)); } else { Certificate cert = getPublicCertificate("MyCert.cer" ); writer = new PdfWriter(fileName, new WriterProperties().setPublicKeyEncryption( new Certificate[] {cert}, new int[] {0}, -encryption | EncryptionConstants.EMBEDDED_FILES_ONLY ) .setPdfVersion(PdfVersion.PDF_1_6)); } writer.setCompressionLevel(CompressionConstants.NO_COMPRESSION); PdfDocument pdf = new PdfDocument(writer); PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(pdf,"attached file".getBytes(),null,"attachment.txt",null,null,null,true); pdf.addFileAttachment("attachment.txt", fs); try (Document doc = new Document(pdf)) { doc.add(new Paragraph("main file")); } } public Certificate getPublicCertificate(String path) throws IOException, CertificateException { FileInputStream is = new FileInputStream(path); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate) cf.generateCertificate(is); return cert; } } 旗。正如测试所显示的那样,对于pdf制作人和读者来说,正确处理这一功能似乎远非微不足道。