Daten unter GNU/Linux verschlüsseln
Durch Verschlüsselung können vertrauliche Daten vor unbefugtem Zugriff geschützt werden. Im Folgenden beschreibe ich, wie man dies unter Gentoo GNU/Linux erreichen kann.
Achtung: Ich hafte nicht für Schäden, die durch das Befolgen dieser Anleitung entstehen.
Ausgangssituation
Für mein Home-Verzeichnis (/home/karsten
) auf meinem Rechner (athlon
) möchte ich eine 60GB Festplatte (/dev/hdb
) verwenden, deren Inhalt verschlüsselt werden soll. Die Festplatte soll nach der Anmeldung am System automatisch aufgeschlossen und in den Verzeichnisbaum eingehängt werden; nach der Abmeldung soll die Festplatte automatisch ausgehängt und zugeschlossen werden. Aufgeschlossen heißt: Der Klartext (die Daten) kann von der Festplatte gelesen werden. Von der zugeschlossenen Festplatte kann nur der Schlüsseltext (die verschlüsselten Daten) gelesen werden.
Konfiguration
Um dies einzurichten, verwende ich die Kernel-Optionen dm-crypt, loop und lrw; sowie die Pakete cryptsetup-luks und pam_mount.
Kernel anpassen
Zuerst muss der Kernel, ich verwende Version 2.6.22, angepasst werden; folgende Optionen sind zu aktivieren:
Device Drivers ---> Block devices <*> Loopback device support
Device Drivers ---> Multi-device support (RAID and LVM) <*> Device mapper support <*> Crypt target support
Cryptographic options ---> <*> LRW support (EXPERIMENTAL)
Jede Option kann auch als Modul übersetzt werden. Nach dem Neustart des Systems (mit dem neuen Kernel) müssen die betreffenden Module geladen werden.
Pakete installieren
Für die Schlüssel-Verwaltung wird cryptsetup-luks benötigt:
root> emerge cryptsetup-luks
Um die Platte nach der Anmeldung einhängen bzw. nach der Abmeldung aushängen zu können, braucht man pam_mount.
root> emerge pam_mount
Achtung: pam_mount ist bei Gentoo maskiert (MASKED). Die Datei /etc/portage/package.keywords muss um folgende Zeilen ergänzt werden:
# für x86 erforderlich sys-auth/pam_mount ~* # für ppc erforderlich sys-auth/pam_mount ** sys-libs/libhx **
Festplatte schreddern
Um Altlasten auf der Festplatte loszuwerden, wird die gesamte Platte mehrmals mit Zufallswerten und abschließend mit Nullen beschrieben.
root> shred -vz -n 4 /dev/hdb
Ist shred
endlich fertig, wurde die Festplatte viermal mit Zufallswerten und abschließend mit Nullen beschrieben. Eine Wiederherstellung von persönlichen Daten sollte nun nahezu unmöglich sein.
Das ganze dauert sehr lange; alternativ kann man sich mit dem Programm dd
auch einen Zufallspool erstellen und diesen für das Beschreiben der Festplatte benutzen.
root> dd bs=10M count=100 if=/dev/urandom of=/tmp/random.img
Mit dd
und einem kleinen Skript kann man /tmp/random.img
nun hintereinander nach /dev/hdb
schreiben; das ist wesentlich schneller als shred
. Hierzu sollte man sich die dd
-Optionen skip
und seek
anschauen (oder mein Ruby-Script verwenden).
Initialisieren der Festplatte
Die Festplatte kann jetzt initialisiert werden:
root> cryptsetup -c aes-lrw-benbi -s 256 -y luksFormat /dev/hdb
Nun wird man darüber informiert, dass sämtliche Daten verloren gehen (bestätigen mit YES
). Anschließend muss man noch eine Passphrase, den Hauptschlüssel eingeben. Hier hat man die freie Wahl, man sollte jedoch eine Phrase eingeben, die zumindest Wörterbuchangriffen standhält. Zur Orientierung ein kleines Beispiel:
Wenn’sch das gewusst hätte, achtsch Mark für Nüscht §$%!
Zur Erläuterung: Es wird die Block-Chiffre AES mit der Betriebsart LRW verwendet; die Schlüssellänge beträgt 256Bit. Es kann laut Dokumentation von lrw auch ein längerer Schlüssel (bis 384Bit) verwendet werden. Ich hatte allerdings keinen Erfolg: Die Festplatte ließ sich anschließend nicht aufschließen. Ein Länge von 256Bit sollte jedoch ausreichen, denn die Wahrscheinlichkeit ist sehr gering, dass ein Angreifer den richtigen aus 2^256 möglichen Schlüsseln in angemessener Zeit ermittelt.
Jetzt können wir die Festplatte aufschließen.
root> cryptsetup luksOpen /dev/hdb _dev_hdb
Die aufgeschlossene Festplatte ist jetzt unter /dev/mapper/_dev_hdb
zu erreichen. Was dort fehlt, ist ein Datei-System; ich habe mich für Ext3 entschieden.
root> mkfs.ext3 -j /dev/mapper/_dev_hdb
Die Festplatte kann jetzt verwendet werden, wir schließen sie allerdings ersteinmal zu.
root> cryptsetup luksClose _dev_hdb
Festplatte in /etc/fstab
eintragen
Folgende Zeile muss hinzugefügt werden:
/dev/hdb /home/karsten crypt noauto,defaults,noatime 0 0
Jetzt lässt sich die Festplatte ganz einfach aufschließen und einhängen.
root> mount /home/karsten
Nach Eingabe der Passphrase sollte die Festplatte in /etc/mtab
auftauchen.
root> mount | grep /home/karsten /dev/mapper/_dev_hdb on /home/karsten type ext3 (rw,noatime)
Für das Aushängen und Zuschließen der Platte sind zwei Befehle notwendig:
root> umount /dev/mapper/_dev_hdb root> cryptsetup luksClose _dev_hdb
pam_mount einrichten
Zuerst machen wir die Platte dem PAM-Modul pam_mount bekannt. Dazu wird der Datei /etc/security/pam_mount.conf.xml
folgende Zeile hinzugefügt:
<volume user="karsten" fstype="crypt" path="/dev/hdb" mountpoint="/home/karsten" />
Anschließend aktivieren wir das Modul in /etc/pam.d/system-auth
.
# hier sind nur die auth- und session-Einträge dargestellt auth required pam_env.so auth optional pam_mount.so auth sufficient pam_unix.so likeauth nullok use_first_pass auth required pam_deny # ... session required pam_limits.so session required pam_unix.so session optional pam_mount.so use_first_pass
Login-Passwort als Schlüssel verwenden
Da die Festplatte automatisch nach der Anmeldung aufgeschlossen werden soll, muss das Login-Passwort ein gültiger Schlüssel für die Festplatte sein. Das Login-Passwort sollte, genau wie die Passphrase, mit Bedacht gewählt werden.
root> cryptsetup luksAddKey /dev/hdb
Jetzt gibt man die Passphrase ein und anschließend zweimal das Login-Passwort. Wenn ich mich nun als karsten
anmelde, wird die Festplatte automatisch aufgeschlossen und eingehängt, nach dem Abmelden wird die Platte ausgehängt und zugeschlossen — fein.
Anmerkung: Man kann auch die Passphrase unter Verwendung des Login-Passworts verschlüsseln und als Datei unter /home
ablegen. Nach der Anmeldung wird die Passphrase automatisch entschlüsselt und die Festplatte mit ihr aufgeschlossen. Diese Variante bietet allerdings keine Vorteile: Hat ein Angreifer das Login-Passwort, kann er auch die Passphrase entschlüsseln und damit die Festplatte aufschließen.
SSH einrichten
Die Anmeldung von einem entfernten Rechner funktioniert nun leider nicht mehr. Dieses Problem ist bekannt, wie ein Blick in die bugs.txt
von pam_mount zeigt:
When interactively asking for the password, the ssh client opens /dev/tty and ignores stdin over which pam_mount passes the password.
Dort wird auch eine Lösung angegeben.
When public key authentication is used, the PAM auth stage is entirely skipped. ... "UseLogin yes" may be used to enable pam_mount -- irrespective of public key authentification, ...
Für die folgenden Schritte muss auf dem Rechner der SSH-Dämon sshd
laufen. Desweiteren benötigt man auf dem Rechner, von dem der Zugriff erfolgen soll (bei mir ibook
), ein RSA-Schlüsselpaar. Der private Schlüssel wird dort im Home-Verzeichnis unter .ssh/id_rsa
abgelegt. Den öffentlichen Schlüssel .ssh/id_rsa.pub
kopiert man nun auf den Rechner mit der verschlüsselten Festplatte (bei mir athlon
). Die verschlüsselte Festplatte darf nicht eingehängt sein!
root@ibook> scp /home/karsten/.ssh/id_rsa.pub athlon:/home/karsten
Auf dem anderen Rechner (athlon
) gehe ich in das Verzeichnis /home/karsten
, lege dort das Verzeichnis .ssh
an und kopiere den öffentlichen Schlüssel dort hin. Er bekommt den Namen authorized_keys
.
root@athlon> mkdir /home/karsten/.ssh root@athlon> mv /home/karsten/id_rsa.pub /home/karsten/.ssh/authorized_keys
Jetzt muss die Datei /etc/ssh/sshd_config
angepasst werden. Dort hängt man folgende Zeile an:
UseLogin yes
Der sshd
muss die Änderung der Konfiguration noch übernehmen.
root@athlon> /etc/init.d/sshd reload
Das war’s. Vom Rechner ibook
kann ich mich nun via ssh
auf dem Rechner athlon
anmelden.
karsten@ibook> ssh athlon reenter password for pam_mount:
Mit dem richtigen Passwort wird die Festplatte aufgeschlossen und eingehängt. Bei falschem Passwort landet man zwar auch in /home/karsten
, allerdings ist dort nicht die verschlüsselte Festplatte eingehängt. Um Verwechslungen auszuschließen, habe ich, bei ausgehängter Festplatte, das Home-Verzeichnis inklusive aller darin enthaltenen Dateien root
zugeordnet und dort eine Datei YOUR_HOME_IS_NOT_MOUNTED
angelegt. Nach einem ls
sieht man sofort, ob was falsch gelaufen ist. Hier die notwendigen Schritte:
root@athlon> mount | grep /home/karsten | wc -l 0 root@athlon> chown -R root:root /home/karsten root@athlon> touch /home/karsten/YOUR_HOME_IS_NOT_MOUNTED
Achtung: Ist die Festplatte aufgeschlossen und eingehängt, findet sshd
die Datei .ssh/authorized_keys
nicht mehr, da sich jetzt unter /home/karsten
die Festplatte befindet. Will man eine weitere ssh
-Session starten, muss die Datei erst angelegt werden.
Probleme beim Aushängen beseitigen
Schließt man eine SSH-Verbindung oder meldet man sich ab, nachdem man mit su
die Identität des Festplatten-Eigentümers angenommen hat, wird die Festplatte nicht ausgehängt, da die erforderlichen root
-Rechte fehlen. Das Aushängen schlägt auch fehl, falls noch Programme auf der Festplatte arbeiten. Mit dem Paket sudo und einer Änderung des Skripts /sbin/umount.crypt
lässt sich das jedoch abändern. Zuerst installieren wir das Paket sudo:
root> emerge sudo
Jetzt erlauben wir dem Eigentümer der Festplatte (hier karsten
) einige Befehle als root
, ohne Passwort-Eingabe, auszuführen.
root> visudo
Folgende Zeile wird eingefügt.
karsten ALL = NOPASSWD: /bin/umount /home/karsten, /sbin/cryptsetup luksClose _dev_hdb
Das Skript /sbin/umount.crypt
zum Aushängen der Festplatte wird um drei Funktionen ergänzt.
function print_error() { echo "ERROR: $1" } function prepare_umount() { while [[ $(fuser -m $1 | cut -d : -f 2 | wc -w) != 0 ]]; do fuser -km $1; sleep 1; done } function force_umount() { UMOUNT="$(which umount) $1" SUDO_UMOUNT="sudo $UMOUNT" CLOSE="$(which cryptsetup) luksClose $2" SUDO_CLOSE="sudo $CLOSE" echo "forcing umount of $1" if [[ $(sudo -l | grep "^ \+(root) NOPASSWD: $UMOUNT\$" | wc -l) == 1 ]]; then $SUDO_UMOUNT if [[ $? == 0 ]]; then echo "closing $2" if [[ $(sudo -l | grep "^ \+(root) NOPASSWD: $CLOSE\$" | wc -l) == 1 ]]; then $SUDO_CLOSE if [[ $? != 0 ]]; then print_error "\"$SUDO_CLOSE\" failed"; fi else print_error "you are not allowed to run \"$SUDO_CLOSE\" as root without password" fi else print_error "\"$SUDO_UMOUNT\" failed" fi else print_error "you are not allowed to run \"$SUDO_UMOUNT\" as root without password" fi }
prepare_umount
fordert alle Programme, die noch auf die Festplatte zugreifen, auf, sich zu beenden, denn sonst kann die Platte nicht ausgehängt werden. force_umount
erzwingt das Aushängen der Platte, falls es zuvor, aufgrund fehlender Rechte, erfolglos war. print_error
dient zur Ausgabe von Fehlern.
prepare_umount
und force_umount
werden wie folgt in das Skript eingefügt:
prepare_umount $1 umount "$1"; if [ $? -ne 0 ]; then echo "${0##*/}: error unmounting $1" >&2 force_umount $1 $DMDEVICE exit 1 fi
Damit der Session-Zähler dekrementiert werden kann, muss der Festplatten-Eigentümer bzw. seine Gruppe (hier users
) noch das Schreibrecht für das Verzeichnis /var/run/pam_umount
erhalten.
root> chown root:users /var/run/pam_mount root> chmod 775 /var/run/pam_mount
Das wars, nun funktioniert (wirklich) alles.
Leistungsbewertung
Das Entschlüsseln der Daten nach dem Lesen und das Verschlüsseln vor dem Schreiben kosten Zeit. Wie sich das auf den Durchsatz der Festplatte auswirkt, kann man mit dem Programm bonnie
messen. Die Installation des Pakets ist ganz einfach.
root> emerge bonnie
Jetzt nehme ich die Identität des Nutzers karsten
an.
root> su - karsten
Mit dem richtigen Passwort wird die Festplatte aufgeschlossen und eingehängt; anschließend wird in das Home-Verzeichnis von karsten
gewechselt. Nun kann der Datendurchsatz der Platte gemessen werden.
karsten ~> bonnie -s 1024
Nach diesem Aufruf werden 1GB Daten (mehrmals) auf die Platte geschrieben und anschließend (mehrmals) wieder ausgelesen. Bei allen Operationen wird die Zeit gemessen. Ist bonnie
fertig, werden die Mess-Ergebnisse ausgegeben.
-------Sequential Output-------- ---Sequential Input-- --Random--- -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---- Machine MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU athlon 1024 24140 79.5 24356 15.4 13134 6.0 26305 77.7 31198 6.0 1618.2 5.2
Vorher habe ich bereits den Datendurchsatz der Festplatte ohne Verschlüsselung gemessen.
-------Sequential Output-------- ---Sequential Input-- --Random--- -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---- Machine MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU athlon 1024 27278 88.4 36210 23.5 16648 7.7 27802 84.6 47837 8.5 1718.0 6.4
Was fällt auf? Das Schreiben und Lesen von Blöcken ist durch die Verschlüsselung ca. 30 Prozent langsamer geworden. Sonst ist der Durchsatz zwar auch geringer, liegt jedoch weit unter 30 Prozent.
Fazit: Ich denke, mit diesem Datendurchsatz kann man leben.
Abschließende Bemerkungen
Die hier vorgestellte Methode eignet sich für Rechner, an denen zu jedem Zeitpunkt maximal eine Person arbeitet. Denn ist die verschlüsselte Platte aufgeschlossen und eingehängt, kann jeder angemeldete Nutzer Dateien auf der Platte lesen, vorausgesetzt, er hat die entsprechenden Rechte.