如何使用所有者密码解密PDF文档?

我需要能够从某些PDF文档中删除安全性/加密,最好使用itextsharp库。 这曾经是可能的( 如何通过使用c#提供文件的密码作为参数来解密pdf文件 ),但对库的更新更新意味着解决方案不再有效。

我知道这可以通过Aspose PDF库( 示例 )来完成,但这似乎是一个昂贵的选择。

编辑

所以这一次我以为我拥有我用来测试这个文档的所有者密码。 但实际上我的密码是用户密码。 我认为它是所有者密码的原因是因为它作为所有者密码工作,其他值不起作用。 我相信用户密码代替用户密码的原因是PdfReader.unethicalreading字段设置为true (它是一个碰巧在代码中的其他地方设置的全局标志)。

为了测试加密PDF文件的代码,我们需要一个加密的示例PDF。 我们将使用EncryptPdf示例创建这样的文件。

 public void manipulatePdf(String src, String dest) throws IOException, DocumentException { PdfReader reader = new PdfReader(src); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); stamper.setEncryption("Hello".getBytes(), "World".getBytes(), PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128 | PdfWriter.DO_NOT_ENCRYPT_METADATA); stamper.close(); } 

使用此代码,我创建了一个加密文件hello_encrypted.pdf ,我将在第一个示例中使用它来演示如何解密文件。

您的原始问题听起来像“如何使用所有者密码解密PDF文档?”

这很容易。 DecryptPdf示例向您展示了如何执行此操作:

 public void manipulatePdf(String src, String dest) throws IOException, DocumentException { PdfReader reader = new PdfReader(src, "World".getBytes()); System.out.println(new String(reader.computeUserPassword())); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); stamper.close(); reader.close(); } 

我们创建一个PdfReader实例,将所有者密码作为第二个参数传递。 如果我们想知道用户密码,我们可以使用computeUserPassword()方法。 我们是否应该加密文件,而不是使用我们知道的所有者密码和我们计算的用户密码,并使用setEncryption()方法重新引入安全性。

但是,由于我们没有这样做,所有安全性都被删除了,这正是您想要的。 可以通过查看hello.pdf文档来检查。

有人可能会争辩说,你的问题属于“它不起作用”的问题,这些问题只能用“它对我有用”的答案来回答。 可以投票来结束你的问题,因为你没有提供可用于重现问题的代码示例,而任何人都可以提供certificate你错的代码示例。

幸运的是,我可以在两行之间阅读,所以我做了另一个例子。

许多PDF都是在没有用户密码的情况下加密的。 任何人都可以打开它们,但会添加加密以强制执行某些限制(例如,您可以查看文档,但无法打印)。 在这种情况下,只有一个所有者密码,如EncryptPdfWithoutUserPassword示例中所示:

 public void manipulatePdf(String src, String dest) throws IOException, DocumentException { PdfReader reader = new PdfReader(src); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); stamper.setEncryption(null, "World".getBytes(), PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128 | PdfWriter.DO_NOT_ENCRYPT_METADATA); stamper.close(); reader.close(); } 

现在我们得到一个加密的PDF,但可以在没有用户密码的情况下打开: hello_encrypted2.pdf

如果我们想操纵PDF,我们仍然需要知道所有者密码。 如果我们没有传递密码,那么iText将正确地抛出exception:

 Exception in thread "main" com.itextpdf.text.exceptions.BadPasswordException: Bad user password at com.itextpdf.text.pdf.PdfReader.readPdf(PdfReader.java:681) at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:181) at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:230) at com.itextpdf.text.pdf.PdfReader.(PdfReader.java:207) at sandbox.security.DecryptPdf.manipulatePdf(DecryptPdf.java:26) at sandbox.security.DecryptPdf.main(DecryptPdf.java:22) 

但是,如果我们不记得所有者密码怎么办? 如果PDF是由第三方制作而我们不想尊重该第三方的意愿怎么办?

在这种情况下,您可以故意不道德并更改静态unethicalreading变量值。 这是在DecryptPdf2示例中完成的:

 public void manipulatePdf(String src, String dest) throws IOException, DocumentException { PdfReader.unethicalreading = true; PdfReader reader = new PdfReader(src); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); stamper.close(); reader.close(); } 

如果文档是使用用户密码所有者密码加密的,则此示例将不起作用,在这种情况下,您必须至少传递一个密码,即“所有者密码”或“用户密码”(事实上您已经拥有)仅使用“用户”密码访问PDF是不道德阅读的副作用。 如果仅引入所有者密码,则如果更改unethicalreading标记标记,iText不需要该所有者密码来操作PDF。

但是:iText中曾经有一个错误,在这种情况下也删除了所有者密码。 这不是理想的行为。 在第一个PdfDecrypt示例中,我们看到我们可以检索用户密码(如果存在用户密码),但无法检索所有者密码。 这是真正的秘密。 使用您所引用的旧版iText,操作后将所有者密码从文件中删除,并且所有者密码永久丢失。

我已修复此错误,修复程序在5.3.5版中。 因此,现在保留了所有者密码。 您可以通过查看hello2.pdf来检查这一点 ,这是我们以“不道德”的方式解密的文件。 (如果有所有者和用户密码,则两者都被保留。)

基于这项研究,我假设您的问题不正确。 您打算问:“ 如果没有所有者密码,我如何解密PDF文档?” 或“如何使用用户密码解密PDF?”

解开我曾经修复的错误是没有意义的。 我们不会恢复旧iText版本的(错误)行为,但这并不意味着您无法实现您想要的。 你只需要愚弄iText认为PDF没有加密。

这显示在DecryptPdf3示例中:

 class MyReader extends PdfReader { public MyReader(String filename) throws IOException { super(filename); } public void decryptOnPurpose() { encrypted = false; } } public void manipulatePdf(String src, String dest) throws IOException, DocumentException { MyReader.unethicalreading = true; MyReader reader = new MyReader(src); reader.decryptOnPurpose(); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); stamper.close(); reader.close(); } 

我们现在使用的是PdfReader的自定义子类,而PdfReader 。 我已将其命名为MyReader并且我添加了一个额外的方法,允许我将encrypted变量设置为false

我仍然需要使用unethicalreading并在创建MyReader实例后,我不得不欺骗这个读者认为原始文件没有使用decryptOnPurpose()方法加密。

这会生成文件hello3.pdf ,该文件不再使用所有者密码进行加密。 只要您拥有用户密码,此示例甚至可用于从使用用户加密的文件和所有者密码中删除所有密码。

我将在回答你关于Aspose不是免费的评论时总结这个答案。 你知道iText是免费软件,但你也应该知道免费不是免费的同义词。 请阅读我对以下问题的回答以获取更多信息: iText Java库是免费的还是需要支付任何费用?

您可以使用命令行工具qpdf

 qpdf –-password=s3cr3t –-decrypt protected.pdf unprotected.pdf 

qpdf还提供了可从其他程序使用的API。

或者,您也可以使用命令行工具pdftk

 pdftk protected.pdf input_pw s3cr3t output unprotected.pdf