Technical Article

การเข้ารหัส PDF ด้วย AES-256 ความเร็วสูงสำหรับเอกสารขนาดใหญ่

ในภาคกฎหมาย การเงิน และการดูแลสุขภาพ การสร้างเอกสาร PDF จำนวนมากถือเป็นวิธีปฏิบัติมาตรฐาน อย่างไรก็ตาม การผลิตเอกสารเป็นเพียงครึ่งหนึ่งของงานเท่านั้น การรักษาความปลอดภัยก็มีความสำคัญไม่แพ้กัน เมื่อคุณมีไปป์ไลน์เก็บถาวรที่ประมวลผล PDF หลายร้อยกิกะไบต์ทุกวัน การนำการเข้ารหัส AES-256 ไปใช้สามารถกลายเป็นคอขวดของประสิทธิภาพได้อย่างรวดเร็ว

ในบทความนี้ เราจะมาสำรวจวิธีการเข้ารหัส PDF ด้วย AES-256 ความเร็วสูงใน Delphi โดยหลีกเลี่ยงหน่วยความจำหมดและปรับรอบการเข้ารหัสให้เหมาะสม

ข้อกำหนดการเข้ารหัส PDF

ความปลอดภัยของ PDF มีการพัฒนาอย่างมาก เวอร์ชันแรกๆ ใช้ RC4 แบบ 40 บิต ซึ่งปัจจุบันสามารถเจาะได้อย่างง่ายดาย มาตรฐานปัจจุบัน (PDF 1.7 Extension Level 3 และ PDF 2.0) กำหนดให้ใช้การเข้ารหัส AES-256

ในไฟล์ PDF คุณไม่ได้เข้ารหัสบล็อกไฟล์ทั้งหมด โครงสร้างเอกสาร (ตาราง XRef และโครงสร้างของพจนานุกรม) จะยังคงเป็นข้อความธรรมดา แต่คุณจะเข้ารหัส Streams (ข้อมูลดิบสำหรับรูปภาพและเนื้อหาหน้า) และ Strings (เช่น ข้อความเมตาดาต้า) สิ่งนี้ต้องการให้ตัวแยกวิเคราะห์ดึงข้อมูล นำไปผ่าน AES CBC (Cipher Block Chaining) และเขียนกลับคืน

คอขวด: การโหลดเข้าสู่หน่วยความจำ

ข้อผิดพลาดทั่วไปเมื่อเข้ารหัส PDF ขนาดใหญ่ (เช่น เอกสารสแกน 2GB) คือการโหลดสตรีมทั้งหมดลงใน TMemoryStream ก่อนส่งผ่านไปยังเอนจินการเข้ารหัส สิ่งนี้นำไปสู่ข้อผิดพลาดหน่วยความจำไม่เพียงพอ (Out-Of-Memory: OOM) ในกระบวนการแบบ 32 บิต และเกิดปัญหาการสลับหน้า (page faulting) อย่างมหาศาลในกระบวนการแบบ 64 บิต

การเข้ารหัสแบบสตรีมมิ่งใน Delphi

ทางออกคือการใช้วิธีการแบบสตรีมมิ่งที่มีการแบ่งส่วน (chunked) ด้วยการใช้ Windows Cryptography API: Next Generation (CNG) หรือไลบรารีอย่าง OpenSSL คุณสามารถอ่านสตรีม PDF ในบล็อก 64KB เข้ารหัสบล็อกนั้น และเขียนลงในสตรีมดิสก์เอาต์พุตโดยตรง

นี่คือตัวอย่างเชิงแนวคิดใน 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 มีทางเลือกหลายทางสำหรับส่วนหลัง (backend) ของ AES:

  • การใช้ Delphi แบบเนทีฟ: ใช้งานง่าย แต่มักจะทำงานช้ากว่าเนื่องจากทำงานบนซอฟต์แวร์ล้วนๆ
  • Windows CNG (BCrypt): ได้รับการปรับแต่งให้เหมาะสมที่สุดและสามารถใช้การเร่งความเร็วด้วยฮาร์ดแวร์ (คำสั่ง AES-NI บนซีพียู Intel/AMD สมัยใหม่)
  • OpenSSL (libcrypto): มาตรฐานอุตสาหกรรม มีความเร็วสูงอย่างไม่น่าเชื่อ แต่ต้องพกพา DLL ภายนอกไปด้วย

สำหรับแอปพลิเคชันเซิร์ฟเวอร์ที่มีทรูพุตสูง (high-throughput) จำเป็นต้องใช้การเร่งความเร็วด้วยฮาร์ดแวร์ AES-NI เมื่อใช้ Windows CNG ใน Delphi การจับคู่ฟังก์ชัน BCryptEncrypt ช่วยให้แอปพลิเคชันของคุณโอนงานหนักไปยังซิลิกอนการเข้ารหัสเฉพาะของ CPU ได้ ซึ่งจะช่วยลดโอเวอร์เฮดของการเข้ารหัสให้เข้าใกล้ศูนย์ได้อย่างมีประสิทธิภาพ

บทสรุป

เมื่อทำการเข้ารหัส PDF ขนาดกิกะไบต์ ให้พึ่งพาการแบ่งสตรีม (stream chunking) แทนการใช้บัฟเฟอร์หน่วยความจำทั้งหมด และตรวจสอบให้แน่ใจว่าส่วนหลังการเข้ารหัสของคุณใช้การเร่งความเร็วด้วยฮาร์ดแวร์ AES-NI การผสมผสานนี้จะรับประกันได้ว่าไปป์ไลน์การจัดเก็บข้อมูลของคุณทำงานด้วยความเร็วของไดรฟ์ NVMe ของคุณแทนที่จะถูกจำกัดด้วย CPU

หมายเหตุ: การเข้ารหัส AES-256 ความเร็วสูงโดยใช้การสตรีมแบบแบ่งส่วนได้รับการรองรับแบบเนทีฟในคอมโพเนนต์ HotPDF VCL Component