Technischer Artikel

HotXLS: Manipulierte XLSX per Agile-HMAC erkennen

HotXLS schreibt einen konformen dataIntegrity-Block in Agile-verschlüsselte XLSX-Pakete und prüft ihn beim Öffnen. Der HMAC-SHA-512 deckt den kompletten EncryptedPackage-Stream ab, einschließlich seines acht Byte großen StreamSize-Präfixes, und wird über dem Chiffretext geprüft, bevor auch nur ein Segment entschlüsselt wird, sodass ein falsches Passwort oder ein verändertes Paket erkannt statt in Datenmüll entschlüsselt wird

Verschlüsselung ohne Integrität ist eine halbe Antwort, und Office-Dateiformate machen diese Lücke leicht zu übersehen, weil die Verschlüsselung von außen so gründlich wirkt. Zu verstehen, was jede Schicht verspricht, ist es, was ein Sicherheits-Review kurz hält

Was verspricht ein verschlüsseltes Arbeitsbuch tatsächlich?

Agile-Verschlüsselung, definiert in [MS-OFFCRYPTO], gibt Vertraulichkeit durch AES im CBC-Modus mit einem aus einem iterierten SHA-512-Passworthash abgeleiteten Schlüssel. Vertraulichkeit ist das gesamte Versprechen dieser Konstruktion. CBC ist kein authentifizierter Modus: Er sagt nichts darüber, ob der Chiffretext, der gerade entschlüsselt wird, der Chiffretext ist, der geschrieben wurde

Die praktische Konsequenz ist konkret. Kippt man Bits in einem verschlüsselten Paket, entschlüsselt CBC sie bereitwillig zu anderem Klartext. Meist erhält man irgendwo weiter unten einen ZIP-Parse-Fehler, weil ein beschädigter Deflate-Stream selten übersteht, aber "meist" leistet in diesem Satz viel Arbeit, und ein Parser-Fehler weiter unten ist ein furchtbarer Ort, um zu erfahren, dass eine Datei verändert wurde. Das dataIntegrity-Element existiert, um die Frage direkt zu beantworten, vor der Entschlüsselung, mit einem MAC über die exakten Bytes

Wie die Prüfung abläuft, und in welcher Reihenfolge

Die Reihenfolge ist der interessante Teil. HotXLS leitet den Zwischenschlüssel aus dem Passwort ab, entschlüsselt den verschlüsselten HMAC-Schlüssel und den HMAC-Wert aus den dataIntegrity-Attributen mit aus Blockschlüsseln abgeleiteten IVs, berechnet HMAC-SHA-512 über das gespeicherte verschlüsselte Paket und vergleicht. Erst danach beginnt die Segmententschlüsselung

Den MAC über dem Chiffretext statt über dem Klartext zu prüfen ist die übliche Encrypt-then-MAC-Disziplin, und das macht die Prüfung aussagekräftig: Ein manipuliertes Paket wird abgelehnt, ohne dass auch nur ein von Angreifern kontrolliertes Byte durch den Entschlüsselungs- und Inflate-Pfad gelaufen ist. Beide Vergleiche im Öffnen-Pfad, der Passwort-Verifier-Hash und der HMAC-Wert, akkumulieren Unterschiede per XOR und OR über das gesamte Digest, statt beim ersten abweichenden Byte vorzeitig zurückzukehren, sodass keiner der beiden eine Byte-Position über Timing preisgibt

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create;
  try
    // Funktioniert für unverschlüsselte, Standard- und Agile-verschlüsselte Dateien
    if Book.OpenEncrypted('incoming.xlsx', PasswordFromVault) = 1 then
      ProcessWorkbook(Book)
    else
      // Falsches Passwort, oder ein Paket, dessen dataIntegrity-HMAC nicht passte
      Quarantine('incoming.xlsx');
  except
    on E: Exception do
      Quarantine('incoming.xlsx: ' + E.Message);
  end;
  Book.Free;
end;

Auf der Schreibseite ändert sich im eigenen Code nichts. SaveAsEncrypted gibt den Block automatisch aus, und die Salts, die Verifier-Eingabe und der HMAC-Schlüssel stammen aus CryptGenRandom. Schlägt dieser Aufruf fehl, löst HotXLS eine Ausnahme aus, statt auf eine schwächere Quelle zurückzufallen. Ein Fail-closed-CSPRNG ist keine Paranoia; ein stiller Rückfall auf eine vorhersagbare Zufallsquelle erzeugt Dateien, die verschlüsselt aussehen, jeden Funktionstest bestehen und wertlos sind

Warum öffnen Dateien ohne den Block trotzdem?

Weil sehr viele im Umlauf befindliche Agile-verschlüsselte Arbeitsbücher von Erzeugern geschrieben wurden, die dataIntegrity ganz weglassen, und sie abzulehnen würde weit mehr legitime Arbeit stören, als es schützen würde. HotXLS behandelt Integrität nur dann als vorhanden, wenn beide Attribute, der verschlüsselte HMAC-Schlüssel und der verschlüsselte HMAC-Wert, vorhanden und wohlgeformt sind. Andernfalls wird die Verifikation übersprungen und die Datei öffnet sich wie zuvor

Das ist eine Kompatibilitätsentscheidung mit einer sicherheitsrelevanten Konsequenz, die man in seinem eigenen Bedrohungsmodell klar benennen sollte: Das Fehlen des Blocks lässt sich nicht davon unterscheiden, dass ein Angreifer ihn entfernt hat, weil die Attribute außerhalb des MACs liegen, den sie tragen würden. Kontrolliert man beide Enden einer Pipeline, sollte ein fehlender Block auf Anwendungsebene als Richtlinienfehler behandelt werden. Nimmt man Dateien aus aller Welt entgegen, sollte man die Prüfung als das behandeln, was sie ist, ein wertvolles Signal, wenn vorhanden, und gar kein Signal, wenn nicht

Passwort zum Ändern ist eine Konvention, keine Grenze

Klassische XLS-Arbeitsbücher unterstützen einen separaten Mechanismus, der routinemäßig mit Verschlüsselung verwechselt wird: die Write Reservation, Excels "Kennwort zum Ändern"-Aufforderung. HotXLS legt sie über SetModifyPassword offen, das das Passwort, ein Recommend-read-only-Flag und den Namen des reservierenden Nutzers entgegennimmt, und meldet den Status über IsWriteReserved. Ein leeres Passwort löscht die Reservierung

Geschrieben wird ein WRITEPROT- und FILESHARING-Recordpaar, das das Recommend-read-only-Flag, einen veralteten 16-Bit-Passworthash und den Nutzernamen als BIFF8-Unicode-String trägt. Dieser 16-Bit-Hash ist eine Prüfsumme, kein kryptografisches Digest, und der Dokumentinhalt wird überhaupt nicht verschlüsselt. Wer die Datei mit einem beliebigen anderen Tool öffnet, liest alles. Die eigentliche Aufgabe des Features ist Koordination: Es sagt der nächsten Person, dass jemand diese Datei als seine eigene zum Bearbeiten betrachtet, in derselben Kategorie wie die in XLSX-Blattschutz und Allow-Optionen behandelten blattbezogenen Kontrollen

var
  Book: IXLSWorkbook;   // interface-gezählt: nicht Free aufrufen
begin
  Book := TXLSWorkbook.Create;
  if Book.Open('shared-model.xls') = 1 then
  begin
    // Read-only empfehlen, reserviert vom Reporting-Dienst
    Book.SetModifyPassword('edit-me', True, 'Reporting Service');

    if Book.IsWriteReserved then
      Book.SaveAs('shared-model.xls', xlExcel97);
  end;
end;

Nutzen Sie beide Schichten für das, worin jede gut ist. Echte Vertraulichkeit kommt von SaveAsEncrypted mit einem Passwort, das niemand außerhalb des Empfängerkreises kennt, was die in AES-geschützter XLSX-Ausgabe beschriebene AES-256-Ausgabe erzeugt. Die Write Reservation kommt obendrauf, wenn das Arbeitsbuch ein gemeinsam bearbeitetes Artefakt ist und Excel fragen soll, bevor jemand darüber speichert

Was auf einem nicht vertrauenswürdigen Aufnahmepfad zu prüfen ist

Integritätsprüfung schützt die verschlüsselte Nutzlast, nicht den Container darum herum. Eine XLSX-Datei ist ein ZIP-Archiv, und die Archivstruktur wird geparst, bevor überhaupt Verschlüsselungslogik läuft, also gehört die Validierung auf Container-Ebene zuerst in die Kette; die konkreten Fehlerbilder werden in ZIP-End-of-Central-Directory-Validierung für nicht vertrauenswürdige XLSX behandelt. Danach sollte man einen Integritätsfehler und ein falsches Passwort als dasselbe operative Ereignis behandeln, weil sie von der eigenen Seite aus konstruktionsbedingt nicht unterscheidbar sind, und beide bedeuten, dass der Datei nicht vertraut werden kann, das zu sein, was der Absender denkt

Protokollieren Sie, welche Dateien überhaupt einen dataIntegrity-Block trugen. Über ein paar tausend Dokumente sagt diese Statistik etwas Nützliches über das Tooling Ihrer Absender aus, und sie macht aus einer Prüfung pro Datei eine Beobachtung auf Flottenebene, nach der man handeln kann

HotXLS liest und schreibt XLS, XLSX und ODS aus Delphi und C++Builder ohne installiertes Excel und implementiert die Standard- und Agile-Verschlüsselungspfade von [MS-OFFCRYPTO] in Pascal. Die Verschlüsselungs-, Schutz- und Workbook-APIs sind auf der HotXLS Delphi Spreadsheet-Komponente-Seite dokumentiert