Trong các lĩnh vực pháp lý, tài chính và chăm sóc sức khỏe, việc tạo ra khối lượng lớn tài liệu PDF là một thực tiễn tiêu chuẩn. Tuy nhiên, việc tạo ra các tài liệu chỉ là một nửa chặng đường; việc bảo mật chúng cũng quan trọng không kém. Khi bạn có một đường ống lưu trữ xử lý hàng trăm gigabyte tệp PDF mỗi ngày, việc áp dụng mã hóa AES-256 có thể nhanh chóng trở thành một điểm nghẽn hiệu suất.
Trong bài viết này, chúng ta sẽ khám phá cách đạt được mã hóa PDF AES-256 tốc độ cao trong Delphi bằng cách tránh cạn kiệt bộ nhớ và tối ưu hóa các vòng lặp mật mã.
Đặc tả mã hóa PDF
Bảo mật PDF đã phát triển đáng kể. Các phiên bản đầu sử dụng RC4 40-bit, ngày nay rất dễ bị phá vỡ. Tiêu chuẩn hiện tại (PDF 1.7 Extension Level 3 và PDF 2.0) bắt buộc mã hóa AES-256.
Trong tệp PDF, bạn không mã hóa toàn bộ khối tệp. Cấu trúc tài liệu (bảng XRef và cấu trúc của từ điển) vẫn ở dạng văn bản thuần túy (plaintext). Thay vào đó, bạn mã hóa các Luồng (Streams) (dữ liệu thô cho hình ảnh và nội dung trang) và các Chuỗi (Strings) (chẳng hạn như văn bản siêu dữ liệu). Điều này yêu cầu trình phân tích cú pháp trích xuất dữ liệu, áp dụng AES CBC (Cipher Block Chaining) và ghi dữ liệu trở lại.
Điểm nghẽn: Tải vào bộ nhớ
Một sai lầm phổ biến khi mã hóa một tệp PDF khổng lồ (ví dụ: một kho lưu trữ được quét 2GB) là tải toàn bộ luồng vào một TMemoryStream trước khi chuyển nó đến công cụ mật mã. Điều này dẫn đến các ngoại lệ Hết bộ nhớ (Out-Of-Memory - OOM) trong các tiến trình 32-bit và lỗi phân trang hàng loạt trong các tiến trình 64-bit.
Mã hóa luồng trong Delphi
Giải pháp là sử dụng phương pháp phát luồng, chia nhỏ thành các khối. Bằng cách sử dụng API Mật mã Windows: Thế hệ Tiếp theo (CNG) hoặc một thư viện như OpenSSL, bạn có thể đọc luồng PDF theo các khối 64KB, mã hóa khối đó và ghi trực tiếp vào luồng đĩa đầu ra.
Dưới đây là ví dụ khái niệm trong Delphi minh họa vòng lặp mã hóa được đệm cho một luồng:
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;
Tối ưu hóa Backend Mật mã
Các nhà phát triển Delphi có một số lựa chọn cho backend AES:
- Các triển khai Delphi gốc: Dễ triển khai, nhưng thường chậm hơn vì chúng thực thi hoàn toàn bằng phần mềm.
- Windows CNG (BCrypt): Được tối ưu hóa cao và có thể sử dụng khả năng tăng tốc phần cứng (các lệnh AES-NI trên các CPU Intel/AMD hiện đại).
- OpenSSL (libcrypto): Tiêu chuẩn ngành, cực kỳ nhanh nhưng yêu cầu cung cấp các tệp DLL bên ngoài.
Đối với các ứng dụng máy chủ thông lượng cao, AES-NI được tăng tốc phần cứng là bắt buộc. Khi sử dụng Windows CNG trong Delphi, việc ánh xạ hàm BCryptEncrypt cho phép ứng dụng của bạn giảm tải các tác vụ nặng cho silicon mật mã chuyên dụng của CPU, làm giảm hiệu quả chi phí mã hóa xuống gần bằng không.
Kết luận
Khi mã hóa các tệp PDF quy mô gigabyte, hãy dựa vào việc chia khối luồng thay vì đệm toàn bộ bộ nhớ và đảm bảo backend mật mã của bạn sử dụng khả năng tăng tốc phần cứng AES-NI. Sự kết hợp này đảm bảo rằng đường ống lưu trữ của bạn chạy ở tốc độ của ổ đĩa NVMe, thay vì bị giới hạn bởi CPU (CPU-bound).
Lưu ý: Mã hóa AES-256 tốc độ cao sử dụng luồng chia khối được hỗ trợ nguyên bản trong HotPDF VCL Component.