Artikel Teknis

Mengenkripsi Output XLSX dengan AES di Delphi: Apa yang Ditulis SaveAsEncrypted HotXLS

Excel mengekspos dua hal yang sama-sama disebut "password," dan hanya satu di antaranya yang merupakan enkripsi. Password pembuka mengunci sebuah cipher sungguhan: tanpa itu file sama sekali tidak bisa dibaca. Password proteksi worksheet dan workbook tidak melakukan hal semacam itu. Keduanya hanya menetapkan sebuah flag yang disepakati untuk dihormati oleh editor yang kooperatif, dan sebuah workbook yang hanya membawa flag itu tetap merupakan zip biasa yang bisa dibaca dengan data yang berada dalam cleartext. Pilih yang salah dan Anda mengirim payroll yang terlihat terkunci di Excel tetapi bisa dibaca di text editor mana pun

Buktinya hanya butuh sepuluh detik. Ganti nama sebuah .xlsx yang diproteksi menjadi .zip, buka di tool arsip mana pun, dan lihat xl/worksheets/sheet1.xml. Jika nilai selnya ada di sana dalam UTF-8 polos, file itu tidak terenkripsi, berapa pun banyaknya prompt password yang dimunculkan Excel ketika seseorang mencoba mengedit sebuah sel. Celah itu bertahan bertahun-tahun di dalam tim yang berasumsi bahwa proteksi sheet berarti kerahasiaan, dan biasanya baru muncul ke permukaan pada hari sebuah security review menjalankan tepatnya penggantian nama ini

HotXLS adalah pustaka spreadsheet native Delphi dan C++Builder, dan ia menjaga kedua fitur itu tetap berada di sisi yang berlawanan dari garis batas tersebut. Proteksi worksheet dan workbook adalah pembatasan pengeditan yang didukung oleh sebuah hash lawas yang sengaja dibuat lemah. SaveAsEncrypted menghasilkan sebuah paket terenkripsi AES yang tidak akan terbuka oleh apa pun kecuali password-nya. Bagian-bagian di bawah ini membahas apa yang ditulis oleh panggilan itu, asimetri yang harus Anda desain di sekelilingnya (HotXLS menulis file terenkripsi tetapi tidak bisa membacanya kembali), dan bagaimana jalur XLS yang lebih lama berbeda

Diagram yang mengontraskan proteksi sheet XLSX Delphi, yang menyimpan hash lemah dan menyisakan data sel terbaca dalam zip biasa, dengan HotXLS SaveAsEncrypted, yang menurunkan kunci AES-128 dan menulis wadah enkripsi OLE
Proteksi sheet menyimpan hash lemah dan membiarkan paket sebagai zip yang terbaca. SaveAsEncrypted menurunkan kunci AES-128 dan menulis container OLE yang tak bisa didaftar alat arsip mana pun

Mengapa Proteksi Sheet Bukan Enkripsi

Metode Protect pada sheet dan ProtectWorkbook pada workbook menyimpan sebuah hash 4 digit heksadesimal dari password. Itu adalah algoritma lawas yang diwarisi baik OOXML maupun BIFF dari Excel era 1990-an, dan dokumentasi formatnya tidak pernah mengklaim bahwa itu melakukan lebih dari sekadar mencegah edit yang tidak disengaja. Paketnya tetap berupa zip biasa yang bisa dibaca: data sel, formula, dan shared string semuanya dalam XML cleartext. Defaultnya justru membuat ini lebih buruk, bukan lebih baik. Setiap sel dimulai dengan Locked=True, sehingga memanggil Protect tanpa lebih dulu membuka kunci sebuah rentang input membekukan seluruh sheet terhadap pengeditan sementara meninggalkan setiap nilai tetap terlihat jelas

Semua itu tidak membuat proteksi jadi tidak berguna. Mengarahkan pengguna ke rentang yang bisa diedit dan menstabilkan sebuah layout untuk pencetakan adalah pekerjaan yang sungguhan, dibahas dalam artikel kami tentang proteksi worksheet dan page setup. Tetapi itu semua adalah pekerjaan usability. Begitu kebutuhannya adalah kerahasiaan, satu-satunya API yang menjawabnya adalah SaveAsEncrypted

Apa yang Sebenarnya Ditulis SaveAsEncrypted

Implementasinya mengikuti ECMA-376 Standard Encryption, dispesifikasikan dalam [MS-OFFCRYPTO] bagian 2.3.4. Password itu melewati 50.000 iterasi SHA-1 untuk menurunkan sebuah kunci AES-128. Sebuah blok verifier, dienkripsi dengan AES-128 dalam mode ECB, memungkinkan sebuah konsumen memastikan password sebelum mendekripsi apa pun, dan seluruh paket workbook kemudian dienkripsi dengan AES-128 dalam mode CBC. Apa yang mendarat di disk sama sekali bukan sebuah zip. Itu adalah sebuah file compound OLE yang memegang stream EncryptionInfo, EncryptedPackage, dan DataSpaces, tanpa direktori xl/ untuk didaftar oleh tool arsip mana pun, itulah sebabnya uji penggantian nama sekarang tidak menemukan apa pun yang bisa dibaca. Excel 2007 dan yang lebih baru membukanya hanya dengan password, dan LibreOffice versi terkini juga membaca Standard Encryption

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  rc: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    Sheet := Book.Sheets.Add('Payroll');
    Sheet.Cells[1, 1].Value := 'Employee';
    Sheet.Cells[1, 2].Value := 'Net pay';
    Sheet.Cells[2, 1].Value := 'A. Garcia';
    Sheet.Cells[2, 2].Value := 4815.16;

    rc := Book.SaveAsEncrypted('payroll-2026-06.xlsx', PasswordFromVault);
    if rc <> 1 then
      raise Exception.CreateFmt('Encrypted save failed (rc=%d)', [rc]);
  finally
    Book.Free;
  end;
end;

Perlakukan variabel password dengan kehati-hatian yang sama seperti sebuah connection string. Ambil dari sebuah vault atau layanan generated-secret pada saat-saat terakhir, jangan pernah mencatatnya ke log, dan jangan pernah menuliskannya ke dalam workbook itu sendiri. Pemeriksaan kode kembalian bukanlah seremoni opsional. Sebuah penyimpanan terenkripsi yang gagal di tengah jalan harus membatalkan pengiriman, karena satu-satunya fallback yang bisa ditawarkan kode pemanggil adalah sebuah salinan yang tidak terenkripsi, dan salinan itu justru insiden yang sengaja ingin dicegah oleh fitur ini

Ada juga sebuah acceptance test yang bisa diperiksa mesin dan hampir tidak berbiaya apa-apa: panggil CanReadEncrypted pada file yang baru saja Anda tulis. Ia mengembalikan true hanya ketika output itu sungguh-sungguh sebuah kontainer enkripsi, sehingga menegaskannya setelah setiap penyimpanan terenkripsi menangkap regresi yang paling penting, sebuah jalur kode yang diam-diam jatuh kembali ke SaveAs biasa, pada saat itu terjadi, bukan berminggu-minggu kemudian di kotak masuk seorang pelanggan. Kata akhir tetap milik sebuah pembukaan manual di Excel dengan password sungguhan selama pengujian rilis

Write-Only Secara Desain: Menangani EXlsxEncryptionNotImplemented

Inilah asimetri yang seharusnya membentuk arsitektur pipeline Anda: HotXLS mengenkripsi saat penyimpanan tetapi tidak mendekripsi saat pembukaan. OpenEncrypted memunculkan EXlsxEncryptionNotImplemented ketika diarahkan ke sebuah paket yang sungguh-sungguh terenkripsi; pada sebuah workbook biasa ia hanya jatuh ke sebuah Open normal. Probe pendampingnya, CanReadEncrypted, mendeteksi kontainer enkripsi OLE dengan murah, sehingga kode intake bisa mengarahkan file semacam itu tanpa memicu exception:

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.CanReadEncrypted(FileName) then
    begin
      // Kontainer terenkripsi: HotXLS tidak bisa mendekripsinya.
      Writeln(FileName + ': needs manual decryption in Excel first');
      Exit;
    end;
    try
      Book.OpenEncrypted(FileName, '');   // file biasa jatuh ke Open
      Writeln(FileName + ': opened, ' + IntToStr(Book.Sheets.Count) + ' sheet(s)');
    except
      on EXlsxEncryptionNotImplemented do
        Writeln(FileName + ': encrypted - routed to manual queue');
    end;
  finally
    Book.Free;
  end;
end;

Asimetri itu punya satu pembacaan arsitektural yang jelas: enkripsi di ujung pengiriman, paling terakhir. Simpan master plaintext-nya di dalam batas kepercayaan Anda, di dalam sebuah database, document store, atau share yang dikontrol aksesnya, dan hasilkan salinan terenkripsi sebagai langkah terakhir sebelum file itu meninggalkan sistem. Sebuah pipeline yang hanya mengarsipkan output terenkripsi telah mengunci dirinya sendiri keluar dari datanya sendiri, karena tidak ada tahap sistem yang sama di kemudian hari yang bisa membuka kembali file-file itu. Ketika sebuah proses HotXLS di hilir membutuhkan workbook itu lagi, berikan padanya master plaintext, jangan pernah artefak pengiriman

Diagram pipeline pemanggilan SaveAsEncrypted HotXLS Delphi: kata sandi vault diproses melalui 50.000 ronde SHA-1 menjadi kunci AES-128, blok verifier ECB, dan enkripsi paket CBC, menghasilkan berkas compound OLE yang diperiksa dengan CanReadEncrypted
Satu panggilan SaveAsEncrypted mengubah password vault menjadi kunci AES-128 dan OLE compound file. CanReadEncrypted memberi penyimpanan gerbang penerimaan yang dapat diperiksa mesin

AES-128 Standard Encryption dan Garis Kepatuhan AES-256

Enkripsi file Office hadir dalam dua generasi. Standard Encryption, yang ditulis HotXLS, menggunakan AES-128 dengan penurunan kunci SHA-1. Agile Encryption datang belakangan dan beralih ke AES-256 dengan SHA-512 dan sebuah kontainer kunci berbeda yang dideskripsikan XML. Keduanya terbuka secara transparan di Excel, dan AES-128 masih sehat secara komputasional untuk melindungi sebuah file dalam perjalanan ke pelanggan

Diagram arsitektur untuk layanan Delphi: master workbook plaintext tetap di dalam batas kepercayaan, HotXLS SaveAsEncrypted berjalan sebagai langkah terakhir di tepi pengiriman, dan peringatan untuk tidak mengarsipkan hanya salinan terenkripsi
Enkripsikan di tepi pengiriman, paling akhir, dari master plaintext yang disimpan di dalam batas kepercayaan. Mengarsipkan hanya salinan terenkripsi mengunci setiap tahap berikutnya dari data miliknya sendiri

Perbedaan itu berhenti bersifat akademis pada hari sebuah kuesioner keamanan meminta "enkripsi AES-256 untuk file at rest." Standard Encryption tidak memenuhi garis itu, sekuat apa pun password-nya, dan tidak ada parameter SaveAsEncrypted yang mengubah algoritma yang dihasilkannya. Jadi nyatakan profilnya secara presisi dalam dokumentasi keamanan Anda: AES-128, ECMA-376 Standard Encryption, penurunan kunci SHA-1 pada 50.000 iterasi. Sebuah klaim yang bertahan melewati review lebih berharga daripada klaim optimis yang runtuh di bawah sebuah audit

Jalur XLS Lawas: RC4 Keluar, RC4 dan XOR Masuk Kembali

Facade BIFF punya bentuk yang berlawanan. Enkripsinya lebih tua dan lebih lemah, tetapi round trip-nya lengkap: apa yang ditulisnya, bisa juga dibacanya kembali. Menyetel EncryptionPassword sebelum SaveAs menghasilkan sebuah .xls terenkripsi RC4 melalui mekanisme FilePass BIFF, dan Open dengan sebuah parameter password membaca ketiga skema lawas itu, RC4, RC4 CryptoAPI, dan obfuskasi XOR yang kuno:

var
  Writer, Reader: IXLSWorkbook;   // referensi interface: tanpa Free manual
begin
  Writer := TXLSWorkbook.Create;
  Writer.Sheets.Add.Cells.Item[1, 1].Value := 'Confidential';
  Writer.EncryptionPassword := 'S3cret!';
  Writer.SaveAs('confidential.xls');

  Reader := TXLSWorkbook.Create;
  if Reader.Open('confidential.xls', 'S3cret!') > 0 then
    Writeln(Reader.Sheets[1].Cells.Item[1, 1].Value);  // Entries berbasis 1
end;

RC4 adalah kriptografi usang dan tidak boleh pernah melindungi data yang penting hari ini; satu-satunya nilai yang tersisa adalah interoperabilitas dengan sistem yang masih bertukar .xls. Sisi bacanya, meski begitu, sepadan perannya dalam pekerjaan migrasi. Sebuah file lawas yang diproteksi password terbuka dengan Open(FileName, Password), dijembatani ke dalam model OOXML, dan diamankan ulang melalui jalur AES, sebuah upgrade satu arah yang berjalan tanpa Excel di mana pun dalam alurnya. Untuk pengiriman terenkripsi bervolume tinggi, catatan throughput sisi tulis dalam artikel kami tentang streaming write untuk job batch server berlaku untuk fase pembangunan konten yang terjadi sebelum enkripsi

Enkripsi dan Proteksi Bukan Rival

Satu poin lagi yang layak diselesaikan, karena ini muncul begitu seseorang membaca peringatan di bagian atas halaman ini sebagai "proteksi itu tidak berguna." Bukan itu maksudnya. Enkripsi dan proteksi menjawab pertanyaan yang berbeda, dan keduanya bisa ditumpuk dengan bersih. Enkripsi memutuskan siapa yang bisa membuka file; proteksi memutuskan apa yang boleh diubah oleh seorang pembaca yang sudah berada di dalamnya. Sebuah pengiriman payroll bisa dengan wajar melakukan keduanya: enkripsi paketnya sehingga hanya pemegang password yang melihatnya, lalu kunci sel-sel formulanya sehingga penerima bisa memfilter dan menyortir tetapi tidak diam-diam menulis ulang perhitungannya. Kesalahannya bukan pada menambahkan proteksi. Kesalahannya adalah membiarkan kehadirannya menggantikan enkripsi ketika kebutuhannya sebenarnya adalah kerahasiaan

Sisi custody-nya tidak punya jaring pengaman, dan itu memang disengaja. Penurunan kunci 50.000 iterasi ada untuk membuat penebakan menjadi mahal, dan tidak ada apa pun di dalam file yang meng-escrow rahasianya. Password yang hilang berarti data yang hilang. Hasilkan, kirim, dan simpan password-password ini dengan disiplin yang sama seperti yang Anda terapkan pada kredensial database, dan enkripsinya akan memegang bagiannya

Enkripsi file yang sungguhan hanya satu panggilan di HotXLS. Disiplinnya hidup di segala sesuatu di sekeliling panggilan itu: custody password, batas write-only yang menjaga HotXLS agar tidak membuka kembali outputnya sendiri, dan sebuah klaim algoritma yang bisa Anda pertahankan dalam sebuah audit. SaveAsEncrypted dan round-trip lawasnya disertakan dalam HotXLS Delphi Component, berjalan secara native di dalam proses Delphi dan C++Builder tanpa otomatisasi Excel di mana pun dalam jalurnya