บทความเทคนิค

ทำไม Excel จึงปฏิเสธเวิร์กบุ๊กที่เข้ารหัสของคุณ: ECB และ RC4

คุณสร้างเวิร์กบุ๊ก เข้ารหัสด้วยรหัสผ่าน ส่งไฟล์ให้เพื่อนร่วมงาน และเพื่อนร่วมงานเปิดไฟล์นั้นใน Excel ตัว Excel จะถามหารหัสผ่าน เพื่อนร่วมงานพิมพ์รหัสผ่านลงไป และ Excel ยอมรับรหัสผ่านนั้น จนถึงจุดนี้การเข้ารหัสดูเหมือนจะถูกต้องดี แต่หลังจากนั้น Excel จะแสดงกล่องข้อความที่ระบุว่าไฟล์เสียหายและไม่สามารถเปิดได้ หรือเปิดขึ้นมาพร้อมค่าตารางของช่องเซลล์ที่ไม่มีความหมายใด ๆ รหัสผ่านนั้นถูกต้อง แต่ไฟล์ก็ยังคงเสียหายอยู่ดี นี่คือสภาวะความล้มเหลวที่สร้างความสับสนที่สุดสำหรับการเข้ารหัสตระกูล Office เนื่องจากส่วนที่ทำหน้าที่ยืนยันความถูกต้องของรหัสผ่านและส่วนที่ทำหน้าที่จัดเก็บข้อมูลจริงของคุณได้รับการปกป้องด้วยขั้นตอนที่แตกต่างกันสองขั้นตอน และการจัดการส่วนใดส่วนหนึ่งให้ถูกต้องก็ไม่ได้ช่วยรับประกันความถูกต้องของอีกส่วนหนึ่งเลย

บั๊กทั้งสองประเด็นที่อธิบายในบทความนี้มีลักษณะโครงสร้างปัญหาแบบเดียวกันนี้ทุกประการ โดยในแต่ละกรณี ตัวทดสอบความถูกต้อง (verifier) ประมวลผลผ่านแต่ส่วนเนื้อหาข้อมูลหลัก (body) ประมวลผลไม่ผ่าน ซึ่งอาจทำให้คุณหลงไปตามหาจุดบกพร่องในระบบตรวจสอบรหัสผ่านหรือพาธการดึงคีย์ที่จริง ๆ แล้วทำงานถูกต้องสมบูรณ์ดี ข้อผิดพลาดที่แท้จริงอยู่ปลายทางถัดไปในขั้นตอนที่ข้อมูลไบต์ของแพ็กเกจถูกแปลงค่า ข้อผิดพลาดทั้งสองตัวเป็นอิสระต่อกัน ตัวหนึ่งอยู่ในพาธ AES และอีกตัวอยู่ในพาธ RC4 แต่แชร์ปัญหาในการวิเคราะห์ร่วมกัน จึงคุ้มค่าที่เราจะทำความเข้าใจว่าทำไมผลลัพธ์ที่ถูกต้องเพียงครึ่งเดียวจึงเป็นกรณีที่ตรวจแก้ได้ยากที่สุด

ทำไมรหัสผ่านที่ถูกต้องจึงไม่ได้พิสูจน์อะไรเกี่ยวกับเนื้อหาข้อมูลหลักเลย

รูปแบบการเข้ารหัสที่ไฟล์ XLSX ยุคปัจจุบันเลือกใช้งานคือ ECMA-376 Standard Encryption ซึ่งจะจัดเก็บอ็อบเจกต์ที่เข้ารหัสสองชิ้นคู่ขนานกันไป ชิ้นแรกคือ EncryptionVerifier: ซึ่งเป็นบล็อกขนาดเล็กที่จัดเก็บค่าสุ่มและค่าแฮช (hash) ของค่าสุ่มนั้น โดยเข้ารหัสด้วยคีย์ที่ดึงมาจากรหัสผ่าน ชิ้นที่สองคือ EncryptedPackage: ซึ่งเป็นคอนเทนเนอร์ zip ของเวิร์กบุ๊กทั้งหมดที่ถูกเข้ารหัสด้วยคีย์เดียวกัน ตัวตรวจสอบ (verifier) นี้มีขึ้นมาเพื่อให้โปรแกรมอ่านสามารถยืนยันความถูกต้องของรหัสผ่านได้ล่วงหน้าก่อนที่จะต้องเสียเวลาประมวลผลถอดรหัสเนื้อหาข้อมูลหลักที่มีขนาดหลายเมกะไบต์ การถอดรหัสตัวตรวจสอบ การหาค่าแฮชของค่าสุ่ม และการเปรียบเทียบกับค่าแฮชที่บันทึกไว้ หากมีค่าตรงกันจะถือว่ารหัสผ่านมีความถูกต้อง

กับดักคือตัวตรวจสอบและตัวแพ็กเกจจะถูกเข้ารหัสผ่านคำสั่งเรียกแยกเฉพาะคนละตัวบนพื้นที่จัดเก็บที่แยกจากกัน คีย์ที่ถูกสร้างขึ้นอย่างถูกต้องย่อมสามารถถอดรหัสตัวตรวจสอบได้อย่างถูกต้องสมบูรณ์โดยไม่สนใจว่าผลลัพธ์ของแพ็กเกจหลังจากนั้นจะเป็นอย่างไร ดังนั้นหากขั้นตอนการแปลงคีย์ของคุณถูกต้องแต่กระบวนการแปลงแพ็กเกจผิดพลาด Excel จะยังคงกู้คืนรหัสผ่านจากตัวตรวจสอบได้สำเร็จและแสดงรายงานล้มเหลวที่เนื้อหาหลัก อาการแสดงจะถูกระบุว่า "รหัสผ่านถูกต้อง แต่ไฟล์เสียหาย" ซึ่งเบี่ยงเบนการสืบค้นไปที่พาธจัดการรหัสผ่านซึ่งเป็นจุดที่ไม่เคยมีข้อผิดพลาดเลย การแยกส่วนทำงานในลักษณะเดียวกันนี้ยังคุมโครงสร้างระบบ RC4 รุ่นเก่าด้วยเช่นกัน: โดยค่าแฮชตัวตรวจสอบจะได้รับการตรวจสอบเป็นจุดแรก และถึงแม้เนื้อหาหลักจะเบี่ยงเบนคลาดเคลื่อนไป ตัวขั้นตอนการตรวจสอบนี้ก็ยังคงรายงานผลสำเร็จอยู่

แผนภาพการเข้ารหัสมาตรฐาน ECMA-376 ในการจัดการของ HotXLS ใน Delphi: คีย์ที่ derive ได้หนึ่งตัวปกป้อง verifier เล็กๆ และ EncryptedPackage ทั้งหมดผ่านการเรียกที่แยกกัน
verifier และแพ็กเกจถูกเข้ารหัสด้วยการเรียกแยกกันบนบัฟเฟอร์แยกกัน รหัสผ่านที่ถูกต้องจึงไม่พิสูจน์อะไรเลยเกี่ยวกับเนื้อหา

บั๊กที่หนึ่ง: การเรียกใช้ AES ในระบบ ECB แทนที่จะเป็น CBC

เอกสารข้อกำหนด [MS-OFFCRYPTO] §2.3.4.15 ระบุว่าระบบ Standard Encryption จะเข้ารหัสแพ็กเกจด้วย AES ในโหมด Electronic Codebook (ECB) บล็อกข้อมูลขนาด 16 ไบต์ของแพ็กเกจที่เติมเต็ม (padded) แต่ละบล็อกจะถูกเข้ารหัสแยกกันอย่างเป็นอิสระด้วยคีย์เดียวกัน ไม่มีการเชื่อมโยงระหว่างบล็อก (chaining) และไม่มีการระบุตัวแปลงค่าเริ่มต้น (initialization vector: IV) นี่เป็นตัวเลือกที่แปลกเมื่อเทียบกับมาตรฐานในปัจจุบันซึ่งมักจะหลีกเลี่ยงโหมด ECB เสมอ แต่ในการทำงานร่วมกันระหว่างระบบ (interoperability) เราไม่มีสิทธิ์ตั้งข้อสงสัยในข้อกำหนด Excel จะถอดรหัสแพ็กเกจในโหมด ECB เสนอ ดังนั้นตัวสร้างไฟล์จึงต้องเข้ารหัสด้วยโหมด ECB เท่านั้นเพื่อให้ทั้งสองระบบเข้าใจตรงกัน

ข้อผิดพลาดที่เกิดขึ้นคือแพ็กเกจถูกเข้ารหัสด้วย AES ในโหมด CBC โดยใช้พารามิเตอร์ IV เป็นศูนย์ทั้งหมด นี่เป็นสาเหตุที่ทำไมคำสั่งดังกล่าวจึงทำงานเกือบสำเร็จ และคำว่าเกือบคือจุดที่เลวร้ายที่สุดในการตรวจสอบแก้ไข ในโหมด CBC บล็อกข้อความดิบตัวแรกจะถูกรัน XOR ร่วมกับ IV ก่อนขั้นตอนการเข้ารหัส เมื่อ IV มีค่าเป็นศูนย์ทั้งหมด การรัน XOR จะไม่มีการเปลี่ยนแปลงใด ๆ ส่งผลให้บล็อกแรกของโหมด CBC-with-zero-IV ได้ผลลัพธ์ข้อความเข้ารหัสลับแบบเดียวกับโหมด ECB ทุกประการ แต่เมื่อเริ่มบล็อกที่สองเป็นต้นไป โหมด CBC จะดึงข้อความเข้ารหัสลับของบล็อกก่อนหน้ามาใช้คำนวณบล็อกถัดไป บล็อกทุกตัวถัดจากบล็อกแรกจึงเบี่ยงเบนออกไปจากโหมด ECB ทั้งหมด

ตอนนี้เมื่อนำเงื่อนไขนี้มาซ้อนทับกับโครงสร้าง เลย์เอาต์ของตัวแพ็กเกจจะวางข้อมูลขนาดความยาว 8 ไบต์แบบ little-endian ไว้ที่ส่วนเริ่มต้นสุดของไฟล์ ดังนั้นส่วนประกอบของไฟล์ที่ Excel ตรวจสอบเร็วที่สุดจะอยู่ในบล็อกแรกหรือบล็อกที่สอง การที่บล็อกแรกทำงานได้สอดคล้องกันพอดีหมายความว่าขั้นตอนการวิเคราะห์ด่านแรกสุดจะผ่านไปได้ด้วยดี ในขณะที่บล็อกถัดจากนั้นทั้งหมดจะถูกถอดรหัสออกมาเป็นสัญญาณรบกวนขยะทั้งหมด การแก้ไขจึงตรงไปตรงมาเมื่อระบุประเภทโหมดได้ถูกต้อง: คือการเข้ารหัสบล็อกข้อมูลขนาด 16 ไบต์ด้วยโหมด ECB และสั่งปิดการเชื่อมโยงข้ามบล็อก ในส่วนเอ็นจิ้น ฟังก์ชัน XlsEncryptStdPackage จะไล่อ่านตารางพื้นที่จัดเก็บขนาด 16 ไบต์ทีละบล็อกและเรียกใช้ AESEncryptECB128Block ในแต่ละบล็อก ซึ่งเป็นสถาปัตยกรรมตัวเดียวกับที่ใช้ประมวลผลบล็อกตัวตรวจสอบ ในโค้ดจะมีคำอธิบายระบุไว้ในลูปอย่างชัดเจนว่า: โหมด CBC ร่วมกับ IV ขนาดศูนย์จะให้ผลลัพธ์ตรงกับโหมด ECB เฉพาะบล็อกแรกเท่านั้น ส่วนที่เหลือของแพ็กเกจจะถูกถอดรหัสออกมาเป็นขยะและ Excel จะปฏิเสธไฟล์นั้นทันที

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create(nil);
  try
    Book.Open('report.xlsx');
    // SaveAsEncrypted ทำให้เวิร์กบุ๊กเป็นซีเรียลแล้วรัน
    // ไปป์ไลน์การเข้ารหัสมาตรฐาน ECMA-376: AES-128 ECB เหนือแพ็กเกจ
    // ตาม [MS-OFFCRYPTO] 2.3.4.15 คืนค่า 1 เมื่อสำเร็จ.
    if Book.SaveAsEncrypted('report_secure.xlsx', 'S3cret!') <> 1 then
      raise Exception.Create('Encryption failed');
  finally
    Book.Free;
  end;
end;

บั๊กที่สอง: การเปลี่ยนคีย์ของ RC4 คลาดเคลื่อนผิดจังหวะ

พาธไฟล์ .xls รุ่นเก่าจะใช้งานระบบการเข้ารหัส RC4 CryptoAPI ซึ่งมีเงื่อนไขต่างออกไป เอกสารข้อกำหนด [MS-OFFCRYPTO] §2.3.6 ระบุว่าระบบการเข้ารหัสจะทำการเปลี่ยนคีย์ใหม่ (re-keyed) ในทุก ๆ ขอบเขตบล็อกขนาด 1024 ไบต์ ตัวสตรีมจะถูกซอยย่อยเป็นบล็อกขนาด 1024 ไบต์ คีย์ RC4 ชุดใหม่จะถูกสร้างขึ้นสำหรับบล็อกหมายเลข 0, 1, 2 เรียงลำดับไป และภายใต้แต่ละบล็อกข้อมูลการไหลของคีย์ (keystream) จะถูกเรียกใช้งานอย่างต่อเนื่องแบบไบต์ต่อไบต์ มีตัวแปรคงที่สองตัวที่ต้องสอดคล้องตรงกันเสมอ: คือการเปลี่ยนคีย์ใหม่บนทุกขอบเขตและการประมวลผลการไหลของคีย์โดยไม่มีช่องว่างภายในบล็อก เนื่องจาก RC4 เป็นระบบรหัสเข้ารหัสลับแบบสตรีม (stream cipher) การไหลของคีย์จึงเป็นลำดับที่จัดเรียงต่อเนื่องกันอย่างชัดเจน ข้อมูลไบต์ลำดับที่ n ที่คุณดึงมาใช้งานจะถูกกำหนดโดยจำนวนไบต์ที่คุณเคยดึงมาก่อนหน้านั้นทั้งหมด ขั้นตอนถอดรหัสจะคำนวณด้วยการ XOR แบบเดียวกันเทียบกับลำดับเดียวกัน ซึ่งหมายความว่าฝั่งผู้ผลิตและผู้บริโภคข้อมูลจำเป็นต้องดึงข้อมูลไบต์เดียวกัน ณ ตำแหน่งพิกัดเดียวกันอย่างไม่มีข้อยกเว้น

นี่คือความท้าทายทั้งหมดของกระบวนการ ระบบรหัสเข้ารหัสลับแบบสตรีมไม่มีกลไกปรับประสานพิกัดเวลาใหม่ (resynchronization) หากคุณปล่อยให้ข้อมูลคีย์รั่วไหลไปเพียงหนึ่งไบต์ ข้อมูลไบต์ถัดจากนั้นทั้งหมดจะถูกนำไป XOR ร่วมกับค่าคีย์ที่ผิดตำแหน่ง และข้อผิดพลาดจะไม่มีทางแก้ไขตัวเองได้สำเร็จ มันจะแผ่ความเสียหายลามยาวไปจนถึงจุดสิ้นสุดของบล็อก และเมื่อตำแหน่งการทำงานผิดเพี้ยนไปแล้ว มันจะลามไปยังบล็อกถัดไปทั้งหมดด้วย บั๊กที่พบในส่วนนี้ทำงานเช่นนั้นทุกประการ ตัวแปรนับบล็อกเริ่มต้นด้วยค่า sentinel เป็นลบหนึ่ง และรูทีนการข้ามคิดเอาเองว่าตัวนับนั้นสอดคล้องกับบล็อกปัจจุบันอยู่แล้ว เมื่อเริ่มประมวลผลจากค่า sentinel นั้น มันจะสั่งเปลี่ยนคีย์และประมวลผลคีย์เต็มขนาด 1024 ไบต์ซึ่งแท้จริงแล้วไม่ควรถูกนำมาใช้งานเลย และทำให้จำนวนที่เหลือเกิดมีค่าติดลบ ตั้งแต่นั้นเป็นต้นไป ตัวถอดรหัสจะทำงานผิดจังหวะ (out of phase) ไปหนึ่งบล็อกเต็ม ตัวตรวจสอบซึ่งผ่านขั้นตอนตรวจวิเคราะห์ก่อนหน้านี้จะยังคงผ่านฉลุย รหัสผ่านจึงดูถูกต้องดีในขณะที่ช่องเซลล์ข้อมูลจริงถอดรหัสออกมาเป็นขยะทั้งหมด

ตรรกะที่ได้รับการแก้ไขแล้วจะบันทึกอยู่ในฟังก์ชัน TXLSDecrypterRC4 ทั้งเมธอด Skip และ Decrypt จะประมวลผลภายใต้ลูปเดียวกันคือ: จะเปลี่ยนคีย์ใหม่เฉพาะเมื่อตำแหน่งพิกัดการทำงานวิ่งข้ามเข้าสู่บล็อกใหม่เท่านั้น โดยที่ดัชนีบล็อกคือตำแหน่งปัจจุบันหารด้วย REKEY_BLOCK_SIZE (1024) จากนั้นประมวลผลข้อมูลไปจนถึงตำแหน่งสิ้นสุดของบล็อกปัจจุบันและไม่มีการคำนวณเกินกว่านั้น ฟังก์ชัน MakeKey จะถูกเรียกใช้พร้อมระบุดัชนีบล็อกเสมอ และไม่มีการส่งค่าล้าสมัยหรือค่าตัวตรวจสอบจำลองเข้ามา และตำแหน่งพิกัดการประมวลผลจะขยับตามจำนวนไบต์ที่ใช้งานจริงอย่างแม่นยำ เพื่อให้ Skip และ Decrypt ยังคงทำงานสอดคล้องตรงจังหวะกับผู้สร้างไฟล์ บทเรียนสำคัญอยู่ในระดับหน่วยที่เล็กที่สุด: ข้อมูลที่เพี้ยนไปเพียงหนึ่งไบต์ในระบบสตรีมไม่ใช่ข้อผิดพลาดเล็กน้อย แต่มันคือความล้มเหลวโดยสมบูรณ์ของระบบประมวลผลถัดไปทั้งหมด

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create(nil);
  try
    // CanReadEncrypted ตรวจสอบลายเซ็น Compound File (OLE2) เพื่อให้
    // คุณแยกสาขาได้ก่อนพยายาม Open ปกติ OpenEncrypted
    // ส่งไฟล์ธรรมดาไปที่ Open และจัดการคอนเทนเนอร์ที่เข้ารหัส
    if Book.CanReadEncrypted('legacy.xls') then
      Book.OpenEncrypted('legacy.xls', 'S3cret!')
    else
      Book.Open('legacy.xls');
    // อ่านเซลล์ที่นี่
  finally
    Book.Free;
  end;
end;

การทำงานร่วมกันภายใต้ข้อกำหนดที่ตายตัวคือความแม่นยำระดับไบต์

ข้อบกพร่องทั้งสองตัวชี้ไปยังหลักการต้นตอประการเดียวกัน และเป็นหลักการที่คุ้มค่าแก่การหยิบยกมาเน้นย้ำเนื่องจากมันส่งผลต่อวิธีที่คุณใช้ประเมินทางเลือกการออกแบบ เมื่อปลายทางผู้รับเอาต์พุตของคุณคือโปรแกรมภายนอกที่ตายตัวซึ่งคุณไม่มีสิทธิ์ไปแก้ไขใด ๆ ตัวโหมดการเข้ารหัสและขั้นตอนการเปลี่ยนคีย์ใหม่จะไม่ใช่รายละเอียดเชิงปฏิบัติที่คุณสามารถนำไปปรับแต่งเพิ่มประสิทธิภาพหรือทำให้ง่ายลงตามใจชอบได้ แต่มันคือข้อตกลงการรับส่งข้อมูล (wire contract) ที่ละเมิดไม่ได้ Excel จะสั่งถอดรหัสด้วยโหมด ECB และเปลี่ยนคีย์บนขอบเขต 1024 ไบต์เสมอไม่ว่าพฤติกรรมนี้จะตรงใจคุณหรือไม่ และหน้าที่เดียวของคุณคือการผลิตข้อมูลไบต์ให้สามารถถอดรหัสออกมาตรงตามไฟล์เดิมภายใต้กระบวนการนั้นพอดิบพอดี โหมดที่ทันสมัยกว่า IV ที่ดูเหมือนไม่มีอันตราย หรือตัวนับจำนวนที่เริ่มต้นตรงตำแหน่งที่สะดวก สิ่งเหล่านี้จะกลายเป็นข้อบกพร่องทันทีหากคลาดเคลื่อนไปจากที่เครื่องอ่านข้อมูลปลายทางคาดหวัง การเขียนโค้ดรองรับมาตรฐานข้อกำหนดที่ตายตัวจะไม่มีคำว่าประมาณการ แต่มันต้องแม่นยำระดับไบต์เท่านั้น

นี่เป็นเหตุผลที่การตรวจสอบด้วยตัวตรวจสอบเพียงอย่างเดียวถือเป็นการทดสอบเบื้องต้น (smoke test) ที่ไม่มีประสิทธิภาพเพียงพอ มันบอกแค่ว่าการแปลงคีย์ทำงานสำเร็จ ซึ่งเป็นสิ่งจำเป็นแต่ยังไม่เพียงพอที่จะใช้เป็นตัวตัดสิน การทดสอบที่ทำเพียงแค่เปิดไฟล์เข้ารหัสและยืนยันว่าป้อนรหัสผ่านผ่านจะรายงานผลสำเร็จทั้ง ๆ ที่เนื้อหาภายในทั้งหมดไม่สามารถอ่านได้ การทดสอบที่แท้จริงต้องทำการถอดรหัสแพ็กเกจและเปรียบเทียบข้อมูลไบต์ที่ได้เทียบกับอินพุตดั้งเดิม หรือทำการเปิดบันทึกเวิร์กบุ๊กวนซ้ำผ่านระบบเข้ารหัสและถอดรหัสเพื่ออ่านค่าเซลล์กลับมาตรวจสอบ ตัวตรวจสอบพิสูจน์รหัสผ่าน และมีเพียงเนื้อหาหลักเท่านั้นที่ช่วยยืนยันความสมบูรณ์ของการเข้ารหัส

แผนภาพ HotXLS เปรียบเทียบ AES แบบ ECB กับ CBC ที่ IV เป็นศูนย์ ข้ามบล็อก 16 ไบต์ของแพ็กเกจ XLSX ที่เข้ารหัส โดยมีเพียงบล็อกแรกที่ตรงกัน และทุกบล็อกถัดไปแตกต่าง
CBC ที่ใช้ IV เป็นศูนย์ให้ผลเหมือน ECB เฉพาะบล็อกแรก ซึ่งเก็บ prefix ความยาวที่ Excel ตรวจสอบเป็นอย่างแรก ส่วนบล็อกถัด ๆ ไปถอดรหัสออกมาเป็นสัญญาณรบกวน

วิธีการเขียนและอ่านเวิร์กบุ๊กที่ได้รับการปกป้องที่รองรับอย่างเป็นทางการ

ข้อมูลฝั่งภายนอกมีขนาดกระชับ ในการบันทึกเวิร์กบุ๊กยุคใหม่ที่ปกป้องด้วยรหัสผ่าน ให้กรอกข้อมูลหรือเปิด TXLSXWorkbook และเรียกใช้เมธอด SaveAsEncrypted พร้อมระบุชื่อไฟล์และรหัสผ่าน มันจะแปลงข้อมูลเวิร์กบุ๊กเป็นข้อมูลอนุกรมและรันขั้นตอนการเข้ารหัส Standard Encryption ที่ได้รับการแก้ไขแล้ว โดยจะส่งคืนค่า 1 เมื่อทำงานสำเร็จ ในส่วนขั้นตอนการอ่านให้เรียก CanReadEncrypted เพื่อตรวจสอบว่าไฟล์นั้นเป็นคอนเทนเนอร์ไฟล์ร่วมแบบเข้ารหัส (encrypted Compound File container) หรือไม่ จากนั้นจึงแยกขั้นตอนการประมวลผล: OpenEncrypted จะจัดการพาธไฟล์เข้ารหัสและสลับกลับมาใช้ Open สำหรับไฟล์ทั่วไป และ Open แบบระบุรหัสผ่านพร้อมใช้งานโดยตรง ขั้นตอนการจัดการโหมดและลูปเปลี่ยนคีย์ที่ระบุไว้ข้างต้นทำงานอยู่เบื้องหลังการเรียกใช้เหล่านี้ คุณมีหน้าที่ระบุรหัสผ่านและชื่อไฟล์ และตัวเอ็นจิ้นจะจัดการทุกอย่างตามข้อกำหนดมาตรฐานให้เอง

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create(nil);
  try
    Book.Open('quarterly.xlsx');
    Book.SaveAsEncrypted('quarterly_locked.xlsx', 'P@ssphrase');
    // เปิดใหม่ฝั่งผู้บริโภค
    Book.OpenEncrypted('quarterly_locked.xlsx', 'P@ssphrase');
  finally
    Book.Free;
  end;
end;

โครงสร้างของผลลัพธ์ที่ได้รับการปกป้อง สตรีม EncryptionInfo บล็อกตัวตรวจสอบ และเลย์เอาต์ของตัวแพ็กเกจ มีรายละเอียดใน บทความการนำเสนอข้อมูลเอาต์พุต XLSX ที่เข้ารหัสด้วย AES ของเรา และสำหรับประเด็นการล็อกในระดับแผ่นงาน (sheet-level locking) และการทำงานของระบบป้องกันที่เกี่ยวเนื่องกับการตั้งค่าหน้ากระดาษและการสั่งพิมพ์ สามารถศึกษาต่อได้ใน บทความการป้องกัน การตั้งค่าหน้ากระดาษ และการสั่งพิมพ์ ทั้งหมดนี้พัฒนาขึ้นบนพาธเข้ารหัสที่อธิบายไว้ในบทความนี้ ซึ่งมีมาพร้อมเป็นส่วนหนึ่งของ HotXLS Delphi spreadsheet component สำหรับ Delphi และ C++Builder ร่วมกับ API การอ่าน การเขียน และการแสดงผลที่มีระบุไว้ในบล็อกนี้

แผนภาพการเลื่อน re-key ของ RC4 ในการเข้ารหัส Excel รุ่นเก่าที่อ่านจาก Delphi: ฝั่งผู้ผลิต re-key ทุก 1024 ไบต์ ขณะที่ผู้บริโภคแบบเริ่มจาก sentinel เผา keystream บล็อกหนึ่งจึงหลุดเฟสไป
stream cipher ไม่มีการซิงก์ใหม่ บล็อก keystream 1024 ไบต์ที่เสียหายเพียงบล็อกเดียวจึงทำให้ทุกเซลล์ที่ถอดรหัสกลายเป็นขยะ ในขณะที่ verifier ยังผ่านอยู่