PowerShell und Hash-Werte

Wenn sie glauben, dass Hashwerte nur etwas zur Überprüfung von Dateien oder bei Signaturen (Kryptografie) zum Einsatz kommen, dann irren Sie sich.

Einsatzbereiche von Hash-Werte

Ein Hash-Wert ist eine Abbildung einer beliebigen Information in verkürzter numerischer Form über einen besonderen Algorithmus. Damit lassen sich allerlei Dinge anstellen.

  • Digitale Signatur
    Wer eine Information überträgt, speichert o.ä. möchte sichergehen, dass Sie unverändert ist. Bei einer Rechnung kann eine Zahl zu viel oder ein verschobenes Komma einen großen unterschied machen. Bei einem ausführbaren Programm kann eine kleine Veränderung ebenfalls großen Schaden herbei führen. Solche schützenswerte Daten können signiert werden. Dazu wird ein Hash-Wert über die Information erstellt und z.B. mit veröffentlicht. So kann jemand feststellen, ob ein Download einer Datei unverändert ist. Wird der Hashwert noch mit einer digitalen Signatur verbunden, kann sogar geprüft werden, wer die Information signiert hat.
  • Konsistenz kontrollieren
    Ein Hashwert ist zugleich eine Art "Prüfsumme". So lassen sich auch lokale Dateien oder Datenbestände mit einem Hashwert versehen und später verifizieren, ob diese unverändert noch vorliegen. Natürlich ist es theoretisch möglich, dass zwei Datenbestände den gleichen Hashwert haben, ob wohl wie nicht identisch sind. Das liegt in der Natur aber die Wahrscheinlichkeit ist deutlich geringer als andere Fehler.
  • Sortieren und Suchen
    Ein Hashwert ist in der Regel eine numerische Darstellung und Nummern sind sehr einfach Aufsteigend zu sortieren oder zu vergleichen. Das geht auf jeden Fall schneller als ein String-Vergleich o.ä. Daher werden viele Informationen als Hashwert mit einem Verweis auf die komplette Information gespeichert. Sucht ein Prozess nach einem Wert dann muss er einfach nur den Hashwert bilden, in der Tabelle nachschauen und bei einem Treffer dem Verweis an die Speicherstelle folgen. Nichts anderes sind "Hashtables" in PowerShell
  • Zuweisen und Verteilen
    Als numerische Werte kann man Hashwerte auch für eine Verteilung von Last verwenden. Ein Loadbalancer sollte die Last von Clients auf verschiedene Zielsysteme gleich verteilen. Ein einfacher Ansatz besteht darin, die Source-IP als Kriterium zu nehmen. Wer nun zwei Backend Server hat, könnte ja einfach alle "geraden" IP-Adressen zum Server und und alle ungeraden Quellen zu Server 2 senden. Das ist noch einfach aber es können ja auch drei oder mehr Server sein. Wer eine Exchange Mailbox anlegt und keine Datenbank angibt, erwartet von Exchange auch eine "Gleichverteilung" auf die Datenbanken. Selbiges gilt für Lync Enterprise Pools. Ein Hashwert über die Information ist schnell gebildet und mit einem "MODULO" auf den Hashwert ist eine gleichmäßige Verteilung sehr wahrscheinlich.
  • Anmeldedaten
    Die Übertragung und insbesondere die Speicherung von Kennworten ist sensibel. Ein Hashwert ist nicht reversibel, d.h. aus einem Hashwert kann das originale Kennwort nicht ermittelt werden. per BruteForce könnte man nur versuchen einen String zu finden, der den gleichen Hashwert ergibt aber der gefundene String ist nicht zwingend das Kennwort. Daher werden heute Zugangsdaten in der Regel nur noch als Hashwert gespeichert und nur noch der Hashwert verglichen.

Damit all das zuverlässig funktioniert, muss die Hash-Funktion Natürlich mehr sein als eine simple "Quersumme" und der Hash muss ausreichend Lang sein. Wer als Ergebnis eines Hash mit 8 Bit arbeiten würde, hätte mit nur 256 möglichen Werten ein Problem. Ein Hashwert mit 128 oder 256 Bit hingegen ist eine so große Zahl, dass eine Dublette höchst unwahrscheinlich ist.

Hashwert errechnen

Es gibt verschiedene mathematische Verfahren, um einen Hashwert zu errechnen. Viele Mathematiker haben sich mit der Thematik beschäftigt um einen robusten schnellen und zuverlässigen Algorithmus zu finden. Die Geschichte der Hashwerte ist schon sehr alt. Ganz am Anfang wurden einfache Paritybits addiert. Bei einer seriellen Übertragung wurden z.B. 8 Bit übertragen und ein weitere Bit hat die Summe der vorherigen Bits übermittelt. So konnten "Single Bit Fehler" erkannt werden aber nicht behoben werden. später wurden zwei Bit verwendet, um SingleBit Fehler zu korrigieren und Mehrbitfehler zu erkennen. Auch auf der CD/DVD gibt es sehr viele Prüfsummen, die eine Überprüfung und sogar Reparatur der Daten erlauben. Auch hier werden die Daten mit mathematischen Formeln zusammengefasst, um mit wenig Speicherplatz einen Mehrwert zu erreichen. Damit sich z.B., zwei Fehler nicht gegenseitig aufheben, dürfen die Daten nicht alle gleiche Gewichtung haben.

Zum Glück müssen sie heute kein Mathematiker sein und einen Hashalgorithmus muss man auch nicht mehr selbst schreiben. Er ist in vielen Betriebssystemen vorhanden und kann einfach genutzt werden.

Wenn Sie den Hash-Wert einer Datei ermitteln wollen, dann ist diese Funktion schon als PowerShell Commandlet vorhanden:

Natürlich können Sie das auch komplett selbst codieren. Interessant ist hier aber eher, dass der Code einen String über die Hash-Funktion verarbeitet. Sie können so also auch einen Hashwert über andere Inhalte erstellen. Hier eine ganz einfach PowerShell-Lösung, um einen String in einen SHA1-Hashwert zu überführen.

# Eventuell muss das Assembly erst referenziert werden
[Reflection.Assembly]::LoadWithPartialName("System.Security") | out-null '

# Verschiedene Versionen das Hashobjekt zu instanzieren
$hasher = [System.Security.Cryptography.SHA1]::Create()
$hasher = new-object System.Security.Cryptography.SHA256Managed

# verschiedene Methoden einen String in ein Bytearray zu überführen
#$bytes = [byte[]][char[]]"Dies ist ein teststring als CharArray zu ByteArray"
$bytes = [System.Text.Encoding]::UTF8.GetBytes("Dies ist ein teststring als CharArray zu ByteArray")

# Hashwert errechnen
$hash = $hasher.ComputeHash($bytes)

# Ausgabe als eine Zeile von Dezimalzahlen 
[string]$hash
# Ausgabe als eine Zeile von HEX-Zahlen
($hash = | foreach { $_.ToString("X2") }) -join ""

Der String kann Natürlich alles enthalten, d.h. den Inhalt einer Mail, eine SIP-Adresse oder sogar eine komplette Datei.

Wer eine entsprechende Windows Version mit Applocker hat, kann auch die Powershell hierzu verwenden:

PS C:\> Get-AppLockerFileInformation -Path C:\Windows\notepad.exe | fl

Path      : %WINDIR%\NOTEPAD.EXE
Publisher : O=MICROSOFT CORPORATION, L=REDMOND, S=WASHINGTON, C=US\MICROSOFT®
            WINDOWS® OPERATING SYSTEM\NOTEPAD.EXE,6.1.7601.18917
Hash      : SHA256
            0x82A726EDBC9C3F903F80F5A6A3C138CD32179932BBEEC20889DF4B629C1A2BCA

Hier wird ein SHA265 Hashwert erstellt.

Hashtable

PowerShell erlaubt wie jede Hochsprache eine Typisierung von Variablen. Anstatt also nur Bits und Bytes zu speichern, kann ich als Entwickler "Typ" einer Variabel vorgeben und der Interpreter/Compiler überprüft Zuweisungen auf ihre Plausibilität. Mit Strings darf man nicht rechnen und zählen während numerische Werte nicht zeichenbasiert verglichen werden dürfen. Siehe dazu auch PS Variablen. Eine besondere Typdefinition ist dabei die Hashtable, die unter VBScript als Dictionary-Objekt bezeichnet wurde. Sie können sich diese wie eine zweispaltige Tabelle vorstellen:

Key Wert

hash1

Wert1

hash2

Wert2

Die Werte können jeden Typ annehmen, also neben einem String oder Zahl auch ein komplexes Objekt sein die mit einem primären Schlüssel verbunden werden. Auch der Schlüssel kann ein beliebiges Objekt sein.

[hashtable]$hash=@{}
$hash.add("key1","value1")
$hash.add("key2","value2")

Eine andere Schreibweise ist

[hashtable]$hash=@{
   key1="value1"
   key2="value2"
}

PowerShell ermittelt dann einen Hashwert über den "Key" und speichert den Wert mit dem Key in der Tabelle. Als Ausgabe sieht das noch unspektakulär aus:

PS C:\> $hash

Name                           Value
----                           -----
key1                           value1
key2                           value2

Interessant wird das erst, wenn Sie schnell die Information zu einem bestimmten Wert suchen, der zugleich ein "Key" ist. Sie können ohne Suchen direkt über den Key auf die Werte zugreifen. Die Werte müssen dabei sich nicht auf Zeichenketten (strings) oder numerische Werte beschränken, sondern können auch komplexe Objekte sein.

Write-Host "Value of Key1:" $hash.item("key1")

Auch hier errechnet PowerShell wieder den Hashwert zu dem gegebenen Key und kann damit sehr schnell erkennen, ob eine Information zu dem Key gespeichert ist und da der Hashwert numerisch ist, ist der Vergleich sehr schnell. Bedeutend schneller als z.B. mit String-Vergleichen durch eine Tabelle zu flitzen. Da Hashwerte in der Tabelle auch immer gleich lang sind, kann man auch mit wenigen Schritten direkt an die Stelle springen und muss nicht sequentiell durchlaufen. Intern kann man an die Mitte springen und vergleichen ob der Hash größer oder kleine ist und dann wieder die Mitte der Hälfte anspringen etc.

Weitere Links