Share via


Codeanalyse der Communicator-Klasse (CNG-Beispiel)

Die Datei Communicator.cs enthält die Methoden zur Verschlüsselung und Entschlüsselung des Beispiels für sichere Cryptography Next Generation (CNG)-Kommunikation.Sie besteht aus nur einer Klasse, die Communicator genannt wird.Diese Klasse enthält die im folgenden Abschnitt behandelten Member und Methoden:

  • Klassenmember

  • Klassenkonstruktor

  • Dispose-Methode

  • StoreDSKey-Methode

  • Send_or_Receive_PublicCryptoKey-Methode

  • SendMessage-Methode

  • ReceiveMessage-Methode

Einen Überblick über das Beispiel sowie Beschreibungen der ín diesem Thema erwähnten Versionen finden Sie unter Beispiel für sichere Cryptography Next Generation (CNG)-Kommunikation.

Klassenmember

Die Communicator-Klasse enthält die folgenden privaten Member:

  • CngKey m_DSKey

    Dieser Member wird von Communicator.StoreDSKey verwendet, um einen digitalen Signaturschlüssel zu speichern.

  • ECDiffieHellmanCng m_ECDH_Cng

    Dieser Member wird vom Konstruktor verwendet, um eine Instanz der ECDiffieHellmanCng-Klasse zu speichern.Die ReceiveMessage-Methode und die SendMessage-Methode verwenden diesen Member, um Schlüsselmaterial abzuleiten.

  • string m_ECDH_local_publicKey_XML

    Dieser Member wird vom Konstruktor verwendet, um den lokalen öffentlichen ECDH (Elliptic Curve Diffie-Hellman)-Kryptografieschlüssel als XML-Zeichenfolgendarstellung zu speichern.Alice, Bob und Mallory verwenden die Send_or_Receive_PublicCryptoKey-Methode, um diese XML-Zeichenfolge auszutauschen.

  • ECDiffieHellmanPublicKey m_ECDH_remote_publicKey

    Dieser Member wird von der Send_or_Receive_PublicCryptoKey-Methode verwendet, um einen öffentlichen Remote-ECDH-Kryptografieschlüssel zu speichern.

Die <legacyBold>Communicator</legacyBold>-Klasse stellt auch den folgenden öffentlichen Member bereit:

  • ChannelManager ChMgr

    Dieser Member wird von Alice, Bob und Mallory verwendet, um benannte Pipedienste bereitzustellen.

Klassenkonstruktor

public Communicator(string mode, string ChannelName)

Der Konstruktor erstellt die folgenden drei Objekte:

  • Eine Instanz der ECDiffieHellmanCng-Klasse mit einem zufälligen Schlüsselpaar und einer Schlüsselgröße von 521 Bits:

    m_ECDH_Cng = new ECDiffieHellmanCng(521)
    

    Das daraus resultierende Objekt wird als privater Member an die Communicator-Klasse gebunden.Jedes Communicator-Objekt erstellt eine einzelne Instanz dieser Klasse.

    Alice und Bob erstellen jeweils ein einzelnes Communicator-Objekt und können auf je einen einzelnen m_ECDH_Cng-Member zugreifen.Mallory erstellt zwei Communicator-Objekte: eines zur Verwendung mit Alice, das andere zur Verwendung mit Bob.Dementsprechend kann Mallory auf zwei m_ECDH_Cng-Member zugreifen.

  • Der öffentliche ECDH- Schlüssel als private XML-Zeichenfolge:

    m_ECDH_XmlString = m_ECDH_CryptoKey.ToXmlString(ECKeyXmlFormat.Rfc4050)
    

    Die ECDiffieHellmanCng.ToXmlString-Methode serialisiert den öffentlichen ECDH-Schlüssel unter Verwendung des ECKeyXmlFormat.Rfc4050-Formats.

    In den Versionen 2 bis 5 des Beispiels sendet Alice die resultierende XML-Zeichenfolge mit ihrer Run-Methode an Bob. Dabei verwendet sie die folgende Codeanweisung:

    Alice.Send_or_Receive_PublicCryptoKey("send", MyColor);
    
  • Eine öffentliche Instanz der ChannelManager-Klasse:

    ChMgr = new ChannelManager(mode, ChannelName)
    

    Der Konstruktor akzeptiert die folgenden zwei Parameter:

    • mode: Eine Zeichenfolge, die angibt, wie die benannte Pipe erstellt wird.Dieser Parameter kann entweder "Server" oder "Client" sein.

    • ChannelName: Eine Zeichenfolge, die einen Namen zur Identifizierung der neuen benannten Pipe bereitstellt.

Dispose-Methode

public void Dispose()

Die Communicator-Klasse erbt die IDisposable-Schnittstelle und stellt die Dispose-Methode zur unmittelbaren Freigabe vertraulicher Ressourcen bereit.Hierzu zählen Objekte des Typs m_ECDH_Cng, m_ECDH_local_publicKey_XML und ChMgr.

Jedes Objekt wird innerhalb einer using-Anweisung in C# erstellt, um sicherzustellen, dass es unmittelbar bei Verlassen des Gültigkeitsbereichs freigegeben wird.

StoreDSKey-Methode

public void StoreDSKey(byte[] DSKeyBlob)

Diese Methode akzeptiert ein Binary Large Object (BLOB), das in einem Bytearray enthalten ist.Sie extrahiert mithilfe der CngKey.Import(array<Byte[], CngKeyBlobFormat)-Methode einen digitalen Signaturschlüssel aus dem BLOB-Schlüssel.Der Schlüssel wird dann mit dem folgenden Code gespeichert:

m_DSKey = CngKey.Import(DSKeyBlob,CngKeyBlobFormat.Pkcs8PrivateBlob);

Die StoreDSKey-Methode wird von Alice, Bob und Mallory in ihren Run-Methoden von folgenden Versionen aufgerufen:

  • In Version 3 bis 5 verwenden Alice, Bob und Mallory diese Methode, um denselben, öffentlich übermittelten Schlüssel zu speichern.

  • In Version 4 und 5 rufen Alice und Bob diese Methode ein zweites Mal auf und überschreiben den m_DSKey-Member mit einem privat übermittelten Schlüssel.

Send_or_Receive_PublicCryptoKey-Methode

Send_or_Receive_PublicCryptoKey(string mode, int color)

Diese Methode akzeptiert zwei Parameter:

  • mode: Eine Zeichenfolge, die entweder das Erstellen eines Pipeservers zum Senden eines Schlüssels oder das Erstellen eines Pipeclients zum Empfangen eines Schlüssel angibt.Der Parameter kann entweder "Server" oder "Client" sein.

  • color: Ein ganzzahliger Wert, der die Farbe festlegt, in der der Schlüssel angezeigt wird.

Die Send_or_Receive_PublicCryptoKey-Methode ähnelt den Communicator-Methoden ReceiveMessage und SendMessage, mit dem Unterschied, dass sie unverschlüsselte kryptografische Schlüssel statt verschlüsselter Meldungen sendet oder empfängt.ReceiveMessage und SendMessage können nicht für kryptografische Schlüssel verwendet werden, da diese Methoden versuchen würden, die Schlüssel zu verschlüsseln und zu entschlüsseln.

Nachdem die Schlüssel ausgetauscht wurden, werden in den Versionen 3 bis 5 des Beispiels die digitalen Signaturen der Schlüssel überprüft.Version 3 verwendet eine digitale Signatur, die über die benannte Pipe PublicChannel gesendet wird.Diese Signatur wird von Mallory abgefangen und zum Signieren der ersetzten Schlüssel und Nachrichten, die er an Alice und Bob sendet, genutzt.Version 3 kann die Validierung der Signatur immer erfolgreich abschließen, weil Alice, Bob und Mallory denselben digitalen Schlüssel verwenden.

Hinweis

Version 4 und 5 verwenden eine private digitale Signatur, um Schlüssel und Nachrichten zu signieren und Sicherheitswarnungen anzuzeigen.Diese Versionen sind nur für Alice und Bob vorgesehen.Dementsprechend weiß Mallory nicht, dass seine Abfangenmanöver bemerkt wurden.

SendMessage-Methode

public bool SendMessage(string plainTextMessage, bool fShowMsg)

Diese Methode wird von Alice, Bob und Mallory über ihre Run-Methoden aufgerufen.Nachrichten werden mit ihr durch die folgenden Schritte verschlüsselt, digital signiert und gesendet:

  1. Zeigt die Klartext-Nachricht an, wenn der fShowMsg-Wert true ist.

  2. Konvertiert die Nachricht mithilfe des folgenden Codes in ein Unicode-Bytearray:

    byte[] UnicodeText = Encoding.Unicode.GetBytes(plainTextMessage);
    
  3. Bestimmt, ob die Nachricht als Klartext gesendet werden soll.Beim Ausführen von Version 1 des Beispiels wird SendMessage zurückgegeben, nachdem die Nachricht mithilfe des folgenden Codes gesendet wurde:

    ChMgr.SendMessage(UnicodeText);
    
  4. Leitet Schlüsselmaterial durch Aufrufen der ECDiffieHellmanCng.DeriveKeyMaterial(ECDiffieHellmanPublicKey)-Methode ab:

    byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey)
    
  5. Erstellt ein temporäres Aes-Objekt:

    Aes aes = new AesCryptoServiceProvider()
    
  6. Initialisiert das Aes-Objekt mit dem Schlüsselmaterial, das in Schritt 4 abgeleitet wurde:

    aes.Key = aesKey;
    
  7. Erstellt ein temporäres MemoryStream-Objekt, um eine verschlüsselte Zeichenfolge aufzunehmen.

  8. Erstellt ein temporäres CryptoStream-Objekt und verschlüsselt damit die Nachricht und schreibt sie in das MemoryStream-Objekt.

  9. Speichert den verschlüsselten Text und den Initialisierungsvektor:

    iv = aes.IV
    ciphertext = ms.ToArray();
    
  10. Signiert den verschlüsselten Text beim Ausführen von Version 3, 4 oder 5 wie folgt:

    • Erstellt ein temporäres ECDsaCng.ECDsaCng(CngKey)-Objekt:

      ECDsaCng ecdsa = new ECDsaCng(m_DSKey)
      
    • Initialisiert die HashAlgorithm-Eigenschaft des Objekts als sicheren Sha512-Hashalgorithmus:

      ecdsa.HashAlgorithm = CngAlgorithm.Sha512
      
    • Erstellt durch Signieren des verschlüsselten Texts eine digitale Signatur:

      signature = ecdsa.SignData(ciphertext);
      
  11. Bereitet die Ausgabenachricht wie folgt vor:

    • Erstellt ein Array mit drei Bytes, um die Längen des Initialisierungsvektors der Nachricht, den verschlüsselten Text und die Signatur aufzunehmen.

    • Erstellt vier System.Collections.Generic.List<T>-Objekte, um das Längenarray aus dem vorherigen Schritt, den Initialisierungsvektor, den verschlüsselten Text und die Signatur aufzunehmen.

    • Verkettet die vier System.Collections.Generic.List<T>-Objekte und konvertiert sie zu einem einzigen Ausgabenachricht-Bytearray.

      byte[] message = list1.ToArray();
      
  12. Sendet die Ausgabenachricht:

    ChMgr.SendMessage(message)
    

ReceiveMessage-Methode

public string ReceiveMessage()

Diese Methode wird von Alice, Bob und Mallory über ihre Run-Methoden aufgerufen.Mit ihr werden Nachrichten empfangen und entschlüsselt und deren digitalen Signaturen überprüft.

Nachrichten werden nicht als Parameter an diese Methode übergeben.Stattdessen liest der ChannelManager-Member der Communicator-Klasse die Nachricht mithilfe des folgenden Codes:

byteBuffer = ChMgr.ReadMessage();

Die ReceiveMessage-Methode führt die folgenden Schritte aus:

  1. Ermittelt, ob die Nachricht als Klartext gesendet wurde.Wird Version 1 des Beispiels ausgeführt, ist die Nachricht in Klartext und muss nicht entschlüsselt werden.In diesem Fall wird die Nachricht zurückgegeben, nachdem sie mithilfe des folgenden Codes in eine ASCII-Zeichenfolge konvertiert wurde:

    AsciiMessage = Encoding.Unicode.GetString(byteBuffer);
    
  2. Unterteilt die Nachricht in Komponenten.In Version 2 bis 5 wird die Nachricht verschlüsselt.In diesem Fall wird die Nachricht in drei separate Bytearrays unterteilt.Das erste Array enthält den Initialisierungsvektor, das zweite den verschlüsselten Text, und das dritte die digitale Signatur des verschlüsselten Texts.

  3. Zeigt den Initialisierungsvektor, den verschlüsselten Text und die Signatur als ASCII-Text an, wenn das fVerbose-Kennzeichen festgelegt ist.

  4. Leitet Schlüsselmaterial ab.Der private ECDiffieHellmanCng-Member, m_ECDH_Cng, der Communicator-Klasse verwendet die ECDiffieHellmanCng.DeriveKeyMaterial-Methode, um gemeinsam genutztes Schlüsselmaterial abzuleiten. Dies ist im folgenden Code dargestellt:

    byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey);
    
  5. Erstellt ein Aes-Objekt durch Instanziieren eines AesCryptoServiceProvider-Objekts:

    Aes aes = new AesCryptoServiceProvider()
    
  6. Initialisiert das Aes-Objekt mit dem aus den vorherigen Schritten abgeleiteten Schlüsselmaterial und Initialisierungsvektor.

  7. Entschlüsselt die Nachricht unter Verwendung des System.IO.MemoryStream-Objekts und des System.Security.Cryptography.CryptoStream-Objekts.

  8. Zeigt die entschlüsselte Nachricht an.

  9. Überprüft in Version 3 bis 5 den verschlüsselten Text der Nachricht mithilfe der digitalen Signatur.Version 3 zeigt keine Sicherheitswarnungen an, da Alice, Bob und Mallory dieselbe Signatur verwenden.Version 4 zeigt Sicherheitswarnungen an, wenn der verschlüsselte Text einer Nachricht eine ungültige Signatur hat.Jedoch steht nur Alice und Bob Version 4 zu Verfügung. Daher sieht Mallory niemals eine Warnung.In Version 5 verursachen ungültig signierte kryptografische Schlüssel einen Programmabbruch, noch bevor eine Meldung gesendet und überprüft wird.

Siehe auch

Konzepte

Beispiel für sichere Cryptography Next Generation (CNG)-Kommunikation

Communicator.cs-Quellcode (CNG-Beispiel)

Quellcodeübersicht (CNG-Beispiel)

Schrittweiser Austausch von Schlüsseln und Nachrichten (CNG-Beispiel)

Erwartete Ausgabe (CNG-Beispiel)