C# 使用 iTextSharp 打开受密码保护的 pdf 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17666577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 10:08:51  来源:igfitidea点击:

Opening password-protected pdf file with iTextSharp

c#asp.netpdfpasswordsitextsharp

提问by Artemis

I'm making an application that should display PDFs with password. This is my code:

我正在制作一个应用程序,应该显示带有密码的 PDF。这是我的代码:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        try
        {
            string filePath = Request.QueryString["filePath"];
            if (filePath.ToUpper().EndsWith("PDF"))
            {
                copyPDF(filePath);
            }
        }
        catch
        {
            string message = "<script language='Javascript'>alert('File Not Found! Call Records Department for verification. ')</script>";
            ScriptManager.RegisterStartupScript(Page, this.GetType(), message, message, false);
        }
    }
}
public void copyPDF(string filePath)
{
    iTextSharp.text.pdf.RandomAccessFileOrArray ra = new iTextSharp.text.pdf.RandomAccessFileOrArray(Server.MapPath(ResolveUrl(filePath)));
    if (ra != null)
    {
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        byte[] password = System.Text.ASCIIEncoding.ASCII.GetBytes("Secretinfo");
        iTextSharp.text.pdf.PdfReader thepdfReader = new iTextSharp.text.pdf.PdfReader(ra, password);
        int pages = thepdfReader.NumberOfPages;
        iTextSharp.text.Document pdfDoc = new iTextSharp.text.Document();
        iTextSharp.text.pdf.PdfCopy pdfCopy = new iTextSharp.text.pdf.PdfCopy(pdfDoc, ms);

        pdfDoc.Open();
        int i = 0;
        while (i < pages)
        {
            pdfCopy.AddPage(pdfCopy.GetImportedPage(thepdfReader, i + 1));
            i += 1;
        }
        pdfDoc.Close();
        Byte[] byteInfo = ms.ToArray();
        Response.Clear();
        Response.ContentType = "application/pdf";
        Response.AddHeader("content-length", byteInfo.Length.ToString());
        Response.BinaryWrite(byteInfo);
        Response.Flush();
        Response.End();
    }
}

My code has no problem opening pdf files without password but it can't open pdfs with password even though the password is supplied. The application executes the catch instead. What seems to be wrong with my code?

我的代码在没有密码的情况下打开 pdf 文件没有问题,但即使提供了密码,也无法打开带密码的 pdf。应用程序改为执行捕获。我的代码似乎有什么问题?

EDIT: I removed the Catchto see the exception thrown.

编辑:我删除了Catch以查看抛出的异常。

Exception Details: System.ArgumentException: PdfReader not opened with owner password

异常详细信息:System.ArgumentException:PdfReader 未使用所有者密码打开

It says the source of the error is Line 51.

它说错误的来源是第 51 行。

Line 49:    while (i < pages)
Line 50:    {
Line 51:         pdfCopy.AddPage(pdfCopy.GetImportedPage(thepdfReader, i + 1));
Line 52:         i += 1;
Line 53:    }

采纳答案by mkl

For certain operations on encrypted documents iText(Sharp) requires that the document not merely is opened with the user password but instead with the owner password. This corresponds to the definition of these passwords in the PDF specification:

对于加密文档的某些操作,iText(Sharp) 要求文档不仅使用用户密码打开,而且使用所有者密码打开。这对应于 PDF 规范中这些密码的定义:

Whether additional operations shall be allowed on a decrypted document depends on which password (if any) was supplied when the document was opened and on any access restrictions that were specified when the document was created:

  • Opening the document with the correct ownerpassword should allow full (owner) access to the document. This unlimited access includes the ability to change the document's passwords and access permissions.
  • Opening the document with the correct userpassword (or opening a document with the default password) should allow additional operations to be performed according to the user access permissions specified in the document's encryption dictionary.

(section 7.6.3.1 in ISO 32000-1)

是否允许对解密文档进行其他操作取决于打开文档时提供的密码(如果有)以及创建文档时指定的任何访问限制:

  • 使用正确的所有者密码打开文档应该允许完全(所有者)访问文档。这种无限制的访问包括更改文档密码和访问权限的能力。
  • 使用正确的用户密码打开文档(或使用默认密码打开文档)应该允许根据文档加密字典中指定的用户访问权限执行其他操作。

ISO 32000-1 中的第 7.6.3.1 节)

iText(Sharp) currently does not check in detail the user access permissions specified in the document's encryption dictionarybut instead always requires the owner password for operations requiring certain permissions, and copying whole pages from a document definitively is one of them.

iText(Sharp) 目前没有详细检查文档加密字典中指定的用户访问权限,而是始终需要所有者密码才能进行需要某些权限的操作,而从文档中明确复制整个页面就是其中之一。

This been said, the iText(Sharp) developers are very much aware (due to many such questions asked)

据说,iText(Sharp) 开发人员非常清楚(由于提出了许多此类问题)

  • that iText(Sharp) users may be entitled to execute such operations even without the owner password on account of the before mentioned user access permissions specified in the document's encryption dictionary,
  • that there are myriad PDFs to which their respective owners applied an owner password (to prevent misuse by others) and then forgot it (or by using a randomly generated one never knew it to start with), and
  • that iText(Sharp) (being open source) can easily be patched by anyone not to respect the differences between user and owner password.
  • 由于上述文档加密字典中指定的用户访问权限,即使没有所有者密码,iText(Sharp) 用户也可能有权执行此类操作
  • 有无数的 PDF,它们各自的所有者应用了所有者密码(以防止其他人滥用)然后忘记了它(或使用随机生成的从不知道它的开始),和
  • iText(Sharp)(开源)可以很容易地被任何人修补而不尊重用户和所有者密码之间的差异。

To allow users to do what they are entitled to and to prevent the spreading of patched copies of the library, iText(Sharp) contains an override for this test in the PdfReaderclass:

为了允许用户做他们有权做的事情并防止库的修补副本传播,iText(Sharp) 在PdfReader类中包含此测试的覆盖:

/**
 * The iText developers are not responsible if you decide to change the
 * value of this static parameter.
 * @since 5.0.2
 */
public static bool unethicalreading = false;

Thus, by setting

因此,通过设置

PdfReader.unethicalreading = true;

you globally override this permission checking mechanism.

您全局覆盖此权限检查机制。

Please respect the rights of PDF authors and only use this override if you indeed are entitled to execute the operations in question.

请尊重 PDF 作者的权利,并且仅当您确实有权执行相关操作时才使用此覆盖。

回答by Enrico Giurin

I applied this workaround and it works:

我应用了这个解决方法并且它有效:

private void fixIssue(PdfReader pdfReader) throws Exception {
        Field f = pdfReader.getClass().getDeclaredField("ownerPasswordUsed");
        f.setAccessible(true);
        f.setBoolean(pdfReader, true);

}

回答by Ivan Melnikov

Try to use this workaround to unlock protected PdfReader. It's work for me:

尝试使用此解决方法解锁受保护的 PdfReader。这对我有用:

public static PdfReader TryToUnlockPdf(PdfReader reader)
{
    if (reader == null)
    {
        return reader;
    }
    try
    {
        var f = reader.GetType().GetField("encrypted", BindingFlags.NonPublic | BindingFlags.Instance);
        f?.SetValue(reader, false);
    }
    catch (Exception)
    { // ignore
    }
    return reader;
}

private static void GetPdfPageFiles(this Page pageFile)
{
    reader = new PdfReader(pageFile.ContentBytes);
    // Unlock protected 
    reader = TryToUnlockPdf(reader);

    // if no using TryToUnlockPdf workaroud - GetImportedPage method raises "System.ArgumentException: PdfReader not opened with owner password"
    var curPage = pdfWriter.GetImportedPage(reader, 0);
}