【问题标题】:Opening password-protected pdf file with iTextSharp使用 iTextSharp 打开受密码保护的 pdf 文件
【发布时间】:2023-11-29 14:29:01
【问题描述】:

我正在制作一个应显示带有密码的 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();
    }
}

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

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

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

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

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

【问题讨论】:

  • 抛出了哪个异常?
  • 它不会抛出异常。它执行 catch 语句,在这种情况下是一个弹出窗口,显示“未找到文件!致电记录部门进行验证。'
  • 嘿@mkl 我删除了 Catch 以找出引发了什么样的异常它说 System.ArgumentException: PdfReader not opens with owner password
  • 您似乎没有提供正确的密码。
  • 可能 PDF 既有用户密码又有所有者密码,而您只提供了用户密码。

标签: c# asp.net pdf passwords itextsharp


【解决方案1】:

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

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

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

ISO 32000-1 中的第 7.6.3.1 节)

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

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

  • 即使没有所有者密码,iText(Sharp) 用户也可能有权执行此类操作,原因是前面提到的文档加密字典中指定的用户访问权限,
  • 有无数的 PDF,其各自的所有者应用了所有者密码(以防止被他人滥用)然后忘记了它(或使用一个随机生成的从不知道它开始的密码),并且
  • iText(Sharp)(开源)可以很容易地被任何不尊重用户和所有者密码差异的人修补。

为了允许用户做他们有权做的事情并防止库的修补副本传播,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;

因此,通过设置

PdfReader.unethicalreading = true;

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

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

【讨论】:

  • 我使用了这个,现在我收到 InvalidCastException 错误 无法将类型为“iTextSharp.text.pdf.PdfArray”的对象转换为类型“iTextSharp. text.pdf.PRIndirectReference'。
  • 那么您的 PDF 或 itext 有错误。能否提供PDF进行分析?
  • 如何为您提供 PDF? (对不起。如果你告诉我该怎么做,我会非常乐意。)
  • * 本身没有文件交换服务。因此,当要在 * 的上下文中提供文件时,通常会使用一些文件共享服务,例如通过 Dropbox 或 google drive 提供文件,并在此处发布 URL。
  • 可以看PDFhere
【解决方案2】:

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

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

}

【讨论】:

  • 虽然我知道在某些情况下必须在 iText 中使用反射来获得有趣的效果,但这里没有必要。
  • 嗯,这只是一种解决方法,正如我所写的。但它有效:) 使用提供的构造函数之一将 ownerPasswordUsed 设置为 true 可能更有意义。 sourceforge.net/p/itext/code/HEAD/tree/trunk/itext/src/main/…
  • @mkl 需要它。我使用旧的 iTextSharp 4.x 来避免商业许可,它没有简单的方法来设置该字段。
  • @ChrisBordeman 好的,所以 在问题的上下文中 没有必要这样做,因为 OP 显然使用了更新版本的 iText。对于 5.0.2 之前的 iText 版本,如果不想修补库本身,反射确实是唯一的解决方案。
【解决方案3】:

尝试使用此解决方法来解锁受保护的 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);
}

【讨论】:

    最近更新 更多