尽管密码错误,pdfbox 加密文件仍会打开

问题描述

下载pdf文件时,我指定了密码“123456789987654abc211234567899klm7654321”。打开的时候可以去掉几个字符,比如

“123456789987654abc211234567899kl” - 文件无论如何都会打开!但是如果我使用

“123456789987654abc211234567899k” - 文件未打开


帮助我了解问题所在

    private static void encryptpdf(
        InputStream inputStream,OutputStream outputStream,String ownerPassword,String userPassword) throws Exception
{
    PDDocument document = PDDocument.load(inputStream);
    if (document.isEncrypted())
    {
        return;
    }
    Accesspermission accesspermission = new Accesspermission();
    StandardProtectionPolicy spp =
            new StandardProtectionPolicy(ownerPassword,userPassword,accesspermission);
    spp.setEncryptionKeyLength(40);
    document.protect(spp);

    document.save(outputStream);
    document.close();
}

enter image description here

解决方法

从 pdf 加密到修订版 4 的密码计算加密密钥的第一步是

密码字符串是从主机系统代码页字符(或系统脚本)生成的,首先将字符串转换为 PDFDocEncoding。如果输入是 Unicode,首先转换为代码页编码,然后转换为 PDFDocEncoding 以实现向后兼容。将生成的密码字符串填充或截断为 32 个字节。如果密码字符串长度超过 32 个字节,则只使用它的前 32 个字节;如果长度小于 32 个字节,则通过从以下填充字符串的开头附加所需数量的额外字节来填充它:

<28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08
2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A>

也就是说,如果密码字符串长度为 n 个字节,则将填充字符串的前 32 - n 个字节附加到密码字符串的末尾。如果密码字符串为空(零长度),表示没有用户密码,则替换整个填充字符串。

(ISO 32000-2 第 7.6.4.3.2 节“算法 2:计算文件加密密钥以加密文档(修订版 4 及更早版本)”)

对于更现代的加密类型,您也有限制,但通常不那么苛刻:

UTF-8 密码字符串应通过使用 stringprep (Internet RFC 3454) 的 SASLprep (Internet RFC 4013) 配置文件处理输入字符串从 Unicode 输入生成使用 Normalize 和 BiDi 选项,然后转换为 UTF-8 表示。

如果超过 127 字节,则将 UTF-8 表示截断为 127 字节。

(ISO 32000-2 第 7.6.4.3.3 节“算法 2.A:从加密文档中检索文件加密密钥以对其进行解密(修订版 6 及更高版本)”)