Einführung

Hier wird ein Setup von GnuPG beschrieben, welches den privaten Teil vom Primary Key auf einem verschlüsselten USB Stick offline speichert. Dies hat folgende Vorteile: Wird in das System eingebrochen, hat der Angreifer nur Zugriff auf die Subkeys und nicht auf den Primary Key. Dann muss man nicht alle Keys widerrufen, sondern nur die Subkeys. Dies hat bedeutet, dass die vorhandenen Key Signaturen behalten werden können und man nach belieben neue Keys zum Verschlüsseln und Signieren generieren kann ohne den Personen den neuen Key mitzuteilen, da der Primary Key unverändert bleibt.

GPG Key generieren

Diese Anleitung basiert auf der GnuPG Version 2.1.1.

Zuerst wird ein neuer GPG Key generiert. Dies wird mit der Option --full-gen-key gemacht, da man nur damit eine eigene Schlüsselgrösse angeben kann.

$ g p g - f u l l - g e n - k e y

Folgende Angaben werden benötigt:

  • (1) RSA and RSA (default): Algorithmus zum Verschlüsseln und Signieren
  • 4096: Schlüsselgrösse wird 4096 Bit
  • 2y: Der Schlüssel läuft in zwei Jahren automatisch ab
    • (Hinweis: Das Ablaufdatum kann aber jederzeit geändert werden. Falls man den Schlüssel aber verlieren sollte, ist man froh, wenn dieser automatisch nach einer gewissen Zeit ungültig wird)
  • Rainer Zufall: Vorname und Name
  • rainer.zufall@example.net: E-Mail Adresse

Dann wird man aufgefordert eine Passphrase einzugeben. Mit dieser wird der Key geschützt und sollte deshalb nicht zu einfach sein. Dauert das Generieren des Keys zu lange, liegt das daran, dass das Device /dev/random nur sehr wenig Zufallswerte liefert. Durch Tastatureingaben und Mausbewegungen wird mehr Entropie erzeugt. Hilfreich ist das Installieren und Aktivieren von haveged, ein Daemon welcher mehr Zufallszahlen generiert. Haveged gilt als sicher.

In diesem Beispiel hat der Key die Key ID 0xB1940999 erhalten.

Zusätzliche User IDs hinzufügen

Möchte man den Key für verschiedene E-Mail Adressen verwenden, kann man zusätzliche User IDs hinzufügen:

$ g R E g p e m p g g a a g p > l i > g l a n s d a a a - d m d v e u e d e d i : r i d e t R s - a s k i : e n y e r r a 0 i x Z n B u e 1 f r 9 a . 4 l z 0 l u 9 f 9 a 9 l l @ e x a m p l e . o r g

Keys und ihre Eigenschaften anzeigen

Mit -K werden die Private Keys aufgelistet. Mit -k werden die Public Keys aufgelistet. Für welche Zwecke die Schlüssel benutzt werden können, ist mit der Option --list-options show-usage zu sehen.

$ s u u s e i i s / g c d d b r p a g i n r r e - s s r l a a . i 4 4 z s 0 [ [ 0 u t 9 u u 9 f - 6 l l 6 a o / t t / l p B i i 3 l t 1 m m E @ i 9 a a F e o 4 t t 3 x n 0 e e E a s 9 ] ] A m 9 2 p s 9 R R 9 l h a a e o 2 i i 2 . w 0 n n 0 n - 1 e e 1 e u 4 r r 4 t s - - > a 1 Z Z 1 < g 2 u u 2 / e - f f - r 2 a a 2 a - 9 l l 9 i K l l n [ [ e 0 S < < E r x C r r ] . B ] a a z 1 i i [ u 9 [ n n e f 4 e e e x a 0 x r r p l 9 p . . i l 9 i z z r @ 9 r u u e e e f f s x s a a : a : l l m l l 2 p 2 @ @ 0 l 0 e e 1 e 1 x x 6 . 6 a a - o - m m 1 r 1 p p 2 g 2 l l - > - e e 2 2 . . 8 8 o n ] ] r e g t > >

Die erste Zeile gibt an, dass dies ein Private Key ist (sec). Danach sieht man die zwei erstellten User IDs. In der letzten Zeile sieht man, dass wir ein Subkey haben.

Was man mit den Keys machen kann, ist in den eckigen Klammern beschrieben. Dieses Verhalten finde ich nützlich und kann mittels list-options show-usage in der Konfigurationsdatei ~/.gnupg/gpg.conf standardmässig aktiviert werden. Zusätzlich ergänzte ich die Konfigurationsdatei mit keyid-format 0xshort, damit die Key IDs mit führendem 0x angezeigt werden. Aus der Manpage von gpg liest man zu den Verwendungszwecken folgendes:

  • E = encryption: Nachrichten ver/entschlüsseln
  • S = signing: Nachrichten signieren / Signatur von Nachrichten überprüfen
  • C = certification: Keys signieren / Signatur von Keys überprüfen
  • A = authentication: Sich gegenüber einem Dienst ausweisen

Der Primary Key 0xB1940999 wird also zum Signieren und zum Zertifizieren benötigt. Der Subkey wird zum entschlüsseln benötigt.

Unser Ziel ist es ein separater Key zum Signieren und Zertifizieren zu erstellen.

Separater Key zum signieren erstellen

Jetzt erstellen wir ein neuen Subkey, mit welchem nur signiert wird:

$ g ( [ g p 4 . p g g ) . g p > . > g R ] a S s d A a - d v e k ( e d e s i y i t g - n k e o y n l 0 y x ) B 1 9 4 0 9 9 9

Der Vorgang ist gleich wie beim erzeugen eines komplett neuen Keys, ausser das als Typ (4) RSA (sign only) ausgewählt wird.

Werden jetzt die Private Keys aufgelistet, sieht man, dass ein neuer Key vorhanden ist, mit welchem man Nachrichten signieren ( [S]) kann (letzte Zeile):

$ / s u u s s h e i i s s / g o c d d b b r p m a g e i / n - e r r r e K m s s s r a a a a . n 4 4 4 z u 0 0 0 u e 9 9 9 f l 6 [ [ 6 6 a / / u u / / l . 0 l l 0 0 l g x t t x x @ n B i i 3 D e u 1 m m E 1 x p 9 a a F 4 a g 4 t t 3 2 m / 0 e e E A p p 9 ] ] A A l u 9 2 3 e b 9 R R 9 C . r a a n i 2 i i 2 2 e n 0 n n 0 0 t g 1 e e 1 1 > . 4 r r 4 4 < k - - - / b 1 Z Z 1 1 r x 2 u u 2 2 a - f f - - i 2 a a 2 2 n 9 l l 9 9 e l l r [ [ [ . S < < E S z C r r ] ] u ] a a f i i [ [ a [ n n e e l e e e x x l x r r p p @ p . . i i e i z z r r x r u u e e a e f f s s m s a a : : p : l l l l l 2 2 e 2 @ @ 0 0 . 0 e e 1 1 o 1 x x 6 6 r 6 a a - - g - m m 1 1 > 1 p p 2 2 2 l l - - - e e 2 2 2 . . 8 8 8 o n ] ] ] r e g t > >

Zusammengefasst sieht unser Setup jetzt so aus:

  • Der Primary Key 0xB1940999 kann signieren und zertifizieren
  • Der Subkey 0x3EF3EA29 kann entschlüsseln
  • Der Subkey 0xD142AA3C kann signieren

Wir möchten privaten Teil vom Schlüssel 0xB1940999 auf ein verschlüsselten USB Stick auslagern.

Keys publizieren

Zuerst konfiguriert man GnuPG, dass ein Keyserver aus einem Pool ausgewählt wird. So hat man keine Probleme, falls der fix eingestellte Keyserver nicht erreichbar sein sollte. Dies wird in der Konfigurationsdatei ~/.gnupg/gpg.conf mit keyserver angegeben. Mit no-honor-keyserver-url sagt man, dass immer der lokal eingetragene Keyserver aus dem Pool verwendet werden soll.

k k e e y y s s e e r r v v e e r r - h o k p p t s i : n / s h k n p o s - . h p o o n o o l r . - s k k e s y - s k e e r y v s e e r r - v u e r r l s . n e t

Der Key kann folgendermassen auf ein Keyserver geladen werden:

$ g p g - s e n d - k e y s 0 x B 1 9 4 0 9 9 9

So kann auf Keyservern nach Public Keys gesucht werden:

$ g p g - s e a r c h - k e y R a i n e r Z u f a l l

Möchte man den Public Key exportieren um beispielsweise auf einer Webseite zu veröffentlichen, kann das so gemacht werden:

$ g p g - a r m o r - e x p o r t - o p t i o n s e x p o r t - m i n i m a l - e x p o r t 0 x B 1 9 4 0 9 9 9

Backup der Keys erstellen

Um ein Backup der Keys zu erstellen, kann man das ganze ~/.gnupg Verzeichnis auf ein externes Medium speichern und sicher aufbewahren. Dieses Medium kann zusätzlich verschlüsselt werden (vgl. nächstes Kapitel).

$ c p - r . g n u p g / / m n t / s e c u r e d e v i c e

Ein Wiederrufszertifikat kann folgendermassen erstellt werden:

$ g p g - g e n - r e v o k e - a r m o r 0 x B 1 9 4 0 9 9 9 > 0 x B 1 9 4 0 9 9 9 _ r e v o k e . a s c

Der Private Key inklusive die privaten Subkeys können folgendermassen exportiert und allenfalls auch ausgedruckt sicher aufbewahrt werden:

$ g p g - a r m o r - e x p o r t - s e c r e t - k e y s 0 x B 1 9 4 0 9 9 9 > 0 x B 1 9 4 0 9 9 9 _ p r i v a t e _ k e y s . a s c

Verschlüsselten USB Stick erstellen

Hierzu löscht man alle vorhandenen Partitionen und fügt eine neue hinzu. Dies kann man beispielsweise mit cfdisk machen. In meinem Beispiel wurde dem USB Stick das Device /dev/sdc zugewiesen.

$ s u d o c f d i s k / d e v / s d c

Jetzt verschlüsselt man mit cryptsetup das Device:

$ W = T A E V A = h r n e s R = i e t r u N = s e i d I = y r f o N = w o y G = i u p c ! = l a p r l s s a y u s s p r p s t v e h p s e ? r h e r a r t w ( s a u r T e s p i y : e t p : - e e c d u a a p e t p s a e - r x o c t n a s s - / e p d l e y a v e i / s n s ) d : - c y 1 Y E - i S s r r 5 e 1 v 2 o c l a u b k l s y F . o r m a t / d e v / s d c 1

Das Blöckgerät kann folgendermassen entschlüsselt werden:

$ E n s t u e d r o p c a r s y s p p t h s r e a t s u e p f l o u r k s / O d p e e v n / s / d d c e 1 v : / s d c 1 s e c u r e g p g

Nach dem Eingeben der Passphrase gibt es ein neues Gerät in /dev/mapper/securepgp. Auf dem wird ein neues Dateisystem angelegt:

$ m k f s . e x t 4 / d e v / m a p p e r / s e c u r e g p g

Dieses Dateisystem kann gemountet werden:

$ m o u n t / d e v / m a p p e r / s e c u r e g p g / m e d i a / s e c u r e g p g

Folgendermassen entfernt man den USB Stick wieder vom System:

$ $ u c m r o y u p n t t s e / t m u e p d i l a u / k s s e C c l u o r s e e g p / g d e v / m a p p e r / s e c u r e g p g

Der USB Stick ist jetzt einsatzbereit.

Privaten Primary Key auf USB Stick auslagern

Zuerst mounten wir den USB Stick und kopieren das Verzeichnis ~/.gnupg darauf:

$ E $ $ n s t m c u e o p d r u o n - p t r c a r s / . y s d g p p e n t h v u s r / p e a m g t s a u e p / p p m f e e l o r d u r / i k s a s / e / O d c s p e u e e v r c n / g u s p r / d g e d c g e 1 p v : / g / m / s e d d c i 1 a / s s e e c c u u r r e e g g p p g g

Dann löschen wir alle Private Keys (es gibt keine Option zum nur den Primary Key ohne die Subkeys zu löschen):

$ g p g - d e l e t e - s e c r e t - k e y s 0 x B 1 9 4 0 9 9 9

Da dies eine eher heikle Operation ist, müssen wir diese für jeden Privat Key bestätigen.

Jetzt besitzen wir aber gar kein Private Key mehr im Verzeichnis ~/.gnupg. Der Primary Key wollen wir dort nicht haben, aber die zwei Subkeys zum Entschlüsseln und Zertifizieren. In GnuPG kann mit der Option --homedir das GnuPG Verzeichnis mit dem Schlüsselmaterial angegeben werden. So können wir die Subkeys vom USB Stick exportieren und in die lokale Installation importieren:

$ g p g - h o m e d i r / m n t / s e c u r e g p g / . g n u p g / - e x p o r t - s e c r e t - s u b k e y s | g p g - i m p o r t

Dazu müssen wir die Passphrases der Private Keys eingeben.

Werden jetzt die Private Keys aufgelistet, sieht man am Hash ( #), dass der private Teil des Primary Keys fehlt, aber der Subkeys vorhanden sind.

$ / s u u s s h e i i s s / g o c d d b b r p m # a g e i / n - e r r r e K m s s s r a a a a . n 4 4 4 z u 0 0 0 u e 9 9 9 f l 6 [ [ 6 6 a / / u u / / l . 0 l l 0 0 l g x t t x x @ n B i i 3 D e u 1 m m E 1 x p 9 a a F 4 a g 4 t t 3 2 m / 0 e e E A p p 9 ] ] A A l u 9 2 3 e b 9 R R 9 C . r a a n i 2 i i 2 2 e n 0 n n 0 0 t g 1 e e 1 1 > . 4 r r 4 4 < k - - - / b 1 Z Z 1 1 r x 2 u u 2 2 a - f f - - i 2 a a 2 2 n 9 l l 9 9 e l l r [ [ [ . S < < E S z C r r ] ] u ] a a f i i [ [ a [ n n e e l e e e x x l x r r p p @ p . . i i e i z z r r x r u u e e a e f f s s m s a a : : p : l l l l l 2 2 e 2 @ @ 0 0 . 0 e e 1 1 o 1 x x 6 6 r 6 a a - - g - m m 1 1 > 1 p p 2 2 2 l l - - - e e 2 2 2 . . 8 8 8 o n ] ] ] r e g t > >

Somit ist unser Ziel erreicht: Der Private Teil des Primary Keys ist nur noch auf dem USB Stick gespeichert. Wenn wir jetzt Nachrichten signieren, wird der Subkey 0xD142AA3C verwendet und nicht der Primary Key.

Eigenen Key signieren lassen

Man kann sich wie gewohnt der Primary Key signieren lassen. An diesem Vorgang ändert sich nichts.

Fremde Keys signieren

Der Vorgang um fremde Keys zu signieren ist folgnder:

  • Fremder Public Key importieren
  • Fingerprint überprüfen
  • Falls OK, weiterfahren. Sonst abbrechen.
  • USB Stick entschlüsseln und mounten.
  • Public Key exportieren auf USB Stick importieren
  • Public Key auf USB Stick signieren
  • Public Key wieder auf die Keyserver hochladen
  • Signierter Key vom USB Stick exportieren und lokal importieren

Angenommen ich möchte den Key 0x23F00BA2 signieren. Dabei geht man folgendermassen vor:

Key von Keyserver importieren:

$ g p g - r e c v - k e y 0 x 2 3 F 0 0 B A 2

Der Key kann auch von einer Datei importiert werden:

$ g p g - i m p o r t < k e y . a s c

Fingerprint anzeigen und mit Fingerprint vergleichen, welcher man von der Person erhalten hat.

$ g p g - f i n g e r p r i n t 0 x 2 3 F 0 0 B A 2

Falls der Fingerprint ok ist, fährt man weiter. Sonst bricht man ab.

Jetzt wird der USB Stick eingesteckt und gemountet:

$ E $ n s t m u e o d r u o n p t c a r s / y s d p p e t h v s r / e a m t s a u e p p p f e l o r u r / k s s / e O d c p e u e v r n / e s g / d p d c g e 1 v : / / s m d e c d 1 i a s / e s c e u c r u e r g e p g g p g

Dann wird der Key exportiert und auf dem USB Stick importiert:

$ g p g - e x p o r t 0 x 2 3 F 0 0 B A 2 | g p g - h o m e d i r / m e d i a / s e c u r e g p g - i m p o r t

Und anschliessend auf der GnuPG Installation vom USB Stick signiert:

$ g p g - h o m e d i r / m e d i a / s e c u r e g p g - s i g n - k e y 0 x 2 3 F 0 0 B A 2

Der signierte Key kann wieder auf die Keyserver geladen werden:

$ g p g - h o m e d i r / m e d i a / s e c u r e g p g - s e n d - k e y s 0 x 2 3 F 0 0 B A 2

Damit der signierte Key auch lokal vorhanden ist, kann man den vom USB Stick exportieren und lokal wieder importieren:

$ g p g - h o m e d i r / m e d i a / s e c u r e g p g - e x p o r t 0 x 2 3 F 0 0 B A 2 | g p g - i m p o r t

Am Schluss wird der USB Stick wieder entfernt:

$ $ u c m r o y u p n t t s e / t m u e p d i l a u / k s s e C c l u o r s e e g p / g d e v / m a p p e r / s e c u r e g p g

Falls der gpg-agent noch auf dem Dateisystem sitzt, kann man diesen mit pkill gpg-agent stoppen. Bei der nächsten Verwendung von GnuPG wird dieser wieder gestartet.

Jetzt ist der Vorgang abgeschlossen: Der Key 0x23F00BA2 wurde mit dem Private Key welcher sich auf dem USB Stick befindet signiert, auf die Keyserver geladen und in der lokalen GnuPG Installation importiert.

Fremde Keys mit einem Skript signieren

Der obige Vorgang sieht etwas kompliziert aus und ist wenn man oft Keys signiert nicht sehr praktisch. Folgendes Skript nimmt einem die Tipparbeit ab:

#!/usr/bin/env bash

KEY="$1"
SECUREDEVICE="/dev/${2:-sdc1}"
SECUREDEVICENAME="securegpg"
SECUREHOME="/media/securegpg"
SECUREGPGDIR="$SECUREHOME/.gnupg"


PrintUsage(){
cat <<< EOI
Usage:
  securegpgsign key [devicename]
  securegpgsign -h | --help
Default Device name is sdc1
Examples:
  securegpgsign 0x23FOOBA2
  securegpgsign 0x23FOOBA2 sde
EOI
}

if  [[ $TEST == "-h" || $TEST == "--help" ]]
then
  PrintUsage
fi
if (($# < 1))
then
  PrintUsage
  exit 1
fi

gpg --recv-key "$KEY"
gpg --fingerprint "$KEY"

echo "Is the fingerprint correct?"
echo "Press Enter to continue or ^C to canel."

read

cryptsetup luksOpen "$SECUREDEVICE" "$SECUREDEVICENAME"
mount "/dev/mapper/$SECUREDEVICENAME" "$SECUREHOME"

gpg --export "$KEY"  | gpg --homedir "$SECUREGPGDIR" --import
gpg --homedir "$SECUREGPGDIR" --sign-key "$KEY"
gpg --homedir "$SECUREGPGDIR" --send-keys "$KEY"
gpg --homedir "$SECUREGPGDIR" --export "$KEY" | gpg --import
pkill gpg-agent
umount "$SECUREHOME"
cryptsetup luksClose "/dev/mapper/$SECUREDEVICENAME"

Mit dem Skript kann folgendermassen ein Key signiert werden:

s u d o / s e c u r e g p g s i g n 0 x 2 3 F O O B A 2 s d e

Die aktuellste Version davon gibt es auf GitHub in meinem Scripts Repository: securegpgsign.

Wir kein Devicename angegeben, wird sdc verwendet. Das Skript muss mit sudo aufgerufen werden, da das Einbinden des USB Sticks Rootrechte erfordert.