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

标签 c# pdf encryption itextsharp

关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。












想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。

6年前关闭。




Improve this question




我需要能够从某些 PDF 文档中删除安全/加密,最好使用 itextsharp 库。这曾经是可能的( How to decrypt a pdf file by supplying password of the file as argument using c#? ),但最近的 change到图书馆意味着解决方案不再有效。

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

编辑

所以一直以来我都认为我拥有用于​​测试这个文件的所有者密码。但实际上我的密码是用户密码。我认为它是所有者密码的原因是因为它作为所有者密码起作用,而其他值不起作用。我相信用户密码代替用户密码起作用的原因是 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 来检查。文档。

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

幸运的是,我可以在字里行间阅读,所以我又做了一个例子。

许多 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 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.<init>(PdfReader.java:181)
    at com.itextpdf.text.pdf.PdfReader.<init>(PdfReader.java:230)
    at com.itextpdf.text.pdf.PdfReader.<init>(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例如,我们看到我们可以检索用户密码(如果存在用户密码),但无法检索所有者密码。这是真正的 secret 。对于您所指的旧版 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 是免费软件,但您也应该知道免费不是免费的同义词。请阅读我对以下问题的回答以获取更多信息:Is iText Java library free of charge or have any fees to be paid?

关于c# - 如何使用所有者密码解密 PDF 文档?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27867868/

相关文章:

iphone - iPhone : Core Data or Property Lists? 上什么更容易加密

android - 阻止非 Android 用户调用 JSON 服务

python - 通过网络或任何其他 key 交换进行 Diffie-Hellman key 交换

c# - Box2D XNA 中的 Pong

c# - 有时连接 CRUD 应用程序 DAL

c# - Autofac:注册 Func<> 或工厂?

c# - 将数字与字符串中的其他符号分开

c# - 如何使用 PdfSharp 创建注释以突出显示现有 PDF 的文本

javascript - 从javascript调用pdfium(chrome原生pdf查看器)

python - 在python中读取pdf文件时编解码器出现unicode错误