Tehnički članak

Šifriranje XLSX izlaza pomoću AES-a u Delphiju: što HotXLS SaveAsEncrypted zapisuje

Excel izlaže dvije stvari koje se obje nazivaju "lozinka", a samo jedna od njih je šifriranje. Lozinka za otvaranje (open password) pokreće stvarnu šifru: bez nje se datoteka uopće ne može pročitati. Lozinke za zaštitu radnog lista i radne knjige ne čine ništa slično. One postavljaju zastavicu koju se urednik slaže poštovati, a radna knjiga koja ne nosi ništa osim te zastavice običan je čitljiv ZIP s podacima u čistom tekstu (cleartext). Odaberite pogrešnu i poslat ćete platnu listu koja izgleda zaključano u Excelu, a može se pročitati u bilo kojem uređivaču teksta

Dokaz traje deset sekundi. Preimenujte zaštićeni .xlsx u .zip, otvorite ga u bilo kojem arhivskom alatu i pogledajte xl/worksheets/sheet1.xml. Ako su vrijednosti ćelija tamo u običnom UTF-8 formatu, datoteka nije šifrirana, bez obzira na to koliko upita za lozinku Excel prikazuje kada netko pokuša urediti ćeliju. Ta praznina preživljava godinama unutar timova koji pretpostavljaju da je zaštita lista povjerljivost, a obično ispliva na površinu na dan kada sigurnosna revizija pokrene upravo ovo preimenovanje

HotXLS je izvorna knjižnica proračunskih tablica za Delphi i C++Builder i drži ove dvije značajke na suprotnim stranama te linije. Zaštita radnog lista i radne knjige su ograničenja uređivanja podržana namjerno slabim naslijeđenim sažetkom. SaveAsEncrypted proizvodi AES-šifrirani paket koji neće otvoriti ništa osim ispravne lozinke. Odjeljci u nastavku pokrivaju što taj poziv zapisuje, asimetriju oko koje morate dizajnirati sustav (HotXLS zapisuje šifrirane datoteke, ali ih ne može ponovno pročitati) i kako se starija XLS staza razlikuje

Zašto zaštita lista nije šifriranje

Metode Protect na listovima i ProtectWorkbook na radnoj knjizi spremaju 4-znamenkasti heksadecimalni sažetak lozinke. To je naslijeđeni algoritam koji su i OOXML i BIFF naslijedili iz Excela iz 1990-ih, a dokumentacija formata nikada ne tvrdi da čini više od zaustavljanja slučajnih uređivanja. Paket ostaje običan čitljiv ZIP: podaci ćelija, formule i dijeljeni nizovi znakova (shared strings) nalaze se u čistom XML tekstu. Zadane postavke čine situaciju gorom, a ne boljom. Svaka ćelija započinje s Locked=True, pa pozivanje Protect bez prethodnog otključavanja ulaznog raspona zamrzava cijeli list protiv uređivanja, ostavljajući svaku vrijednost na vidjelu

Ništa od toga ne čini zaštitu beskorisnom. Usmjeravanje korisnika u uredne raspone i stabilizacija izgleda za ispis stvarni su poslovi, pokriveni u našem članku o zaštiti radnog lista i pripremi stranice. Ali to su poslovi upotrebljivosti. Onog trenutka kada je zahtjev povjerljivost, jedini API koji na njega odgovara je SaveAsEncrypted

Što SaveAsEncrypted zapravo zapisuje

Implementacija slijedi ECMA-376 Standardno šifriranje, specificirano u specifikaciji [MS-OFFCRYPTO] odjeljku 2.3.4. Lozinka prolazi kroz 50 000 iteracija SHA-1 kako bi se izveo AES-128 ključ. Blok verifikatora, šifriran s AES-128 u načinu rada ECB, omogućuje potrošaču da potvrdi lozinku prije nego što išta dešifrira, a cijeli paket radne knjige se zatim šifrira s AES-128 u CBC načinu. Ono što slijeće na disk uopće nije ZIP. To je OLE compound file koji sadrži tokove EncryptionInfo, EncryptedPackage i DataSpaces, bez direktorija xl/ koji bi arhivski alat mogao izlistati, zbog čega test preimenovanja sada ne pronalazi ništa čitljivo. Excel 2007 i novije verzije otvaraju ga samo s lozinkom, a trenutni LibreOffice također čita Standardno šifriranje

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 s istom pažnjom kao i niz za povezivanje (connection string). Dohvatite je iz trezora (vault) ili usluge generiranja tajni u posljednjem trenutku, nikada je nemojte bilježiti u zapisnik (log) i nikada je nemojte zapisivati u samu radnu knjigu. Provjera povratnog koda nije neobavezna ceremonija. Šifrirano spremanje koje ne uspije na pola puta mora prekinuti isporuku, karena jedina alternativa koju pozivajući kod može ponuditi je nešifrirana kopija, a ta je kopija upravo onaj incident koji ova značajka želi spriječiti

Postoji i strojno provjerljiv test prihvaćanja koji ne košta gotovo ništa: pozovite CanReadEncrypted na datoteci koju ste upravo zapisali. Vraća true samo kada je izlaz stvarno spremnik šifriranja, pa provjera toga (asserting) nakon svakog šifriranog spremanja hvata najvažniju regresiju — stazu koda koja se tiho vratila na običan SaveAs — u trenutku kada se to dogodi, a ne tjednima kasnije u kupčevu sandučiću. Posljednja riječ ipak pripada ručnom otvaranju u Excelu sa stvarnom lozinkom tijekom testiranja izdanja

Samo za pisanje prema dizajnu: rukovanje s EXlsxEncryptionNotImplemented

Ta asimetrija ima jedno jasno arhitektonsko tumačenje: šifrirajte na rubu isporuke, na samom kraju. Držite čisti tekst (plaintext) unutar svoje granice povjerenja — u bazi podataka, spremištu dokumenata ili dijeljenom resursu s kontroliranim pristupom — i stvorite šifriranu kopiju kao posljednji korak prije nego što datoteka napusti sustav. Cjevovod koji arhivira samo šifrirani izlaz zaključao je sam sebe od vlastitih podataka, jer nijedan kasniji korak istog sustava ne može ponovno otvoriti te datoteke. Kada nizvodni proces HotXLS-a ponovno zatreba radnu knjigu, predajte mu izvornik u čistom tekstu, nikada isporučeni šifrirani dokument

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;

AES-128 Standardno šifriranje i linija usklađenosti s AES-256

Šifriranje Office datoteka dolazi u dvije generacije. Standardno šifriranje, ono koje HotXLS piše, koristi AES-128 s SHA-1 izvodom ključa. Agile šifriranje došlo je kasnije i prelazi na AES-256 s SHA-512 i drugačijim, XML-om opisanim spremnikom ključa. Oba se transparentno otvaraju u Excelu, a AES-128 je i dalje računski pouzdan za zaštitu datoteke u prijenosu do kupca

Razlika prestaje biti akademska onog dana kada sigurnosni upitnik zatraži "AES-256 šifriranje datoteka u mirovanju". Standardno šifriranje ne zadovoljava tu liniju, bez obzira na to koliko je lozinka jaka, i nijedan parametar metode SaveAsEncrypted ne mijenja algoritam koji ona emitira. Stoga točno navedite profil u svojoj sigurnosnoj dokumentaciji: AES-128, ECMA-376 Standardno šifriranje, SHA-1 izvod ključa s 50 000 iteracija. Tvrdnja koja preživi reviziju vrijedi više od optimistične koja se uruši pod revizijom

Naslijeđena XLS staza: RC4 van, RC4 i XOR natrag unutra

BIFF sučelje ima suprotan oblik. Njegovo šifriranje je starije i slabije, ali je cijeli krug potpun: ono što zapiše može i pročitati natrag. Postavljanje EncryptionPassword prije SaveAs proizvodi RC4-šifrirani .xls putem BIFF mehanizma FilePass, a metoda Open s parametrom lozinke čita sve tri naslijeđene sheme: 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 zastarjela kriptografija i nikada ne bi trebao štititi podatke koji su danas važni; njegova jedina preostala vrijednost je interoperabilnost sa sustavima koji još uvijek razmjenjuju .xls. Strana čitanja ipak opravdava svoje postojanje u radovima na migraciji. Naslijeđena datoteka zaštićena lozinkom otvara se s Open(FileName, Password), premošćuje se u model OOXML i ponovno osigurava putem AES staze — to je jednosmjerna nadogradnja koja se izvodi bez Excela bilo gdje u krugu. Za šifrirane isporuke velikog volumena, bilješke o propusnosti na strani spremanja u našem članku o strujnom pisanju za poslužiteljske serijske poslove primjenjuju se na fazu izgradnje sadržaja koja se događa prije šifriranja

Šifriranje i zaštita nisu suparnici

Još jedna točka koju vrijedi razjasniti, jer se pojavljuje onog trenutka kada netko protumači upozorenje na vrhu ove stranice kao "zaštita je beskorisna". Nije. Šifriranje i zaštita odgovaraju na različita pitanja i čisto se nadopunjuju. Šifriranje odlučuje tko može otvoriti datoteku; zaštita odlučuje što čitatelj koji je već unutra smije promijeniti. Isporuka platne liste može razumno činiti oboje: šifrirati paket tako da ga vidi samo vlasnik lozinke, a zatim zaključati ćelije s formulom tako da primatelj može filtrirati i sortirati, ali ne i tiho prepisivati izračune. Pogreška nikada nije u dodavanju zaštite. Pogreška je dopustiti da njezina prisutnost zamijeni šifriranje kada je zahtjev bio povjerljivost

Strana pohrane lozinki nema sigurnosnu mrežu, i to je namjerno. Izvođenje ključa od 50 000 iteracija postoji kako bi pogađanje bilo skupo, a ništa unutar datoteke ne pohranjuje tajnu kod treće strane (escrow). Izgubljena lozinka znači izgubljene podatke. Generirajte, isporučujte i pohranjujte ove lozinke s istom disciplinom koju primjenjujete na vjerodajnice baze podataka, i šifriranje će odraditi svoj dio posla

Stvarno šifriranje datoteka je jedan poziv u HotXLS-u. Disciplina živi u svemu oko tog poziva: čuvanju lozinke, granici samo za pisanje (write-only) koja sprječava HotXLS da ponovno otvori vlastiti izlaz i tvrdnji o algoritmu koju možete braniti u reviziji. Poziv SaveAsEncrypted i naslijeđeno povratno putovanje dolaze s komponentom HotXLS Component, radeći nativno u procesima Delphija i C++Buildera bez ikakve automatizacije Excela bilo gdje na tom putu