Zeichenfolgenverschlüsselung mit Visual Basic .NET

Veröffentlicht: 10. Nov 2002 | Aktualisiert: 09. Nov 2004

Von Brian David Patterson

Wenn Sie schon einmal die verschiedenen .NET-Hilfedateien zum Thema Verschlüsselung durchsucht haben, sind auch Sie möglicherweise zu der verblüffenden Erkenntnis gelangt, dass sich die Beispiele zu diesem Thema immer nur mit der Verschlüsselung von Dateiinhalten befassen. Dies ist natürlich nicht sehr hilfreich, wenn Sie etwas verschlüsseln müssen, was sich nicht in einer Datei befindet - und Daten in einer Datei zu speichern, nur um sie zu verschlüsseln und dann wieder zurückzuladen, wäre reichlich absurd.

In diesem Artikel befasse ich mich mit einigen der Verschlüsselungsklassen, die von .NET Framework bereitgestellt werden. Nachdem Sie in den Grundzügen verstanden haben, wie diese Algorithmen verwendet werden, zeige ich Ihnen am Beispiel einer Bestellanwendung, wie Kreditkartendaten verschlüsselt werden, bevor diese auf einem SQL Server- oder einem Oracle-Datenbankserver gespeichert werden.

Auf dieser Seite

 Voraussetzungen
 Verschlüsselung und das .NET Framework
 Beispiel: Eine Auftragseingangsanwendung
 Zusammenfassung
 Informationsquellen zum Thema Verschlüsselung

Zur Homepage von Wrox

Diesen Artikel können Sie dank freundlicher Unterstützung von Wrox auf MSDN Online lesen. Wrox ist ein Partner von MSDN Online.

Zur Partnerübersichtsseite von MSDN Online

Voraussetzungen

Bevor Sie sich im Detail mit diesem Thema auseinandersetzen, und damit Sie den vorliegenden Artikel in allen Aspekten verstehen und die Beispielanwendung umfassend nutzen können, sollten Sie sicherstellen, dass Sie mit den folgenden Fakten vertraut sind:

  • Programmieren einer standardmäßigen Windows Forms-Anwendung

  • Bytearrays

  • SQLClient- und/oder OleDB-Klassen

  • Zeichenfolgenkonvertierungsroutinen

Darüber hinaus benötigen Sie Zugriff auf einen SQL Server 2000- oder einen Oracle 8i/9i-Datenbankserver sowie die Berechtigung zum Entwickeln neuer Datenbanken.

 

Verschlüsselung und das .NET Framework

Viele der hier besprochenen Verschlüsselungsmethoden laufen im Allgemeinen unter dem Begriff "Verschlüsselung mit privaten Schlüsseln". Dies bedeutet im Wesentlichen, dass Sie einen Schlüssel (wie beispielsweise ein Kennwort) für die Verschlüsselung und den gleichen Schlüssel für die Entschlüsselung der Daten verwenden. Diese Algorithmen des privaten Schlüssels (oder auch symmetrische Algorithmen) sind bedeutend schneller als Systeme, bei denen die Verschlüsselung mit dem öffentlichen Schlüssel erfolgt.

Dieser Geschwindigkeitszuwachs ist zwar von Vorteil, allerdings sollten auch die Nachteile nicht außer Acht gelassen werden. Denn da es nur einen Schlüssel zum Verschlüsseln und Entschlüsseln gibt, müssen Sie mit den Daten auch den geheimen Schlüssel weitergeben, wenn Sie verschlüsselte Daten an eine andere Person weitergeben möchten. Denn nur so kann diese Person die Daten entschlüsseln. Die Weitergabe des Schlüssels ist ein erheblicher Schwachpunkt, da die Daten von Dritten abgefangen und somit auch von Unbefugtem entschlüsselt werden könnten.

Die Algorithmen des privaten Schlüssels werden in der Regel auch als Blockcode bezeichnet, da Daten hiermit abschnittsweise, also in so genannten Blöcken verschlüsselt werden. Bei sämtlichen Verschlüsselungsmethoden mit Ausnahme der nach Rijndael werden acht Byte große Blöcke für die Datenverschlüsselung verwendet. Stark vereinfachte Formen dieser Blockziffern verschlüsseln einen Datenblock und machen dann mit dem nächsten Block weiter, wobei für die Verschlüsselung der einzelnen Blöcke jeweils der gleiche Schlüssel verwendet wird. Wenn die Blöcke 1 und 3 nun die gleichen Daten enthalten, sind konsequenterweise auch die verschlüsselten Gegenstücke identisch. Das kann natürlich dazu führen, dass eine beliebige Person die Verschlüsselungsmethode knackt und den Chiffrierschlüssel ausliest. Zur Lösung dieses Problems verwenden die nachstehenden Algorithmen einen so genannten Initialisierungsvektor.

Dieser Initialisierungsvektor wird mit dem Schlüssel für die Verschlüsselung des ersten Datenblocks kombiniert. Wenn der Algorithmus dann die nachfolgenden Datenblöcke verschlüsselt, werden auch Informationen aus dem vorherigen Block mitgegeben, um den Verschlüsselungsprozess jeweils komplizierter zu gestalten. Daher sind bei Verwendung eines Initialisierungsvektors die verschlüsselten Gegenstücke der Blöcke 1 und 3 auch dann vollkommen unterschiedlich, wenn diese Blöcke die gleichen Daten enthalten.

Beim Einsatz der verschiedenen Verschlüsselungsklassen in .NET ist es äußerst hilfreich zu wissen, dass sich diese in der Funktionsweise jeweils sehr ähnlich sind. Wenn Sie also Code für den Einsatz einer Verschlüsselungsmethode wie beispielsweise TripleDES schreiben, kann die Verschlüsselungsmethode später mit sehr geringem Aufwand geändert werden. Wir wollen nun einmal einen kurzen Blick auf einige der von .NET Framework bereitgestellten Verschlüsselungsalgorithmen werfen.

DES

Der Datenverschlüsselungsstandard (DES, Data Encryption Standard) war, wie der Name schon sagt, mehr als 30 Jahre lang der Industriesstandard für die Verschlüsselung. Wie bereits erwähnt, verschlüsselt auch DES Daten mithilfe von 8 Byte langen Blöcken. Zum Verschlüsseln der Daten wird der gleiche Schlüssel wie zum Entschlüsseln verwendet. Beim Verschlüsseln von Daten mit DES müssen Sie einen 8 Byte langen Schlüssel bereitstellen, der wiederum auf einen 7 Byte-Schlüssel verkleinert wird. Dies geschieht, da der Algorithmus das achte Bit jedes Schlüsselbytes zu Paritätszwecken entfernt.

Bei DES erfolgt die Verschlüsselung in 16 Durchgängen. Anders ausgedrückt, der von Ihnen bereitstellte Schlüssel wird zunächst zum Verschlüsseln eines Datenblocks verwendet. Anschließend wird der Schlüssel geringfügig verändert, und der gleiche Datenblock wird erneut verschlüsselt. Dies wird fortgesetzt, bis der Datenblock 16 x verschlüsselt wurde.
Bei DES werden standardmäßige mathematische und logische Operatoren für die Verschlüsselung eingesetzt - diese Methode konnte in den späten 70er Jahren sehr einfach in die damals verfügbare Computerhardware implementiert werden.

Da die Verschlüsselungsroutine sehr repetitiv ist, war DES auch ein idealer Kandidat für die Einbettung in Mikrochips, was auch zu einer weiteren Beschleunigung des Verfahrens beitrug.
Die DES-Verschlüsselung wurde im Jahre 1997 allerdings im Rahmen einer von RSA Security gesponserten Herausforderung offiziell geknackt. Dies erforderte verbesserte Implementierungen des Verschlüsselungsstandards, mit denen wir uns in Kürze befassen werden.

RC2

RC2 (Rivest Cipher) wurde als Ersatz für DES entwickelt und ist beim Einsatz in Software 3 x so schnell wie DES. Wie bei DES wird auch hierbei mit einer 8 Byte-Blockziffer gearbeitet. Im Gegensatz zu DES akzeptiert RC2 jedoch eine Schlüssellänge, die nur von der maximalen Zeichenfolgenlänge der Computerplattform beschränkt wird. Es heißt sogar, dass die Geschwindigkeit des Algorithmus in keiner Weise von der Länge des Schlüssels beeinträchtigt wird. Die RC2-Verschlüsselung kommt zwar in vielen Softwareprodukten zum Einsatz, ist jedoch längst nicht so populär wie DES.

RSA

RSA ist ebenfalls ein sehr bekanntes Verschlüsselungssystem mit öffentlichem Schlüssel. Um einmal eine Verschlüsselung mit öffentlichem Schlüssel zu demonstrieren, folgt ein Beispiel:
Einmal am Tag sende ich eine EDI 850-Bestellungsdatei an eine Vertriebsagentur. Diese habe ich damit beauftragt, die zahlreichen Anwendungen zu vertreiben, die ich entwickle und verkaufe. Anstatt nun die Datei im Klartext an die FTP-Site meines Händlers zu uploaden, wo jeder darauf zugreifen und die hierin enthaltenen Informationen lesen kann, habe ich mich für eine verschlüsselte Datei entschieden. Meine Vertriebsagentur stellt mir hierzu ihren öffentlichen Schlüssel zur Verfügung. Mithilfe dieses öffentlichen Schlüssels verschlüssele ich nun die Daten. Nachdem die Datei verschlüsselt wurde, uploade ich sie auf die FTP-Site des Händlers. Dort kann dieser die Datei mit seinem privaten Schlüssel entschlüsseln, bevor die Daten in das Warehousesystem importiert werden.

Wie Sie anhand dieses Beispiels sehen, verwende ich mein Kennwort für die eigentliche Verschlüsselung der Daten, liefere jedoch den öffentlichen Schlüssel meines Händlers mit. Der öffentliche Schlüssel stellt sicher, dass die Daten so verschlüsselt werden, dass der Händler zum Entschlüsseln der Daten nur seinen privaten Schlüssel eingeben muss. Wollte ich nun eine weitere Kopie der Datei an meinen Steuerberater schicken, könnte ich diese mit dem öffentlichen Schlüssel meines Händlers und meines Steuerberaters verschlüsseln.

RSA löst damit das seit Jahren anstehende Problem des Schlüsselaustauschs, indem nämlich unterschiedliche Schlüssel für die Ver- und Entschlüsselung verwendet werden. RSA ist sehr sicher und kommt in vielen tausend Implementierungen überall auf der Welt zum Einsatz. Die heute gängigste Anwendung ist sicherlich PGP (Pretty Good Privacy), mit der jeder Dateien und E-Mails mit öffentlichen Schlüsseln verschlüsseln kann.

Als praktische Einsatzmöglichkeit für RSA wäre beispielsweise Folgendes denkbar: Sie vertreiben Waren für die ACME Corporation, und zu diesem Zweck sammeln Sie die Bestellungen und senden diese an ACME für die Verarbeitung. Beim Versand der Bestellungen könnten Sie die Daten nun mit dem öffentlichen Schlüssel verschlüsseln, so dass nur ACME diese mit dem zugehörigen privaten Schlüssel entschlüsseln kann. Da wir im vorliegenden Fall jedoch Bestellinformationen nur für den eigenen Bedarf verschlüsseln möchten, ist RSA für uns ein wenig zu mächtig, daher wollen wir es hierfür nicht verwenden.

TripleDES

Wie der Name schon andeutet, besitzt TripleDES die dreifache Verschlüsselungsstärke von Standard-DES. TripleDES setzt zudem einen 24 Byte langen Schlüssel voraus, der in drei 8 Byte-Schlüssel aufgeteilt wird, um jeden Block 3 x zu verschlüsseln. Betrachten wir einmal die Verschlüsselungsdurchgänge, dann wird jeder Block damit eigentlich 48 x verschlüsselt. Sie können sich also vorstellen, dass TripleDES ein sehr sicherer Verschlüsselungsalgorithmus ist, daher bildet er auch die Basis für die folgende Testanwendung.

Verschlüsselung und Bytearrays

Beim Verschlüsseln von Daten - und in unserem Fall geht es ja um die Verschlüsselung von Text - kann jeder zu verschlüsselnde Buchstabe in eines von 256 möglichen ASCII-Zeichen umgewandelt werden. Da nicht alle diese Zeichen auf dem Bildschirm dargestellt werden können, gestaltet sich die Anzeige des verschlüsselten Textes auf dem Bildschirm etwas schwierig. Um die Weitergabe von verschlüsselten Daten zu vereinfachen, arbeiten die hierbei eingesetzten Verschlüsselungsalgorithmen mit Bytearrays.

Bei dieser Methode werden Zeichenfolgendaten in die Funktionen übergeben und es wird ein Bytearray mit verschlüsselten Daten zurückgegeben. Dies bedeutet aber, dass wir auch beim Entschlüsseln der Daten die ursprünglich verschlüsselten Informationen als Bytearray übergeben müssen und wiederum ein Bytearray zurückerhalten. Wenn wir also die Daten speichern oder für den Benutzer anzeigen möchten, müssen wir das Bytearray erst wieder in die eigentlichen Zeichen umwandeln, die es repräsentiert.

Bytearrays wirken sich auch auf die Art und Weise aus, wie wir Daten in einer Datenbank speichern können. Die einfache Definition einer NVARCHAR-Spalte in SQL Server ist nicht ausreichend, da dieser Datentyp für die Verarbeitung von Zeichenfolgeninformationen und nicht von Binärdaten gedacht ist. Wir wollen uns daher im Vorfeld kurz mit den beiden von uns verwendeten Datenbanken und der Art und Weise befassen, wie Daten eingespeichert werden.

Speichern verschlüsselter Daten in SQL Server

Zum Speichern von Bytearrays in SQL Server müssen wir einen von zwei Datentypen verwenden. Der Datentyp Binär kann 1 bis 8.000 Byte an Informationen aufnehmen und weist eine feste Größe auf. Wenn Sie also eine Spalte vom Typ Binär mit der Größe 10 definieren und in dieser Spalte nur 2 Byte speichern, werden trotzdem die vollen 10 Byte verwendet. Dies ist Platzverschwendung, daher sollte der Datentyp Binär nur bei vollständig konstanten Daten verwendet werden. Im vorliegenden Fall geht es um die Verschlüsselung von Kreditkartennummer mit unterschiedlichen Längen, also wäre der Einsatz eines binären Datentyps nicht sinnvoll.

Als weitere Option steht der Datentyp varbinary zur Verfügung. Dieser kann ebenfalls zwischen 1 und 8.000 Byte an Binärdaten aufnehmen. Wie Sie vielleicht schon vermuten, weist der Datentyp varbinary eine variable Größe auf und ist daher für unsere Anwendungsgröße wesentlich besser geeignet. Somit verschwenden wir beim Speichern von verschlüsselten Kreditkartennummern keinen Platz mehr.
Wenn Sie Binärdaten mit mehr als 8.000 Byte, wie beispielsweise ein großes Dokument oder sogar ein Bild speichern müssen, bleibt Ihnen als weitere Option der Datentyp "image". Der Datentyp "image" hat ebenfalls eine variable Länge und kann bis zu 2.147.483.647 Datenbyte aufnehmen!

Speichern verschlüsselter Daten in Oracle

Oracle bietet für das Speichern von Binärdaten für unsere Zwecke zwei geeignete Datentypen an. Zum einen gibt es den Datentyp RAW, der eine variable Größe aufweist und bis zu 2.000 Byte an Daten aufnehmen kann. Zum anderen gibt es das BLOB (Binary Large OBject) mit einer Kapazität von bis zu 4 GB. Da wir es nur mit etwa 20 Byte an Daten zu tun haben, ist der Datentyp RAW für unsere Zwecke absolut ausreichend.

 

Beispiel: Eine Auftragseingangsanwendung

Als Nächstes erstellen wir eine Auftragseingangsanwendung. Diese Anwendung enthält die üblichen Angaben wie Name und Adresse sowie Kreditkarteninformation, denn hierüber soll auch die Zahlung abgewickelt werden. Nach der Eingabe der Informationen können Sie ggf. auf eine Schaltfläche klicken, um die Bestellung zu speichern. Im Anschluss klicken Sie auf eine weitere Schaltfläche, um alle Bestellungen in der Datenbank anzuzeigen. Natürlich fehlen in der Anwendung diverse Funktionen wie beispielsweise der Rechnungsbetrag. Aber es geht hier ja auch nicht um den Entwurf eines Frameworks für eine Auftragseingangsanwendung, sondern um den Einsatz der Verschlüsselungsmethode TripleDES für einen bestimmten Zweck.

Entwurf der Hauptoberfläche

Die Hauptoberfläche der Anwendung enthält 8 Textfelder, 1 Kombinationsfeld und 2 Schaltflächen. Erstellen Sie also ein neues Windows-Anwendungsprojekt, und positionieren Sie die Steuerelemente im Formular. Ordnen Sie die Steuerelemente ähnlich wie in Abbildung 1 gezeigt an.

Bild01

Aus rein ästhetischen Gründen enthält das vorstehende Formular noch eine Grafik im Kopfbereich, die für diese Demonstration jedoch ohne Belang ist. Nachdem Sie alle Steuerelemente an den geeigneten Stellen positioniert haben, legen Sie die jeweils erforderlichen Eigenschaften wie in Tabelle 1 gezeigt fest.

Steuerelement

Name

Text

Schaltfläche

btnSaveOrder

Save Order

Schaltfläche

btnViewOrders

View Orders

Textfeld

txtFirstName

--

Textfeld

txtLastName

--

Textfeld

txtAddress

--

Textfeld

txtCity

--

Textfeld

txtState

--

Textfeld

txtZip

--

Textfeld

txtCCNumber

--

Textfeld

txtCCExp

--

Kombinationsfeld

cmbCCType

<Siehe unten>

Die Beschriftungen auf dem Hauptformular haben keinen praktischen Zweck außer der Bezeichnung des jeweiligen Steuerelements, daher können die Beschriftungen ggf. auch entfallen. Nachdem Sie das Kombinationsfeld hinzugefügt haben, müssen Sie mithilfe des Eigenschaften-Explorers die Items-Eigenschaft des Steuerelements bearbeiten. In die Items-Eigenschaft können Sie die Namen einiger Kreditkarteninstitute eingeben. Zur Demonstration habe ich American Express, Discover, MasterCard und Visa eingetragen.

Neben der Hauptoberfläche benötigen wir für diese Anwendung noch ein weiteres Formular, in dem wir alle bisher gespeicherten Bestellungen unverschlüsselt anzeigen können. Fügen Sie dem Projekt ein weiteres Windows Form mit Namen AllOrders.vb hinzu. Für dieses Formular ist nur eine Schaltfläche und ein ListView-Steuerelement erforderlich. Sie können den Standardnamen des ListView-Steuerelements ggf. beibehalten. Legen Sie die Name-Eigenschaft der Schaltfläche auf btnOK fest. Ich habe Anchor-Eigenschaften für beide Steuerelemente festgelegt, damit diese mit dem Fenster die Größe ändern, aber auch das ist nicht unbedingt erforderlich.

Bild02

Programmieren der Verschlüsselungsklasse

Nachdem die Formulare nun fertig gestellt sind, benötigen wir noch den Verschlüsselungscode, damit wir mit dem Speichern von Daten in der Datenbank beginnen können. Fügen Sie dem Projekt eine neue Klasse hinzu und nennen Sie die Datei TripleDES.vb. Im nächsten Schritt fügen Sie der neuen Klasse dann ein paar Namespaces hinzu. Geben Sie am Anfang der Klassendatei den folgenden Code ein:

Imports System
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography

Da wir nun Zugriff auf die entsprechenden Namespaces haben, können wir mit dem Programmieren der Ver- und Entschlüsselungsroutinen beginnen. Wie schon bei der Beschreibung von DES erwähnt, ist für die Verschlüsselung ebenso wie für die Entschlüsselung ein Schlüssel und ein Initialisierungsvektor erforderlich. Fügen Sie also diese beiden Elemente als Private-Mitglieder der Klasse hinzu. Geben Sie die folgenden (fett dargestellten) Codezeilen in die TripleDES-Klasse ein.

Public Class TripleDES
    Private key() As Byte = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
                              13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}
  Private iv() As Byte = {65, 110, 68, 26, 69, 178, 200, 219}

Wie Sie sehen, ist der Chiffrierschlüssel 24 Byte und der Initialisierungsvektor 8 Byte lang. Sie können die vorstehenden Zahlen gerne auch durch eigene Zahlen ersetzen.
Nun beginnen Sie mit der Entwicklung der Verschlüsselungsfunktion. Kopieren Sie den folgenden Code in die TripleDES-Klasse. Anschließend gehen wir den Code Zeile für Zeile durch, um die Funktionsweise zu untersuchen.

Public Function Encrypt(ByVal plainText As String) As Byte()
    ' Declare a UTF8Encoding object so we may use the GetByte
    ' method to transform the plainText into a Byte array.
    Dim utf8encoder As UTF8Encoding = New UTF8Encoding()
    Dim inputInBytes() As Byte = utf8encoder.GetBytes(plainText)
    ' Create a new TripleDES service provider 
    Dim tdesProvider As TripleDESCryptoServiceProvider = New 
TripleDESCryptoServiceProvider()
    ' The ICryptTransform interface uses the TripleDES
    ' crypt provider along with encryption key and init vector
    ' information 
    Dim cryptoTransform As ICryptoTransform = 
tdesProvider.CreateEncryptor(Me.key, Me.iv)
    ' All cryptographic functions need a stream to output the
    ' encrypted information.  Here we declare a memory stream
    ' for this purpose.
    Dim encryptedStream As MemoryStream = New MemoryStream()
    Dim cryptStream As CryptoStream = New CryptoStream(encryptedStream, 
cryptoTransform, CryptoStreamMode.Write)
    ' Write the encrypted information to the stream.  Flush the information
    ' when done to ensure everything is out of the buffer.
    cryptStream.Write(inputInBytes, 0, inputInBytes.Length)
    cryptStream.FlushFinalBlock()
    encryptedStream.Position = 0
    ' Read the stream back into a Byte array and return it to the calling
    ' method.
    Dim result(encryptedStream.Length - 1) As Byte
    encryptedStream.Read(result, 0, encryptedStream.Length)
    cryptStream.Close()
    Return result
  End Function

Um den Verschlüsselungsprozess zu starten, müssen wir zunächst die Zeichenfolge übergeben, die verschlüsselt werden soll. Damit dieser Prozess ordnungsgemäß funktionieren kann, müssen die Zeichenfolgendaten im nächsten Schritt in ein Bytearray umgewandelt werden. Denn alle Verschlüsselungsmethoden erwarten ausschließlich dieses Datenformat. Dies erfolgt mithilfe der UTF8Encoding-Klasse. Wir deklarieren einfach ein Byte-Arrayobjekt, das die Rückgabe von GetBytes akzeptiert, um die Byte-Arrayumwandlung für uns durchführen zu können.
Die nächsten beiden Zeilen der Anwendung dienen dazu, einen neuen TripleDESCryptoServiceProvider zu instantiieren, der die eigentliche Verschlüsselung übernimmt. Darüber hinaus ist auch ein ICryptoTransform-Objekt erforderlich, das unseren privaten Schlüssel und den Initialisierungsvektor für den Verschlüsselungsprozess aufnimmt.

Der Unterschied zwischen diesem Algorithmus und vielen der Beispiele, die Sie in den .NET-Hilfedateien finden, besteht darin, dass wir die Daten im Arbeitsspeicher und nicht in einer Datei auf der Festplatte verschlüsseln. Zu diesem Zweck müssen Sie ein MemoryStream-Objekt entwickeln, das die gesamten verschlüsselten Ausgabedaten aufnimmt. Wie Sie dem vorstehenden Code entnehmen können, erzeugen wir ein MemoryStream-Objekt namens encryptedStream. Daraufhin teilen wir dann dem CryptoStream-Objekt mit, dass dies genau die richtige Stelle für die verschlüsselten Daten ist.

Nachdem die Daten in das MemoryStream-Objekt verschlüsselt wurden, rufen Sie die FlushFinalBlock-Methode auf. So können Sie sicherstellen, dass alle Daten im MemoryStream platziert wurden. Anschließend lesen Sie die Daten aus MemoryStream wieder in ein Bytearray aus, das an die aufrufende Funktion zurückgegeben werden kann.

Die Entschlüsselung der Daten ähnelt der Verschlüsselung, weil exakt der gleiche Schlüssel verwendet wird. Der feine Unterschied besteht darin, dass wir nun ein Byte-Array zur Verarbeitung übernehmen und dass wir das resultierende Byte-Array nach Abschluss der Entschlüsselung in eine Zeichenfolge umwandeln müssen. Sie wird dann an die aufrufende Funktion zurückgegeben. Setzen Sie nun den folgenden Code in die TripleDES-Klasse.

Public Function Decrypt(ByVal inputInBytes() As Byte) As String
    ' UTFEncoding is used to transform the decrypted Byte Array
    ' information back into a string.
    Dim utf8encoder As UTF8Encoding = New UTF8Encoding()
    Dim tdesProvider As TripleDESCryptoServiceProvider = New 
TripleDESCryptoServiceProvider()
    ' As before we must provide the encryption/decryption key along with
    ' the init vector.
    Dim cryptoTransform As ICryptoTransform = 
tdesProvider.CreateDecryptor(Me.key, Me.iv)
    ' Provide a memory stream to decrypt information into
    Dim decryptedStream As MemoryStream = New MemoryStream()
    Dim cryptStream As CryptoStream = New CryptoStream(decryptedStream, 
cryptoTransform, CryptoStreamMode.Write)
    cryptStream.Write(inputInBytes, 0, inputInBytes.Length)
    cryptStream.FlushFinalBlock()
    decryptedStream.Position = 0
    ' Read the memory stream and convert it back into a string
    Dim result(decryptedStream.Length - 1) As Byte
    decryptedStream.Read(result, 0, decryptedStream.Length)
    cryptStream.Close()
    Dim myutf As UTF8Encoding = New UTF8Encoding()
    Return myutf.GetString(result)
  End Function

Damit wird die Verschlüsselungsklasse gewrappt. Und wenn wir jetzt noch die Datenbank aufgebaut haben, können wir mit dem Speichern von Daten beginnen.

Aufbau der Datenbank

An diesem Punkt können Sie sich entscheiden, ob Sie die Datenbank lieber mit SQL Server oder auf Oracle verwenden möchten. Der Unterschied zwischen den Datenbanken liegt lediglich im Primärschlüssel. In SQL Server generieren Sie einfach einen Primärschlüssel in der Tabelle und definieren diesen als eine Identity, mit einem sich automatisch erhöhenden Wert.

Bei Oracle müssen Sie hingegen den Primärschlüssel erzeugen und anschließend die Sequenz definieren, aus der die jeweils schrittweise erhöhte Nummer abgerufen und in den jeweiligen Datensatz gesetzt werden kann.

In SQL Server entwickeln Sie nun eine Datenbank mit Namen 3DESOrders und führen dann in Enterprise Manager den folgenden SQL-Code aus, um eine Tabelle für die Auftragsdaten zu erstellen.

CREATE TABLE [dbo].[CUSTOMER_ORDER] (
       [Order_ID] [int] IDENTITY (1, 1) NOT NULL ,
        [First_Name] [nvarchar] (15) NULL ,
        [Last_Name] [nvarchar] (25) NULL ,
        [Address] [nvarchar] (50) NULL ,
        [City] [nvarchar] (20) NULL ,
        [State] [nvarchar] (2) NULL ,
        [Zip] [nvarchar] (10) NULL ,
        [CC_Type] [nvarchar] (20) NULL ,
        [CC_Number] [varbinary] (100) NULL ,
        [CC_Exp] [nvarchar] (5) NULL 
) ON [PRIMARY]
GO

Beim Erzeugen der Tabelle in Oracle empfiehlt es sich zudem, einen neuen Benutzer für die Tabelle zu erstellen, so dass diese Tabelle nicht dem System-Tablespace hinzugefügt wird. Deswegen ist der erforderliche SQL-Code ein wenig umfangreicher. Wenn Sie mit Oracle als Back-End-Datenbank arbeiten, führen Sie den folgenden SQL-Code aus, um die erforderliche Tabelle, die Sequenz und den Benutzer zu entwickeln.

CREATE USER "ORDERS"  PROFILE "DEFAULT" 
    IDENTIFIED BY "orders" DEFAULT TABLESPACE "USERS" 
    TEMPORARY TABLESPACE "TEMP" 
    QUOTA UNLIMITED 
    ON USERS 
    ACCOUNT UNLOCK;
GRANT "CONNECT" TO "ORDERS";
CREATE TABLE ORDERS.CUSTOMER_ORDER
(
       ORDER_ID     NUMBER(18,2) UNIQUE NOT NULL,
       FIRST_NAME   VARCHAR2(15),
       LAST_NAME    VARCHAR2(25),
       ADDRESS      VARCHAR2(50),
       CITY         VARCHAR2(20),
       STATE        VARCHAR2(2),
       ZIP          VARCHAR2(10),
       CC_TYPE      VARCHAR2(20),
       CC_NUMBER    RAW(100),
       CC_EXP       VARCHAR2(5),
       CONSTRAINT PK_CUSTOMER_ORDER PRIMARY KEY (ORDER_ID )
)
create sequence ORDERID start with 1 increment by 1;

Vor weiteren Schritten prüfen Sie mit SQL Server Enterprise Manager oder mit dem entsprechenden Oracle-Tool, dass die Tabelle tatsächlich angelegt wurde und ordnungsgemäß funktioniert.

Speichern einer verschlüsselten Bestellung

Zum Speichern einer verschlüsselten Bestellung in der Datenbank sind sieben Schritte erforderlich:

  • Erstellen der Variablen zum Speichern der entsprechenden Daten.

  • Abrufen der Daten aus dem Auftragseingangsformular und Speichern der Daten in Variablen.

  • Deklarieren der Parameter zur Definition der Datentypen, die in die Datenbank aufgenommen werden sollen.

  • Öffnen einer Verbindung zur Datenbank.

  • Definieren der SQL-Anweisung zum Einfügen.

  • Laden der vorher hinzugefügten Parameter in das Befehlsobjekt.

  • Und schließlich: Speichern der Daten.

Wir werden den Code zum Speichern der Bestellung allerdings als privates Unterprogramm (Subroutine) implementieren, anstatt ihn einfach dem Click-Ereignis einer Schaltfläche zuzuordnen. Fügen Sie also den folgenden Code der Form1-Klasse hinzu:

Private Sub InsertOrderItem()
     ' Here is our connection string.  This uses a trusted connection so 
     ' your user id must have access to the database you are attempting to
     ' connect to.  Replace the "data source" with the correct server.
     Dim ODC As String = "data source=dotnetserver;initial catalog=3DESOrders; 
Trusted_Connection=true;workstation id=POWERHOUSE;packet size=4096"
     Dim myConnection As New SqlConnection(ODC)
     Dim myCommand As New SqlCommand()
     ' Used for storing the information we wish to save.
     Dim FirstName As String
     Dim LastName As String
     Dim Address As String
     Dim City As String
     Dim State As String
     Dim Zip As String
     Dim CCType As String
     Dim CCNumber() As Byte
     Dim CCExp As String
     Dim TDES As New TripleDES()
     ' Retrieve the order information
     FirstName = txtFirstName.Text
     LastName = txtLastName.Text
     Address = txtAddress.Text
     City = txtCity.Text
     State = txtState.Text
     Zip = txtZip.Text
     CCType = cmbCCType.Text
     CCNumber = TDES.Encrypt(txtCCNumber.Text)
     CCExp = txtCCExp.Text
     ' Declare parameters for the information we wish to insert into the
     ' database.
     Dim paramFirstName As New SqlParameter("@FirstName", FirstName)
     Dim paramLastName As New SqlParameter("@LastName", LastName)
     Dim paramAddress As New SqlParameter("@Address", Address)
     Dim paramCity As New SqlParameter("@City", City)
     Dim paramState As New SqlParameter("@State", State)
     Dim paramZip As New SqlParameter("@Zip", Zip)
     Dim paramCCType As New SqlParameter("@CCType", CCType)
     Dim paramCCNumber As New SqlParameter("@CCNumber", CCNumber)
     Dim paramCCExp As New SqlParameter("@CCExp", CCExp)
     myCommand.Connection() = myConnection
     myCommand.Connection.Open()
     myCommand.CommandText = "INSERT INTO CUSTOMER_ORDER
        (FIRST_NAME,LAST_NAME,ADDRESS,CITY,STATE,ZIP,CC_TYPE,CC_NUMBER,CC_EXP) VALUES 
        (@FirstName,@LastName,@Address,@City,@State,@Zip,@CCType,@CCNumber,@CCExp)"
     myCommand.Parameters.Clear()
     myCommand.Parameters.Add(paramFirstName)
     myCommand.Parameters.Add(paramLastName)
     myCommand.Parameters.Add(paramAddress)
     myCommand.Parameters.Add(paramCity)
     myCommand.Parameters.Add(paramState)
     myCommand.Parameters.Add(paramZip)
     myCommand.Parameters.Add(paramCCType)
     myCommand.Parameters.Add(paramCCNumber)
     myCommand.Parameters.Add(paramCCExp)
     ' Actually insert the information into the database.
     myCommand.ExecuteNonQuery()
     myConnection.Close()
End Sub

Mit diesem Unterprogramm können Sie nur auf eine SQL Server-Datenbank zugreifen. Wenn Sie hiermit arbeiten möchten, müssen Sie den Eintrag unter data source so ändern, dass dieser auf Ihren Server mit SQL Server verweist. Im vorstehenden Code befindet sich die Datenbank auf einem Server mit Namen dotnetserver. Wenn Sie mit einer Oracle-Datenbank arbeiten, müssen Sie zwei Codezeilen ändern. Mit der ersten Zeile wird die Verbindung zur Datenbank definiert. Ersetzen Sie Zeile 2 des vorstehenden Codes durch die folgende Zeile:

Dim ODC As String = "Provider=MSDAORA.1;Password=orders;User ID=orders;Data Source=tst"

Ebenso wie die Verbindungszeichenfolge müssen Sie auch alle Sql-Befehle durch OleDb ersetzen. Auf diese Weise wird aus SqlParameter z. B. OleDbParameter. Ein orders-Benutzer wurde bereits mit dem vorstehenden SQL-Skript erzeugt. Möglicherweise müssen Sie jedoch auch hier die Datenquelleneinstellung unter data source so ändern, dass auf die Oracle-Instanz (auch als die SID bezeichnet) verwiesen wird. Nachdem Sie die Verbindungszeichenfolge angepasst haben, müssen Sie nur noch die eigentliche Anweisung zum Einfügen ändern. Da die Daten bei Oracle und SQL Server werden auf unterschiedliche Weisen eingefügt. Ersetzen Sie die Einfügeanweisung durch die folgende Codezeile:

myCommand.CommandText = "INSERT INTO 
CUSTOMER_ORDER( ORDER_ID, FIRST_NAME, LAST_NAME, ADDRESS,CITY, STATE, ZIP, 
CC_TYPE, CC_NUMBER, CC_EXP) VALUES (ORDERID.NEXTVAL, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

Mit dieser Zeile des SQL-Codes kommt die ORDERID-Sequenz zum Einsatz, die durch Aufruf einer Funktion namens NextVal generiert wurde. Hiermit wird der nächste sequenzielle Wert abgerufen und die Folgenummer damit um den Wert 1 erhöht.
Nachdem wir nun die SQL Server- und die Oracle-Version des Codes definiert haben, wollen wir uns näher mit dem Code an sich befassen. Wie Sie sehen, lassen sich Daten mit einer sehr einfachen Routine in Datenbanken einfügen. Möglicherweise haben Sie auch schon festgestellt, dass wir ganz am Anfang eine Instanz der TripleDES-Klasse instantiieren und später die Encrypt-Methode dieser Klasse aufrufen. Hiermit wird die Kreditkartennummer aus dem Formular an die Verschlüsselungsroutine übergeben und kommt als ein Bytearray zurück, das dann in der Datenbank gespeichert wird. Die Verwendung dieser Klasse ist wirklich kinderleicht.
Sie brauchen nun zudem noch eine Routine, um alle Werte aus dem Auftragseingangsformular zu löschen. Fügen Sie daher auch das folgende Unterprogramm der Form1-Klasse hinzu:

Private Sub ClearItems()
    txtFirstName.Text = ""
    txtLastName.Text = ""
    txtAddress.Text = ""
    txtCity.Text = ""
    txtState.Text = ""
    txtZip.Text = ""
    cmbCCType.Text = ""
    txtCCNumber.Text = ""
    txtCCExp.Text = ""
End Sub

Nachdem nun beide Unterprogramme platziert wurden, können wir tatsächlich Daten in der Datenbank speichern. Kehren Sie zum Projektexplorer zurück, und zeigen Sie Form1 des Projekts an. Doppelklicken Sie auf die Schaltfläche Save Order, damit Sie die Click-Methode dieser Schaltfläche ändern können. Setzen Sie den folgenden (fett dargestellten) Code in das Click-Ereignis der Schaltfläche.

Private Sub btnSaveOrder_Click(ByVal sender As 
System.Object, ByVal e As System.EventArgs) Handles btnSaveOrder.Click
        InsertOrderItem()
        ClearItems()
    End Sub

Die Anwendung sollte nun die Kreditkartennummer verschlüsseln und die Daten speichern können - lassen wir es auf einen Versuch ankommen. Führen Sie die Anwendung aus, und geben Sie einige Bestelldaten ein, wie in der nachstehenden Abbildung 3 gezeigt.

Bild03

Wenn Sie die Daten eingegeben haben, klicken Sie auf die Schaltfläche Save Order. Die Daten sollten in der Datenbank gespeichert und sämtliche Angaben aus dem Bestellformular gelöscht werden.
Wenn Sie mit SQL Server arbeiten, können Sie die soeben an die Tabelle übergebenen Daten einfach im Server-Explorer anzeigen. Erweitern Sie die Serververbindung und suchen Sie die Tabelle, in der die Bestellung gerade gespeichert wurde (siehe auch Abbildung 4).

Bild04

Wenn Sie die Tabelle gefunden haben, können Sie mit der rechten Maustaste darauf klicken und Retrieve Data from Table wählen, um die Daten anzuzeigen. Die SQL Server-Datenansicht zeigt lediglich, dass sich Binärdaten in der Tabelle befinden.

Bild05

Unter Oracle können Sie ein Tool wie TOAD (Tool for Oracle Application Developers) verwenden, um die Daten anzuzeigen. Mithilfe von TOAD können wir tatsächlich auch Daten in jeder Spalte anzeigen. Vergessen Sie nicht, dass die Daten im verschlüsselten byte-Format vorliegen und daher wenig aussagekräftig sind. Sie können aber zumindest prüfen, dass tatsächlich Daten eingefügt wurden, wie auch nachstehend gezeigt:

Bild06

Entschlüsseln der Auftragsdaten

Sie werden sich vielleicht erinnern, dass wir zu Beginn der Anwendungsentwicklung dem Projekt ein Formular mit Namen AllOrders.vb hinzugefügt haben. Wechseln Sie nun im Projektexplorer zu diesem Formular und doppelklicken Sie darauf. Wir möchten dem Form Load-Ereignis Code hinzufügen. Wenn das Formular geladen wird, sollen Daten aus der Datenbank abgerufen, entschlüsselt und im ListView-Steuerelement angezeigt werden. Wir könnten nun einfach ein Grid-Steuerelement verwenden und dieses mit der Datenbank verknüpfen.

Da wir aber mit verschlüsselten Daten arbeiten, hätten wir dann keine Möglichkeit, die Daten zu entschlüsseln, bevor sie in das Steuerelement geladen werden. Daher müssen wir mit einer Schleife sämtliche Datensätze durchgehen, diese entschlüsseln und dann im ListView-Steuerelement anzeigen.
Fügen Sie dem Form Load-Ereignis den folgenden (fett dargestellten) Code hinzu.

Private Sub AllOrders_Load(ByVal sender As System.Object,
 ByVal e As System.EventArgs) Handles MyBase.Load
    Dim dr As DataRow
    Dim CCNumber As String
    Dim TDES As TripleDES
    Dim lvi As ListViewItem
    ' load all of the orders
    Dim gsConn As SqlConnection = New SqlConnection("data source=dotnetserver;initial 
catalog=3DESOrders; 
                 Trusted_Connection=true;workstation id=POWERHOUSE;packet size=4096")
    ' Declare our select command to retrieve all orders from the database
    Dim selectCMD As SqlCommand = New SqlCommand("SELECT * from CUSTOMER_ORDER", gsConn)
    selectCMD.CommandTimeout = 30
    Dim itemDA As SqlDataAdapter = New SqlDataAdapter()
    itemDA.SelectCommand = selectCMD
    gsConn.Open()
    ' Fill a dataset with all the orders.
    Dim orderDS As DataSet = New DataSet()
    itemDA.Fill(orderDS, "CUSTOMER_ORDER")
    gsConn.Close()
    ' Loop through all the orders decrypting the credit card
    ' information
    For Each dr In orderDS.Tables("CUSTOMER_ORDER").Rows
        TDES = New TripleDES()
        CCNumber = TDES.Decrypt(dr.Item("CC_NUMBER"))
        ' Now that the information has been decrypted, lets
        ' add it to our ListView control.
        lvi = New ListViewItem()
        lvi.Text = dr.Item("FIRST_NAME")
        lvi.SubItems.Add(dr.Item("LAST_NAME"))
        lvi.SubItems.Add(dr.Item("ADDRESS"))
        lvi.SubItems.Add(dr.Item("CITY"))
        lvi.SubItems.Add(dr.Item("STATE"))
        lvi.SubItems.Add(dr.Item("ZIP"))
        lvi.SubItems.Add(dr.Item("CC_TYPE"))
        lvi.SubItems.Add(CCNumber)
        lvi.SubItems.Add(dr.Item("CC_EXP"))
        ListView1.Items.Add(lvi)
    Next
End Sub

Dieser Code gilt ebenfalls nur für SQL Server. Wenn Sie ihn nutzen möchten, müssen Sie den Datenquellenverweis wieder so ändern, dass er auf den zu verwendenden Server zeigt. Wenn Sie den Code unter Oracle einsetzen möchten, müssen Sie lediglich die Verbindungszeichenfolge so ändern, dass der Oracle-Treiber verwendet wird. Außerdem müssen Sie wieder alle Sql-Verweise in OleDb-Verweise ändern. Ersetzen Sie die Verbindungszeichenfolge durch die nachstehende Codezeile, wenn Sie mit Oracle arbeiten:

Dim gsConn As OleDbConnection = New OleDbConnection
    ("Provider=MSDAORA.1;Password=orders;User ID=orders;Data Source=tst")

Mit diesem Code können Sie die Daten nun aus der Datenbank laden und entschlüsseln. Jetzt fehlt allerdings noch der Code, mit dem das Formular tatsächlich geöffnet wird. Kehren Sie zu Form1 des Projekts zurück und doppelklicken Sie auf die Schaltfläche View Orders, damit Sie auch dem Click-Ereignis dieser Schaltfläche noch etwas Code hinzufügen können. Fügen Sie dem Click-Ereignis der Schaltfläche also noch folgenden Code hinzu:

Dim frmAllOrders As New AllOrders()
        frmAllOrders.ShowDialog()

Wir können die Anwendung nun ausführen und auf die Schaltfläche View Orders klicken. Nach kurzer Zeit sollten die entschlüsselten Daten wie nachstehend gezeigt im ListView-Steuerelement angezeigt werden.

Bild07

 

Zusammenfassung

Die im aufgeführten Beispiel bereitgestellte Klasse kann zum Verschlüsseln sensibler Informationen verwendet werden, bevor diese in eine Datenbank oder einfach nur in eine Textdatei übergeben werden. Mit ein paar Handgriffen kann diese Wrapperklasse zudem für den Einsatz von DES, RC2 oder eines anderen .NET-Kryptografieproviders angepasst werden. Die hier beschriebenen Methoden sind nicht nur einfach zu nutzen, sondern bieten auch ein leistungsfähiges Tool. Dieses stellt sicher, dass private Daten auch wirklich privat bleiben.

 

Informationsquellen zum Thema Verschlüsselung

Wenn Sie mehr über Verschlüsselung und die verschiedenen Algorithmen erfahren möchten, empfiehlt sich ein Besuch der Website CounterPane. CounterPane ist eine Sicherheitsberatungsfirma, die sich in der Hauptsache mit Kryptografie befasst. Der Präsident von CounterPane hat zudem ein Buch mit dem Titel Applied Cryptography herausgebracht, in dem viele der Algorithmen detailliert beschrieben werden und das auch den Quellcode der Algorithmen in C enthält.

Die Verwendung der Verschlüsselung mit öffentlichen Schlüsseln bietet ebenfalls viele Vorzüge, obwohl wir uns hiermit im vorliegenden Artikel nur ganz am Rande befassen konnten. Wenn Sie Näheres hierüber erfahren möchten, sollten Sie die folgenden englischsprachigen Websites besuchen:

Verwandte Links (englischsprachig)
Applied Cryptography von Bruce Schneier

Verwandte ASPToday-Artikel (englischsprachig)
Using AspEncrypt in Web Applications: Part 1
Cryptography
Site Security Using Microsoft's CryptoAPI
Securing Financial Transactions with ASP.NET