LUKS Header auf USB-Stick verschieben (für Debian Jessie): Unterschied zwischen den Versionen

Aus codecivil
Zur Navigation springen Zur Suche springen
Zeile 29: Zeile 29:
 
ergänzen,
 
ergänzen,
 
* in remoteheader_script.sh die Zeilen
 
* in remoteheader_script.sh die Zeilen
  <nowiki>
+
  <pre style="white-space: pre;
 +
white-space: -moz-pre;
 +
white-space: -pre;
 +
white-space: -o-pre;">
 
/bin/dd&nbsp;if=$REMOTEHEADER_FILE&nbsp;of=/etc/remoteheader/header&nbsp;bs=$REMOTEHEADER_BLOCKSIZE&nbsp;skip=$REMOTEHEADER_SKIPBLOCKS&nbsp;count=$REMOTEHEADER_READBLOCKS&nbsp;2>/dev/null&nbsp;&&  
 
/bin/dd&nbsp;if=$REMOTEHEADER_FILE&nbsp;of=/etc/remoteheader/header&nbsp;bs=$REMOTEHEADER_BLOCKSIZE&nbsp;skip=$REMOTEHEADER_SKIPBLOCKS&nbsp;count=$REMOTEHEADER_READBLOCKS&nbsp;2>/dev/null&nbsp;&&  
{{nowrap begin}}/sbin/cryptsetup luksOpen $REMOTEHEADER_DEVICENAME_ENCRYPTED --header /etc/remoteheader/header $REMOTEHEADER_DEVICENAME_DECRYPTED && {{nowrap end}}
+
/sbin/cryptsetup luksOpen $REMOTEHEADER_DEVICENAME_ENCRYPTED --header /etc/remoteheader/header $REMOTEHEADER_DEVICENAME_DECRYPTED &&
/sbin/vgchange -ay </nowiki>
+
/sbin/vgchange -ay </pre>
 
durch  
 
durch  
 
  <nowiki>
 
  <nowiki>

Version vom 31. März 2016, 14:54 Uhr

Ausgangssituation und Ziel

Wir gehen davon aus, dass Sie eine LUKS verschlüsselte Festplatte haben, deren Header Sie entfernen und stattdessen von einem USB Stick aus benutzen wollen. Für Geräte, die erst nach dem Bootprozess entschlüsselt werden, ist dies im Allgemeinen kein Problem. Soll dagegen von dem Gerät gebootet werden, ist der Vorgang etwas komplizierter und wird hier beschrieben. Die beschriebene Vorgehensweise ist für Debian Jessie geeignet.

FAQ

Wozu sollte ich den Header von der Festplatte entfernen?

LUKS-verschlüsselte Partitionen sind schwer zu knacken, sofern man keine Konfigurationsfehler begangen hat. Jedoch benötigt jede LUKS-Partition einen Header, in dem steht, wie genau verschlüsselt wird und wo die verschlüsselten Daten beginnen. Dieser Header ist natürlich unverschlüsselt. Selbst mit den Informationen des Headers ist eine Entschlüsselung jedoch sehr aufwendig. Aber: Seine Existenz verrät, dass verschlüsselte Daten vorliegen; und mit einem erpressten Passwort oder Schlüsselfile werden diese Daten zugänglich. Ist der Header (sowie Boot-Partition und Bootloader) aber nicht auf dem Gerät zu finden, das verschlüsselt worden ist, so sind seine Inalte nicht mehr von zufälligen Daten zu unterscheiden und eine Verschlüsselung kann abgestritten werden. Zudem benötigt ein Angreifer nun das Passwort/Schlüsselfile und den Header, man hat also nebenbei eine wirksame Zwei-Faktor-Authentifizierung eingerichtet.

Ist das nicht unsicherer, wenn ich den Header unverschlüsselt mit mir herumtrage?

Der Header ist auch auf der Festplatte schon unverschlüsselt und kann direkt ausgelesen werden, sobald man physischen Zugriff auf das Gerät hat. Auf dem Header ist aber der eigentliche Schlüssel nur verschlüsselt abgelegt; verschlüsselt mit dem Passwort oder Schlüsselfile, das man angelegt hat. Um bei einem schwachen Passwort die Daten auf dem Gerät zu entziffern, reichte zuvor ein Zugang zum Rechner. Nun muss ein Angreifer den USB Stick und den Rechner in die Hände bekommen. Zwei Arten von Unsicherheit treten aber in der Tat neu auf:

  • Erhält jemand den USB Stick, so kann er in Ruhe eine Brute-Force-Attacke gegen den Master Key auf dem Header fahren. Hat er den geknackt und bekommt nun physischen Zugriff auf das verschlüsselte Gerät, so sind dessen Daten sofort entziffert. Der Master Key lässt sich nur durch eine komplette Neuverschlüsselung ändern, so dass ein Verlust des USB Sticks großen Sicherungsaufwand bedeutet.
  • Files auf einem USB-Stick sind volatiler und die Gefahr einer unabsichtlichen Zerstörung des Headers größer als zuvor. Um dem zu begegnen, schreiben wir den Header nicht als Datei oder in die initramfs auf den Stick, sondern in einen unpartitionierten Bereich. Dort kann nur absichtlich geschrieben oder gelesen werden. Wie zuvor aber auch, ist es empfehlenswert, ein Backup des Headers zu haben.

Was genau ist unsere Strategie?

Unsere Vorgensweise ist inspiriert von https://wiki.ubuntuusers.de/System_verschl%C3%Bcsseln/Entschl%C3%Bcsseln_mit_einem_USB-Schl%C3%Bcssel. Dort wird beschrieben, wie man einen USB-Stick als LUKS-Schlüssel einrichtet.

Wir schreiben ein Shellskript, das für die Entschlüsselung unter Benutzung des entfernten Headers sorgt. Die Disk-Entschlüsselung startet mit dem Aufruf von cryptroot. Dies geschieht als letztes Script im Ordner /usr/share/initramfs-tools/scripts/local-top. Um dem zuvor zu kommen, legen wir unser Shellskript in diesen Ordner. Über einen Hook sorgen wir dafür, dass dem Shellskript die normalen cryptsetup und vgchange zur Verfügung stehen.

Das Shellskript lädt eine Konfigurationsdatei, die dem Skript sagt, wo der Header auf dem Stick zu finden ist - in einem unpartitionierten Bereich des Sticks - und lädt ihn in das temporäre Filesystem der initramfs. Dort wird er zum Entschlüsseln benutzt. Im Kontrast dazu, den Header direkt in das initrd.img-File zu schreiben, hat das die Vorteile, dass der Header nicht auf dem Filesystem vorgehalten werden muss (weder in der Bootpartition noch in den verschlüsselten Partitionen), um Kernel-Updates reibungslos zu erlauben. Der Header wird nur kurz während des Bootvorgangs in den RAM des Rechners geladen und ist ansonsten nirgends auf dem Filesystem zu finden.

Warum kann ich nicht einfach die header option in der crypttab benutzen?

Debian Jessie benutzt beim Booten nicht die normale cryptsetup-Binary, sondern "systemd-cryptsetup". Momentan ist die Übergabe der "header"-Option dafür nicht implementiert. Wir laden deshalb die später benutzte cryptsetup-Binary nach und benutzen sie mit der Header-Option während der intitramfs-Phase.

Diese Information bezieht sich auf systemd in der Version 215-17+deb8u3. Falls Sie bereits eine spätere Version haben, könnte es durchaus sein, dass Sie die Header-Option benutzen können. Das sollten Sie dann auch tun. In dem Fall müssen Sie aber immer noch die USB-Module rechtzeitig laden, um den Header vom USB Stick ins initramfs zu bekommen. Die Vorgehensweise wäre fast identisch, nur folgende drei Änderungen wären nach dem Erstellen der Dateien remoteheader.conf, remoteheader.hook und remoteheader_script.sh nötig:

  • in /etc/crypttab
header=/etc/remoteheader/header

ergänzen,

  • in remoteheader_script.sh die Zeilen
/bin/dd if=$REMOTEHEADER_FILE of=/etc/remoteheader/header bs=$REMOTEHEADER_BLOCKSIZE skip=$REMOTEHEADER_SKIPBLOCKS count=$REMOTEHEADER_READBLOCKS 2>/dev/null && 
/sbin/cryptsetup luksOpen $REMOTEHEADER_DEVICENAME_ENCRYPTED --header /etc/remoteheader/header $REMOTEHEADER_DEVICENAME_DECRYPTED &&
/sbin/vgchange -ay	

durch

/bin/dd if=$REMOTEHEADER_FILE of=/etc/remoteheader/header bs=$REMOTEHEADER_BLOCKSIZE skip=$REMOTEHEADER_SKIPBLOCKS count=$REMOTEHEADER_READBLOCKS 2>/dev/null 

ersetzen (in einer Zeile) und

  • in remoteheader.hook die Zeilen
. /usr/share/initramfs-tools/hook-functions # provides copy_exec

und

copy_exec /sbin/cryptsetup /sbin/        # provides cryptsetup
copy_exec /sbin/vgchange   /sbin/        # provides lvm2 vgchange 

entfernen.

Die Anleitung Schritt für Schritt

Wir werden das Bootimage ändern, daher besteht immer die Gefahr, dass das geänderte System zunächst nicht bootet. Halten Sie für diesen Notfall ein Live-Linux-System bereit, von dem Ihr Rechner booten kann.

Alle Schritte sollten Sie als Root ausführen. Gegebenenfalls müssen Sie daher sudo vor die entsprechenden Befehle schreiben.

Wir gehen im Folgenden davon aus, dass die verschlüsselte Partition /dev/sda5 ist und der USB Stick unter /dev/sdb zu finden ist. Bitte passen Sie die unten folgenden Schritte Ihrer Situation entsprechend an.

Um herauszufinden, wie die Gerätedateien tatsächlich heißen, kann man den Befehl lsblk benutzen. LUKS-entschlüsselte Geräte sind die Eltern der Geräte vom Typ crypt.

Dateien kopieren

Sie benötigen die folgenden drei Dateien:

Kopieren Sie bitte die Linkinhalte in Files mit dem angegebenen Namen.

Verzeichnisse vorbereiten

Wir legen das Verzeichnis an, das unsere Bootkonfiguration ergänzen soll.

mkdir /etc/remoteheader

Vorbereitung des USB Sticks

Wir exportieren zunächst den Header

cryptsetup luksHeaderBackup /dev/sda5 --header-backup-file /etc/remoteheader/header

und sehen uns an, wieviel Platz wir dafür benötigen:

ls -l /etc/remoteheader

Meistens sind dies zwischen zwei und drei Megabyte. Nun müssen wir dafür sorgen, dass auf dem USB-Stick mindestens so viel unpartitionierter Platz zur Verfügung steht. Dazu kann man jedes Partitionierungsprogramm verwenden, am sichersten aber erscheint uns gparted:

gparted /dev/sdb

Falls gparted nicht zur Verfügung steht, kann es mittels

apt-get install gparted

nachinstalliert werden. Mittels fdisk kontrollieren wir nun das Ergebnis:

fdisk -l /dev/sdb

Das kann dann zum Beispiel so aussehen:

Disk /dev/sdb: 7.4 GiB, 7902068736 bytes, 15433728 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x000178bc

Device     Boot Start      End  Sectors  Size Id Type
/dev/sdb1  *       62 15294407 15294346  7.3G 83 Linux 

In diesem Fall haben wir vor der Partition /dev/sdb1 62 und danach 15433728-15294407-1=139320 Blöcke von jeweils 512 Bytes zur Verfügung. Vor die Partition passt der Header also nicht, dahinter aber haben wir große Auswahl. Wir könnten zum Beispiel bei Block 15300000 mit dem Header beginnen. Um das zu tun, benutzen wir dd:

dd if=/etc/remoteheader/header of=/dev/sdb bs=512 seek=15300000

Passen Sie bei der Benutzung von dd besonders auf: Fehler können im Allgemeinen nicht rückgängig gemacht werden und eine falsche Gerätedatei kann verheerende Folgen haben.

Sicherung des Headers

Für den Fall, dass etwas schief läuft, sollten wir eine weitere Kopie des Headers in der Boot-Partition haben.

cp /etc/remoteheader/header /boot/header

Editieren von remoteheader.conf

Um die Datei remoteheader.conf anzupassen, benötigen wir folgende Informationen:

  • Die ID des USB Sticks. Diese dient dazu, dass der Header nur von diesem speziellen USB-Stick gelesen wird. Eine Byte-für-Byte-Kopie des USB-Sticks würde nicht funktionieren. Die ID des Sticks findet man so heraus:
ls -l /dev/disk/by-id

Es ist die ID, die zum Gerät /dev/sdb verlinkt. Sie ist meist von der Form "usb-....-0:0". Wir schreiben sie in Anführungszeichen hinter

REMOTEHEADER_DISKID=

Wollen Sie den Header auf mehreren USB-Sticks benutzen können (ein Backup des Headers sollte stets vorhanden sein), so schreiben Sie hier alle IDs hintereinander, getrennt durch jeweils ein Leerzeichen.

  • Den Gerätenamen, vor und nach der Entschlüsselung. Hier haben wir angenommen, dass der erste /dev/sda5 heißt und Debian nennt dann das entschlüsselte Gerät sda5_crypt, sofern man keine andere Angaben macht. Dies sind die Default-Einstellungen
REMOTEHEADER_DEVICENAME_ENCRYPTED="/dev/sda5"
REMOTEHEADER_DEVICENAME_DECRYPTED="sda5_crypt" 

und müssen bei Bedarf angepasst werden. Wir hätten diese Information auch aus der crypttab lesen können, aber da das Skript kein vollständiges crypttab-Parsing durchführt, wäre dies Augenwischerei.

  • Die Blockgröße des Geräts, meist 512. Sie ist in der Ausgabe des obigen fdisk-Befehls zu finden und wir tragen sie als
REMOTEHEADER_BLOCKSIZE=

ein.

  • Der Startblock des Headers auf dem Stick. Hier haben wir 15300000 gewählt, also wäre
REMOTEHEADER_SKIPBLOCKS="15300000"

einzutragen.

  • Die Länges Headers in Blocks. Ist <HEADERSIZE> die Größe des Heades in Bytes und <BLOCKSIZE> die Blockgröße, so bestimmen wir sie mittels
echo <HEADERSIZE>/<BLOCKSIZE> | bc -l

Dies sollte ganzzahlig sein. Wir tragen den Wert als

REMOTEHEADER_READBLOCKS=

in die Konfigurationsdatei ein.

Verschieben der Dateien

Alle Dateien müssen Root gehören:

chown root:root remoteheader.conf remoteheader.hook remoteheader_script.sh

Die Konfigurationsdatei muss nun in dem neuen /etc-Ordner zu finden und mit minimalen Rechten ausgestattet sein.

cp remoteheader.conf /etc/remoteheader/
chmod 400 /etc/remoteheader/remoteheader.conf  

Das Hook-Skript und das Boot-Skript müssen ausführbar sein und in die richtigen Verzeichnisse:

chmod 755 remoteheader.hook remoteheader_script.sh
cp remoteheader.hook /etc/initramfs-tools/hooks/
cp remoteheader_script.sh /usr/share/initramfs-tools/scripts/ 

Update der initramfs

Um den laufenden Kernel herauszufinden, benutzen Sie

uname -r 

und um den entsprechenden Kernel zu aktualisieren, können Sie einfach

update-initramfs -k $(uname -r) -u 

benutzen, oder hinter -k die gewünschte Kernelversion schreiben. Um alle Kernels zu aktualisieren, schreiben Sie "all" anstatt der Kernelversion. Die einzigen Fehlermeldungen, die hier auftreten dürfen, sind von der Form "Device /dev/sda5 already opened. FAILED to decrypt using ...". Treten weitere Fehler auf, sollten Sie hier aufhören und auf Fehlersuche gehen. Erst, wenn dieser Schritt erfolgreich war, fahren Sie mit dem nächsten fort.

Entfernung des Headers von der Festplatte und Reboot

Wir überschreiben den Header mit (quasi-)zufälligen Daten:

head -c <HEADERSIZE> /dev/urandom > /dev/sda5; sync 

Die heruntergeladenen Dateien sollten nun entfernt werden.

rm -f remoteheader.conf remoteheader.hook remoteheader_script.sh 

Das System kann nun neu gebootet werden.

Entfernung der Sicherungskopie des Headers

Bootet der Rechner wie gewünscht, so sollte die Sicherungskopie entfernt werden.

shred -uz /boot/header 

Troubleshooting

Wiederherstellung des Headers (mit Sicherheitskopie)

Sollte der Rechner beim ersten Test nicht mehr booten, starten Sie ein Live-Linux-System. In einer Shell können Sie dann den folgenden Befehl ausführen.

cryptsetup luksHeaderRestore /dev/sda5 --header-backup-file /boot/header

Da der Header vollständig entfernt wurde, muss der Vorgang mit YES bestätigt werden. Jeder nicht-aktualisierte Kernel sollte nun wieder booten. Die aktualisierten Kernel booten, wenn der USB-Stick mit dem Header nicht eingesteckt ist.

Wiederherstellung des Headers (ohne Sicherheitskopie)

Weigert sich der Rechner plötzlich zu booten und haben Sie die Sicherheitskopie wie empfohlen entfernt, haben wir die Möglichekit, den Header so wieder zu finden:

Wir entpacken die modifizierte initramfs, hier mit <INITRAMFS> bezeichnet, lesen die Konfigurationsdatei aus und erzeugen die Sicherheitskopie:

mkdir temp; cd temp; gunzip -c /boot/<INITRAMFS> | cpio -i
. etc/remoteheader/remoteheader.conf
dd if=/dev/sdb of=/boot/header bs=$REMOTEHEADER_BLOCKSIZE skip=$REMOTEHEADER_SKIPBLOCKS count=$REMOTEHEADER_READBLOCKS 

Nun gehen wir wie oben vor.

Wiederherstellung des Headers (ohne Sicherheitskopie und Konfigurationsdatei)

Fehlt Ihnen auf unerklärliche Weise auch die Konfigurationsdatei, so durchsuchen wir den Stick so lange, bis wir auf den Header treffen:

hexdump -C /dev/sdb | grep LUKS | awk '{ print $1 }' 

gibt uns die Startadressen gefundener LUKS-Header in hexadezimaler Form. Das kann ziemlich lange dauern. Bekommen Sie mehrere Treffer, so haben Sie vielleicht noch alte Header oder entfernte Kopien auf dem Stick. Schwieriger wird es nun, das Ende des Headers zu finden. Dazu nehmen Sie eine vielversprechende der erhaltenen Adressen, sagen wir <STARTADDRESS_HEX> und führen die Suche

hexdump -C /dev/sdb -s 0x<STARTADDRESS_HEX> | grep "00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00" | awk '{ print $1 }'

durch. Liegt eine der gefundenen Addresse etwa 2 bis 3 MB von der Startadresse entfernt, sagen wir <ENDADDRESS_HEX>, so sind wir dem Ende des Headers nahe. Wir berechnen nun die dezimale Start- und Endaddresse als

STARTADDRESS=$((0x<STARTADDRESS_HEX>))
ENDADDRESS=$((0x<ENDADDRESS_HEX>))

Die Länge des Headers in Blöcken (von hier 512 Bytes) und die anderen Parameter setzen wir dann als

REMOTEHEADER_BLOCKSIZE=512
REMOTEHEADER_SKIPBLOCKS=$((STARTADDRESS/512))
REMOTEHEADER_READBLOCKS=$(((ENDADDRESS-STARTADDRESS)/512 + 4))

und schreiben den Header

dd if=/dev/sdb of=/boot/header bs=$REMOTEHEADER_BLOCKSIZE skip=$REMOTEHEADER_SKIPBLOCKS count=$REMOTEHEADER_READBLOCKS 

Nun haben wir hoffentlich wieder die Sicherheitskopie des Headers.