【问题标题】:How to check pdf file is password protected?如何检查pdf文件是否受密码保护?
【发布时间】:2022-03-10 01:17:55
【问题描述】:

如何在java中检查pdf文件是否受密码保护? 我知道有几个工具/库可以做到这一点,但我想知道这是否可以通过 java 中的程序来实现。

【问题讨论】:

  • 您回答了自己的问题。使用 itext 之类的开源库并编写一个 java 程序进行测试。
  • 我想其中一些工具/库是用纯java 编写的(而其他一些可以用其他语言编写,但这不是主题问题),不是吗? :) 如果是这样,为什么你不能编写自己的密码检查实现?
  • 正如@aga 指出的那样,显然可以在Java 中做到这一点。因此,您的问题很可能遗漏了您未提及的一些额外要求。请说明您的要求。

标签: java pdf


【解决方案1】:

更新

根据 mkl 在此答案下方的评论,规范似乎允许使用两种类型的 PDF 结构:(1) 交叉引用表 (2) 交叉引用流。以下解决方案仅针对第一种类型的结构。此答案需要更新以解决第二种类型。

====

上面提供的所有答案都参考了一些第三方库,这是 OP 已经知道的。 OP 要求使用本机 Java 方法。我的回答是肯定的,你可以做到,但需要做很多工作。

这需要两个步骤:

第 1 步判断 PDF 是否加密

根据 Adob​​e 的 PDF 1.7 specs(第 97 和 115 页),如果预告片记录包含密钥“\Encrypted”,则 pdf 被加密(加密可以是简单的密码保护或 RC4 或 AES 或一些自定义加密)。这是一个示例代码:

    Boolean isEncrypted = Boolean.FALSE;
    try {
        byte[] byteArray = Files.readAllBytes(Paths.get("Resources/1.pdf"));
        //Convert the binary bytes to String. Caution, it can result in loss of data. But for our purposes, we are simply interested in the String portion of the binary pdf data. So we should be fine.
        String pdfContent = new String(byteArray);
        int lastTrailerIndex = pdfContent.lastIndexOf("trailer");
        if(lastTrailerIndex >= 0 && lastTrailerIndex < pdfContent.length()) {
            String newString =  pdfContent.substring(lastTrailerIndex, pdfContent.length());
            int firstEOFIndex = newString.indexOf("%%EOF");
            String trailer = newString.substring(0, firstEOFIndex);
            if(trailer.contains("/Encrypt"))
                isEncrypted = Boolean.TRUE;
        }
    }
    catch(Exception e) {
        System.out.println(e);
        //Do nothing
    }

第 2 步找出加密类型

这一步比较复杂。我还没有代码示例。但这里是算法:

  1. 从预告片中读取密钥“/Encrypt”的值,如上述步骤 1 中所述。例如。值为 288 0 R。
  2. 查找字节“288 0 obj”。这是文档中“加密字典”对象的位置。该对象边界以字符串“endobj”结束。
  3. 在此对象中查找键“/Filter”。 “过滤器”是识别文档安全处理程序的过滤器。如果“/Filter”的值为“/Standard”,则文档使用内置的基于密码的安全处理程序。

如果你只是想知道PDF是否被加密,而不用担心加密是所有者/用户密码或一些高级算法的形式,你不需要上面的第2步。

希望这会有所帮助。

【讨论】:

  • 如果 pdf 使用交叉引用流而不是表,这将不起作用。
  • @mkl 您能否举个例子详细说明一下?如果需要,我很乐意更新我的答案。目标是帮助社区提供最有效的答案。
  • 使用交叉引用流的 pdf 没有您的代码所要求的预告片。而是将预告片条目添加到交叉引用流字典中。
  • @mkl,您能否附上一个使用外部参照流而不是外部参照表的示例 PDF?规范清楚地表明加密信息存储在预告片字典中。
  • 由于我目前只使用智能手机,因此手头没有示例文件。但只需查看规范 ISO 32000-1,第 7.5.8 节“交叉引用流”:交叉引用流是流对象(参见 7.3.8,“流对象”),并包含一个字典和一个数据流。每个交叉引用流包含与一个交叉引用部分的交叉引用表(参见 7.5.4,“交叉引用表”)和尾(参见 7.5.5,“文件尾”)等效的信息。我>
【解决方案2】:

您可以使用 PDFBox:

http://pdfbox.apache.org/

代码示例:

try
{
    document = PDDocument.load( yourPDFfile );

    if( document.isEncrypted() )
    {
      //ITS ENCRYPTED!
    }
}

使用maven?

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0</version>
</dependency>

【讨论】:

  • 使用getNumberOfPages()获取页数也很有帮助
【解决方案3】:

使用iText pdf API 我们可以识别受密码保护的PDF。

示例:

    try {
            new PdfReader("C:\\Password_protected.pdf");            
        } catch (BadPasswordException e) {
            System.out.println("PDF is password protected..");
        } catch (Exception e) {
            e.printStackTrace();
        }

【讨论】:

  • iText 受 AGPL 许可。所以,我建议使用 PDFBox。
  • 阅读器不够用,因为 pdf 从未打开过。第二行应该是 new PdfDocument(new PdfReader(filePath));
【解决方案4】:

您可以使用 Itext 验证 pdf,即它是否可读、可写。

下面是代码sn-p,

boolean isValidPdf = false;
try {
    InputStream tempStream = new FileInputStream(new File("path/to/pdffile.pdf"));
    PdfReader reader = new PdfReader(tempStream);
    isValidPdf = reader.isOpenedWithFullPermissions();
    } catch (Exception e) {
        isValidPdf = false;
    }

【讨论】:

    【解决方案5】:

    在 java 中的正确做法是每个 @vhs。

    然而,到目前为止,在任何应用程序中,最简单的是使用非常轻量级的 pdfinfo 工具来过滤加密状态,在这里使用 windows cmd 我可以立即得到一个报告,即同一文件的两个不同副本被加密

    >forfiles /m *.pdf /C "cmd /c echo @file &pdfinfo @file|find /i \"Encrypted\""
    
    "Certificate (9).pdf"
    Encrypted:      no
    
    "ds872 source form.pdf"
    Encrypted:      AES 128-bit
    
    "ds872 filled form.pdf"
    Encrypted:      AES 128-bit
    
    "How to extract data from a particular area in a PDF file - Stack Overflow.pdf"
    Encrypted:      no
    
    "Test.pdf"
    Encrypted:      no
    
    >
    

    【讨论】:

      【解决方案6】:

      解决办法:

      1) 安装PDF解析器http://www.pdfparser.org/

      2) 在本节编辑 Parser.php:

      if (isset($xref['trailer']['encrypt'])) {
      echo('Your Allert message');
      exit();}
      

      3)在您的 .php 表单帖子(例如 upload.php)中插入:

      for the first require  '...yourdir.../vendor/autoload.php';
      

      然后编写这个函数:

      function pdftest_is_encrypted($form) {
      $parser = new \Smalot\PdfParser\Parser();
      $pdf    = $parser->parseFile($form);
      }
      

      然后调用函数

      pdftest_is_encrypted($_FILES["upfile"]["tmp_name"]);
      

      这就是全部,如果您尝试使用密码加载 PDF,系统会返回错误“您的警报消息”

      【讨论】:

      • 你的答案是 PHP 的,但问题是 Java 解决方案。
      猜你喜欢
      • 2013-03-31
      • 2016-02-19
      • 2023-03-03
      • 2015-08-24
      • 2013-02-05
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 2014-12-30
      相关资源
      最近更新 更多