Technical Article

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

Excel izlaže dve stvari koje se nazivaju „lozinka“, a samo jedna od njih predstavlja šifrovanje. Lozinka za otvaranje aktivira pravi šifarski algoritam: bez nje se datoteka uopšte ne može pročitati. Lozinke za zaštitu radnog lista i radne sveske ne čine ništa slično. One samo postavljaju zastavicu koju se kompatibilni uređivač obavezuje da poštuje, a radna sveska koja ne sadrži ništa osim te zastavice je obična čitljiva zip arhiva sa podacima u čistom tekstu. Izaberite pogrešnu opciju i poslaćete platne spiskove koji izgledaju zaključano u Excel-u, a mogu se pročitati u bilo kom tekstualnom uređivaču.

Dokaz traje deset sekundi. Preimenujte zaštićenu .xlsx datoteku u .zip, otvorite je u bilo kom arhivatoru i pogledajte datoteku xl/worksheets/sheet1.xml. Ako su vrednosti ćelija tamo u običnom UTF-8 formatu, datoteka nije šifrovana, bez obzira na to koliko upita za lozinku Excel prikazuje kada neko pokuša da izmeni ćeliju. Taj bezbednosni propust godinama opstaje u timovima koji pretpostavljaju da je zaštita lista isto što i poverljivost, a obično ispliva na površinu onog dana kada bezbednosna revizija izvrši upravo ovo preimenovanje.

HotXLS je nativna biblioteka tabela 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 starim hešom. Metoda SaveAsEncrypted generiše AES-šifrovani paket koji se ne može otvoriti bez lozinke. Odeljci u nastavku pokrivaju šta ovaj poziv upisuje, asimetriju oko koje morate da projektujete svoj sistem (HotXLS upisuje šifrovane datoteke 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 heš lozinke od 4 heksadecimalne cifre. To je stari algoritam koji su i OOXML i BIFF nasledili iz Excel-a iz 1990-ih, a dokumentacija formata nikada ne tvrdi da on čini više od sprečavanja slučajnih izmena. Paket ostaje obična čitljiva zip arhiva: podaci u ćelijama, formule i deljeni tekstualni nizovi nalaze se u čistom tekstu XML-a. Podrazumevano ponašanje stvar čini još gorom. Svaka ćelija počinje sa Locked=True, tako da pozivanje metode Protect bez prethodnog otključavanja ulaznog opsega zamrzava ceo list za uređivanje, dok sve vrednosti ostaju potpuno vidljive.

Ništa od ovoga ne čini zaštitu beskorisnom. Usmeravanje korisnika na opsege koji se mogu uređivati i stabilizacija izgleda za štampanje su stvarni zadaci, pokriveni u našem članku o zaštiti radnog lista i podešavanju stranice. Ali to su zadaci koji se tiču upotrebljivosti. Onog trenutka kada je zahtev poverljivost, jedini API koji na to daje odgovor jeste SaveAsEncrypted.

Ša SaveAsEncrypted zapravo upisuje

Šta SaveAsEncrypted zapravo upisuje

Implementacija prati standard ECMA-376 Standard Encryption, definisan u specifikaciji [MS-OFFCRYPTO] odeljak 2.3.4. Lozinka prolazi kroz 50.000 iteracija SHA-1 algoritma kako bi se dobio AES-128 ključ. Blok za verifikaciju (verifier block), šifrovan pomoću AES-128 u ECB režimu, omogućava aplikaciji koja otvara datoteku da potvrdi lozinku pre nego što bilo šta dešifruje, a zatim se ceo paket radne sveske šifruje pomoću AES-128 u CBC režimu. Ono što se snima na disk uopšte nije zip. To je OLE složena datoteka (OLE compound file) koja sadrži tokove EncryptionInfo, EncryptedPackage i DataSpaces, bez xl/ direktorijuma koji bi arhivator mogao da izlista, zbog čega test preimenovanja sada ne pronalazi ništa čitljivo. Excel 2007 i novije verzije ga otvaraju samo uz lozinku, 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 promenljivu lozinke sa istom pažnjom kao i string za povezivanje sa bazom podataka (connection string). Preuzmite je iz trezora (vault) ili servisa za generisanje tajni u poslednjem trenutku, nikada je ne beležite u dnevnik rada i nikada je ne upisujte u samu radnu svesku. Provera povratnog koda nije samo formalnost. Šifrovano čuvanje koje ne uspe na pola puta mora prekinuti isporuku, jer jedina alternativa koju pozivajući kod može da ponudi jeste nešifrovana kopija, a ta kopija je upravo incident koji ova funkcija treba da spreči.

Takođe postoji i automatski test prihvatanja koji ne košta skoro ništa: pozovite CanReadEncrypted nad datotekom koju ste upravo upisali. Ova metoda vraća true samo kada je izlaz zaista kontejner šifrovanja, pa provera ovog uslova nakon svakog šifrovanog čuvanja detektuje najgori mogući propust (kodnu putanju koja je tiho prešla na obično čuvanje SaveAs) u trenutku kada se desi, a ne nedeljama kasnije u sandučetu klijenta. Konačnu potvrdu ipak daje ručno otvaranje u Excel-u sa pravom lozinkom tokom testiranja verzije pred izdavanje.

Samo za upis po dizajnu: rukovanje greškom EXlsxEncryptionNotImplemented

Evo asimetrije koja bi trebalo da oblikuje arhitekturu vašeg sistema: HotXLS šifruje prilikom čuvanja, ali ne dešifruje prilikom otvaranja. Metoda OpenEncrypted izaziva izuzetak EXlsxEncryptionNotImplemented kada se usmeri na stvarno šifrovani paket; na običnoj radnoj svesci ona jednostavno prelazi na standardni poziv Open. Pomoćna metoda CanReadEncrypted brzo detektuje OLE kontejner šifrovanja, tako da kod za prijem može da usmeri takve datoteke 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 jasan arhitektonski zaključak: šifrujte na samom kraju procesa isporuke. Čuvajte originalni tekstualni master unutar vaše bezbednosne granice (u bazi podataka, skladištu dokumenata ili deljenom direktorijumu sa kontrolisanim pristupom), a šifrovanu kopiju kreirajte kao poslednji korak pre nego što datoteka napusti sistem. Sistem koji arhivira samo šifrovani izlaz zaključao je sopstvene podatke, jer nijedna kasnija faza tog istog sistema ne može ponovo otvoriti te datoteke. Kada nizvodni HotXLS proces ponovo zatreba radnu svesku, prosledite mu originalni master u čistom tekstu, a nikada artifakt isporuke.

AES-128 Standard Encryption i usaglašenost sa AES-256 standardom

Šifrovanje Office datoteka dolazi u dve generacije. Standard Encryption, koje HotXLS upisuje, koristi AES-128 sa SHA-1 derivacijom ključa. Agile Encryption se pojavio kasnije i koristi AES-256 sa SHA-512 i drugačijim XML kontejnerom ključa. Oba se transparentno otvaraju u Excel-u, a AES-128 je i dalje računski siguran za zaštitu datoteka u tranzitu do kupca.

Razlika prestaje da bude akademska onog dana kada bezbednosni upitnik zatraži „AES-256 šifrovanje datoteka u mirovanju“. Standard Encryption ne ispunjava taj zahtev, bez obzira na to koliko je lozinka jaka, i nijedan parametar metode SaveAsEncrypted ne menja algoritam koji ona generiše. Zato precizno navedite profil u svojoj bezbednosnoj dokumentaciji: AES-128, ECMA-376 Standard Encryption, SHA-1 derivacija ključa sa 50.000 iteracija. Tvrdnja koja može proći reviziju vredi više od optimistične tvrdnje koja pada na prvoj proveri.

Stara XLS putanja: RC4 izlaz, RC4 i XOR ulaz

BIFF fasada ima suprotan oblik. Njeno šifrovanje je starije i slabije, ali je ciklus potpun: ono što upiše, može i da pročita nazad. Postavljanje svojstva EncryptionPassword pre poziva SaveAs generiše RC4-šifrovanu .xls datoteku preko BIFF mehanizma FilePass, a metoda Open sa parametrom lozinke čita sve tri stare šeme: RC4, RC4 CryptoAPI i prastaru XOR opstrukciju:

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; njena jedina preostala vrednost je interoperabilnost sa sistemima koji još uvek razmenjuju .xls. Strana čitanja, međutim, ima veliku vrednost u migracionim poslovima. Zaštićena stara datoteka se otvara pomoću Open(FileName, Password), prenosi u OOXML model i ponovo obezbeđuje kroz AES putanju, što predstavlja jednosmernu nadogradnju koja radi bez ikakve potrebe za Excel-om. Kod grupnih šifrovanih isporuka visokog obima, napomene o propusnosti na strani čuvanja iz našeg članka o strimovanju upisa za serverske grupne poslove primenjuju se na fazu kreiranja sadržaja koja se odvija pre šifrovanja.

Šifrovanje i zaštita nisu rivali

Još jednu stavku vredi razjasniti, jer se javlja čim neko protumači upozorenje na vrhu ove stranice kao „zaštita je bezvredna“. Nije bezvredna. Šifrovanje i zaštita daju odgovore na različita pitanja i mogu se kombinovati. Šifrovanje određuje ko može da otvori datoteku; zaštita određuje šta čitalac koji je već unutra može da promeni. Isporuka platnog spiska može opravdano koristiti oba: šifrovati paket tako da ga vidi samo vlasnik lozinke, a zatim zaključati ćelije sa formulama kako bi primalac mogao da filtrira i sortira podatke, ali ne i da tiho prepisuje proračune. Greška nije u dodavanju zaštite. Greška je u tome što se njeno prisustvo uzima kao zamena za šifrovanje kada je zahtev poverljivost.

Strana upravljanja lozinkama nema sigurnosnu mrežu, i to je namerno tako. Derivacija ključa sa 50.000 iteracija postoji kako bi pogađanje bilo skupo, a ništa unutar datoteke ne čuva tajnu u rezervi. 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 datoteka predstavlja samo jedan poziv u HotXLS-u. Disciplina leži u svemu što se dešava oko tog poziva: čuvanje lozinke, granica rada samo za upis koja sprečava HotXLS da ponovo otvori sopstveni izlaz i tvrdnja o algoritmu koju možete odbraniti tokom revizije. Metode SaveAsEncrypted i stari dvosmerni proces isporučuju se uz HotXLS Component, i izvršavaju se nativno u procesima Delphi-ja i C++Builder-a bez ikakve Excel automatizacije.