HotXLS číta Excel súbory so šifrovaním Agile, čo je ochrana heslom, ktorú Excel 2010 a každá novšia verzia používajú predvolene, a to prostredníctvom jediného volania: TXLSXWorkbook.OpenEncrypted. Komponent analyzuje XML deskriptor šifrovania, odvodí kľúče z hesla pomocou reťazca hashov SHA-512 so spin-countom, overí heslo voči šifrovanému verifikátoru a potom dešifruje balík v 4096-bajtových segmentoch AES-CBC. Nie je do toho zapojená žiadna inštalácia Excelu, COM rozhranie ani externé DLL knižnice pre kryptografiu
Tento článok sa venuje konkrétne strane čítania šifrovania Agile. Dva súvisiace problémy majú svoje vlastné články: interoperabilita so staršími schémami RC4 a XOR vo vnútri starých súborov BIFF .xls je popísaná v článku o interop ECB a RC4 a vytváranie zošitov chránených heslom s ECMA-376 Standard Encryption je opísané v článku o výstupe XLSX chránenom AES. Tu súbor už existuje, niekto iný ho zašifroval a vašou úlohou je ho otvoriť
Scenár, ktorý si to vyžaduje, je známy každému, kto prevádzkuje linku na spracovanie dokumentov. Importná služba na strane servera prijíma nahrané zošity; na stroji nie je nainštalovaný Excel a ani nikdy nebude; a jedného dňa zákazník nahrá úplne obyčajný súbor .xlsx, ktorý čítačka ZIP odmietne, pretože to vôbec nie je ZIP. Zákazník ho uložil s heslom. Od tej chvíle váš loader buď rozumie špecifikácii [MS-OFFCRYPTO], alebo vráti súbor používateľovi, ktorý zo svojho pohľadu neurobil nič neobvyklé
Čo je šifrovanie Agile v Excel súbore?
Šifrovanie Agile je schéma ochrany heslom definovaná v špecifikácii [MS-OFFCRYPTO] §2.3.4.10 až §2.3.4.15 a je to to, čo Excel 2010 a novší zapisujú zakaždým, keď je zošit uložený s heslom. Zašifrovaný súbor už nie je balíkom ZIP. Ide o kontajner OLE Compound File Binary (CFB), ktorý obsahuje dva toky: EncryptionInfo, ktorý popisuje, ako bolo šifrovanie vykonané, a EncryptedPackage, čo je skutočný ZIP .xlsx zašifrovaný ako nepriehľadný objekt blob. Podpis CFB (D0 CF 11 E0 A1 B1 1A E1) je rovnaký ako podpis starších súborov BIFF .xls, preto premenovaný alebo zašifrovaný súbor nemožno klasifikovať iba podľa prípony
To, čo odlišuje šifrovanie Agile od jeho predchodcov, je samopopisný formát EncryptionInfo. Po 8-bajtovom prefixe verzie, kde hlavná aj vedľajšia verzia sú obe 4, je tok XML deskriptorom v kódovaní UTF-8. Element keyData deklaruje šifru (AES), režim zreťazenia (ChainingModeCBC), hash (SHA512), dĺžku kľúča v bitoch, veľkosť bloku a soľ Base64. Element keyEncryptor pre heslo nesie vlastnú soľ, spinCount a tri Base64 payloads: encryptedVerifierHashInput, encryptedVerifierHashValue a encryptedKeyValue. Excel zapisuje AES-256 so spin countom 100 000, ale deskriptor môže deklarovať aj AES-128 alebo AES-192 a HotXLS rešpektuje to, čo hovorí hodnota keyBits a nepredpokladá automaticky 256
Jeden vstupný bod pre textový formát, Standard aj Agile zošity
Metóda TXLSXWorkbook.OpenEncrypted spracováva všetky tri stavy, s ktorými sa volajúci môže stretnúť — obyčajný ZIP, Standard-encrypted aj Agile-encrypted — takže spracovateľ nahrávania nemusí súbory pred načítaním klasifikovať. Metóda najprv preskúma súbor: ak chýba podpis CFB, odkáže ho na bežnú cestu Open a heslo sa jednoducho ignoruje. Ak je súbor kontajnerom CFB, najprv sa pokúsi o Standard Encryption ECMA-376 a ak je podpis verzie EncryptionInfo Agile 4.4, odovzdá ho linke Agile. Návratová hodnota je 1 pri úspechu, čo je rovnaký kontrakt ako pri metóde Open
Ako sa z hesla stane kľúč AES?
Šifrovanie Agile nikdy nepoužíva heslo priamo. HotXLS najprv vypočíta iterovaný hash: počiatočný digest je SHA-512 nad soľou hesla spojenou s UTF-16LE bajtmi hesla, a potom je digest rehashovaný spinCount-krát, pričom v každom kole sa pred predchádzajúci digest pripojí 32-bitové počítadlo iterácií typu little-endian. S predvoleným spin countom Excelu 100 000 ide o stotisíc sériových volaní SHA-512 na jeden pokus o heslo, a to je hlavným účelom. Spin count je škrtiaca klapka pre hrubú silu (brute-force throttle): legitímneho volajúceho stojí pár milisekúnd jednorazovo, zatiaľ čo útočníka so slovníkovým útokom stojí rovnakých pár milisekúnd za každý jednotlivý pokus
Overenie hesla a pasca skrátenia saltSize
HotXLS overuje heslo predtým, ako sa dotkne balíka, pomocou páru verifikátorov z deskriptora. Dešifruje encryptedVerifierHashInput prvým odvodeným kľúčom, hashuje výsledok pomocou SHA-512, dešifruje encryptedVerifierHashValue druhým odvodeným kľúčom a porovnáva oba digests bajt po bajte. Nezhoda znamená, že heslo je nesprávne, čo sa nahlási ako samostatný výsledok a nie ako poškodený zošit, a čo je dôležité, znamená to, že telo balíka sa nikdy nedešifruje so zlým kľúčom, takže nemôže nastať scenár, kedy by nesprávne heslo vytvorilo zdanlivo vierohodné poškodené dáta
Je tu jeden detail špecifikácie, v ktorom sa dá ľahko urobiť chyba. Špecifikácia [MS-OFFCRYPTO] §2.3.4.13 definuje verifikátor ako saltSize bajtov náhodných dát, kde saltSize je dĺžka soli kľúča a nie veľkosť bloku šifry. Keďže šifrovaný text AES-CBC je zarovnaný na bloky, dešifrovaný vstup verifikátora sa vracia doplnený (padded) na násobok 16 bajtov a pred hashovaním sa musí skrátiť späť na saltSize. Excel vždy zapisuje saltSize rovnajúcu sa blockSize, obe 16, so an implementation that skips the truncation passes every test against real Excel output and then fails on the first file from a producer that chose a different salt length. HotXLS skracuje na dĺžku soli, pretože to je to, čo špecifikácia skutočne hovorí, pričom skutočnosť, že sa tieto dve hodnoty v praxi zhodujú, je náhoda a nie pravidlo
Ako sa dešifruje EncryptedPackage?
Tok EncryptedPackage začína 8-bajtovou veľkosťou čistého textu v little-endian formáte, za ktorou nasleduje šifrovaný text v 4096-bajtových segmentoch, a HotXLS ho dešifruje segment po segmente s novým IV pre každý segment. Samotný kľúč balíka nie je odvodený z hesla: je to náhodný stredný kľúč, ktorý zapisovač zašifroval do encryptedKeyValue, a HotXLS ho rozbalí s tretím odvodeným kľúčom, pričom ho skráti na dĺžku kľúča deklarovanú v keyData. IV každého segmentu je SHA-512 nad soľou keyData spojenou s 32-bitovým little-endian indexom segmentu, skrátený na veľkosť bloku. Táto konštrukcia znamená, že akýkoľvek 4096-bajtový segment možno dešifrovať nezávisle, čo robí tento formát v princípe vhodným pre náhodný prístup (random access), aj keď HotXLS dešifruje celý balík do pamäte a vrátené bajty ZIP odovzdá bežnému XLSX loaderu
Deklarovaná veľkosť čistého textu vykonáva finálnu časť práce. Výstup AES-CBC je zarovnaný na bloky, takže posledný segment nesie až 15 bajtov doplnenia (padding), ktoré nie sú súčasťou dokumentu; dešifrovaný buffer sa skráti na prefix veľkosti a výsledkom je presne ZIP .xlsx, ktorý Excel zašifroval. HotXLS pred dešifrovaním overuje prefix voči skutočnej dĺžke toku, takže skrátené nahrávanie alebo manipulácia s poľom veľkosti zlyhajú čisto, bez pretečenia
Hlásenie chýb a skutočné limity
Chybové stavy sa zámerne držia oddelene. Nesprávne heslo vyvolá výnimku s jasnou správou o nesprávnom hesle, riadenou nezhodou verifikátora, takže používateľské rozhranie môže vyzvať používateľa na nový pokus. Kontajner CFB, ktorého deskriptor deklaruje algoritmy mimo podporovanej sady, čokoľvek iné ako AES s reťazením CBC a hashovaním SHA-512 v Agile deskriptore, alebo kontajner, ktorý nie je Standard ani Agile, vyvolá odlišnú výnimku identifikujúcu schému ako nepodporovanú. Tieto dva stavy sa nesmú zamieňať: opakovaný pokus o zadanie hesla pri nepodporovanej schéme mrhá časom používateľa a nahlásenie nesprávneho hesla ako chyby formátu pošle váš tím podpory nesprávnym smerom
Limity stojí za to uviesť na rovinu. HotXLS číta Agile deskriptory, ktoré deklarujú AES v režime CBC so SHA-512, čo pokrýva to, čo Excel 2010 až Excel 365 reálne zapisujú, a to vo všetkých troch veľkostiach kľúčov. Deskriptory deklarujúce iné šifry alebo algoritmy hashovania sú odmietnuté a nepokúša sa o ne hádanie, a certifikátové key encryptory sa nekonzultujú, iba tie pre heslo. Na strane zápisu HotXLS v súčasnosti vytvára Standard Encryption a nie Agile, čo je rozdiel, na ktorom záleží, ak nadväzujúce nástroje kontrolujú schému; podrobnosti sú v článku o zápise XLSX výstupu chráneného AES
Nahrávanie chránené heslom prestáva byť špeciálnym prípadom, akonáhle loader pristupuje k šifrovaniu ako k súčasti formátu súboru a nie ako k výnimke z neho. Vstupný bod OpenEncrypted, odvodenie SHA-512 so spin-countom a segmentovaná linka AES-CBC opísané tu sa dodávajú ako súčasť komponentu HotXLS Delphi Excel Component, spolu so zvyškom jeho natívneho jadra pre čítanie a zápis formátov XLS a XLSX pre Delphi a C++Builder