You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用iText5加密的AES-256 PDF文本可被轻易读取,如何加密需自定义解密

解决自定义AES加密PDF内容,仅允许自定义程序解密的问题

你遇到的核心问题是iText 5默认的PDF加密是遵循PDF官方标准的,Adobe阅读器等标准工具会自动识别并处理这种加密(哪怕你可能不小心设置了空密码或开放权限)。如果想要让只有你的自定义程序才能读取文本,不能依赖PDF标准加密,得自己对PDF的内容流做自定义加密处理。

为什么当前方法无效?

当你用iText的setEncryption方法加密PDF时,本质是给PDF套了一层标准的加密外壳,完全符合PDF规范中定义的加密算法(比如AES-256)。所有合规的PDF阅读器都内置了这套标准解密逻辑,所以只要能通过权限验证,就能正常解析内容,这也是为什么任何人都能轻松读取的原因。

正确的实现思路

我们需要绕过PDF标准加密体系,直接对PDF内部的页面内容流进行自定义AES加密。这样标准阅读器打开时会看到乱码(因为无法识别你的自定义加密逻辑),只有你的程序读取内容流后,用对应的AES密钥解密才能还原文本。

具体步骤(结合iText 5代码)

  1. 读取原PDF,获取每个页面的内容流字节数据
  2. 用自定义AES算法加密这些内容流字节
  3. 将加密后的内容流替换回PDF页面
  4. 保存修改后的PDF(此时标准阅读器无法正常解析内容)
  5. 编写自定义解密程序,读取加密后的PDF内容流,用相同AES密钥解密还原文本

示例代码实现

加密部分代码

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.*;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.Key;

public class CustomPdfEncryptor {
    public static final String SRC = "/2016.pdf";
    public static final String DEST = "/enc.pdf";
    // 自定义AES密钥(实际使用时请妥善保管,建议从安全配置读取)
    // 密钥长度:16位=AES-128,24位=AES-192,32位=AES-256
    private static final String AES_KEY = "MySecureAESKey12345678";

    public static void main(String[] args) throws IOException, DocumentException {
        try {
            // 初始化AES加密器
            Key secretKey = new SecretKeySpec(AES_KEY.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            // 读取原PDF并准备修改
            PdfReader reader = new PdfReader(SRC);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(DEST));

            // 遍历所有页面,加密内容流
            int totalPages = reader.getNumberOfPages();
            for (int i = 1; i <= totalPages; i++) {
                // 获取当前页面的原始内容流字节
                byte[] contentBytes = reader.getPageContent(i);
                // 加密内容流
                byte[] encryptedBytes = cipher.doFinal(contentBytes);
                // 替换原页面内容为加密后的字节
                PdfContentByte contentByte = stamper.getOverContent(i);
                contentByte.reset();
                contentByte.addRawBytes(encryptedBytes);
            }

            stamper.close();
            reader.close();
            System.out.println("自定义加密PDF生成完成");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

解密部分代码(自定义程序专用)

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.Key;

public class CustomPdfDecryptor {
    public static final String SRC = "/enc.pdf";
    private static final String AES_KEY = "MySecureAESKey12345678"; // 和加密时完全一致的密钥

    public static void main(String[] args) throws IOException {
        try {
            // 初始化AES解密器
            Key secretKey = new SecretKeySpec(AES_KEY.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);

            PdfReader reader = new PdfReader(SRC);
            int totalPages = reader.getNumberOfPages();

            for (int i = 1; i <= totalPages; i++) {
                // 获取加密后的页面内容流
                byte[] encryptedBytes = reader.getPageContent(i);
                // 解密内容流
                byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
                // 将解密后的PDF语法内容转为纯文本
                String rawContent = new String(decryptedBytes);
                // 可选:用iText的文本提取工具解析纯文本
                String plainText = PdfTextExtractor.getTextFromPage(new PdfReader(rawContent.getBytes()), i);
                System.out.println("第" + i + "页解密后的纯文本:");
                System.out.println(plainText);
            }
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

关键注意事项

  • 密钥安全:AES密钥是解密的核心,必须妥善保管,避免硬编码在代码中(建议从环境变量或加密配置文件读取)。
  • 内容流特性:PDF内容流是PDF语法指令集合,不是纯文本,解密后需要用PdfTextExtractor等工具才能提取出可读文本。
  • 资源加密扩展:上述代码仅加密页面内容流,PDF中的字体、图片等资源未加密。如果需要加密这些资源,需额外处理PDF的资源字典数据。
  • 预期效果:加密后的PDF在标准阅读器中会显示乱码或空白,这是正常现象,只有你的自定义解密程序才能正确解析内容。

内容的提问来源于stack exchange,提问作者desperado06

火山引擎 最新活动