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

时间:2013-07-16 01:25:41

标签: c# asp.net pdf passwords itextsharp

我正在创建一个应该显示带密码的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:    }

3 个答案:

答案 0 :(得分:19)

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

  

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

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

ISO 32000-1中的第7.6.3.1节)

iText(夏普)目前不会详细检查文档加密词典中指定的用户访问权限,而是始终要求所有者密码用于需要特定权限的操作,以及从文档复制整个页面最终是其中之一。

据说,iText(夏普)开发人员非常清楚(由于提出了许多这样的问题)

  • iText(夏普)用户可能有权在没有所有者密码的情况下执行此类操作,因为前面提到的文档加密字典中指定的用户访问权限
  • 有各种各样的所有者使用所有者密码(以防止他人滥用),然后忘记它(或使用随机生成的一个从未知道它开始)的无数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作者的权利,如果您确实有权执行相关操作,请仅使用此覆盖。

答案 1 :(得分:1)

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

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

}

答案 2 :(得分:0)

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