Laptop – SSD mit dm-crypt/Luks -Verschlüsselung und Opensuse Leap 15 – V – kryptierte Partitionen und Alignment

Nach den Überlegungen in den letzten Artikeln dieser Serie

Laptop – SSD mit dm-crypt/Luks -Verschlüsselung und Opensuse Leap 15 – I – Vorüberlegungen
Laptop – SSD mit dm-crypt/Luks -Verschlüsselung und Opensuse Leap 15 – II – Vorüberlegungen zur Virtualisierung
Laptop – SSD mit dm-crypt/Luks -Verschlüsselung und Opensuse Leap 15 – III – Zugriffs-Layer
Laptop – SSD mit dm-crypt/Luks -Verschlüsselung und Opensuse Leap 15 – IV – Disk-Layout

sind wir gut gerüstet, um für Tests zur Voll-Verschlüsselung eines Laptops passende LVM-Volumes anzulegen und mit einem “LUKS on LVM”-Layer zu versehen. (LVM on LUKS wenden wir uns später zu). Ich sage aus guten Gründen “Tests” – nicht finale Installation. Es gibt Einiges, was man falsch machen kann oder was zu unpraktikablen Konsequenzen führt. Im Besonderen, wenn man sich ein wenig abseits der normalen Installationsprozeduren (hier von Opensuse) bewegt.

Ich werde nachfolgend den Umgang mit einer jungfräulichen SSD diskutieren. Arbeitet ihr nicht mit einer leeren SSD/HDD und wollt ihr alte Installationen nicht verlieren, empfehle ich vorherige vollständige Backups – mit zusätzlichem Aufschreiben von UUIDs plus ggf. separatem Backup der Verzeichnisse “/etc/” und “/boot”. Der Verlust vorhandener Daten ist bei Fehlern möglich.

Bevor man eine vorhandene Laptop-SSD mit funktionstüchtigen Installationen komplett durch eine neue SSD ersetzt, liegt es nahe, die Voll-Verschlüsselung zunächst separat zu testen. Dazu nutzt man die neue SSD vorübergehend als externes, bootbares Laufwerk am USB-3-Anschluss eines laufenden Linux-Systems. Im besten Fall kann man die Test-Installation nach einem Einbau in den Laptop und Anschluss an den dortigen SATA-III-Bus direkt weiter nutzen. Dachte ich so …

Dieses Vorgehen führte bei mir aber zu Problemen mit dem Alignment der anzulegenden Partitionen und Volumes. Das war durchaus lehrreich. Ich werde deshalb darauf eingehen, obwohl es unser Kernthema nur am Rande berührt. Ein weiteres wichtiges Thema dieses Artikels sind die Einstellungen zur Verschlüsselung. Dabei ist vor allem die Anzahl der “PBKDF2”-Iterationen interessant.

Hinweis: Diejenigen, die sich mit der Funktionsweise von LUKS noch nicht so gut auskennen, mögen jetzt einen Blick in den Artikel
crypt/Luks – Begriffe, Funktionsweise und die Rolle des Hash-Verfahrens – I
und den Nachfolge-Artikel werfen. Dort sind etliche weiterführende Links angegeben. Hilfreich ist ferner ein Blick in die man-Seiten zum Kommando “cryptsetup“. LVM-Grundkenntnisse setze ich voraus.

Vorgehen für Tests und Einschränkungen

Ich habe meine neue SSD also an eine USB-3-Buchse eines laufenden Linux-Systems angeschlossen. Dafür stehen mir mehrere USB-Gehäuse (Icy Box, Inateck, ..) zur Verfügung, die natürlich verschiedene USB-to-SATA-Controller enthalten. Ich konzentriere mich nachfolgend auf einen JMicron-Controller.

Das laufende Linux-System kann auf einer bereits vorhandenen Disk des Laptops installiert sein. Oder es ist ein von einem DVD/USB-Stick gebootetes Live-System, oder – wie bei mir – ein Desktop-System. Die spätere Installation des Opensuse-
Systems und das Testen des Boot- und Hibernate-Verhaltens führen wir dann am Laptop selbst durch, indem wir sein BIOS für das wahlweise Booten vom externen USB-Device konfigurieren.

Warum Tests? U.a. wg. der Dauer des Bootvorgangs …
Warum müssen wir überhaupt testen? Ich möchte diesbezüglich auf die Artikel
Full encryption with LUKS (SHA512, aes-xts-plain64) – grub2 really slow …
crypt/Luks – Begriffe, Funktionsweise und die Rolle des Hash-Verfahrens – I + Nachfolgeartikel
verweisen:

dm-crypt/LUKS nutzt PBKDF2; am besten mit Hunderttausenden oder Millionen von Hash-Iterationen. Die entscheidende Frage ist: Wie schnell führt Grub2 diese Iterationen aus? Meine Erfahrung zeigt: Grub2 ist wesentlich langsamer als der später gebootete Kernel! Das kann zu unerträglich langen Boot-Vorgängen führen.

Dann ist ein u.U. Kompromiss zwischen Usability und Security nötig. Eine passende Parametrierung muss deshalb ausgetestet werden.

Ein weiterer Punkt, der auf einem Laptop Tests erfordert, ist Hibernation (im Zusammenspiel mit Grub2 und einem initramfs).

Zudem: Wer meint, die externe Disk samt Installation später direkt am SATA-Controller des Laptops verwenden zu können, täuscht sich womöglich. Einige SATA-to-USB-Controller treiben nämlich wunderliche Dinge mit der Blockbehandlung. Siehe etwa:
https://superuser.com/questions/679725/how-to-correct-512-byte-sector-mbr-on-a-4096-byte-sector-disk
https://superuser.com/questions/1251611/sata-to-usb-cable-sector-size

Es kann daher sein, dass man nach einem Einbau der SSD in den Laptop alles noch mal einrichten und installieren muss. Der aktuelle Installer von Leap 15 erlaubt vor dem Wechsel in den YaST Partitioner allerdings ein Arbeiten auf der Kommandozeile. Da kann man denn all das machen, was ich nachfolgend bespreche. Es gibt auch einige Einschränkungen bei meinem Vorgehen:

Einschränkungen:

  • Controller-Abhängigkeit des Alignments: Das genaue Alignment-Verhalten von “parted” und anderen Tools ist abhängig vom Typ des (externen) USB-to-SATA-Disk-Controllers. Hat man ein System mit eSATA-Anschluss, so sollte man deshalb den eSATA-Anschluss anstelle des USB-Anschlusses zur Vorbereitung der Partitionierung nutzen. Man geht dann einigen der nachfolgend geschilderten Probleme von vornherein aus dem Weg. Wer Spaß am Schrauben hat, kann natürlich die SSDs auch direkt in den Laptop ein- und im Bedarfsfall wieder ausbauen.
  • CPU-Abhängigkeit der PBKDF2-Iterationen: Die Anzahl der PBKDF2-Iterationen ist kritisch für die Dauer des Bootvorgangs; der Zeitbedarf ist stark von der Leistung des Systems (CPU!) abhängig. Die von mir unten angegebenen Zahlen müssen für eure Systeme ggf. anders gewählt werden.
  • Spezifische SSD: Ich nutze eine Samsung 850 Pro. Diese meldet sich am SATA-Bus mit spezifischen Topologie-Parametern an. Diese Parameter – insbesondere die sog. I/O-Limits – sollte man für seine SSD in Erfahrung bringen.
  • Legacy Bios: Mein Reise-Laptop ist nur mit einem Legacy BIOS ausgestattet; ich kann daher nichts zu evtl. Problemen mit UEFI und Secure Boot sagen. Ich sehe aber nicht, warum die Kernschritte wesentlich anders verlaufen sollten. Dennoch habe ich über Probleme mit Secure Boot und Hibernation gelesen. Ich reiche
    Erkenntnisse ggf. nach, sobald ich Zeit habe, mich um andere Laptops zu kümmern.
  • Kein Dual Boot: Ich betrachte kein Dual Boot mit Windows. Windows läuft bei mir nur virtualisiert. Ich betrachte ferner keine RAID-Konfiguration.

Infos nach Anschluss der SSD per USB an den Desktop

Mein externes USB-Gehäuse erlaubt einen Anschluss an USB-3-Interfaces. Wie kann man die Device-Erkennung am USB-Bus auf einem Linux-System prüfen? Hier lohnt sich ein Blick in die Ausgaben von “dmesg” unmittelbar nach dem Anschluss, von “hwinfo” und auch von “lsusb”. Dort sucht man dann nach relevanten Einträgen. Tipp: Unter Opensuse liefert die in YaST integrierte Variante von “hwinfo” einen wesentlich übersichtlicheren Output als die Kommandozeile.

Ich möchte euch nicht mit Details des (langen) hwinfo-Outputs langweilen; hingewiesen sei aber darauf, dass weder “hwinfo”, noch “lsusb” den Plattentyp direkt erkennen. Erkannt wird vielmehr der USB-to-SATA-Controller von JMicron; genutzt wird ferner der generelle “uas“-Treiber. “uas” steht für “USB attached to SCSI”; dieser Treiber unterstützt USB 3.0:

74: SCSI b00.0: 10600 Disk
  [Created at block.245]
  Unique ID: ACFm.Sg0UF0FeCBD
  Parent ID: MZfG.Bel4xd9U8W0
  SysFS ID: /class/block/sdg
  SysFS BusID: 11:0:0:0
  SysFS Device Link: /devices/pci0000:00/0000:00:14.0/usb2/2-5/2-5.4/2-5.4:1.0/host11/target11:0:0/11:0:0:0
  Hardware Class: disk
  Model: "USB 3.0"
  Vendor: "USB"
  Device: "3.0"
  Revision: "0508"
  Serial ID: "0123456789ABCDEF"
  Driver: "uas", "sd"
  Driver Modules: "uas"
  Device File: /dev/sdg (/dev/sg8)
  Device Files: /dev/sdg, /dev/disk/by-id/scsi-1USB_3.0_0123456789ABCDEF, /dev/disk/by-id/scsi-33000000000000800, /dev/disk/by-id/scsi-SUSB_3.0_0123456789ABCDEF, /dev/disk/by-id/usb-USB_3.0_0000000000080-0:0, /dev/disk/by-id/wwn-0x3000000000000800, /dev/disk/by-path/pci-0000:00:14.0-usb-0:5.4:1.0-scsi-0:0:0:0
  Device Number: block 8:96-8:111 (char 21:8)
  Geometry (Logical): CHS 62260/255/63
  Size: 1000215216 sectors a 512 bytes
  Capacity: 476 GB (512110190592 bytes)
  Config Status: cfg=new, avail=yes, need=no, active=unknown
  Attached to: #31 (USB Controller)

Gemäß der Meldungen des Controllers geht der uas-Treiber von Sektoren mit 512 Bytes aus. “lsusb” sieht den Controller von JMicron und dmesg bestätigt den Anschluss eines SuperSpeed USB Devices; das ist ein klarer Hinweis auf USB 3.0, was denn auch bestätigt wird:

mytux:~ # lsusb
...
Bus 002 Device 004: ID 152d:0578 JMicron Technology Corp. / JMicron USA Technology Corp. 
Bus 002 Device 002: ID 174c:3074 ASMedia Technology Inc. ASM1074 SuperSpeed hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
...
mytux:~ # lsusb -t
...
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/10p, 5000M
    |__ Port 5: Dev 2, If 0, Class=Hub, Driver=hub/4p, 5000M
        |__ Port 4: Dev 3, If 0, Class=Mass Storage, Driver=uas, 5000M
...
mytux:~ # dmesg
.... 
7103.869903] usb 2-5.4: new SuperSpeed USB device number 3 using xhci_hcd
[ 7103.890930] usb 2-5.4: New USB device found, idVendor=152d, idProduct=0578
[ 7103.890933] usb 2-5.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 7103.890936] usb 2-5.4: Product: USB
[ 7103.890938] usb 2-5.4: Manufacturer: jmicron
[ 7103.890941] usb 2-5.4: SerialNumber: 0000000000080
[ 7103.916378] usbcore: registered new interface driver usb-storage
[ 7103.920168] scsi host11: uas
[ 7103.920546] scsi 11:0:0:0: Direct-Access     USB      3.0              0508 PQ: 0 ANSI: 6
[ 7103.921082] sd 11:0:0:0: Attached scsi generic 
sg8 type 0
[ 7105.936733] usbcore: registered new interface driver uas
[ 7105.937350] sd 11:0:0:0: [sdg] 1000215216 512-byte logical blocks: (512 GB/477 GiB)
[ 7105.937351] sd 11:0:0:0: [sdg] 4096-byte physical blocks
[ 7105.937488] sd 11:0:0:0: [sdg] Write Protect is off
[ 7105.937489] sd 11:0:0:0: [sdg] Mode Sense: 53 00 00 08
[ 7105.937753] sd 11:0:0:0: [sdg] Disabling FUA
[ 7105.937755] sd 11:0:0:0: [sdg] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 7105.940713]  sdg: sdg1 sdg2 sdg3 sdg4 sdg5 sdg6
[ 7105.942448] sd 11:0:0:0: [sdg] Attached SCSI disk
[ 

Hinweis: Intern nutzt die SATA-Platte einen Samsung-eigenen MEX-Controller. Die Platte erscheint bei mir als Laufwerk /dev/sdg. (Der aufmerksame Leser hat auch registriert, dass auf dieser SSD schon mal 6 Test-Partitionen angelegt wurden; das tut den nachfolgende Ausführungen aber keinen Abbruch 🙂 .)

Partitionserstellung und Alignment-Korrekturen

Ich legte dann die ersten der im letzten Artikel diskutierten Partitionen mit YaST’s Partitioner an. Wie in

Linux SSD partition alignment – problems with external USB-to-SATA controllers – I
Linux SSD partition alignment – problems with external USB-to-SATA controllers – II

im Detail erläutert und begründet, führte das zu einem Alignment der Startadressen von Partitionen auf Vielfache von 65535 (512 Byte)-Sektoren.

65535 Sektoren entsprechen 33553920 Bytes, oder ca. 31,9995 MiB. Das wiederum entspricht nicht einem erwarteten 1MiB-Alignment (Vielfache von 2048 Sektoren oder Blocks a 512 Byte) für SSDs.

“fdisk” meldet entsprechend Folgendes:

mytux:~ # fdisk -l -u /dev/sdg
Disk /dev/sdg: 477 GiB, 512110190592 bytes, 1000215216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 33553920 bytes
Disklabel type: gpt
Disk identifier: 16AE9144-0451-4038-8D0D-D74F627D479B

Device         Start       End   Sectors  Size Type
/dev/sdg1      65535    131069     65535   32M BIOS boot
/dev/sdg2     131070   1376234   1245165  608M EFI System
/dev/sdg3    1376235  37027274  35651040   17G Linux swap
....
Partition 1 does not start on physical sector boundary.
Partition 2 does not start on physical sector boundary.
Partition 3 does not start on physical sector boundary.
...

Ein genauer Blick auf den Output zeigt, dass der Controller eine physikalische Block-Size von 4096 Byte vorgaukelt. Das erklärt die Warnungen. Nun gilt aber:

  • Die Samsung SSD selbst meldet andere Topologie-Parameter für die logische und physikalische Sektor-Größe (beide 512 Byte) und auch für die minimale und optimale I/O-Size, wenn sie direkt an einem SATA-III-Controller angeschlossen ist; siehe dazu die oben genannten Artikel. Schuld an dem seltsamen Alignment sind also Standard-Einstellungen für die parted-Bibliothek, auf die YaSTs Partitioner aufsetzt und der entsprechende Umgang mit den verschiedenen I/O-Sizes: Für das Aligment wird die optimale I/O-Size (hier: 33553920 Bytes) herangezogen.
  • Dieselbe SSD (!) erführe direkt an einem SATA-Controller ein anderes, nämlich ein 1MiB-Standard-Alignment. Sie
    meldet nämlich eine optimale I/O-Size von “0”, was gemäß einer “Heuristik” dann zum 1MiB-Alignment führt (s. die genannten Artikel).

Das durch den externen Controller erzwungene Alignment kann später eine negative Auswirkung auf die Performance der SSD nach sich ziehen, wenn die dann direkt an den SATA-III-Bus des Laptops angeschlossen wird. Zudem wird man Systemmeldungen zu einem problematischen Alignment erhalten. Ich empfehle daher in solchen Situationen, von vornherein eine Korrektur auf ein Standard-1MiB-Alignment (Startadressen und Größe der Partitionen als Vielfaches von 2048 Sektoren) vorzunehmen.

Die “Korrektur” erfordert eine manuelle (Neu-) Anlage der geplanten Partitionen mit dem YaST-Partitioner unter Eingabe der Start- und Endblöcke (bzw. Sektoren). Ein dem 1MiB-Standard besser entsprechendes Layout ist etwa:

mytux:/ # fdisk -l -u /dev/sdg
Disk /dev/sdg: 477 GiB, 512110190592 bytes, 1000215216 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 33553920 bytes
Disklabel type: gpt
Disk identifier: 16AE9144-0451-4038-8D0D-D74F627D479B

Device         Start       End   Sectors  Size Type
/dev/sdg1      65536    131071     65536   32M BIOS boot
/dev/sdg2     131072   1400831   1269760  620M EFI System
/dev/sdg3    1400832  37052415  35651584   17G Linux LVM
/dev/sdg4   37052416 529883135 492830720  235G Linux LVM

Alle Startsektor-Nummern wie auch die Größe der Partitionen sind nun ohne Rest durch 2048 teilbar (1 MiB-Alignment). Ihr erkennt sicher, dass ich am Anfang ca. 32 MB Platz gelassen habe. Das ist nicht notwendig, entspricht aber der sog. optimal_io_size des JMicron -Ccontrollers besser.

Volume Groups und Logische Volumes

Der aufmerksame Leser durch den letzten Output schon mitbekommen, dass ich zwei Partitionen für LVM-Betrieb ausgelegt habe:

  • /dev/sdg3 für den späteren SWAP (über LUKS on LVM !);
  • /dev/sdg4 für verschiedenen LVM-Volumes – u.a. eines für das spätere root-Filesystem.

Da wir zunächst “LUKS on LVM”-Konfigurationen testen wollen, möchte ich zwei zugehörige Volume Groups [VG] – “vgs” und “vga” – definieren, von denen jede jeweils eine der genannten Partitionen umfasst.

Legt man die VGs naiverweise mit YaST’s Partitioner an, handelt man sich jedoch erneut ein Alignment-Problem ein: Auch die unter Opensuse Leap für das LVM-System standardmäßig aktivierte “Alignment-Detection” nutzt den Wert der optimalen I/O-Size für den Offset des Datenbereichs in der Volume Group.

Man kann das am Beispiel einer Partition “/dev/sdg7” studieren, die auf 1MiB-Partitionsgrenzen ausgerichtet wurde. Nach der Erzeugung einer Volume Group [VG] mit YaST, die die gesamte Partition als Physical Volume [PV] finden wir mittels des Kommandos “pvs”:

mytux:~ # pvs -o +pe_start,vg_extent_size --units s /dev/sdg7
  PV         VG  Fmt  Attr PSize     PFree     1st PE  Ext  
  /dev/sdg7  vgb lvm2 a--  10420224S 10420224S  65535S 8192S

Der erste “Physical Extend” (1st PE) hat einen Offset von 65535 Sektoren – was nicht zum 1MiB-Alignment passt.

Wie müssen wir alos vorgehen, um das für die Partitionen /dev/sdg3 und /dev/sdg4 besser zu machen? Ich erläutere das für “/dev/sdg3”. Ich gehe dabei davon aus, dass man über YaST bereits eine VG “vgs” angelegt hatte. Wir müssen dann zunächst diese VG und auch alle PV-Signaturen entfernen:

 
mytux:~ # vgchange -a n vgs
  0 logical volume(s) in volume group "vgs" now active
mytux:~ # vgremove vgs
  Volume group "vgs" successfully removed
mytux:~ # pvremove /dev/sdg3
  Labels on physical volume "/dev/sdg3" 
successfully wiped.

Dann erzeugen wir die VG erneut:

 
mytux:/ # vgcreate  -s 4M --dataalignment 2048s  -f -v  vgs /dev/sdg3 
    Wiping internal VG cache
    Wiping cache of LVM-capable devices
    Wiping signatures on new PV /dev/sdh3.
    Set up physical volume for "/dev/sdg3" with 35651584 available sectors.
    Zeroing start of device /dev/sdg3.
    Writing physical volume data to disk "/dev/sdg3".
  Physical volume "/dev/sdg3" successfully created.
    Adding physical volume '/dev/sdg3' to volume group 'vgs'
    Archiving volume group "vgs" metadata (seqno 0).
    Creating volume group backup "/etc/lvm/backup/vgs" (seqno 1).
  Volume group "vgs" successfully created

Zu den Parametern siehe die Man-Seiten. (Den Parameter –dataalignmentoffset konnte ich dabei ignorieren; er wird vom JMicron Controller korrekt mit 0 angegeben.)

Standardmäßig werden Extends von 4.00 MiB angelegt. Wir erhalten (in Units von Sektoren):

mytux:/ # pvs -o +pe_start,vg_extent_size --units s /dev/sdg3
  PV         VG  Fmt  Attr PSize     PFree     1st PE  Ext  
  /dev/sdg3  vgs lvm2 a--  35643392S 35643392S   2048S 8192S

Gut! Genauso geht man anschließend für “/dev/sdg4” vor.

     
mytux:~ # vgchange -a n vga
  0 logical volume(s) in volume group "vga" now active
mytux:~ # vgremove vga
  Volume group "vga" successfully removed
mytux:~ # pvremove /dev/sdg4
  Labels on physical volume "/dev/sdg4" successfully wiped.
mytux:~ # vgcreate  -s 4M --dataalignment 2048s  -f -v  vga /dev/sdg4
    Wiping internal VG cache
    Wiping cache of LVM-capable devices
    Wiping signatures on new PV /dev/sdg4.
    Set up physical volume for "/dev/sdg4" with 492830720 available sectors.
    Zeroing start of device /dev/sdg4.
    Writing physical volume data to disk "/dev/sdg4".
  Physical volume "/dev/sdg4" successfully created.
    Adding physical volume '/dev/sdg4' to volume group 'vga'
    Archiving volume group "vga" metadata (seqno 0).
    Creating volume group backup "/etc/lvm/backup/vga" (seqno 1).
  Volume group "vga" successfully created
mytux:~ # pvs -o +pe_start,vg_extent_size --units s /dev/sdg4
  PV         VG  Fmt  Attr PSize      PFree      1st PE  Ext  
  /dev/sdg4  vga lvm2 a--  492822528S 492822528S   2048S 8192S

Die logischen Volumes kann man dann wieder mit YaST anlegen. Es geht natürlich aber auch auf der Kommandozeile; z.B.:

     
mytux:~ # lvcreate -n lva1 -L80G vga
  Logical volume "lva1" created.
mytux:~ # lvdisplay /dev/vga
  --- Logical volume ---
  LV Path                /dev/vga/lva1
  LV Name                lva1
  VG Name                vga
  LV UUID                0jfDMG-QsKz-kafl-Icaf-OxCO-KrHw-Ag3CPh
  LV Write Access        read/write
  LV Creation host, time mytux, 2018-12-11 16:53:26 +0100
  LV Status              available
  # open                 0
  LV Size                80.00 GiB
  Current LE             20480
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     1024
  Block device           254:18
mytux:~ #  
mytux:~ # lvcreate -n lvs1 -l100%VG vgs
  Logical volume "lvs1" created.
mytux:~ # lvdisplay /dev/vgs
  --- Logical volume ---
  LV Path                /dev/vgs/lvs1
  LV Name                lvs1
  VG Name                vgs
  LV UUID                MLWZps-KL3l-Y1Hs-9EVM-BlBk-J1Cn-QvHNJn
  LV Write Access        read/write
  LV Creation host, time mytux, 2018-12-10 14:37:58 +0100
  LV Status              available
  # open                 0
  LV 
Size                17.00 GiB
  Current LE             4351
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     1024
  Block device           254:17
mytux:~ # lvs 
  LV          VG       Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  ...
  lva1        vga      -wi-a-----  80.00g                                                    
  lvs1        vgs      -wi-a-----  17.00g  
  ..

Wir haben nun sowohl ein Logical Volume “/dev/vgs/lvs1” zur späteren Anlage eines SWAP als auch ein Volume “/dev/vga/lva1” zur Anlage eines root-Filesystems für unsere Installation. Das genügt für erste Tests von “Luks on LVM”. Weitere Partitionen und Volumes legen wir später nach dem gleichen Muster an. (Das ganze Theater mit dem manuellen Alignment entfällt natürlich, sobald man die SSD in den Laptop eingebaut hat.)

Verschlüsselung der Volumes – Parameter für cryptsetup

Erst aber müssen wir aber unsere Logical Volumes, die bislang als unformatierte Raw Devices fungieren, verschlüsseln. Dazu benutzen wir den Befehl “cryptsetup luksFormat”. Zuvor müssen wir uns aber die Größe bestimmter Parameter überlegen.

Die Sicherheit von LUKS hängt u.a. am PBKDF2-Verfahren, das eine eingegebene Passphrase mit vielen Iterationen in einen Hash umwandelt, der uns dann den Zugang zum LUKS-Master-Key [MK] für das verschlüsselte Volume verschafft. Vorgegeben wird die Iterationszahl normalerweise über eine Zeitangabe (iter-time). Siehe hierzu
crypt/Luks – Begriffe, Funktionsweise und die Rolle des Hash-Verfahrens – I.

Nun ist mein Desktop etwa um einen Faktor 3 leistungsfähiger als mein Laptop. Noch wichtiger ist jedoch, dass Grub2 bzgl. der Durchführung von PBKDF2-Iterationen im Vergleich zum Kernel eine lahme Ente ist. Im Artikel
Full encryption with LUKS (SHA512, aes-xts-plain64) – grub2 really slow …
hatte ich bereits erläutert, dass ein Faktor 7 bis 8 (!) an Performance-Reduktion bzgl. PBKDF2-Iterationen möglich ist. Die Performance des Kernels kann man mit dem Kommando “cryptsetup benchmark” testen:

mytux:~ # cryptsetup benchmark
# Tests are approximate using memory only (no storage IO).
..
PBKDF2-sha256    1349518 iterations per second for 256-bit key
PBKDF2-sha512    1182160 iterations per second for 256-bit key
...

Der Kernel schafft an meinem Desktop (!) ca. 1,2 Millionen Iterationen für SHA256 oder SHA512 pro Sekunde. Wir gehen zur Sicherheit erstmal auf 300.000 Iterationen herunter. Ich rechne dann mit einer Zeit von Grub2 am Laptop für die initiale Entschlüsselung bis zur Anzeige der Grub-Optionen im Bereich < 10 Sek. Das kann ich gerade noch ertragen. Die Verringerung der Iterationszahl bedeutet aber einen Abstrich an Sicherheit (!!).

Wie gesagt: Es ist Grub2, das diese Reduktion erforderlich macht – nicht der Kernel selbst. Ist der erstmal geladen, geht alles viel schneller. Wir werden später testen, ob wir zumindest die Anzahl an Iterationen für den SWAP-Bereich und Volumes für virtualisierte Systeme nicht erheblich erhöhen können.

Wie können wir nun die gewünschte Iterationszahl für LUKS-1-Volumes direkt vorgeben? Hierzu gibt es die Option “–pbkdf-force-iterations”.

Weitere LUKS-Parameter
Wir möchten als Basis-Hash-Verfahren für PBKDF2 SHA512 einsetzen. Auch der zentrale Master-Key für die (symmetrische) Verschlüsselung der Daten soll eine Länge von 512 Bit haben. Das hat u.a. damit zu tun, dass dies bei Einsatz von XTS-Verfahrens (wie aes-xts-
plain64) XTS-512 faktisch einem Sicherheitsstandard von AES-256, also einer Schlüssellänge von 256 Bit, entspricht. Siehe hierzu die am Ende des Artikels angegebenen Links.

Ferner gilt es, auch bei der Verschlüsselung mit LUKS einen Offset-Parameter zu beachten:
Header und Datenbereich (= Payload) sind getrennt. Das Alignment des Payload-Bereichs wird durch einen Parameter “–align-payload” geregelt. Wir setzen ihn für ein 1MiB-Alignment auf “2048”. (Hinweis: Den kleinst möglichen Offset erhält man mit –align-payload=8 ).

Insgesamt landen wir dann bei einem Kommando der Form

cryptsetup –cipher aes-xts-plain64 –key-size 512 –hash sha512 –pbkdf-force-iterations 300000 –align-payload=2048 -v luksFormat   /dev/vgs/lvs1

zur Initialisierung der Verschlüsselung für unser Raw Volume “/dev/vgs/lvs1”. Falls das Schriftbild in der Abbildung zu unklar sein sollte: Alle Optionen bis auf “v” haben ein Doppel “-” => “–“.

“cryptsetup luksFormat” erstellt dabei den sogenannten “LUKS-Header” am Beginn des zu verschlüsselnden Volumes, erzeugt den Master-Key [MK] zur Datenverschlüsselung, verschlüsselt diesen mit einem Hash, der aus der abgefragten Passphrase über das PBKDF2-Verfahren erzeugt wird, und legt den MK in verschlüsselter und gesplitteter Form (Stripes) ab. Ferner wird der Offset des Datenbereichs (Payload) definiert. “luksFormat” nimmt allerdings noch keine Formatierung des Payload-Bereichs im Sinne eines Filesystems vor!

mytux:~ # cryptsetup --cipher aes-xts-plain64 --key-size 512 --hash sha512 --pbkdf-force-iterations 300000  --align-payload=2048 -v luksFormat /dev/vgs/lvs1

WARNING!
========
This will overwrite data on /dev/vgs/lvs1 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase for /dev/vgs/lvs1: 
Verify passphrase: 
Command successful.

mytux:~ # cryptsetup luksDump /dev/vgs/lvs1
LUKS header information for /dev/vgs/lvs1

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha512
Payload offset: 4096
MK bits:        512
MK digest:      5d .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
MK salt:        bc .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
                61 .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
MK iterations:  18750
UUID:           d6bcf6fb-641c-4238-4f55-bc677d22d245

Key Slot 0: ENABLED
        Iterations:             300000
        Salt:                   q5 .....
                                44 ...
        Key material offset:    8
        AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED
mytux:~ # 

Hinweise:

  • cryptsetup luksDump(s.u.) gibt die Anzahl der in 512 Byte Blöcken an (4096 * 512 = 2MiB). Zur Bedeutung der verschiedenen Angaben siehe meine früheren Artikel zu LUKS in diesem Blog.
  • Man sieht, dass die Anzahl der PBKDF2-Iterationen für den MK-Digest (Fingerprint) des Master-Keys deutlich geringer als die Anzahl der Iterationen für den bislang einzigen Key-Slot (um einen typischen Faktor 16); das ist aber nicht so sicherheitsrelevant wie die Anzahl der Iterationen zur Berechnung des Keys selbst. Wie man es schafft, hier größere Werte zu bekommen und trotzdem die Iterationszahl für die Passphrases zu begrenzen, erläutere ich im nächsten Artikel.
  • Der Platzbedarf für den Offset umfasst für unsere Alignment-Vorgabe typische 2 MiB.

Analog geht man für “/dev/vga/lva1” vor. Ich verzichte hier auf die Darstellung der Kommandos
und des Outputs.

Hinweis:

Es kann durchaus sinnvoll sein, für die Ver-/Entschlüsselung des root-Filesystem und des Swaps die gleiche Passphrase zu benutzen. Das spart im Boot-Vorgang später Zeit und überflüssige Eingaben, wenn man Plymouth nutzt (s. den übernächsten Artikel).

Wir haben nun zwei verschlüsselte Logical Volumes; die zugehörigen Crypto-UUIDs sind:

lvs1 – Crypto-UUID: d6bcf6fb-641c-4238-4f55-bc677d22d245
lva1 – Crypto-UUID: db43615a-23e2-5125-49c1-ccbc2041e76c

Diese Crypto-UUIDs sind wichtig für spätere Einträge in der Grub-Konfiguration.

Swap und Filesystem

Es bleibt noch, Filesysteme und den SWAP anzulegen. Das geht in diesem Stadium am einfachsten über die Kommandozeile. In jedem Fall muss das betreffende Volume zuerst mittels des Kommandos “cryptsetup open” für die Entschlüsselung geöffnet werden. Dabei werden neue Einträge unter “/dev/mapper” erzeugt; die Bezeichnung des gemappten Devices (hier: cr-sdg-swap) ist vorzugeben:

mytux:~ # cryptsetup open /dev/vgs/lvs1 cr-sdg-swap
Enter passphrase for /dev/vgs/lvs1: 
mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     480 Dec 12 12:34 .
drwxr-xr-x 29 root root   12480 Dec 12 12:34 ..
crw-------  1 root root 10, 236 Dec 12 08:58 control
lrwxrwxrwx  1 root root       8 Dec 12 12:19 cr-sdg-swap -> ../dm-19
..
lrwxrwxrwx  1 root root       8 Dec 12 12:34 vga-lva1 -> ../dm-17
lrwxrwxrwx  1 root root       8 Dec 12 12:18 vgs-lvs1 -> ../dm-18
...
mytux:~ # mkswap /dev/mapper/cr-sdg-swap
mkswap: warning: /dev/mapper/cr-sdg-swap is misaligned
Setting up swapspace version 1, size = 17 GiB (18247315456 bytes)
no label, UUID=663e1134-ab5d-3aac-bb6f-d45b7b1f34dc

Die Warnung zum “misaligned swap” ignorieren wir; sie ist angesichts unseres Abweichens von den vom Controller vorgegaukelten I/O-Size-Daten verständlich. Aber wir sorgen ja für den späteren SATA-III-Betrieb vor.

Nun führen wir analoge Schritte für das Volume “/dev/vga/lva1” durch, welches später unser root-Filesystem (inkl. /boot-Directory) aufnehmen soll:

mytux:~ # cryptsetup open /dev/vga/lva1 cr-sdg-root
Enter passphrase for /dev/vga/lva1: 
mytux:~ # la /dev/mapper
total 0
drwxr-xr-x  2 root root     480 Dec 12 12:34 .
drwxr-xr-x 29 root root   12480 Dec 12 12:34 ..
crw-------  1 root root 10, 236 Dec 12 08:58 control
lrwxrwxrwx  1 root root       8 Dec 12 12:37 cr-sdg-root -> ../dm-20
lrwxrwxrwx  1 root root       8 Dec 12 12:19 cr-sdg-swap -> ../dm-19
...
lrwxrwxrwx  1 root root       8 Dec 12 12:34 vga-lva1 -> ../dm-17
lrwxrwxrwx  1 root root       8 Dec 12 12:18 vgs-lvs1 -> ../dm-18
..

mytux:~ # mkfs.ext4 /dev/mapper/cr-sdg-root
mke2fs 1.43.8 (1-Jan-2018)
Creating filesystem with 20971008 4k blocks and 5242880 inodes
Filesystem UUID: a3202dac-a44e-4344-b551-dd123ce893b2
Superblock backups stored on blocks: 
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
        4096000, 7962624, 11239424, 20480000

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (131072 blocks): done
Writing superblocks and filesystem accounting information: done   

Details zum Filesystem fragt man bei Bedarf über “tune2fs -l /dev/mapper/cr-sdg-root” ab.

Relevant sind hier wieder die UUIDs für die formatierten Volumes bzw. Filesysteme; diese weichen von jenen der Crypto-Devices ab(!):

root-fs: UUID=a3202dac-a44e-4344-b551-dd123ce893b2
swap:   UUID=663e1134-ab5d-3aac-bb6f-d45b7b1f34dc

Diese UUIDs sind später
für Einträge in die Datei “/etc/fstab” relevant.

Man vergesse zum Abschluss unserer Übung nicht, die geöffneten Crypto-Devices wieder zu schließen:

mytux:~ # cryptsetup close cr-sdg-root
mytux:~ # cryptsetup close cr-sdg-swap

Fazit und Ausblick

Externe USB-to-SATA-Controller zwingen einen während der Testphase mit einer externen SSD zur Korrektur des Alignments für den späteren Betrieb des Devices am SATA-III-Bus des Laptops. Dabei ist das 1-MiB-Alignment nicht nur bzgl. der Partitionen, sondern auch bzgl. des ersten Extends der PV/VG-Struktur unter LVM zu beachten. Ferner ist das Offset des Datenbereichs in LUKS-verschlüsselten Volumes an 1MiB-konformen Sektorgrenzen auszurichten.

“LUKS on LVM” lässt sich danach in wenigen, überschaubaren Schritten realisieren. Bzgl. der Anzahl von PBKDF2-Iterationen sollte man die generelle Performance des Endgeräts (hier: des Laptops) über “cryptsetrup benchmark” ermitteln – und dann für die Verzögerungen beim Booten durch Grub2 einen Faktor > 7 einrechnen.

Im nächsten Beitrag

Laptop – SSD mit dm-crypt/Luks -Verschlüsselung und Opensuse Leap 15 – VI – Key-Slots, PBKDF2- und MK-Iterationen

befasse ich mich mit einer individuellen Festlegung der PBKDF2-Iterationen für den Master-Key-Digest und die LUKS-Slots. Zudem erstellen wir Backups der LUKS Header.

Links

Generelles Vorgehen zur Verschlüsselung
https://www.schnatterente.net/software/gentoo-linux-komplett-verschluesseln
https://wiki.archlinux.org/index.php/Dm-crypt/Encrypting_an_entire_system

Alignment Probleme mit externen Controllern
https://superuser.com/questions/1291467/trouble-figuring-out-optimal-alignment-of-multiple-partitions-on-a-931-5-gib-ext
https://www.suse.com/de-de/support/kb/doc/?id=7007193

Alignment und Swap-Encryption
https://unix.stackexchange.com/questions/421587/dmsetup-luksformat-creating-an-alignment-inconsistency/421588
https://nwrickert2.wordpress.com/2017/12/05/another-install-of-opensuse-15-0/
https://lizards.opensuse.org/2009/07/13/

Zeitdauer Boot und LUKS-Parameter
Cryptsetup FAQ of the Gitlab Wiki für “cryptsetup” und dort im besonderen Section 3.5 zu “Unlocking a LUKS device takes very long …”.

Backup of header
https://blog.tinned-software.net/create-a-luks-encrypted-partition-on-linux-mint/

Luks und LVM
https://resources.infosecinstitute.com/luks-and-lvm/

Symmetrisches XTS-Verschlüsselung
https://security.stackexchange.com/questions/101995/explanation-of-the-xts-encryption-mode
https://en.wikipedia.org/wiki/Disk_encryption_theory