Tipp 0196 Kennwort sicher speichern
Autor/Einsender:
Datum:
  Michael Werner
30.11.2009
Entwicklungsumgebung:   VB.Net 2008
Framework:   2.0
Wenn Sie ein sensibles Passwort über SaltPasswortHash verschlüsseln und in der Registry sicher speichern, "versalzen" Sie jedem Hacker die Suppe: Ein Hash ist schon sehr schwer zurück zu verfolgen. Aber ein SaltHash setzt noch einen oben drauf: Er wirkt wie ein Salzstreuer in den Augen des Angreifers.
Ein SaltHash hängt an das Kennwort eine Zufalls-Byte-Folge mit bestimmter Länge an, so dass 
ein Entschlüsseln des Kennwortes praktisch unmöglich wird. Gespeichert wird der verschlüsselte SaltHash in der Registry mit Application.UserAppDataRegistry und dessen Methode SetValue (Lesen mit GetValue). In der Registry werden die Daten unter folgendem Pfad abgelegt:  HKEY_CURRENT_USER\Software\[Firma]\[Anwendung]\[Version].
 
Imports System.Text.Encoding
Imports System.Security.Cryptography

Namespace zaack

  Public Class SaltPasswordHashRegistry

#Region " Öffentliche Methoden "

  ''' <summary>
  ''' SaltPasswordHash erzeugen und in der Registry speichern
  ''' </summary>
  ''' <param name="pw">String</param>
  ''' <remarks> 1. öffentliche Methode (Public)</remarks>
  Public Sub CreateSaltHashAndSaveInRegistry(ByVal pw As String)
     'SaltPasswordHash erzeugen
    Dim saltPwHash As Byte() = _
     CreateSaltedPasswordHash(ASCII.GetBytes(pw), CreateSalt(2000))

     'Speichern in der Registry
    WriteToRegistry(saltPwHash)

  End Sub

  ''' <summary>
  ''' Neues Passwort mit dem aus der Registry vergleichen
  ''' </summary>
  ''' <param name="pw">String</param>
  ''' <returns>Boolean</returns>
  ''' <remarks> 2. öffentliche Methode (Public)</remarks>
  Public Function CheckNewPassword(ByVal pw As String) As Boolean
    Return VerifyPassword(ASCII.GetBytes(pw), ReadFromRegistry)
  End Function

#End Region

#Region " Registry "

  ''' <summary>
  ''' Speichern in der Registry
  ''' Application.UserAppDataRegistry
  ''' </summary>
  ''' <param name="SaltPwHash"></param>
  ''' <remarks></remarks>
  Private Sub WriteToRegistry(ByVal SaltPwHash As Byte())
    Dim name As String = "Password"
    Try
      Application.UserAppDataRegistry.SetValue(name, SaltPwHash)
    Catch ex As Exception
      MessageBox.Show(ex.Message)
    End Try
  End Sub

  ''' <summary>
  ''' Das gespeicherte SaltHashPasswort aus der Registry auslesen
  ''' </summary>
  ''' <returns>Byte()-Array oder Nothing</returns>
  ''' <remarks></remarks>
  Private Function ReadFromRegistry() As Byte()
    Dim name As String = "Password"
    Try
      If Not Application.UserAppDataRegistry.GetValue(name) _
        Is Nothing Then
        Return _
           CType(Application.UserAppDataRegistry.GetValue(name), _
           Byte())
      Else
        Return Nothing
      End If

    Catch ex As Exception
      MessageBox.Show(ex.Message)
      Return Nothing
    End Try
  End Function


#End Region

#Region " SaltPasswordHash "

  ''' <summary>
  ''' Salz bestimmter Länge erzeugen
  ''' </summary>
  ''' <param name="SaltLength">Integer</param>
  ''' <returns>Salt As Byte()</returns>
  ''' <remarks></remarks>
  Private Function CreateSalt(ByVal SaltLength As Integer) _
    As Byte()
    Dim Salt(SaltLength - 1) As Byte
     'Kryptografischer Zufallszahlen-Generator
    Dim csp As New RNGCryptoServiceProvider
    csp.GetBytes(Salt)
    Return Salt
  End Function

  ''' <summary>
  ''' Hauptfunktion:
  ''' Das gesalzene Kennwort erzeugen  (Hashwert + Salz)
  ''' </summary>
  ''' <param name="UnsaltedPassword">Kennwort als Byte()</param>
  ''' <param name="Salt">Salz-Byte()</param>
  ''' <returns>Byte()</returns>
  ''' <remarks>Kennwort als Byte()</remarks>
  Private Function CreateSaltedPasswordHash(ByVal _
    UnsaltedPassword As Byte(), ByVal Salt As Byte()) As Byte()
     ' Byte-Array-Größe bestimmen
    Dim SaltedPassword(UnsaltedPassword.Length + _
      Salt.Length - 1) As Byte
     ' Das ungesalzene Kennwort vorne einfügen
    UnsaltedPassword.CopyTo(SaltedPassword, 0)
     ' Salz annfügen
    Salt.CopyTo(SaltedPassword, UnsaltedPassword.Length)

     ' Den Hashwert für das gesalzene Kennwort erzeugen:
    Dim SaltedPasswordHash As Byte() = CreateHash(SaltedPassword)

     ' Hashwert plus Salz, Byte-Array-Größe bestimmen
    Dim SaltedPasswordHashPlusSalt(SaltedPasswordHash.Length + _
      Salt.Length - 1) As Byte
     ' Hashwert einfügen
    SaltedPasswordHash.CopyTo(SaltedPasswordHashPlusSalt, 0)
     ' Salzwert anhängen
    Salt.CopyTo(SaltedPasswordHashPlusSalt, _
      SaltedPasswordHash.Length)

     ' Gesalzenes Kennwort zurückgeben
    Return SaltedPasswordHashPlusSalt
  End Function

  ''' <summary>
  ''' Hash-Vergleich des gespeicherten mit zu prüfendem Kennwort
  ''' </summary>
  ''' <param name="UnsaltedPassword">Byte()</param>
  ''' <param name="StoredPassword">Byte()</param>
  ''' <returns>Boolean</returns>
  ''' <remarks></remarks>
  Private Function VerifyPassword(ByVal UnsaltedPassword _
    As Byte(), ByVal StoredPassword As Byte()) As Boolean
     ' Einen Hashwert vom zu prüfenden Kennwort erzeugen
    Dim UnsaltedPasswordHash As Byte() = CreateHash(New Byte() {0})
     ' Die Salt-Länge bestimmen
    Dim SaltLength As Integer = StoredPassword.Length - _
      UnsaltedPasswordHash.Length
    Dim SaltStart As Integer = StoredPassword.Length - SaltLength
    Dim Salt(SaltLength - 1) As Byte

     ' Parameter bei Nothing False
    If (UnsaltedPassword Is Nothing) OrElse _
      StoredPassword Is Nothing) Then
      Return False
    End If

     ' Salzwert ermitteln
    Dim i As Integer
    For i = 0 To SaltLength - 1
      Salt(i) = StoredPassword(SaltStart + i)
    Next
     ' Hash für das gesalzene Kennwort erzeugen
    Dim SaltedPasswordHash As Byte() = _
      CreateSaltedPasswordHash(UnsaltedPassword, Salt)
     ' Den Hash mit dem gespeicherten Wert vergleichen
    Return CompareByteArray(StoredPassword, SaltedPasswordHash)

  End Function

  ''' <summary>
  ''' Hashwert (SHA1) aus einem übergebenen Bytearray erzeugen
  ''' </summary>
  ''' <param name="ByteArrayToHash">Byte()</param>
  ''' <returns>Byte()</returns>
  ''' <remarks></remarks>
  Private Function CreateHash(ByVal ByteArrayToHash As Byte()) _
    As Byte()
    Dim sha As SHA1 = SHA1.Create()
    Return sha.ComputeHash(ByteArrayToHash)

  End Function

  ''' <summary>
  ''' Byte-Arrays vergleichen
  ''' </summary>
  ''' <param name="bArr1">Byte()</param>
  ''' <param name="bArr2">Byte()</param>
  ''' <returns>Boolean</returns>
  ''' <remarks></remarks>
  Private Function CompareByteArray(ByVal bArr1 As Byte(), _
    ByVal bArr2 As Byte()) As Boolean
     ' Gleiche Länge?
    If (bArr1.Length <> bArr2.Length) Then
      Return False
    End If
     ' Iterieren und einzelne Arrayelemente vergleichen
    Dim i As Integer
    For i = 0 To bArr1.Length - 1
      If bArr1(i) <> bArr2(i) Then
        Return False
      End If
    Next

    Return True
  End Function

#End Region

  End Class

End Namespace
 
Weitere Links zum Thema
Hashcodes mit MD5 generieren
Passwortsicherheit durch SaltHash
Verschlüsseln mit DES und TripleDES

Windows-Version
98/SE
ME
NT
2000
XP
Vista
Win 7


Download  (42 kB) Downloads bisher: [ 277 ]

Vorheriger Tipp Zum Seitenanfang Nächster Tipp

Startseite | Tipps | Projekte | Tutorials | Bücherecke | VB-/VBA-Tipps | API-Referenz | Komponenten | VB.Net-Forum | VB/VBA-Forum | DirectX-Forum | Foren-Archiv | DirectX | Chat | Spielplatz | Links | Suchen | Stichwortverzeichnis | Feedback | Impressum

Seite empfehlen Bug-Report
Letzte Aktualisierung: Montag, 28. November 2011