Aus Linux-Magazin 10/2006

Sicherheitstest: Verschlüsselte Filesysteme unter Linux

Ob die aktuellen Crypto-Dateisysteme unter Linux wirksam schützen, hängt von den kryptographischen Qualitäten ab und davon, ob ihre Bedienung den Admins und Anwendern schmeckt. Oftmals sorgen Programmierfehler sogar für zusätzliche Sicherheitslöcher. Dieser Test deckt Schwächen auf.

Verschlüsselnde Dateisysteme gibt es unter Linux reichlich (Tabelle 1). Doch bereits der erste Eindruck irritiert: Keiner der Testkandidaten nennt ein klares Bedrohungsszenario (vergleiche vorherigen Artikel) oder verrät wenigstens die Designprinzipien. Kaum ein System dokumentiert technische Details. Lobenswerte Ausnahmen sind nur Truecrypt und Enc-FS. Daraus folgt, dass beim Auditing tonnenweise Quellcode zu analysieren ist (per Reverse Engineering) und über die Motivation der Entwickler bestenfalls Spekulationen gelingen.

Tabelle 1:
Testfeld

 

Filesystem

Version

Implementierung

Container

Ebene

Windows-Portierung

Loop-AES

3.1d

Kernel

Datei oder Partition

Blockdevice

ja [5]

DM-Crypt

Kernel 2.6.15

Kernel

Datei oder Partition

Blockdevice

ja [9]

Cryptsetup-LUKS

1.0.3

Kernel

Datei oder Partition

Blockdevice

ja [9]

Truecrypt

4.2a

Kernel

Datei oder Partition

Blockdevice

ja

Crypto-FS

0.5.2

Userspace

Verzeichnis

Dateien

nein

Enc-FS

1.2.5

Userspace

Verzeichnis

Dateien

ja

Bei der Recherche zu diesem Artikel stellte sich heraus, dass die Quellen-Analyse weniger einem Code Audit gleicht, sondern eher einer archäologischen Ausgrabung. Relevante Funktionen verbergen sich unter mehreren Schichten von Code-Ablagerungen mit aufgegebenen Software- und Verschlüsselungsexperimenten. Die verraten immerhin, wie die Entwickler Varianten durchprobiert haben, um das Schlüsselmaterial und die chiffrierten Daten zu bearbeiten.

Die Technik der Crypto-Dateisysteme gliedert sich nach mehreren Kriterien. Einerseits nach der Implementierung im Kernel oder im Userspace, andererseits danach, ob sie eine Datei oder ein Verzeichnis als Container nutzen oder die Daten in einer eigenen Partition ablegen, sowie danach, ob sie jede Datei einzeln verschlüsseln oder ein komplettes Volume auf Blockdevice-Ebene anbieten. Tabelle 1 ordnet die Systeme nach diesen Kriterien und sagt, ob es eine Windows-Portierung gibt. Letzteres ist für viele Anwender im Mischbetrieb Linux/Windows entscheidend.

Loop-AES

Loop-AES [1] ist das älteste der hier vorgestellten Crypto-Filesysteme. Es nutzt das seit Jahren im Kernel vorhandene »loop«-Modul und verträgt sich sogar noch mit dem 2.0-Kernel. Die Funktionsweise ähnelt dem längst als unsicher entlarvten Cryptoloop-Verfahren [2]. Loop-AES arbeitet auf Blockdevice-Ebene und schreibt die verschlüsselten Daten in eine Containerdatei oder in eine eigens dafür vorbereitete Partition.

Als erste Hürde erweist sich die Installation aus dem Quellpaket. Sie benötigt die passenden Kernelsourcen inklusive der beim Kompilieren entstandenen Komponenten – in der Regel muss der Admin dazu den Kernel selber bauen. Zudem muss er das elementare Paket »util-linux« [3] patchen und neu übersetzen. Es enthält wichtige Systembefehle, beispielsweise »mount«. Immerhin erklärt die Readme-Datei [4] den Vorgang recht gut. Sie enthält weitere nützliche Hinweise, etwa zu Loop-AES in Verbindung mit Software-Suspend.

Wegen der tiefen Eingriffe ins System ist gut beraten, wer sich möglichst an die distributionsspezifischen Pakete hält. Ubuntu macht es hier relativ einfach, wie Listing 1 zeigt. Der Aptitude-Aufruf in Zeile 1 installiert die benötigten Pakete. Danach bewährt sich der »module-assistant« in den Zeilen 2 bis 4, um ein passendes Loop-AES-Paket aus den Quellen zu erstellen.

Listing 1: Loop-AES auf
Ubuntu

01 sudo aptitude install loop-aes-utils loop-aes-source
02 sudo module-assistant update
03 sudo module-assistant prepare
04 sudo module-assistant build loop-aes
05 sudo dpkg -i loop-aes-2.6.15-26-686_3.1b-8+2.6.15-26.45_i386.deb
06 
07 losetup -e AES256 /dev/loop0 /dev/hda6
08 mkfs.xfs /dev/loop0
09 mount /dev/loop0 /home/chris/loopaes

Es tritt zwar ein kleiner Bug auf, ist aber auch schnell behoben: Beim »build«-Aufruf meckert das System, dass »debian/rules« die nötigen Rechte fehlen. Lösung des Problems: Ein weiteres Terminalfenster öffnen, die Rechte per »chmod +x /usr/src/modules/loop-aes/debian/rules« händisch setzen und danach den Build-Vorgang fortsetzen. Zeile 5 installiert das resultierende Paket.

Durch die gute Integration ins System mit eigens angepassten Werkzeugen ist Loop-AES recht einfach benutzbar. Zeile 7 in Listing 1 zeigt den Losetup-Aufruf, der eine logische Verbindung zwischen dem Loopdevice »loop0« und der Partition »/dev/hda6« herstellt. Als Blockdevice dürfte hier auch eine normale Datei stehen, die dann als Container das Crypto-Blockdevice aufnimmt.

Nach der Angabe des mindestens 20-stelligen Passworts schreibt Losetup die von Loop-AES benötigten Header auf die Partition. Mit dem Anlegen eines XFS-Dateisystems in Zeile 8 ist das Loopdevice bereit und lässt sich per »mount« ins System einbinden. Nach einem »umount« ist noch ein »losetup -d /dev/loop0« nötig, um auch die logische Zuordnung zum physikalischen Device zu trennen. Wer das Mounten automatisieren will, ergänzt Folgendes in »/etc/fstab«:

/dev/hda6 /home/chris/loopaes xfs defaults,loop=/dev/loop0,encryption=AES256 0 0

Obwohl Loop-AES recht tiefe Eingriffe ins System verlangt und seine Technik bereits Staub ansetzt, ist es in der Praxis recht einfach und gut nutzbar. Mit Crosscrypt [5] sind Loop-AES-Container auch unter Windows zu lesen.

Sicherheit von Loop-AES

Eine verwirrende Vielzahl von Optionen beim Kompilieren und Verwenden des Filesystems behindert die Sicherheitsanalyse. Die Verschlüsselungsfunktionen verhalten sich je nach gewählter Option radikal unterschiedlich. Der unübersichtliche Code behindert das Audit ebenfalls: Es ist schwer herauszufinden, was im Inneren von Loop-AES vorgeht und ob der Code wirklich tut, was er tun soll.

Loop-AES verzichtet beim Hashen des Passworts auf einen Salt, der verhindern würde, dass gleiche Passwörter zu identischen Keys führen. Zudem berechnet Loop-AES den Verschlüsselungskey mit nur einer Hashing-Iteration (etwa SHA-256 oder SHA-512). Das ist anfällig für vorausberechnete Wörterbuchangriffe: Der Cracker erzeugt vorab mit Hilfe von Wörterbüchern und zusätzlichen Regeln eine Liste möglicher Passwörter und berechnet zu jedem die Hashfunktion. Er muss dann nur noch diese Hashes als Keys probieren, nicht mehr alle möglichen Zahlenkombinationen (das wäre ein Brute-Force-Angriff).

Das Readme für Loop-AES [4] behauptet dagegen, dass Loop-AES sowohl ein Salting als auch mehrfache Iterationen vorsieht. Die dazu passenden Beispiele für Konfigurationsdateien, die Google aufspürt, lassen jeden Salt vermissen und setzen den Iterationen-Wert auf 100 (das entspricht 100000 Iterationen). Per Default sieht Loop-AES weder Salting noch Passwort-Hash-Iterationen vor.

Zitterpartie

Wählt der User ausdrücklich Iterationen (das scheint nur bei AES-256 möglich zu sein), dann verschlüsselt die Software zwei 128-Bit-Blöcke mit dem initialen Key und tauscht die höherwertigen 64 Bit des ersten 128-Bit-Blocks gegen die niederwertigen 64 Bit des zweiten Blocks. Diesen Algorithmus wiederholt es so lange wie gewünscht, um den finalen 256-Bit-Schlüssel zu erhalten.

Die Daten chiffriert Loop-AES, dem Namen entsprechend, mit dem AES-Algorithmus und verwendet dabei den CBC-Modus. Es gibt eine unübersichtliche Menge an Optionen zur Verarbeitung des IV (Initialisierungsvektor). Sie legen etwa die Sektornummer oder einen MD5-Hash dieser Zahl als IV fest.

Mit anderen Crypto-Programmen teilt Loop-AES einen groben Programmierfehler: Der Code prüft an keiner Stelle die Rückgabewerte von Funktionsaufrufen. Sollte etwas beim Berechnen der Keys schief laufen, dann arbeitet die Software unbekümmert weiter und merkt nicht einmal, dass die Schlüssel nur aus Nullen bestehen. Die Daten bleiben faktisch unverschlüsselt.

Der Code ist aber oft so schlampig geschrieben, dass die Programme vermutlich eher mit einer Null-Pointer-Dereferenz abstürzen, bevor sie leere Schlüssel tatsächlich verwenden. Sich darauf zu verlassen, dass nachlässige Programmierung vor schlimmeren Fehlern schützt, wäre aber erst recht fahrlässig.

Abbildung 1: Cryptsetup (oben) nimmt vom User ein Passwort entgegen und berechnet daraus mit einem Hashverfahren einen Schlüssel konstanter Länge, den es an den Kernel weiterreicht (Mitte). Mit diesem Key ver- und entschlüsselt DM-Crypt (unten) den Inhalt der Festplatte (Backing Blockdevice).

Abbildung 1: Cryptsetup (oben) nimmt vom User ein Passwort entgegen und berechnet daraus mit einem Hashverfahren einen Schlüssel konstanter Länge, den es an den Kernel weiterreicht (Mitte). Mit diesem Key ver- und entschlüsselt DM-Crypt (unten) den Inhalt der Festplatte (Backing Blockdevice).

Abbildung 2: Cryptsetup-LUKS speichert alle Parameter der verschlüsselten Partition im Partitionsheader des Backing Blockdevice (links oben). Anders als sein Vorgänger (Abbildung 1) verwendet LUKS für den Festplatteninhalt einen Master-Key, den es mit dem Passwort des Benutzers schützt.

Abbildung 2: Cryptsetup-LUKS speichert alle Parameter der verschlüsselten Partition im Partitionsheader des Backing Blockdevice (links oben). Anders als sein Vorgänger (Abbildung 1) verwendet LUKS für den Festplatteninhalt einen Master-Key, den es mit dem Passwort des Benutzers schützt.

DM-Crypt

DM-Crypt (Abbildung 1 und [6]) ist seit Kernelversion 2.6.4 offizieller Bestandteil des Device-Mappers und dort für die transparente Verschlüsselung von Daten verantwortlich. Das System kann die Daten in einer eigenen Partition oder (via Losetup) einer Containerdatei ablegen. Im Gegensatz zu Loop-AES ist DM-Crypt nicht auf einen Algorithmus festgelegt – es stellt dem Anwender alle im Kernel vorhandenen Algorithmen zur Wahl. Anders als sein unsicherer Vorgänger Cryptoloop [2] taugt das Verfahren auch für Journaled-Filesysteme wie Ext 3 oder XFS. DM-Crypt bindet sogar Cryptoloop-Container ein und erleichtert damit einen sauberen Umstieg.

Zusätzlich zum Kernelmodul braucht dieses System einige Userspace-Werkzeuge. Das Programm »cryptsetup« sollte mittlerweile zum Standardumfang jeder Distribution gehören. Leider stellt sich das sonst so benutzerfreundliche Ubuntu quer und versteckt dieses wichtige Paket in der Universe-Sektion.

LUKS

Heute kommt Cryptsetup meist in Verbindung mit dem von Clemens Fruhwirth entwickelten LUKS (Linux Unified Key Setup, [7], [8]) zum Einsatz. Die folgende Beschreibung beschränkt sich daher auf diese verbesserte Methode. LUKS speichert seine Metadaten vollständig im Header des Containers (Abbildung 2). Dabei verwaltet es mehrere Passwörter, die der Admin sogar einzeln widerrufen kann, ohne die Daten neu zu verschlüsseln. Das erlaubt sicheren Zugriff durch mehrere Personen. In Verbindung mit Free OTFE [9] liest sogar Windows die DM-Crypt-Formate.

Für LUKS ist ein angepasstes Cryptsetup-Paket nötig, das die aktuellen Distributionen bereits enthalten. Sollte dies nicht der Fall sein, finden sich unter [10] viele Pakete, etwa für Suse Linux 10. Ein Container ist schnell vorbereitet:

cryptsetup luksFormat -y -c aes-cbc-essiv:sha256 /dev/hda6
cryptsetup luksOpen /dev/hda6 crypto
mkfs.ext3 /dev/mapper/crypto

Das erste Kommando bereitet »/dev/hda6« als zu verschlüsselndes Device vor. Es legt den Header des Containers an, der später unter anderem das Schlüsselmaterial aufnimmt. Die Option »-y« bewirkt eine doppelte Abfrage der Passphrase. Alternativ arbeitet Cryptsetup auch mit einer Schlüsseldatei.

Der Parameter »-c aes-cbc-essiv:sha256« sorgt dafür, dass DM-Crypt die Daten im CBC-Modus (Cipher Block Chaining) schreibt und ihnen einen SHA-256-gehashten Initialisierungsvektor auf den Weg gibt. Ohne diese Angabe wären die Daten anfällig für Watermarking, bei dem ein Angreifer Dateien präpariert und später – trotz Verschlüsselung – nachweisen kann, dass diese Files im Container liegen. Wer nicht auf die standardmäßige Schlüssellänge von 128 Bit vertrauen möchte, verdoppelt sie zum Beispiel mit »-s 256«.

Das »luksOpen« des zweiten Befehls unterstellt das physikalische Device dem Device-Mapper. Es ist nun unter dem Namen »crypto« ansprechbar. Ähnlich wie auf einem Raid- oder LVM-Device (Logical Volume Manager) legt die letzte Zeile daraufhin ein Filesystem an, in diesem Fall Ext 3. Das Kommando »cryptsetup luksRemove crypto« entfernt das Device wieder aus dem System.

DM-Crypts großer Vorteil ist die gute Integration ins Gesamtsystem. Debian und Ubuntu zeigen, wie Admin-freundlich das sein kann: Er automatisiert den gesamten Vorgang per Konfigurationsdatei beim Systemstart. Sehr elegant und unbemerkt vom Anwender richtet er etwa ein verschlüsseltes Swap ein:

swap /dev/hda2 /dev/random swap

Dieser Eintrag in »/etc/crypttab« gilt für den Swapspace in »/dev/hda2«. Bei jedem Systemstart gewinnt DM-Crypt einen zufälligen Schlüssel aus »/dev/random« und verschlüsselt damit das Swap-Device. Die erhöhte Sicherheit hat aber ihren Preis: Suspend to Disk funktioniert damit nicht mehr.

Sicherheit von DM-Crypt

DM-Crypt teilt viele Eigenschaften mit Loop-AES: Beide sind Kernelmodule und irritieren mit ihrer Menge an Optionen beim Übersetzen sowie zur Laufzeit. Die Default-Konfiguration begnügt sich mit einer einzelnen Iteration des RIPEMD-160-Hash und verzichtet auf einen Salt. Als Default-IV-Modus kommt »plain« zum Einsatz, der schlicht die 32-Bit-Sektornummer als IV verwendet.

Immerhin gibt es einen besseren Modus namens ESSIV, der die Sektornummer verschlüsselt (dadurch kann ein Angreifer sie nicht mehr vorhersagen). Allerdings lassen eine Websuche nach Konfigurationen sowie das Beispiel auf der Homepage vermuten, dass die Anwender ESSIV kaum verwenden. Zudem hält sich der Sicherheitsgewinn in Grenzen, da auch der ESSIV für alle Daten in diesem Sektor konstant bleibt. Aus Crypto-Sicht müsste jeder Sektor bei jeder Änderung einen neuen IV erhalten.

Deutlich besser schneidet die LUKS-Variante ab, allerdings nimmt auch sie als Default-Einstellung die unsicheren DM-Crypt-Parameter. Immerhin nimmt Cryptsetup-LUKS per Default die Nummer des verschlüsselten Sektors als IV, wenn es ein Device im LUKS-Format erzeugt. Die Hauptaufgabe der LUKS-Erweiterung ist aber Schlüsselverarbeitung, und die ist tatsächlich deutlich verbessert. Sie verwendet die etablierte Standard-Schlüsselgenerierung nach PBKDF2, um einen Key aus dem Passwort abzuleiten.

Truecrypt

Truecrypt [12] will nicht nur sicher, sondern auch portabel sein. Die Software nutzt verschlüsselte Container sowohl unter Linux als auch unter Windows. Als Verschlüsselungsalgorithmen stehen AES, Blowfish, Cast 5, Serpent, Triple-DES und Twofish zur Wahl, sogar eine Reihenschaltung mehrerer Varianten ist möglich. Zur Integritätssicherung stehen drei Hash-Algorithmen (RIPEMD-160, SHA-1 und Whirlpool) bereit. Truecrypt ist in der Lage, sowohl Dateien als auch Partitionen als Container zu handhaben. Die erste Methode ist bei Truecrypt-Anwendern stärker verbreitet.

Besonders betonen die Entwickler die umstrittene Möglichkeit, das Vorhandensein verschlüsselter Daten glaubwürdig abzustreiten (siehe vorhergehenden Artikel). Truecrypt versucht das mit einem präparierten Container, der keine Hinweise auf Verschlüsselung zulassen soll. Die Software füllt ihn mit zufälligem Datenmüll und stopft – analog zu russischen Matroschka-Puppen – einen inneren Container an des Ende der äußeren Hülle (Abbildung 3).

Abbildung 3: Ein Truecrypt-Container ohne (oben) und mit (unten) verstecktem Volume. Letzteres erkennt selbst Truecrypt nur mit Hilfe des richtigen Schlüssels und eines Brute-Force-Angriffs.

Abbildung 3: Ein Truecrypt-Container ohne (oben) und mit (unten) verstecktem Volume. Letzteres erkennt selbst Truecrypt nur mit Hilfe des richtigen Schlüssels und eines Brute-Force-Angriffs.

Um nicht Gefahr zu laufen, die Daten des inneren Containers bei der Nutzung des äußeren zu beschädigen, bindet »–protect-hidden« (kurz »-P«) den äußeren Container besonders ein. Truecrypt fragt daraufhin beide Schlüssel ab, da nicht einmal das Programm selbst ohne Kenntnis der Lage und des richtigen Schlüssels ein Volume erkennt.

Linux-Portierung

Seit der Truecrypt-Version 4.2 (im April 2006 erschienen) unterstützt die von Windows stammende Open-Source-Software auch unter Linux das Anlegen verschlüsselter Dateien. Vorher war dieser initiale Schritt nur unter Windows möglich. Die Herkunft der Software ist noch nicht überwunden, ihre Anpassung noch unvollständig. Unter anderem fehlt die von Windows bekannte grafische Benutzeroberfläche. Unter Windows gibt es eine sehr gute und ausführliche Dokumentation; für Linux existiert erst eine recht dürftige Manpage.

Viel schwerer wiegt für Endanwender die teils umständliche Benutzung. Das beginnt bereits bei der Installation: Die Webseite des Projekts bietet zwar fertige Pakete für gängige Linux-Distributionen an, allerdings versagen sie meist nach einem Kernelupdate. Auch wenn das Changelog behauptet, dass ein erneutes Kompilieren innerhalb einer Kernelversion nicht mehr nötig sei, ist etwa unter Ubuntu 6.06 dennoch Handarbeit angesagt. Listing 2 zeigt die nötigen Schritte in den Zeilen 1 bis 10.

Listing 2: Truecrypt auf
Ubuntu

01 sudo aptitude install build-essential linux-source gawk
02 cd /usr/src
03 sudo tar xvjf linux-source-2.6.15.tar.bz2
04 cd linux-source-2.6.15
05 sudo cp /boot/config-2.6.15-26-686 .config
06 sudo make prepare
07 cd /usr/src
08 tar xvzf truecrypt-4.2a-source-code.tar.gz
09 cd truecrypt-4.2a/Linux
10 sudo ./build.sh
11 sudo ./install.sh

Je nach Leistungsfähigkeit des Systems dauert der Vorgang ein paar Minuten bis zu mehreren Stunden. Der in Zeile 10 angestoßene Build-Prozess kompiliert unnötigerweise den kompletten Kernel, um im Anschluss daran das Modul »truecrypt« und die zugehörigen Werkzeuge zu bauen. Ist (wie unter Ubuntu) das Paket »gawk« nicht standardmäßig installiert, bricht dieser Prozess außerdem mit einem Fehler ab.

Umständliche Installation

Die ersten drei Fragen des Installationsskripts (in Zeile 11 aufgerufen) darf der Admin getrost mit »yes« beantworten. Sofern er auch die vierte Frage bejaht, ob »non-admin«-Benutzer Truecrypt verwenden dürfen, versieht der Installer das Binary mit einem Set-UID-Bit und kreiert damit einen potenziellen Angriffspunkt. Da die Programmierung recht sauber aussieht, bleibt dieses Risiko immerhin wohl kalkulierbar.

Ein neues Truecrypt-verschlüsseltes Filesystem legt der Admin per »truecrypt –create« an. Verzichtet er darauf, gleich beim Aufruf alle Optionen anzugeben, fragt das Tool die Informationen interaktiv ab. Das Beispiel in Listing 3 führt zu einer Containerdatei unter »/home/chris/truecrypt/test« (Zeilen 1 und 2) und bereitet sie mit dem FAT-Dateisystem vor (Zeile 3). Diesen kleinsten gemeinsamen Nenner beim Datenaustausch zwischen Windows- und Linux-Systemen verwendet Truecrypt als Standardeinstellung. Wer das nicht möchte, kann dem Container später auch manuell das gewünschte Filesystem spendieren.

Listing 3: Truecrypt-FS
anlegen

01 Volume type: 1
02 Enter file or device name for new volume: /home/chris/truecrypt/test
03 Filesystem: FAT
04 Enter volume size (bytes - size/sizeK/sizeM/sizeG): 100M
05 Hash algorithm: 1
06 Encryption algorithm: 1
07 Enter password for new volume '/home/chris/truecrypt/test':
08 Re-enter password:
09 Enter keyfile path [none]:
10 
11 truecrypt /home/chris/truecrypt/test /mnt

Im Fall einer dateibasierten Verschlüsselung fragt das Tool zusätzlich noch die Größe des Containers ab (100 MByte, Zeile 4). Im weiteren Verlauf folgt die Wahl der Hash- und Verschlüsselungsalgorithmen. Voreingestellt sind RIPEMD-160 und AES mit einer Schlüssellänge von 256 Bit.

Anders als bei anderen Crypto-Systemen kommt hierbei allerdings die Tweakable Narrow-Block Encryption LRW zum Tragen (siehe Kasten “LRW”). Das altbewährte, aber nicht so sichere Cipher Block Chaining (CBC) unterstützt Truecrypt zwar auch, vom Einsatz raten die Entwickler aber sinnvollerweise ab.

LRW

Der LRW-Verschlüsselungsmodus ([13], nach seinen Erfindern Liskov, Rivest und Wagner benannt) gehört zu den justierbaren Blockchiffren, genauer zu den justierbaren Narrow-Block-Chiffren. Das behebt einige der Probleme des CBC-Modus, ohne unter dem Overhead von justierbaren Wide-Block-Chiffren zu leiden und ohne von Patenten belastet zu sein. LRW hat nur unerheblich mehr Overhead als CBC, zudem taugt der Algorithmus für Parallelverarbeitung, zum Beispiel in Hardware.

Justage anhand der Sektornummer

Zusätzlich zum Verschlüsselungsschlüssel erwartet LRW einen weiteren Wert namens Justage (Tweak; andere Krypto-Operationen bezeichnen vergleichbare Werte als Salt). Ähnlich wie ein Salt braucht die Justage nicht geheim zu sein. Sie sorgt nur dafür, dass das Chiffrat für jeden Justage-Wert unterschiedlich ausfällt, selbst wenn der Klartext identisch bleibt. Damit verwandelt sie einen einzelnen Block-Verschlüsselungsalgorithmus in eine ganze Familie unabhängiger Blockchiffren. Bei Festplattenverschlüsselung bietet es sich an, die Sektornummer und die Position des AES-Blocks innerhalb des Sektors als Justage zu verwenden. Dieser Wert ist einzigartig für jeden AES-Block.

Während es bei CBC möglich ist, verschlüsselte Blöcke von einem Ort an einen anderen zu verschieben und sie dennoch dechiffrierbar bleiben, führt dieser Copy&Paste-Angriff bei LRW nicht mehr zum Erfolg. Verschlüsseln mit einem Tweak und entschlüsseln mit einem anderen erzeugt nur Datenmüll.

In Abbildung 4 sind neben dem untauglichen ECB (Electronic Codebook) sowohl CBC als auch LRW dargestellt. Die Justage berechnet sich üblicherweise als Sektornummer multipliziert mit 32 plus dem Index innerhalb des Sektors. Der Faktor 32 ergibt sich aus der Division von 512 (Anzahl Bytes pro Sektor) durch 16 (Bytes pro AES-Block). Die Justage ist, einfach ausgedrückt, die AES-Blocknummer, vom Anfang des verschlüsselten Device gezählt [14].

Abbildung 4: Der ECB-Modus (links) chiffriert Klartextblöcke einzeln, gleiche Eingaben Pi in die Verschlüsselungsfunktion E führen zu identischen Ausgaben Ci. CBC (Mitte) startet mit einer Xor-Verknüpfung von IV und erstem Klartextblock. Das Whitening bei LRW (rechts) berechnet sich aus der Position n auf der Festplatte und dem geheimen Schlüssel K.

Abbildung 4: Der ECB-Modus (links) chiffriert Klartextblöcke einzeln, gleiche Eingaben Pi in die Verschlüsselungsfunktion E führen zu identischen Ausgaben Ci. CBC (Mitte) startet mit einer Xor-Verknüpfung von IV und erstem Klartextblock. Das Whitening bei LRW (rechts) berechnet sich aus der Position n auf der Festplatte und dem geheimen Schlüssel K.

Ein ganz praktisches Problem des LRW-Modus aus dem Draft-Standard ist AES-Kundigen bereits aus einem anderen Kontext bekannt: Vor Jahren gab es bei den 16 AES-Kandidaten sechs Varianten, um die 128 Bit bei der Ein- und Ausgabe anzuordnen. Bei LRW wiederholt sich das Chaos. Der AES-GCM-Verschlüsselungsmodus (Galois/Counter Mode [15], verwendet im WLAN-Standard 802.11) und LRW interpretieren die Bit- und Byte-Anordnung im Block unterschiedlich (Big-Endian und Little-Endian).

Ungeschickte Entscheidung für Big-Endian

Die rechenintensive Folge dieses organisatorischen Missgeschicks: GCM deutet die Daten als Little-Endian, LRW aber als Big-Endian und muss daher die Reihenfolge der 128 Bits eines Blocks umdrehen. Da GCM bereits recht verbreitet ist, unter anderem in WLAN-Hardware, sind beide Modi weitgehend unvereinbar. Bleibt abzuwarten, welcher sich auf lange Sicht durchsetzt. Im Testfeld dieses Artikels setzt nur Truecrypt den LRW-Modus ein.

Clemens Fruhwirth hat bei der Arbeit an Cryptsetup-LUKS für DM-Crypt auch ein LRW-Patch geschrieben [8] und Anfang 2005 versucht, es in den Kernel aufnehmen zu lassen. Das ist ihm aufgrund technischer Konflikte beim Speichermanagement leider nicht gelungen.

Zufälle

Abschließend fragt das Tool nach einem Passwort, zusätzlich oder an seiner Stelle arbeitet Truecrypt auf Wunsch auch mit Schlüsseldateien. Wer ausschließlich die Datei nutzen will, lässt das Passwort leer. Fürs Sammeln der Entropie (Zufallswerte) wertet Truecrypt Mausbewegungen und Tastatureingaben aus, statt sich auf »/dev/random« zu verlassen. Auf Basis dieses Zufallswerts überschreibt Truecrypt den kompletten Container mit einer Pseudo-Zufallszahlenfolge, um Rückschlüsse auf die darin abgelegten Daten zu verhindern.

Fürs Aushängen des Filesystems ist das Kommando »truecrypt –dismount /mnt« zuständig. Ein automatisiertes Einbinden von Truecrypt-Containern beim Systemstart ist deutlich schwieriger als zum Beispiel bei DM-Crypt. Wer »/home« verschlüsseln möchte, muss eigene Skripte programmieren. Eine Hilfe könnte Pamscript [16] sein, das Skripte bei der PAM-Authentifizierung (Pluggable Authentication Modules) ausführt.

Ein prinzipielles Problem beim Einsatz von externen Kernelmodulen teilt auch Truecrypt: Sollte das Modul nach einem Kernelupdate nicht mehr funktionieren, dann kommt der User zunächst nicht mehr an seine Daten.

Sicherheit von Truecrypt

Im Testfeld ist Truecrypt das kryptographisch ausgefeilteste und professionellste Programm. Es enthält gute Dokumentation und stützt sich auf Standards wie die PBKDF2-Schlüsselableitungsfunktion und den LRW-Modus (siehe Kasten “LRW”) für sektorbasierte Verschlüsselung. Einzig bei Truecrypt sind die Defaults sicher, die Software prüft konsequent die Funktionsrückgabewerte und meldet Fehler an den Benutzer.

An Truecrypt irritiert nur, dass sich die Entwickler am Rumpelstilzchen-Sicherheitsmodell (siehe vorhergehenden Artikel) orientieren und die Container als Datenmüll tarnen. Das geht so weit, dass Truecrypt selber einen Brute-Force-Angriff gegen den Volume-Header fährt, um an die Daten im Container heranzukommen. Das Passwort ist zwar bekannt, aber Truecrypt muss alle Hash- und Verschlüsselungsalgorithmen probieren, bis es auf brauchbare Daten stößt.

Es entsteht damit ein unnötig zwiespältiger Eindruck: Das Programm weckt den sehr guten Eindruck, dass die Entwickler ihren Job wirklich beherrschen. Andererseits geben sich just diese Entwickler reichlich verbohrt, wenn es um umstrittene Sicherheitseigenschaften geht.

Ab in den Userspace

Mit dem Aufkommen der Userspace-basierten Dateisysteme LUFS (Linux Userland Filesystem [17]) und des jüngeren FUSE (Filesystem in Userspace, [18]) entstanden interessante Projekte, die es eigenständig wohl nicht in den Kernel geschafft hätten. Zum Beispiel erlauben es Gmail-FS [19] oder FTPFS [20], Googles Maildienst oder einen FTP-Server so einzubinden, als handle es sich um ein lokales Verzeichnis. Die Idee liegt nahe, Verschlüsselungsfunktionen ähnlich zu integrieren. Gegenüber Kernel-seitigen Lösungen hat das einige Vorteile:

  • Im Userspace beheimatete Dateisysteme fungieren als Filter und
    erleichtern es, Daten sicher an Orten zu speichern, die sich der
    Kontrolle des Anwenders entziehen. Zum Beispiel wäre es
    für Rootserver-Betreiber denkbar, Daten verschlüsselt auf
    dem für Backups gedachten FTP-Server des Providers
    abzulegen.
  • Userspace-Filesysteme arbeiten auf Datei-Ebene. Im Gegensatz zu
    ihren starren Container-basierten Verwandten nutzen sie das ohnehin
    vorhandene Filesystem und passen sich an dessen Größe
    an.
  • Da die verschlüsselten Dateien und deren Metadaten direkt
    im Filesystem vorliegen, ist es für Backup-Tools einfach,
    geänderte Dateien zu erkennen und nur sie zu
    übertragen.

Die Sichtbarkeit der Metadaten ist gleichzeitig der größte Nachteil des Verfahrens. Wer auf das Filesystem Zugriff hat, kennt die Anzahl der verschlüsselten Dateien inklusive ihrer Berechtigungen sowie deren ungefähre Größe (meist auf 8 oder 16 Byte genau). Je nach System und Konfiguration bleiben sogar die Dateinamen im Klartext erhalten.

Crypto-FS

Crypto-FS [21] ist das simpelste der hier vorgestellten Crypto-Filesysteme. Es basiert auf LUFS, läuft mittlerweile aber auch unter FUSE. Da keine der großen Distributionen die Software derzeit als Paket anbietet, ist zunächst Handarbeit angesagt. Ein paar Abhängigkeiten sind zu erfüllen: passende Devel-Pakete für FUSE oder LUFS, zusätzlich Libgcrypt [22] ab Version 1.1.44 sowie Glib [23] ab Version 2.6.

Nach dem obligatorischen »./configure && make && make install« empfiehlt es sich, die mitgelieferte Beispiel-Konfigurationsdatei »cryptofs.conf« anzupassen und als ».cryptofs« in dem Verzeichnis abzulegen, das später die verschlüsselten Dateien aufnimmt. Beim ersten Durchlauf fragt Crypto-FS das künftige Passwort ab. Es gibt zwei Aufrufvarianten, ganz FUSE-typisch als eigenständiges Binary namens »cryptofs« oder als LUFS-Modul per »lufsmount«:

cryptofs -r /home/chris/.cryptofs /home/chris/cryptofs
lufsmount cryptofs://home/chris/.cryptofs /home/chris/cryptofs

Der absolute Pfad ist unerlässlich, da der Mount sonst ins Leere zeigt. Um potenziellen Angreifern möglichst wenig Informationen über die verschlüsselten Daten zu geben, verschlüsselt Crypto-FS die Dateinamen und legt sie Base-64-kodiert ab. Die Größe der Datei bleibt jedoch sichtbar.

Sicherheit von Crypto-FS

Crypto-FS verschlüsselt einzelne Dateien mit einer vom User wählbaren Chiffre, typischerweise AES im CBC-Modus. Beim Generieren des Initialisierungsvektors geht das Programm eigene Wege: Nachdem es das Benutzerpasswort in einen Verschlüsselungskey verwandelt hat, chiffriert es einen Buffer mit Nullbytes und erhält n IV-Werte. Für jeden n-ten Dateiblock nutzt Crypto-FS den IV mit der Nummer n. Da die Anzahl der Dateiblöcke in der Praxis n weit überschreitet, verwendet das Dateisystem jeden IV mehrfach und begeht damit einen kryptographischen Kapitalfehler.

Bei der Transformation des Passworts in einen Schlüssel begnügen sich die Entwickler mit dem einzelnen Aufruf einer Hashfunktion, typischerweise SHA-1, und verzichten sogar auf einen Salt. Damit ist das Programm anfällig für vorausberechnete Wörterbuchangriffe. Zu allem Überfluss prüft die Software keine Funktionsrückgabewerte. Scheitert eine Funktionen, die Schlüssel verarbeitet oder Daten verschlüsselt, arbeitet Crypto-FS kommentarlos mit leerem Schlüssel weiter oder schleust die Daten gleich im Klartext durch.

Enc-FS

Enc-FS [24] basiert auf dem modernen FUSE (Filesystem in Userspace, [18]), das seit Linux 2.6.14 zum Standardumfang des Kernels gehört. Aktuelle Enc-FS-Versionen benötigen mindestens FUSE 2.5 sowie Rlog [25]. Für die Verschlüsselung greift Enc-FS auf OpenSSL zurück. Sind alle Voraussetzungen erfüllt, baut der Dreisatz »./configure && make && make install« die Software aus den Quellen und installiert sie.

Die grundlegende Bedienung ist denkbar einfach. Nach dem Aufruf des Kommandos »encfs ~/.encfs ~/encfs« fragt das Programm die in Listing 4 zu sehenden Optionen ab. Sollten eines oder beide Verzeichnisse nicht existieren, erzeugt Enc-FS sie auf Wunsch selbst (Zeilen 1 und 2). Beim ersten Durchlauf legt das System im Quellverzeichnis die Datei ».encfs5« mit den nötigen Informationen ab, um die in diesem Verzeichnis liegenden Dateien zu entschlüsseln. Ein Backup der Daten darf dieses File also auf jeden Fall vergessen.

Enc-FS bietet dem Anwender einen Standard- und einen Paranoia-Modus. Der Standardmodus nutzt den Blowfish-Algorithmus mit einer Schlüssellänge von 160 Bit und verschlüsselt die Dateinamen. Beim Verschlüsseln verarbeitet die Software 512-Byte-Blöcke, verkettet die Initialisierungsvektoren und initialisiert die Dateiheader getrennt.

Angemessene Paranoia

Der Paranoia-Modus verspricht höhere Sicherheit durch den Einsatz von AES mit der Blockgröße 256 Bit. Zusätzlich zu den Maßnahmen des Standardmodus speichert Paranoia-Enc-FS jeden Block zusammen mit einer Prüfsumme, um Veränderungen der Daten zu erkennen. Außerdem fließt der Dateiname mit in den Initialisierungsvektor des Inhalts ein. Ein Umbenennen der Datei führt folglich zum vollständigen Neuverschlüsseln. Hardlinks funktionieren damit aber nicht mehr, was unter anderem Programmen wie Mutt oder Procmail Probleme bereitet.

Darüber hinaus enthält Enc-FS einen so genannten Expertenmodus, bei dem der Benutzer sämtliche Einstellungen selbst wählt. Er kann auf alle OpenSSL-Algorithmen zurückgreifen. Wer die Dateinamen lieber im Klartext lässt, hat hier die Möglichkeit, dies einzustellen.

Im Gegensatz zu Crypto-FS bietet Enc-FS interessante Funktionen, die die Arbeit mit dem System einfacher oder sicherer machen. So lässt sich ein Enc-FS-Mount automatisch nach einer definierten Zeitspanne aus dem System aushängen. Das ist gerade in Verbindung mit der PAM-Integration [26] interessant. Nicht einmal in Fragen der Plattformwahl braucht sich Enc-FS vor seinen Verwandten zu verstecken: Seit Version 1.3 ist die Software auch nativ unter FreeBSD nutzbar, darüber hinaus findet sich unter [27] eine Windows-Portierung.

Geschwindigkeit

Alle getesteten Crypto-Filesysteme mussten sich auch in einem Benchmark bewähren. Als Testmaschine kam ein IBM Thinkpad T40p zum Einsatz. Das Notebook ist mit 1,5 GByte RAM und einer Hitachi-Festplatte mit 7200 U/min ausgestattet. Die Werte wurden unter Ubuntu 6.06 LTS mit Hilfe von Bonnie++ [28] und 3-GByte-Datensets ermittelt. In jedem Fall diente XFS im verschlüsselten Container als Dateisystem.

Sicher mit angezogener Bremse

Die Ergebnisse in Abbildung 6 geben klar zu erkennen, wie stark Verschlüsselung die Performance beeinträchtigt. Obwohl es nur die Hälfte des normalen Durchsatzes zulässt, bleibt DM-Crypt sowohl beim Lesen als auch beim Schreiben recht konstant. Seine Stärke spielt es besonders bei blockweisen Operationen aus. Die Leistung von Truecrypt bricht bei Schreibvorgängen ein und fällt hier sogar hinter das im Userspace beheimatete Enc-FS zurück. Beim Lesen hingegen holt es auf und liegt mit DM-Crypt fast auf einer Höhe.

Loop-AES ist der schnellste Kandidat beim zeichenweisen Schreiben und Lesen, bleibt bei ganzen Blöcken aber gegenüber DM-Crypt auf der Strecke. Enc-FS schlägt sich für ein im Userspace beheimatetes Filesystem recht gut und zeigt große Stärke beim blockorientierten Lesen und Schreiben. Im Falle kleinerer Daten hingegen gibt es sich ähnlich schwach wie Truecrypt und bricht besonders beim Lesen ein. Weit abgeschlagen liegt Crypto-FS, das nur rund ein Drittel der Leistung bei unverschlüsselten Daten erbringt.

Sicherheit von Enc-FS

Enc-FS verschlüsselt jede Datei mit einer Blockchiffre, etwa AES im CBC-Modus. Wegen eines Programmierfehlers verwendet die Software allerdings CFB (Cipher Feedback) anstelle von CBC (Cipher Block Chaining). Jeder 512 Byte große Sektor enthält 504 Byte Daten und einen auf 8 Byte verkürzten HMAC (Hashed MAC) das Klartexts. Statt den HMAC einfach abzuschneiden, berechnet Enc-FS einen Xor-Wert aller Bytes. Dieser Wert dient zudem als Initialisierungsvektor. Ändert sich ein einzelnes Bit im Sektor-Klartext, dann ändert sich auch der IV und folglich der komplette chiffrierte Sektor.

Dateinamen schützt Enc-FS, indem es sie erst verschlüsselt und dann Base-64-kodiert ablegt. Wieder verwendet das Programm einen HMAC, den es aus dem Dateinamen gewinnt, als IV. Um zu verhindern, dass gleichnamige Dateien ein identisches Chiffrat erhalten, setzt Enc-FS bei der MAC-Berechnung den absoluten Pfadnamen ein.

Selbst gebastelt

Der Verschlüsselungsmodus ist ein komplexes, selbst gebasteltes Gebilde. Als Erstes verknüpft das Programm jedes Byte per Xor-Operation mit dem folgenden Byte. Entspricht die Sektorgröße der Blockgröße des Verschlüsselungsalgorithmus, dann verschlüsselt Enc-FS den kompletten Sektor im CBC-Modus. Andernfalls verwendet es CFB. Das ist vermutlich ein Fehler, da sich das bessere CBC auch anbietet, wenn die Datenmenge ein ganzzahliges Vielfaches der Blockgröße ist. Der Sektor ist immer größer als ein Verschlüsselungsblock, daher kommt CBC hier nie zum Einsatz.

Anschließend dreht Enc-FS die Reihenfolge der Bytes in jedem 64-Byte-Abschnitt um. Zum Schluss kommt eine weitere Runde mit Xor- und Verschlüsselungsoperationen. Das soll offenbar den gleichen Datenmaskierungseffekt erzielen wie eine justierbare Wide-Block-Chiffre, erreicht aber trotz vergleichbaren Rechenaufwands nicht deren kryptographische Sicherheit.

Ganz ohne Salz

Die Passworttransformation verzichtet auch bei Enc-FS auf einen Salt und begnügt sich mit 16 Hashing-Iterationen. Erst bei 1000 oder 2000 Iterationen gelten vorausberechnete Wörterbuchangriffe als praktisch unmöglich.

Wie viele der Mitbewerber prüft Enc-FS kaum Rückgabewerte von Funktionswerten. Geht etwas schief, bleiben die Daten unverschlüsselt. Selbst wenn der Code Return-Werte prüft, begeht er gravierende Fehler. Statt sicherzustellen, dass eine Operation erfolgreich war, nimmt das Programm an, dass per Default alles gut geht, und prüft nur einen Teil der möglichen Fehlerbedingungen. Schlägt die Funktion mit einem unerwarteten Rückgabewert fehl, übersieht Enc-FS dies und arbeitet unbeirrt weiter.

Ein Beispiel hierfür ist die Methode »CipherV3::randomize« in Enc-FS 1.3.1 (siehe den Ausschnitt aus »CipherV3.cpp« in Listing 5). Sie benutzt in Zeile 4 die Funktion »RAND_bytes()« beim Erzeugen eines Verschlüsselungskey. Diese Funktion kann allerdings mit den Werten 0 und -1 scheitern. Dummerweise erkennt Zeile 4 nur den Wert 0 als Fehler. Gibt »RAND_bytes()« den Fehlercode »-1« zurück, bleibt dies unbemerkt und Enc-FS arbeitet mit einem Schlüssel, der nur aus Nullen besteht.

Listing 5:
Enc-FS-Code

01 void CipherV3::randomize( unsigned char *buf, int len ) const
02 {
03     memset( buf, 0, len );
04     if(RAND_bytes( buf, len ) == 0)
05     {
06         char errStr[120];
07         unsigned long errVal = 0;
08         if((errVal = ERR_get_error()) != 0)
09         {
10             rWarning("openssl error: %s", ERR_error_string( errVal, errStr ));
11         }
12     }
13 }

Wenig Gehaltvolles

Die meisten Crypto-Dateisysteme unter Linux hinterlassen einen schalen Geschmack. Sie begehen kryptographische Fehler und sind meist schwach implementiert (typischer Fehler: Rückgabewerte von Funktionen ignorieren). Die positive Ausnahme von der Regel ist mit Truecrypt ausgerechnet eine Software, die ursprünglich nur unter Windows lief und unter Linux derzeit weniger gut integriert ist als die Konkurrenz.

Über den zweiten Platz darf sich DM-Crypt in der Cryptsetup-LUKS-Variante freuen. Es arbeitet performant und hat weniger kryptographische Fehler als die restlichen Mitstreiter, vorausgesetzt der Anwender sorgt für eine sichere Konfiguration. Per Default ist auch dieses Produkt unnötig schwach. Bitter ist auch, dass es das LRW-Patch nicht in den Kernel geschafft hat. (fjl)

Infos

[1] Loop-AES: [http://loop-aes.sourceforge.net]

[2] Christian Ney, “Lese-Schutz – verschlüsseltes Home unter Red Hat, Debian und Gentoo”: Linux-Magazin 03/04, S. 46

[3] Util-linux: [ftp://ftp.kernel.org/pub/linux/utils/util-linux/]

[4] Readme zu Loop-AES: [http://loop-aes.sourceforge.net/loop-AES.README]

[5] Crosscrypt: [http://www.scherrer.cc/crypt/]

[6] DM-Crypt: [http://www.saout.de/misc/dm-crypt/]

[7] Cryptsetup-LUKS: [http://luks.endorphin.org/dm-crypt]

[8] Clemens Fruhwirth, “Festplattenverschlüsselung mit DM-Crypt und Cryptsetup-LUKS”: Linux-Magazin 08/05, S. 28

[9] Free OTFE: [http://www.freeotfe.org]

[10] LUKS for the Masses: [http://luks.endorphin.org/masses]

[11] RFC 2898, “PKCS #5 – Password-Based Cryptography Specification Version 2.0”: [http://tools.ietf.org/html/rfc2898]

[12] Truecrypt: [http://www.truecrypt.org]

[13] Moses Liskov, Ron Rivest, David Wagner, “Tweakable Block Ciphers”: Proceedings of Crypto 2002, Springer-Verlag, Lecture Notes in Computer Science No. 2442

[14] Clement Kent (Editor), “Draft Proposal for Tweakable Narrow-block Encryption”: IEEE P1619 Working Group, 6. August 2004

[15] Morris Dworkin, “Recommendation for Block Cipher Modes of Operation – Galois/Counter Mode (GCM) for Confidentiality and Authentication”, NIST Special Publication 800-38D: [http://csrc.nist.gov/publications/drafts/Draft-NIST_SP800-38D_Public_Comment.pdf]

[16] Pamscript: [http://linux.bononline.nl/linux/pamscript/01/build.html]

[17] LUFS: [http://lufs.sourceforge.net/lufs/]

[18] FUSE: [http://fuse.sourceforge.net]

[19] Gmail-FS: [http://richard.jones.name/google-hacks/gmail-filesystem/gmail-filesystem.html]

[20] FTPFS: [http://ftpfs.sourceforge.net]

[21] Crypto-FS: [http://www.reboot.animeirc.de/cryptofs/]

[22] Libgcrypt: [ftp://ftp.gnupg.org/gcrypt/alpha/libgcrypt/]

[23] Glib: [http://www.gtk.org]

[24] Enc-FS: [http://arg0.net/wiki/encfs]

[25] Rlog: [http://arg0.net/wiki/rlog]

[26] Pam_encfs: [http://hollowtube.mine.nu/wiki/index.php?n=Projects.PamEncfs]

[27] Enc-FS für Windows: [http://www.crc32.net/encfs/]

[28] Bonnie++: [http://www.coker.com.au/bonnie++/]

Die Autoren

Christian Ney arbeitet als Unix- und Firewall-Administrator bei einer Regionalfluggesellschaft und berät darüber hinaus kleine und mittelständische Firmen in Sicherheits- und Hochverfügbarkeitsfragen.

Peter Gutmann ist Wissenschaftler im Department of Computer Science der University of Auckland, Neuseeland. Er arbeitet an Design und Analyse kryptographischer Sicherheitsarchitekturen, ist Coautor von PGP und hat viele Berichte und RFCs zu Sicherheit und Verschlüsselung veröffentlicht. Von ihm stammen außerdem das Open-Source-Sicherheits-Toolkit Cryptlib sowie das Buch “Cryptographic Security Architecture Design and Verification” (Springer-Verlag, 2003).

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben