Technical Article

针对海量文档的高速 AES-256 PDF 加密

在法律、金融和医疗保健领域,生成大量 PDF 文档是标准做法。然而,生成文档只是成功了一半,保护它们的安全性同样至关重要。当您的归档管道每天处理数百 GB 的 PDF 时,应用 AES-256 加密可能会迅速成为性能瓶颈。

在本文中,我们将探讨如何通过避免内存耗尽并优化加密循环,在 Delphi 中实现高速的 AES-256 PDF 加密。

PDF 加密规范

PDF 安全性已经发生了显着演变。早期版本使用的是 40 位 RC4,这在今天很容易被破解。当前的标准(PDF 1.7 扩展级别 3 和 PDF 2.0)强制要求使用 AES-256 加密。

在 PDF 中,您并不加密整个文件块。文档结构(XRef 表和字典的结构)保持明文。相反,您只加密(图像和页面内容的原始数据)和字符串(例如元数据文本)。这需要解析器提取数据,应用 AES CBC(密码块链接),然后将其写回。

瓶颈:加载到内存

在加密大型 PDF(例如 2GB 扫描的档案)时,一个常见的错误是在将其传递给加密引擎之前,将整个流加载到 TMemoryStream 中。这会导致 32 位进程中出现内存不足(OOM)异常,并在 64 位进程中导致大量的缺页错误。

Delphi 中的流式加密

解决方案是使用分块的流式方法。使用 Windows 密码学 API(CNG,Next Generation)或像 OpenSSL 这样的库,您可以以 64KB 为数据块读取 PDF 流,对该数据块进行加密,然后将其直接写入输出磁盘流。

以下是一个概念性的 Delphi 示例,演示了针对流的缓冲加密循环:

uses
  System.Classes, System.SysUtils;

const
  BUFFER_SIZE = 65536; // 64KB chunks

// This represents your AES-256 encryption routine
procedure EncryptStreamChunk(const InBuffer; var OutBuffer; BytesRead: Integer; const Key: TBytes; const IV: TBytes);
begin
  // Call to Windows CNG (BCryptEncrypt) or OpenSSL (EVP_EncryptUpdate)
  // ...
end;

procedure EncryptLargePDFStream(InputStream, OutputStream: TStream; const Key, IV: TBytes);
var
  InBuffer, OutBuffer: array of Byte;
  BytesRead: Integer;
begin
  SetLength(InBuffer, BUFFER_SIZE);
  // AES CBC requires padding, so the output buffer must be slightly larger
  SetLength(OutBuffer, BUFFER_SIZE + 16); 

  InputStream.Position := 0;
  OutputStream.Position := 0;

  repeat
    BytesRead := InputStream.Read(InBuffer[0], BUFFER_SIZE);
    if BytesRead > 0 then
    begin
      EncryptStreamChunk(InBuffer[0], OutBuffer[0], BytesRead, Key, IV);
      // Write the encrypted cipher text directly to disk
      OutputStream.Write(OutBuffer[0], BytesRead); // Note: padding logic omitted for brevity
    end;
  until BytesRead < BUFFER_SIZE;
end;

优化密码学后端

Delphi 开发人员对于 AES 后端有几种选择:

  • 原生 Delphi 实现: 易于部署,但通常较慢,因为它们纯粹在软件中执行。
  • Windows CNG(BCrypt): 高度优化并可利用硬件加速(现代 Intel/AMD CPU 上的 AES-NI 指令)。
  • OpenSSL(libcrypto): 行业标准,速度极快,但需要附带外部 DLL。

对于高吞吐量的服务器应用程序,硬件加速的 AES-NI 是必不可少的。在 Delphi 中使用 Windows CNG 时,映射 BCryptEncrypt 函数允许您的应用程序将繁重的工作转移给 CPU 专用的加密芯片,从而有效地将加密开销降低至接近零。

结论

加密 GB 级 PDF 时,请依赖流分块而不是全内存缓冲,并确保您的加密后端利用了硬件 AES-NI 加速。这种组合保证了您的归档管道能以 NVMe 驱动器的速度运行,而不是受制于 CPU 瓶颈。

注意:HotPDF VCL Component 原生支持利用分块流的高速 AES-256 加密。