Tehnički članak

Šifrovanje XLSX izlaza pomoću AES-a u Delphi-ju: šta upisuje metoda SaveAsEncrypted u HotXLS-u

Excel izlaže dve stvari koje se obe nazivaju "lozinka", a samo jedna od njih predstavlja šifrovanje. Lozinka za otvaranje (open password) pokreće stvarnu šifru: bez nje se fajl uopšte ne može pročitati. Lozinke za zaštitu radnog lista i radne sveske ne rade ništa slično. One samo postavljaju oznaku (flag) koju se kompatibilni editor slaže da poštuje, a radna sveska koja ne nosi ništa osim te oznake je obična, čitljiva zip arhiva sa podacima koji stoje u čistom tekstu. Izaberite pogrešnu i isporučićete platni spisak koji u Excel-u izgleda zaključano, ali se može pročitati u bilo kom tekstualnom editoru

Dokazivanje traje deset sekundi. Preimenujte zaštićeni .xlsx fajl u .zip, otvorite ga u bilo kom arhivskom alatu i pogledajte datoteku xl/worksheets/sheet1.xml. Ako su vrednosti ćelija tamo u običnom UTF-8 formatu, fajl nije šifrovan, bez obzira na to koliko lozinki Excel traži kada neko pokuša da izmeni ćeliju. Taj bezbednosni propust godinama preživljava u timovima koji pretpostavljaju da je zaštita lista isto što i poverljivost, a obično ispliva na površinu onog dana kada bezbednosna provera pokrene upravo ovo preimenovanje

HotXLS je izvorna biblioteka za tabele za Delphi i C++Builder, i ona drži ove dve funkcije na suprotnim stranama te linije. Zaštita radnog lista i radne sveske predstavljaju ograničenja uređivanja podržana namerno slabim, zastarelim hešom. Metoda SaveAsEncrypted proizvodi paket šifrovan AES algoritmom koji se ne može otvoriti bez ispravne lozinke. Odeljci u nastavku pokrivaju šta taj poziv upisuje, asimetriju oko koje morate projektovati sistem (HotXLS upisuje šifrovane fajlove, ali ih ne može čitati nazad) i kako se starija XLS putanja razlikuje

Zašto zaštita lista nije šifrovanje

Metode Protect na listovima i ProtectWorkbook na radnoj svesci čuvaju lozinku kao heš od 4 heksadecimalne cifre. To je zastareli algoritam koji su OOXML i BIFF nasledili iz Excel-a iz 1990-ih, a dokumentacija formata nikada i ne tvrdi da on radi išta više osim što sprečava slučajne izmene. Paket ostaje obična čitljiva zip arhiva: podaci o ćelijama, formule i zajednički stringovi (shared strings) su u XML-u u čistom tekstu. Podrazumevano podešavanje to čini još gorim, a ne boljim. Svaka ćelija počinje sa Locked=True, pa pozivanje metode Protect bez prethodnog otključavanja opsega za unos zamrzava čitav list od uređivanja, dok istovremeno ostavlja svaku vrednost svima vidljivu

Ništa od ovoga ne čini zaštitu beskorisnom. Usmeravanje korisnika na opsege koji se mogu uređivati i stabilizacija rasporeda za štampanje su stvarni zadaci, pokriveni u našem članku o zaštiti radnih listova i podešavanju stranica. Ali to su poslovi koji se tiču upotrebljivosti (usability). Onog trenutka kada je zahtev poverljivost podataka, jedini API koji na to odgovara je SaveAsEncrypted

Šta SaveAsEncrypted zapravo upisuje

Implementacija prati standardnu šemu šifrovanja ECMA-376 (Standard Encryption), specificiranu u [MS-OFFCRYPTO] odeljku 2.3.4. Lozinka prolazi kroz 50.000 iteracija SHA-1 algoritma kako bi se izvedio ključ AES-128. Blok verifikatora (verifier block), šifrovan algoritmom AES-128 u ECB režimu, omogućava potrošaču da potvrdi lozinku pre nego što išta dešifruje, a čitav paket radne sveske se zatim šifruje pomoću AES-128 u CBC režimu. Ono što završava na disku uopšte nije zip. To je OLE compound fajl koji sadrži EncryptionInfo, EncryptedPackage i DataSpaces tokove (streams), bez xl/ direktorijuma koji bi arhivski alat mogao da izlista, zbog čega test preimenovanja sada ne pronalazi ništa čitljivo. Excel 2007 i noviji ga otvaraju samo sa lozinkom, a i trenutni LibreOffice takođe čita 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;

Tretirajte varijablu lozinke sa istom pažnjom kao i string konekcije (connection string). Preuzmite je iz trezora (vault) ili servisa za generisanje tajni u poslednjem trenutku, nikada je nemojte logovati i nikada je nemojte upisivati u samu radnu svesku. Provera povratnog koda (return-code) nije opciona ceremonija. Šifrovano čuvanje koje ne uspe na pola puta mora prekinuti isporuku, jer jedino rešenje za hitne slučajeve (fallback) koje pozivni kod može ponuditi je nešifrovana kopija, a ta kopija je upravo incident čije sprečavanje je i razlog postojanja ove funkcije

Takođe postoji i mašinski proverljiv test prihvatanja koji ne košta skoro ništa: pozovite metodu CanReadEncrypted na fajlu koji ste upravo upisali. Ona vraća true (tačno) samo kada je izlaz zaista kontejner za šifrovanje, tako da potvrđivanje ovog uslova nakon svakog šifrovanog čuvanja hvata najvažniju regresiju — putanju koda koja se tiho vratila na običan SaveAs, u trenutku kada se to desi, a ne nedeljama kasnije u sandučetu klijenta. Konačna potvrda i dalje pripada manuelnom otvaranju u Excel-u sa stvarnom lozinkom tokom testiranja izdanja

Samo za upis po dizajnu: rukovanje greškom EXlsxEncryptionNotImplemented

Evo asimetrije koja bi trebala da oblikuje arhitekturu vašeg cevovoda (pipeline): HotXLS šifruje prilikom čuvanja, ali ne vrši dešifrovanje prilikom otvaranja. Metoda OpenEncrypted podiže izuzetak EXlsxEncryptionNotImplemented kada je usmerena na stvarni šifrovani paket; na običnoj radnoj svesci ona jednostavno prolazi (fall through) do normalnog poziva Open. Prateća sonda CanReadEncrypted jeftino detektuje OLE kontejner za šifrovanje, tako da kod na prijemu može usmeriti takve fajlove bez izazivanja izuzetka:

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.CanReadEncrypted(FileName) then
    begin
      // Encrypted container: HotXLS cannot decrypt it.
      Writeln(FileName + ': needs manual decryption in Excel first');
      Exit;
    end;
    try
      Book.OpenEncrypted(FileName, '');   // plain files fall through to 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;

Ta asimetrija ima jedno jasno arhitektonsko tumačenje: šifrujte na samoj ivici isporuke, na kraju. Čuvajte originalni čist tekst (plaintext master) unutar vaših granica poverenja, u bazi podataka, skladištu dokumenata ili deljenom direktorijumu sa kontrolisanim pristupom, i kreirajte šifrovanu kopiju kao poslednji korak pre nego što fajl napusti sistem. Cevovod koji arhivira samo šifrovani izlaz zaključao je sam sebe i ostao bez sopstvenih podataka, jer nijedan kasniji korak istog sistema ne može ponovo otvoriti te fajlove. Kada nizvodni HotXLS proces ponovo zatreba radnu svesku, predajte mu original u čistom tekstu, nikada isporučeni šifrovani artefakt

AES-128 Standard Encryption i linija usklađenosti sa AES-256

Šifrovanje Office fajlova dolazi u dve generacije. Standardno šifrovanje (Standard Encryption), ono koje HotXLS upisuje, koristi algoritam AES-128 sa SHA-1 izvođenjem ključa. Agile Encryption se pojavilo kasnije i prelazi na AES-256 sa SHA-512 i drugačijim kontejnerom ključa opisanim u XML-u. Oba formata se transparentno otvaraju u Excel-u, a AES-128 je i dalje računski pouzdan za zaštitu fajla u tranzitu do klijenta

Razlika prestaje da bude akademska onog dana kada bezbednosni upitnik zatraži "AES-256 šifrovanje fajlova u mirovanju (at rest)". Standardno šifrovanje ne ispunjava taj zahtev, bez obzira na to koliko je jaka lozinka, i nijedan parametar metode SaveAsEncrypted ne menja algoritam koji ona emituje. Stoga precizno navedite profil u vašoj bezbednosnoj dokumentaciji: AES-128, ECMA-376 Standard Encryption, SHA-1 izvođenje ključa sa 50.000 iteracija. Tvrdnja koja preživi reviziju vredi više od obtimistične koja se sruši na prvoj proveri

Zastarela XLS putanja: RC4 na izlazu, RC4 i XOR na ulazu

BIFF fasada ima suprotan oblik. Njeno šifrovanje je starije i slabije, ali je kružni tok kompletan: ono što upiše, može i da pročita nazad. Postavljanje svojstva EncryptionPassword pre poziva SaveAs proizvodi .xls fajl šifrovan RC4 algoritmom preko BIFF mehanizma FilePass, a metoda Open sa parametrom lozinke čita sve tri zastarele šeme: RC4, RC4 CryptoAPI i drevnu XOR obfuskaciju:

var
  Writer, Reader: IXLSWorkbook;   // interface refs: no manual Free
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 are 1-based
end;

RC4 je zastarela kriptografija i nikada ne bi trebalo da štiti podatke koji su danas važni; jedina preostala vrednost mu je interoperabilnost sa sistemima koji još uvek razmenjuju stariji .xls format. Strana čitanja, međutim, pronalazi svoju ulogu u poslovima migracije. Zastareli fajl zaštićen lozinkom se otvara preko Open(FileName, Password), prebacuje u OOXML model i ponovo osigurava kroz AES putanju — jednostrani apgrejd koji se izvršava bez učešća Excel-a u petlji. Za velike količine šifrovanih isporuka, napomene o protoku na strani čuvanja u našem članku o strimovanju upisa za serverske batch poslove odnose se na fazu izgradnje sadržaja koja se dešava pre šifrovanja

Šifrovanje i zaštita nisu rivali

Još jedna tačka koju vredi razjasniti, jer se pojavljuje onog trenutka kada neko pročita upozorenje na vrhu ove stranice kao "zaštita je beskorisna". Nije tako. Šifrovanje i zaštita odgovaraju na različita pitanja i lepo se kombinuju. Šifrovanje odlučuje ko može otvoriti fajl; zaštita odlučuje šta čitalac koji je već unutra može promeniti. Isporuka platnog spiska može razumno koristiti oba: šifrovati paket tako da ga vidi samo vlasnik lozinke, a zatim zaključati ćelije sa formulama tako da primalac može filtrirati i sortirati, ali ne i tiho prepravljati proračune. Greška nije u dodavanju zaštite. Greška je dopuštanje da njeno prisustvo zameni šifrovanje kada je zahtevana poverljivost podataka

Na strani čuvanja nema sigurnosne mreže, i to je po dizajnu. Izvođenje ključa sa 50.000 iteracija postoji da bi nagađanje bilo skupo, i ništa unutar fajla ne čuva tajnu u depozitu. Izgubljena lozinka znači izgubljene podatke. Generišite, isporučujte i čuvajte ove lozinke sa istom disciplinom koju primenjujete na akreditive baze podataka, i šifrovanje će odraditi svoj deo posla

Pravo šifrovanje fajla je samo jedan poziv u HotXLS-u. Društvena disciplina živi u svemu oko tog poziva: čuvanje lozinke, granica samo za upis koja sprečava HotXLS da ponovo otvori sopstveni izlaz i tvrdnja o algoritmu koju možete odbraniti u reviziji. Metoda SaveAsEncrypted i stariji kružni tok se isporučuju sa HotXLS komponentom, radeći izvorno u procesima Delphi-ja i C++Builder-a bez ikakve automatizacije Excel-a na tom putu