vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
NEU! sevCoolbar 3.0 - Professionelle Toolbars im modernen Design!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   RSS-Feeds  | Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2019
 
zurück
Rubrik: Verschiedenes / Sonstiges   |   VB-Versionen: VB201505.06.19
Generische Dictionary: verschlüsselte Serialisierung

Eine Klasse, die von der generischen Dictionary (System.Collections) abgeleitet ist. Sie ermöglicht die verschlüsselte Serialisierung des Dateninhalts (Passwort).

Autor:   Manfred BohnBewertung:     [ Jetzt bewerten ]Views:  660 
ohne HomepageSystem:  Vista, Win7, Win8, Win10kein Beispielprojekt 

Das Net-Framework bietet mit der Binär-Serialisierung eine bequeme Möglichkeit, den Inhalt von strukturierten Datenklassen in einer Datei zu speichern. Um diese Informationen mit einem Passwort zu schützen, können die Kryptographie-Methoden im System.Security-Namespace herangezogen werden.

Als Beispiel habe ich eine Klasse von der generischen Dictionary abgeleitet und zwei Methoden für das Verschlüsseln sowie Serialisieren der Auflistung der Schlüssel-Wert-Paare eingefügt.

Voraussetzung ist dabei, daß die Datentypen der Schlüssel und der Werte serialisierbar sind. Wenn eigene Klassen in der Dictionary verwendet werden, sind sie durch das entsprechende Attribut zu kennzeichnen (vgl. Beispiel).<(p>

Eine (unvollständige) Liste der binär-serialisierbaren Net-Klassen:
https://docs.microsoft.com/de-de/dotnet/standard/serialization/binary-serialization

Den Code zur Verschlüsselung habe ich dem VB-Archiv-Tipp 1351 "(Text-) Verschlüsselung (VB.NET)" entnommen.
Um Verwechslungen auszuschließen, wird auch eine Versionskennung der abgeleiteten Dictionary-Klasse gespeichert und vor dem Lesen überprüft.

Option Strict Off
Imports System
Imports System.Collections.Generic ' Dictionary
Imports System.Runtime.Serialization ' Formatters
Imports System.Security 'Verschlüsselung (Cryptography)
 
<System.Serializable>
Public Class SerializableDictionary(Of TKey As IEquatable(Of TKey), TValue)
  Inherits Dictionary(Of TKey, TValue)
 
  Const Version As String = "SerializableDictionary 1.0"
 
  Dim fmt As New Formatters.Binary.BinaryFormatter
 
  Public Sub New()
      MyBase.New
  End Sub
 
  Public Sub New(info As SerializationInfo, context As StreamingContext)
    MyBase.New(info, context)
  End Sub
  ''' <summary>Speichern des Daten-Inhalts (Schlüssel-Wert-Paare)</summary>
  ''' <param name="filepath">Pfad und Name der Datei, die gelesen werden soll</param>
  ''' <param name="password">Optionales Passwort (falls Verschlüsselung erfolgen soll)</param>
  ''' <param name="AllowOverwrite">Überschreiben einer vorhandenen Datei erlauben</param>
  ''' <param name="msg">Meldung, falls Serialisieren, Verschlüsseln, Speichern scheitert</param>
  ''' <returns>Alles OK?</returns>
  Public Function Serialize(ByVal filepath As String, 
                       Optional ByVal password As String = "",
                       Optional ByVal AllowOverwrite As Boolean = False,
                       Optional ByRef msg As String = "") As Boolean
 
    If AllowOverwrite Then
      IO.File.Delete(filepath)
    Else
      If IO.File.Exists(filepath) Then
        msg = "Datei existiert bereits"
        Return False
      End If
    End If
 
    Dim data() As Byte
 
    ' Serialisierung der Daten innerhalb des Speichers durchführen
    Try
      Using msdata As New IO.MemoryStream
        ' Versions-Kennung ausgeben
        fmt.Serialize(msdata, Version)
        ' Daten serialisieren
        fmt.Serialize(msdata, Me)
        fmt.Serialize(msdata, Version)
        ' Bytearray aus dem Stream erstellen
        data = msdata.ToArray
      End Using
    Catch ex As Exception
      msg = "Fehler bei Serialisierung" & vbCrLf & ex.Message
      Return False
    End Try
 
 
    If password <> String.Empty Then
      ' Verschlüsselung der serialisierten Bytefolge
      Dim rd As New Cryptography.RijndaelManaged
      Dim md5 As New Cryptography.MD5CryptoServiceProvider
      Dim key() As Byte = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password))
      md5.Clear()
      rd.Key = key
      rd.GenerateIV()
      Dim iv() As Byte = rd.IV
 
      Try
        Using msenc As New IO.MemoryStream,
        cs As New Cryptography.CryptoStream
        (msenc, rd.CreateEncryptor, Cryptography.CryptoStreamMode.Write)
 
          msenc.Write(iv, 0, iv.Length)
          cs.Write(data, 0, data.Length)
          cs.FlushFinalBlock()
          ' Array mit verschlüsselter Bytefolge füllen
          data = msenc.ToArray
        End Using
      Catch
        msg = "Fehler bei Verschlüsselung" : Return False
      End Try
    End If
 
    Try
      ' Schreiben der Daten-Bytes in die Datei
      IO.File.WriteAllBytes(filepath, data)
      Return True
    Catch ex As Exception
      msg = "Datei - Fehler beim Schreiben" & vbCrLf & ex.Message
      Return False
    End Try
  End Function
  ''' <summary>Lesen der serialisierten Daten eines Dictionary</summary>
  ''' <param name="filepath">Pfad und Name der Datei, die gelesen werden soll</param>
  ''' <param name="password">Optionales Passwort (falls Verschlüsselung vorliegt)</param>
  ''' <param name="msg">Meldung, falls Lesen, Entschlüsseln oder Deserialisieren scheitert</param>
  Public Function Deserialize(ByVal filepath As String,
                              Optional ByVal password As String = "",
                              Optional ByRef msg As String = "") As Boolean
 
    msg = ""
    Dim datadec(), data(0) As Byte
    Try
      datadec = IO.File.ReadAllBytes(filepath)
    Catch ex As Exception
      msg = "Lesefehler Datei " & vbCrLf & ex.Message
      Return False
    End Try
 
    Dim rd As New Cryptography.RijndaelManaged
    Dim rijndaelIvLength As Integer = 16
    Dim md5 As New Security.Cryptography.MD5CryptoServiceProvider
    Dim key() As Byte = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password))
 
    If password <> String.Empty Then
      Try
        ' Entschlüsselung der Daten-Bytes
        Using msdec As New IO.MemoryStream(datadec)
          Dim iv(15) As Byte
          md5.Clear()
          msdec.Read(iv, 0, rijndaelIvLength)
          rd.IV = iv
          rd.Key = key
 
          Using cs As New Cryptography.CryptoStream _
            (msdec, rd.CreateDecryptor, Cryptography.CryptoStreamMode.Read)
 
            Array.Resize(Of Byte)(data, CInt(msdec.Length - rijndaelIvLength))
            cs.Read(data, 0, data.Length)
          End Using
        End Using
      Catch ex As Exception
        msg = "Fehler bei Entschlüsselung"
        Return False
      End Try
    Else
      data = datadec 'Die Daten sind nicht passwortgeschützt
    End If
 
 
    Try
      ' Deserialisierung der Daten-Bytes
      Using ms As New IO.MemoryStream(data)
 
        Dim vers As String = DirectCast(fmt.Deserialize(ms), String)
        If vers <> Version Then
          msg = "Falsche Serialisierungs-Version"
          Return False
        End If
 
        Dim dic_temp As SerializableDictionary(Of TKey, TValue) =
          DirectCast(fmt.Deserialize(ms), SerializableDictionary(Of TKey, TValue))
        vers = DirectCast(fmt.Deserialize(ms), String)
 
        If vers <> Version Then
          msg = "Falsches Dateiende gefunden"
          Return False
        End If
 
        Me.Clear()
        For Each kvp As KeyValuePair(Of TKey, TValue) In dic_temp
          Me.Add(kvp.Key, kvp.Value)
        Next kvp
        dic_temp = Nothing
        Return True
      End Using
 
    Catch ex As Exception
      msg = "Fehler bei Deserialisierung" & vbCrLf & ex.Message
      Return False
    End Try
  End Function
End Class

Beispiel:
Eine serialisierbare Klasse mit den Daten für eine Person.
Die Implementierung der IEquatable-Schnittstelle erlaubt die Prüfung auf Gleichheit des Dateninhalts zweier Instanzen.

<System.Serializable>
Private Class Person
  Implements IEquatable(Of Person)
 
  Public Property Name As String
  Public Property Vorname As String
  Public Property Alter As Integer
  Public Property Ausbildung As List(Of String)
 
 
  Public Function Equals1(other As Person) As Boolean Implements IEquatable(Of Person).Equals
 
    Dim sc As StringComparer = StringComparer.CurrentCultureIgnoreCase
 
    With other
      If sc.Compare(Name, .Name) <> 0 Then Return False
      If sc.Compare(Vorname, .Vorname) <> 0 Then Return False
      If Alter <> .Alter Then Return False
      If Ausbildung.Count <> .Ausbildung.Count Then Return False
      For i As Integer = 0 To Ausbildung.Count - 1
        If sc.Compare(Ausbildung(i), .Ausbildung(i)) <> 0 Then Return False
      Next i
    End With
 
    Return True
  End Function
 
 
  Public Shared Operator <>(ByVal a As Person, ByVal b As Person) As Boolean
    Return Not a.Equals1(b)
  End Operator
 
  Public Shared Operator =(ByVal a As Person, ByVal b As Person) As Boolean
    Return a.Equals1(b)
  End Operator
End Class

Demonstration:

Private Sub Demo()
 
  ' Erstellung der Dictionary
  Dim personen As New SerializableDictionary(Of Integer, Person)
 
  ' Erstellung von Testdaten
  Dim vn As String() = {"Hans", "Gerhard", "Dieter", "Elke", "Gudrun", "Meike"}
  Dim hn As String() = {"Müller", "Meier", "Schneider", "Schuster", "Meyer", "Özoguz"}
  Dim sch() As String = 
    {"ohne Abschluß", "Realschule", "Fachakademie", "Handwerk", "Hochschule"}
  Dim ber() As String = 
    {"Verkäufer", "Schreiner", "Installateur", "Techniker", "Lehrer", "Arzt"}
 
  Dim rndm As New Random(1234)
 
  For i As Integer = 1 To 100
    Dim p As New Person
    p.Vorname = vn(rndm.Next(0, 6))
    p.Name = hn(rndm.Next(0, 6))
    p.Alter = rndm.Next(10, 61)
    p.Ausbildung = New List(Of String)
    p.Ausbildung.Add(sch(rndm.Next(0, 5)))
    p.Ausbildung.Add(ber(rndm.Next(0, 6)))
 
    ' Füllen der Dictionary / eindeutige Kennung als Schlüssel
    personen.Add(1000 + i, p)
  Next i
 
  Dim msg As String = ""
  Dim filepath As String = "G:Datenpersonendictionary.ser"
  Dim password As String = "az162xe" 'in der Praxis per Dialog vom User abfragen
 
  ' Verschlüsseltes Speichern der Daten 
  If Not personen.Serialize(filepath, password, False, msg) Then
    MsgBox(msg, MsgBoxStyle.Exclamation)
  End If
 
  ' Lesen und Entschlüsseln der Daten
  Dim personen2 As New SerializableDictionary(Of Integer, Person)
  If Not personen2.Deserialize(filepath, password, msg) Then
    MsgBox(msg, MsgBoxStyle.Exclamation)
  End If
 
  ' Vergleich des Dateninhalts der beiden Klasseninstanzen
  For Each key As Integer In personen2.Keys
    If personen2(key) <> personen(key) Then Stop
  Next key
End Sub

Dieser Tipp wurde bereits 660 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2019 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel