Show-EncryptionAsymmetric

Ich hatte vor Kurzem die Aufgabe, ein Script zu schreiben, dass vertrauliche Informationen auslesen und im Dateisystem ablegen muss. Das Script soll im Systemkontext als geplante Aufgabe laufen. Die gespeicherten Informationen müssen geschützt abgelegt sein. NTFS-Berechtigungen und EFS-Verschlüsselung hab ich ausgeschlossen. Dann gäbe es ja noch eine symmetrische Verschlüsselung (siehe Beitrag von 27.09.2017). Dafür muss aber das Script aber über den Schlüssel verfügen. Nur wo soll man den speichern? In einer Textdatei? Dann macht die Verschlüsselung keinen Sinn, wenn sie wäre mit dem Key und der Logik für einen Angreifer kein Hindernis.

Besser wäre eine asymmetrische Verschlüsselung. Diese basiert auf einem Schlüsselpaar, bestehend aus einem PrivareKey und einem PublicKey. Über mathematische Zusammenhänge ist (aktuell) sichergestellt, dass

  • Inhalt, der mit dem PrivateKey verschlüsselt wurde nur mit dem PublicKey entschlüsselt werden kann
  • Inhalt, der mit dem PublicKey verschlüsselt wurde nur mit dem PrivateKey entschlüsselt werden kann

Und genau dass wollte ich verwenden!

  • Ich gebe dem Script den PublicKey meines Zertifikates. Mit diesem Key kann der Angreifer nichts anfangen.
  • Das Script kann damit aber meinen Inhalt verschlüsselt ablegen.
  • Nur ich (der Eigentümer des PrivateKeys) kann den Inhalt wieder entschlüsseln. Und den PrivateKey lege ich eben NICHT mit beim Script ab. 🙂

Die PowerShell bietet aber leider keine BuildIn-Funktionen für einen asymmetrische Textverschlüsselung an. Dennoch kann man mit ihr auf die erforderlichen Zertifikate zugreifen und Methoden aus .net verwenden. Das war also mein Ansatz:

# lese ein Zertifikat aus meinem Benutzer-Zertifikatspeicher
# Für dieses muss ich einen PrivateKey haben:
    $CertThumbPrint = '180180CC2715AA4153D5D98385806CC8F64960C1'
    $Certificate    = Get-ChildItem -Path "Cert:\CurrentUser\My" | 
        Where-Object {$_.Thumbprint -eq $CertThumbprint}

# Das ist die Verschlüsselung
    $TextLesbar    = 'meine Geheimnisse'
    $TextBytes     = [System.Text.Encoding]::UTF8.GetBytes($TextLesbar)                        
    $TextEncrypted = $Certificate.PublicKey.Key.Encrypt($TextBytes,$true)

# Und das die Entschüsselung
    $TextBytes     = $Certificate.PrivateKey.Decrypt($TextEncrypted,$true)                    
    $TextLesbar    = [System.Text.Encoding]::UTF8.GetString($TextBytes) 
    $TextLesbar

Es ist also recht einfach. Und ohne PrivateKey im $Certificate gibt es auch keine Methode Decrypt… 🙂

Diesen Ansatz hab ich nun in 2 Funktionen verbaut. Dabei wollte ich möglichst universell arbeiten können. Was die Funktionen wie im einzelnen erledigen kann dem ZIP-File entnommen werden. Ich möchte hier aber direkt die Parameter der Funktionen erläutern.

Encrypt-String

Folgende Parameter habe ich deklariert:

, Show-EncryptionAsymmetric

Man kann den KlarText auf verschiedene Weise übergeben:

  • als Klartext-Argument für den Parameter String
  • über ein Formularfeld mit verdeckter Eingabe
  • oder über die Pipeline

Der PublicKey wird so angegeben

  • mit dem ThumbPrint als Argument für den Parameter $CertThumbprint (dann muss sich das Zertifikat im persönlichen Zertifikatspeicher des Benutzers ODER des Computers geben und die Berechtigung des Zugriffes muss gegeben sein)
  • ODER mit dem Dateisystempfad zur CER-Datei. Diese muss den PublicKey enthalten und erreichbar sein
  • ODER es wird die erste CER-Datei im aktuellen Verzeichnis gewählt (für Scripte recht angenehm: läuft das Zertifikat ab, tauscht man einfach die CER-Datei aus und der ScriptCode muss nicht geändert werden – Stichwort „Digitale ScriptSignatur“!)

Der letzte Parameter bestimmt über das Ausgabeverhalten der verschlüsselten Informationen. Per Default gibt die Funktion den EncryptedString über Return zurück, Alternativ kann aber auch ein Dateisystempfad für eine Datei angegeben werden. Diese Datei hat als Besonderheit in der ersten Zeile den Zertifikat-ThumbPrint des verwendeten Zertifikates. Das vereinfacht die Entschlüsselung in der 2. Funktion erheblich! 🙂

Mit ein paar Voraussetzungen kann ich es demonstrieren. Ich hab in meinem Verzeichnis eine Klartextdatei und ein Zertifikat mit einem PublicKey (es ist nur ein Sigel im Dateisymbol erkennbar. Ein PrivateKey wäre durch nen kleinen Schlüssel gekennzeichnet):

, Show-EncryptionAsymmetric

So könnte dann die Zertifikatauswahl aussehen:

, Show-EncryptionAsymmetric

Ein Export in eine Datei ist ebenso recht einfach. Seht ihr die erste Zeile in der Datei?

, Show-EncryptionAsymmetric

Und auch die verdeckte Eingabe ist einfach:

, Show-EncryptionAsymmetric

Was ist mit der Pipeline?

, Show-EncryptionAsymmetric

Funktioniert, oder? 🙂 Dann auf zur Entschlüsselung…

Decrypt-String

Folgende Parameter habe ich deklariert:

, Show-EncryptionAsymmetric

Der verschlüsselte Inhalt kann also entweder:

  • über den Parameter String als Argument übergeben werden
  • ODER über die Pfadangabe der vorher verschlüsselten Datei (Zur Erinnerung: diese Datei muss mit der Funktion Encrypt-String erzeugt worden sein!!!)
  • ODER mit einem über die Pipeline übergebenen Dateiobjekt

Nur bei der Angabe des Strings ist der Parameter $CertThumbprint erforderlich. Das dazu passende Zertifikat muss im persönlichen Zertifikatspeicher des Benutzers oder des Computers liegen (beim Computer-Store benötigt der User administrative Rechte).

So könnte dann die Anwendung aussehen:

, Show-EncryptionAsymmetric

, Show-EncryptionAsymmetric

Alles Zusammen

Den gesamten Code (mit PS-Hilfe und etlichen Beispielen) gibt es hier: Show-EncryptionAsymmetric

Testet aber bitte den Code, bevor ihr damit Daten verschlüsselt und danach nicht mehr entschlüsseln könnt. Wer sich den Code genau ansieht, wird sehen, dass ich da keinen MasterKey eingebaut habe… 🙂

Stay Tuned!

Kommentar hinterlassen