Visual Basic - Technik, FAQ, Tricks, Beispiele

Home / Allgemein / Sicherheit / Encode

Strings schnell ver- und entschlüsseln

Historie
27.08.2007Behandeln eines StrConv-Bugs, welcher bei leeren Zeichenketten auftritt.
Vielen Dank an Manuel Ratzinger für den entsprechenden Fehler-Hinweis!
06.06.2005Debugging; Umstellung auf (etwas langsameres aber robustes) Verfahren via StrConv-Funktion
22.09.2001Erste Version benutzt Speichermapping

Motivation: Verschlüsselung mit VB

Einleitung

Für viele Anwendungsbereiche wird eine schnelle Verschlüsselung benötigt: Ob zur Speicherung von Passwörtern in Datenbanken, oder zur Unkenntlichmachung von Texten oder beliebigen Dateien.

Die unten vorgestellten Routinen erfüllen zumindest folgende Anforderungen:

Nachfolgend wird u.a. gezeigt, wie ein Byte-Array verschlüsselt werden kann, und wie dies dazu genutzt werden kann, einen String schnell zu verschlüsseln.

Beispiele

Einen Text mit Passwort "abc" verschlüsseln und anschließend wieder entschlüsseln:

Dim s As String
s = "Hallo Welt!"
EncodeString s, "abc"
'das (unleserliche) Ergebnis steht in s
EncodeString s, "abc"
'jetzt steht wieder "Hallo Welt!" in s

Via Funktion verschlüsselten Text hexadezimal anzeigen:

MsgBox HexDump(EncodeStr("Hallo", "abc"))
'zeigt "B69D3F3F3F" an

Ein Byte-Array verschlüsseln (am fiktiven Beispiel einer Binärdatei):

Dim b() As Byte
'ReadData "c:\test\bla.exe", b
EncodeArrayB b, "abc"
'WriteData "c:\test\bla.exe", b

Code / Quelltext

EncodeArrayB

Das Herzstück der Verschlüsselung (der eigentliche Algorithmus) ist hier zu finden: Ein gegebenes Byte-Array wird Byte für Byte durch Anwendung der Xor-Funktion verschlüsselt. Da die zweimalige Anwendung von Xor (mit dem gleichen Wert) den ursprünglichen Wert wiederherstellt, ist die Entschlüsselung mit dieser Routine ebenfalls möglich.

Public Sub EncodeArrayB( _
    ByRef ByteArray() As Byte, _
    Optional ByRef Password As String _
  )
  Const MagicByte As Byte = &HFF
  Dim PwdLen As Long
  Dim PwdAsc As Byte
  Dim i As Long
  Dim j As Long
  Dim LB As Long
  Dim UB As Long
  
  PwdLen = Len(Password)
  Select Case PwdLen
  Case 0 'Kein Password verwenden:
  
    For i = LBound(ByteArray) To UBound(ByteArray)
      ByteArray(i) = ByteArray(i) Xor MagicByte Xor (i And &HFF)
    Next i
  
  Case 1 'Einzelnes Zeichen als Password verwenden:
  
    PwdAsc = Asc(Password) Xor MagicByte
    For i = LBound(ByteArray) To UBound(ByteArray)
      ByteArray(i) = ByteArray(i) Xor PwdAsc Xor (i And &HFF)
    Next i
  
  Case Else 'Password verwenden:
  
    LB = LBound(ByteArray)
    UB = UBound(ByteArray)

    'Buchstaben-weise das Passwort durchlaufen:
    For j = 1 To PwdLen

      PwdAsc = Asc(Mid$(Password, j, 1)) Xor MagicByte
      For i = LB To UB Step PwdLen
        ByteArray(i) = ByteArray(i) Xor PwdAsc Xor (i And &HFF)
      Next i
      LB = LB + 1

    Next j
  
  End Select

End Sub

Man beachte, wie durch die Fallunterscheidung nach der Passwort-Länge eine optimale Performance sichergestellt wird.

EncodeString

Um Byte-weise auf die einzelnen Zeichen eines Strings zuzugreifen, wird der String an ein Byte-Array zugewiesen. VB würde eigentlich ein Zeichen in jeweils zwei Elemente des Byte-Arrays ablegen (wegen Unicode-Darstellung), daher muss der String vorher mit der VB-Funktion StrConv konvertiert werden (und hinterher wieder zurück).

Eine andere Idee wäre der Zeichen-weise Zugriff via Mid$ gewesen, sowohl beim Lesen, als auch beim Schreiben. Aber im Vergleich zur direkten Operation auf Bytes (also Zahlenwerte) ist die Kodierung von Zeichen deutlich aufwändiger und langsamer; man müßte ständig die VB-Funktionen Asc und Chr$ benutzen, welche nun wirklich nicht die schnellsten sind.

Also habe ich mich für die erste Idee entschieden:

Public Sub EncodeString( _
    ByRef Text As String, _
    Optional ByRef Password As String _
  )
  Dim Bytes() As Byte

  If Len(Text) Then
    Bytes = StrConv(Text, vbFromUnicode)
    EncodeArrayB Bytes, Password
    Text = StrConv(Bytes, vbUnicode)
  End If

End Sub

Die Fallunterscheidung (prüfen, ob der Text nicht leer ist) ist notwendig, da die StrConv-Funktion Probleme beim Umgang mit leeren Zeichenketten hat.

EncodeStr

Für einzelne Fälle kann es ganz praktisch sein, den Text in der original-Variable nicht zu verändern. Daher gibt die folgende Funktion eine Kopie zurück:

Public Function EncodeStr( _
    ByRef Text As String, _
    Optional ByRef Password As String _
  ) As String

  EncodeStr = Text
  EncodeString EncodeStr, Password

End Function

© Jost Schwider, 22.09.2001-27.08.2007 - http://vb-tec.de/strcode.htm