Műszaki cikk

XLSX-fájlok AES-titkosítása Delphiben a HotXLS-szel

Az Excelben két dolgot is „jelszónak” hívnak, és csak az egyik jelent titkosítást. A megnyitási jelszó valódi rejtjelezőt kulcsol: nélküle a fájl egyáltalán nem olvasható. A munkalap- és munkafüzetvédelmi jelszavak semmi ilyet nem tesznek. Egy jelzőt állítanak be, amelynek tiszteletben tartására egy együttműködő szerkesztő hajlandó, és az a munkafüzet, amely ezen a jelzőn kívül semmit nem hordoz, egyszerű, olvasható zip, benne tiszta szövegként az adattal. Válassza rosszul, és olyan bérszámfejtést szállít ki, amely az Excelben zártnak látszik, bármelyik szövegszerkesztőben viszont olvasható

A bizonyítás tíz másodpercbe telik. Nevezzen át egy védett .xlsx fájlt .zip kiterjesztésűre, nyissa meg bármelyik tömörítőprogrammal, és nézze meg az xl/worksheets/sheet1.xml részt. Ha a cellaértékek ott vannak sima UTF-8 kódolással, a fájl nincs titkosítva, akárhány jelszókérdést dob is fel az Excel, amikor valaki egy cellát próbál szerkeszteni. Ez a rés évekig fennmarad olyan csapatokban, amelyek a munkalapvédelmet bizalmasságnak hiszik, és rendszerint azon a napon derül ki, amikor egy biztonsági felülvizsgálat pontosan ezt az átnevezést elvégzi

A HotXLS natív Delphi és C++Builder táblázatkezelő könyvtár, és a két funkciót ennek a vonalnak az ellentétes oldalain tartja. A munkalap- és munkafüzetvédelem szerkesztési korlátozás, amelyet szándékosan gyenge, régi hash támogat. A SaveAsEncrypted AES-titkosított csomagot állít elő, amelyet a jelszón kívül semmi nem nyit meg. Az alábbi szakaszok azt veszik sorra, mit ír ki ez a hívás, milyen aszimmetria köré kell terveznie (a HotXLS ír titkosított fájlt, de visszaolvasni nem tudja), és miben tér el a régebbi XLS-útvonal

Diagram, amely szembeállítja a Delphi XLSX munkalapvédelmet, amely gyenge hash-t tárol és a cellaadatokat olvashatóan hagyja egy sima zipben, a HotXLS SaveAsEncrypted hívásával, amely AES-128 kulcsot származtat és OLE titkosítási konténert ír
A munkalapvédelem gyenge hash-t tárol, és a csomagot olvasható zipként hagyja. A SaveAsEncrypted AES-128 kulcsot származtat, és olyan OLE-konténert ír, amelyet egyetlen tömörítőprogram sem tud kilistázni

Miért nem titkosítás a munkalapvédelem

A munkalapok Protect metódusai és a munkafüzet ProtectWorkbook metódusa a jelszó négy hexadecimális jegyű hash-ét tárolja. Ez az a régi algoritmus, amelyet az OOXML és a BIFF egyaránt az 1990-es évek Exceljétől örökölt, és a formátum dokumentációja soha nem állítja, hogy ennél többet tenne a véletlen szerkesztések megakadályozásánál. A csomag közönséges, olvasható zip marad: a cellaadat, a képletek és az osztott sztringek mind tiszta szövegű XML-ben. Az alapértelmezés ezen inkább ront, mint javít. Minden cella Locked=True állapotban indul, tehát ha úgy hívja a Protect metódust, hogy előbb nem oldja fel egy beviteli tartomány zárolását, az egész munkalapot befagyasztja a szerkesztés ellen, miközben minden érték jól láthatóan ott marad

Ettől még a védelem nem haszontalan. Az, hogy a felhasználókat szerkeszthető tartományokba tereljük, és hogy stabilizáljuk az elrendezést nyomtatáshoz, valódi feladat, amelyről a munkalapvédelemről és az oldalbeállításról szóló cikkünk szól. Ezek azonban használhatósági feladatok. Abban a pillanatban, amint a követelmény a bizalmasság, az egyetlen API, amely megválaszolja, a SaveAsEncrypted

Mit ír ki valójában a SaveAsEncrypted

A megvalósítás az ECMA-376 Standard Encryption sémát követi, amelyet az [MS-OFFCRYPTO] 2.3.4. szakasza határoz meg. A jelszó 50 000 SHA-1 iteráción fut át, hogy AES-128 kulcsot származtasson belőle. Egy ellenőrzőblokk, amelyet AES-128 ECB módban titkosítanak, lehetővé teszi, hogy a fogadó fél megerősítse a jelszót, mielőtt bármit visszafejtene, majd a teljes munkafüzetcsomag AES-128 CBC módban titkosítódik. Ami a lemezre kerül, az egyáltalán nem zip. OLE összetett fájl, amely az EncryptionInfo, az EncryptedPackage és a DataSpaces streameket tartalmazza, és nincs benne xl/ könyvtár, amelyet egy tömörítőprogram kilistázhatna – ezért nem talál most az átnevezéses teszt semmi olvashatót. Az Excel 2007 és későbbi verziói pusztán a jelszóval megnyitják, és a jelenlegi LibreOffice is olvassa a Standard Encryption sémát

Folyamatábra egy Delphi HotXLS SaveAsEncrypted hívásról: a széfből származó jelszó 50 000 SHA-1 körön át AES-128 kulccsá válik, ECB ellenőrzőblokkal és CBC csomagtitkosítással, OLE összetett fájlt előállítva, amelyet a CanReadEncrypted hívás ellenőriz
Egyetlen SaveAsEncrypted hívás a széfből származó jelszót AES-128 kulccsá és OLE összetett fájllá alakítja. A CanReadEncrypted géppel ellenőrizhető átvételi kaput ad a mentéshez
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;

A jelszóváltozót ugyanolyan gondossággal kezelje, mint egy kapcsolati sztringet. Kérje le széfből vagy titokgeneráló szolgáltatásból az utolsó pillanatban, soha ne naplózza, és soha ne írja bele magába a munkafüzetbe. A visszatérési kód ellenőrzése nem elhagyható szertartás. Az a titkosított mentés, amely félúton elbukik, kénytelen megszakítani a kiszállítást, mert az egyetlen tartalék, amelyet a hívó kód felkínálhat, egy titkosítatlan másolat – és éppen ez az az incidens, amelynek megelőzésére ez a funkció létezik

Van ezenfelül egy géppel ellenőrizhető átvételi teszt is, amely szinte semmibe nem kerül: hívja meg a CanReadEncrypted műveletet az imént kiírt fájlra. Csak akkor ad vissza igazat, ha a kimenet valóban titkosítási konténer, tehát ha minden titkosított mentés után állítja ezt, elkapja a legfontosabb regressziót – azt a kódútvonalat, amely csendben visszaesett egy sima SaveAs hívásra –, méghozzá abban a pillanatban, amikor megtörténik, nem hetekkel később egy ügyfél postaládájában. A végső szó azért továbbra is a kiadási teszteléskor, valódi jelszóval, Excelben végzett kézi megnyitásé

Tervezetten csak írásra: az EXlsxEncryptionNotImplemented kezelése

Íme az aszimmetria, amelynek alakítania kell a folyamat architektúráját: a HotXLS mentéskor titkosít, megnyitáskor viszont nem fejt vissza. Az OpenEncrypted az EXlsxEncryptionNotImplemented kivételt váltja ki, ha valódi titkosított csomagra irányítják; sima munkafüzeten egyszerűen átcsúszik egy normál Open hívásba. A társszonda, a CanReadEncrypted, olcsón észleli az OLE titkosítási konténert, így a beolvasó kód a kivétel kiváltása nélkül irányíthatja el az ilyen fájlokat:

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.CanReadEncrypted(FileName) then
    begin
      // Titkosított konténer: a HotXLS nem tudja visszafejteni.
      Writeln(FileName + ': needs manual decryption in Excel first');
      Exit;
    end;
    try
      Book.OpenEncrypted(FileName, '');   // a sima fájlok az Open hívásba csúsznak át
      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;

Ennek az aszimmetriának egyetlen világos architekturális olvasata van: a kiszállítás peremén titkosítson, utolsóként. A nyílt szövegű mesterpéldányt tartsa a bizalmi határon belül – adatbázisban, dokumentumtárban vagy hozzáférés-vezérelt megosztáson –, a titkosított másolatot pedig utolsó lépésként állítsa elő, mielőtt a fájl elhagyja a rendszert. Az a folyamat, amely csak a titkosított kimenetet archiválja, kizárta magát a saját adataiból, mert ugyanannak a rendszernek egyetlen későbbi szakasza sem tudja újra megnyitni ezeket a fájlokat. Amikor egy downstream HotXLS-folyamatnak ismét szüksége van a munkafüzetre, a nyílt szövegű mesterpéldányt adja neki, soha nem a kiszállítási terméket

Architektúradiagram Delphi szolgáltatásokhoz: a nyílt szövegű munkafüzet-mesterpéldány a bizalmi határon belül marad, a HotXLS SaveAsEncrypted utolsó lépésként fut a kiszállítás peremén, és figyelmeztetés szerepel az ellen, hogy csak a titkosított másolatot archiválják
Titkosítson a kiszállítás peremén, utolsóként, a bizalmi határon belül tartott nyílt szövegű mesterpéldányból. Ha csak a titkosított másolatot archiválja, minden későbbi szakaszt kizár a saját adataiból

AES-128 Standard Encryption és az AES-256 megfelelőségi vonal

Az Office fájltitkosítása két nemzedékben létezik. A Standard Encryption, amelyet a HotXLS ír, AES-128 titkosítást használ SHA-1 kulcsszármaztatással. Az Agile Encryption később érkezett, és AES-256 titkosításra vált SHA-512 mellett, egy másik, XML-lel leírt kulcskonténerrel. Mindkettőt átlátszóan megnyitja az Excel, és az AES-128 számításilag ma is szilárd ahhoz, hogy egy fájlt ügyfélhez vezető úton védjen

A különbség azon a napon szűnik meg elméletinek lenni, amikor egy biztonsági kérdőív „a nyugalmi állapotú fájlok AES-256 titkosítását” kéri. A Standard Encryption ezt a vonalat nem éri el, bármilyen erős is a jelszó, és a SaveAsEncrypted egyetlen paramétere sem változtat az általa kibocsátott algoritmuson. Ezért a profilt pontosan írja le a biztonsági dokumentációjában: AES-128, ECMA-376 Standard Encryption, SHA-1 kulcsszármaztatás 50 000 iterációval. Az az állítás, amely túléli a felülvizsgálatot, többet ér egy derűlátónál, amely egy audit alatt összeomlik

A régi XLS-útvonal: RC4 kifelé, RC4 és XOR visszafelé

A BIFF-homlokzat alakja fordított. A titkosítása régebbi és gyengébb, de az oda-vissza út teljes: amit kiír, azt vissza is tudja olvasni. Ha a SaveAs előtt beállítja az EncryptionPassword értéket, RC4-titkosítású .xls fájl születik a BIFF FilePass mechanizmusán keresztül, a jelszóparaméterrel hívott Open pedig mind a három régi sémát olvassa: az RC4, az RC4 CryptoAPI és az ősrégi XOR-elhomályosítás:

var
  Writer, Reader: IXLSWorkbook;   // interfészhivatkozások: nincs kézi 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);  // A bejegyzések egy alapúak
end;

Az RC4 elavult kriptográfia, és ma már soha nem védhet olyan adatot, amely számít; egyetlen megmaradt értéke az együttműködés azokkal a rendszerekkel, amelyek még .xls fájlokat cserélnek. Az olvasási oldal viszont kiérdemli a helyét a migrációs munkában. Egy jelszóval védett régi fájl az Open(FileName, Password) hívással megnyílik, átvezethető az OOXML-modellbe, és az AES-útvonalon újra biztosítható – ez egyirányú korszerűsítés, amely a hurokban sehol nem igényel Excelt. Nagy volumenű titkosított kiszállításoknál a kiszolgálói kötegfeladatokhoz való streamelt írásról szóló cikkünk mentésoldali átbocsátóképességi megjegyzései a titkosítás előtti tartalomépítési fázisra érvényesek

A titkosítás és a védelem nem vetélytársak

Még egy pontot érdemes lezárni, mert abban a pillanatban felmerül, amint valaki az oldal tetején álló figyelmeztetést úgy olvassa, hogy „a védelem semmit nem ér”. Nem így van. A titkosítás és a védelem különböző kérdésre válaszol, és tisztán egymásra rétegezhetők. A titkosítás azt dönti el, ki nyithatja meg a fájlt; a védelem azt, mit módosíthat az az olvasó, aki már belül van. Egy bérszámfejtési kiszállítás ésszerűen tehet mindkettőt: titkosítja a csomagot, hogy csak a jelszó birtokosa lássa, majd zárolja a képletcellákat, hogy a címzett szűrhessen és rendezhessen, de ne írhassa át csendben a számításokat. A hiba soha nem az, hogy védelmet ad hozzá. A hiba az, ha hagyja, hogy a védelem jelenléte a titkosítás helyébe lépjen ott, ahol a követelmény a bizalmasság volt

A titokőrzés oldalán nincs védőháló, és ez így van kitalálva. Az 50 000 iterációs kulcsszármaztatás azért létezik, hogy drágává tegye a találgatást, és a fájlon belül semmi nem helyezi letétbe a titkot. Az elveszett jelszó elveszett adat. Ezeket a jelszavakat ugyanazzal a fegyelemmel állítsa elő, szállítsa ki és tárolja, amelyet az adatbázis-hitelesítő adatokra alkalmaz, és a titkosítás állni fogja a saját oldalát

A valódi fájltitkosítás a HotXLS-ben egyetlen hívás. A fegyelem mindabban él, ami a hívás körül van: a jelszó őrzésében, abban a csak írásra szóló határban, amely megakadályozza, hogy a HotXLS újra megnyissa a saját kimenetét, és egy olyan algoritmusállításban, amelyet egy auditon meg tud védeni. A SaveAsEncrypted és a régi oda-vissza út a HotXLS Delphi Component részeként érkezik, natívan futva Delphi és C++Builder folyamatokban, az útvonalon sehol nem használva Excel-automatizálást