Partager via


Analyse du code de la classe Communicator (Exemple CNG)

Le fichier Communicator.cs encapsule les méthodes de chiffrement et de déchiffrement pour l'exemple de communication sécurisée CNG (Cryptography Next Generation).Il se compose d'une seule classe nommée Communicator.Cette classe contient les membres et les méthodes décrits dans les sections suivantes :

  • Membres de classe

  • Constructeurs de classe

  • Méthode Dispose

  • Méthode StoreDSKey

  • Méthode Send_or_Receive_PublicCryptoKey

  • Méthode SendMessage

  • Méthode ReceiveMessage

Consultez Communication sécurisée Cryptography Next Generation (CNG), exemple pour obtenir une vue d'ensemble de l'exemple et des descriptions des versions mentionnées dans cette rubrique.

Membres de classe

La classe Communicator contient les membres privés suivants :

  • CngKey m_DSKey

    Communicator.StoreDSKey utilise ce membre pour stocker une clé de signature numérique.

  • ECDiffieHellmanCng m_ECDH_Cng

    Le constructeur utilise ce membre pour stocker une instance de la classe ECDiffieHellmanCng.Les méthodes ReceiveMessage et SendMessage utilisent ce membre pour dériver le matériel de clé.

  • string m_ECDH_local_publicKey_XML

    Le constructeur utilise ce membre pour stocker une représentation sous forme de chaîne XML de la clé de chiffrement ECDH (Elliptic Curve Diffie-Hellman) publique locale.Alice, Bob et Mallory utilisent la méthode Send_or_Receive_PublicCryptoKey pour échanger cette chaîne XML.

  • ECDiffieHellmanPublicKey m_ECDH_remote_publicKey

    La méthode Send_or_Receive_PublicCryptoKey utilise ce membre pour stocker une clé de chiffrement ECDH publique distante.

La classe Communicator fournit également le membre public suivant :

  • ChannelManager ChMgr

    Alice, Bob et Mallory utilisent ce membre pour fournir des services de canal nommé.

Constructeurs de classe

public Communicator(string mode, string ChannelName)

Le constructeur crée les trois objets suivants :

  • Une instance de la classe ECDiffieHellmanCng avec une paire de clés aléatoire, à l'aide d'une taille de clé de 521 bits :

    m_ECDH_Cng = new ECDiffieHellmanCng(521)
    

    L'objet obtenu est lié à la classe Communicator en tant que membre privé.Chaque objet Communicator crée une instance unique de cette classe.

    Alice et Bob créent chacun un objet Communicator unique et peuvent accéder à un membre m_ECDH_Cng unique.Mallory crée deux objets Communicator : un à utiliser avec Alice et l'autre à utiliser avec Bob.Il peut donc accéder à deux membres m_ECDH_Cng.

  • La clé publique ECDH sous forme de chaîne XML privée :

    m_ECDH_XmlString = m_ECDH_CryptoKey.ToXmlString(ECKeyXmlFormat.Rfc4050)
    

    La méthode ECDiffieHellmanCng.ToXmlString sérialise la clé ECDH publique à l'aide du format ECKeyXmlFormat.Rfc4050.

    Dans les versions 2 à 5 de l'exemple, Alice envoie à Bob la chaîne XML obtenue dans sa méthode Run à l'aide de l'instruction de code suivante :

    Alice.Send_or_Receive_PublicCryptoKey("send", MyColor);
    
  • Une instance publique de la classe ChannelManager :

    ChMgr = new ChannelManager(mode, ChannelName)
    

    Le constructeur accepte les deux paramètres suivants :

    • mode : chaîne qui indique comment créer le canal nommé.Ce paramètre peut être « server » ou « client ».

    • ChannelName : chaîne qui fournit un nom permettant d'identifier le nouveau canal nommé.

Méthode Dispose

public void Dispose()

La classe Communicator hérite de l'interface IDisposable et fournit la méthode Dispose pour libérer immédiatement des ressources sensibles.Cela concerne notamment les objets m_ECDH_Cng, m_ECDH_local_publicKey_XML et ChMgr.

Chaque objet est créé dans une instruction C# using pour garantir que l'objet sera libéré dès qu'il sera hors de portée.

Méthode StoreDSKey

public void StoreDSKey(byte[] DSKeyBlob)

Cette méthode accepte un objet blob contenu dans un tableau d'octets.Il extrait une clé de signature numérique de l'objet blob de clé à l'aide de la méthode CngKey.Import(array<Byte[], CngKeyBlobFormat).La clé est ensuite stockée grâce au code suivant :

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

Alice, Bob et Mallory appellent la méthode StoreDSKey dans leurs méthodes Run, selon les versions suivantes :

  • Dans les versions 3 à 5, Alice, Bob et Mallory utilisent cette méthode pour stocker la même clé transmise publiquement.

  • Dans les versions 4 et 5, Alice et Bob appellent cette méthode une deuxième fois et remplacent le membre m_DSKey par une clé transmise en privé.

Méthode Send_or_Receive_PublicCryptoKey

Send_or_Receive_PublicCryptoKey(string mode, int color)

Cette méthode accepte deux paramètres :

  • mode : chaîne qui indique s'il faut créer un serveur de canaux pour envoyer une clé ou un client de canal pour recevoir une clé.Ce paramètre peut être « server » ou « client ».

  • color : entier qui spécifie la couleur utilisée pour afficher la clé.

La méthode Send_or_Receive_PublicCryptoKey est semblable aux méthodes CommunicatorReceiveMessage et SendMessage, excepté qu'elle envoie ou reçoit des clés de chiffrement non chiffrées au lieu de messages chiffrés.Les méthodes ReceiveMessage et SendMessage ne peuvent pas être utilisées pour les clés de chiffrement car elles tenteraient de chiffrer et de déchiffrer les clés.

Après avoir échangé les clés, les versions 3 à 5 de l'exemple valident les signatures numériques des clés.La version 3 utilise une signature numérique transmise sur le canal nommé PublicChannel.Cette signature est interceptée et utilisée par Mallory pour signer les clés et les messages de substitution qu'il envoie à Alice et Bob.Dans la version 3, la signature est toujours validée car Alice, Bob et Mallory utilisent la même clé de signature numérique.

Notes

Les versions 4 et 5 utilisent une signature numérique privée pour signer les clés et les messages et affichent des avertissements de sécurité.Ces versions ne sont données qu'à Alice et Bob.Par conséquent, Mallory ne sait pas que ses interceptions ont été détectées.

Méthode SendMessage

public bool SendMessage(string plainTextMessage, bool fShowMsg)

Alice, Bob et Mallory appellent cette méthode à partir de leurs méthodes Run.Elle chiffre, signe numériquement et envoie des messages en suivant ces étapes :

  1. Affiche le message texte en clair si fShowMsg a la valeur true.

  2. Convertit le message en tableau d'octets Unicode à l'aide du code suivant :

    byte[] UnicodeText = Encoding.Unicode.GetBytes(plainTextMessage);
    
  3. Détermine si le message doit être envoyé en texte en clair.Si l'exemple exécute la version 1, SendMessage est retourné après avoir envoyé le message à l'aide du code suivant :

    ChMgr.SendMessage(UnicodeText);
    
  4. Dérive le matériel de clé en appelant la méthode ECDiffieHellmanCng.DeriveKeyMaterial(ECDiffieHellmanPublicKey) :

    byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey)
    
  5. Crée un objet Aes temporaire.

    Aes aes = new AesCryptoServiceProvider()
    
  6. Lance l'objet Aes avec le matériel de clé dérivé à l'étape 4 :

    aes.Key = aesKey;
    
  7. Crée un objet MemoryStream temporaire pour stocker une chaîne chiffrée.

  8. Crée un objet CryptoStream temporaire et l'utilise pour chiffrer le message et l'écrire dans l'objet MemoryStream.

  9. Enregistre le texte chiffré et le vecteur d'initialisation :

    iv = aes.IV
    ciphertext = ms.ToArray();
    
  10. Signe le texte chiffré comme suit si l'exemple exécute la version 3, 4 ou 5 :

    • Crée un objet ECDsaCng.ECDsaCng(CngKey) temporaire.

      ECDsaCng ecdsa = new ECDsaCng(m_DSKey)
      
    • Lance la propriété HashAlgorithm de l'objet comme un algorithme de hachage sécurisé Sha512 :

      ecdsa.HashAlgorithm = CngAlgorithm.Sha512
      
    • Crée une signature numérique en signant le texte chiffré :

      signature = ecdsa.SignData(ciphertext);
      
  11. Prépare le message de sortie comme suit :

    • Crée un tableau de trois octets pour stocker les longueurs du vecteur d'initialisation du message, du texte chiffré et de la signature.

    • Crée quatre objets System.Collections.Generic.List<T> pour stocker le tableau de longueurs de l'étape précédente, le vecteur d'initialisation, le texte chiffré et la signature.

    • Concatène les quatre objets System.Collections.Generic.List<T> et les convertit en tableau d'octets de message de sortie unique :

      byte[] message = list1.ToArray();
      
  12. Envoie le message de sortie :

    ChMgr.SendMessage(message)
    

Méthode ReceiveMessage

public string ReceiveMessage()

Alice, Bob et Mallory appellent cette méthode à partir de leurs méthodes Run.Elle reçoit et déchiffre des messages et valide leurs signatures numériques.

Les messages ne sont pas passés en tant que paramètres à cette méthode.Le membre ChannelManager de la classe Communicator lit le message à l'aide du code suivant :

byteBuffer = ChMgr.ReadMessage();

La méthode ReceiveMessage effectue les étapes suivantes :

  1. Détermine si le message a été envoyé en texte en clair.Si la version 1 de l'exemple s'exécute, le message est en texte en clair et ne nécessite pas de déchiffrement.Dans ce cas, le message est retourné après avoir été converti en chaîne ASCII à l'aide du code suivant :

    AsciiMessage = Encoding.Unicode.GetString(byteBuffer);
    
  2. Divise le message en composants.Dans les versions 2 à 5, le message est chiffré.Dans ce cas, le message est réparti dans trois tableaux d'octets distincts.Le premier tableau contient le vecteur d'initialisation, le deuxième contient le texte chiffré et le troisième contient la signature numérique du texte chiffré.

  3. Affiche le vecteur d'initialisation, le texte chiffré et la signature sous forme de texte ASCII si l'indicateur fVerbose est défini.

  4. Dérive le matériel de clé.Le membre ECDiffieHellmanCng privé, m_ECDH_Cng, de la classe Communicator utilise la méthode ECDiffieHellmanCng.DeriveKeyMaterial pour dériver le matériel de clé partagé, comme l'indique le code suivant :

    byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey);
    
  5. Crée un objet Aes en instanciant un objet AesCryptoServiceProvider :

    Aes aes = new AesCryptoServiceProvider()
    
  6. Initialise l'objet Aes avec le matériel de clé et le vecteur d'initialisation dérivés des étapes précédentes.

  7. Déchiffre le message à l'aide des objets System.IO.MemoryStream et System.Security.Cryptography.CryptoStream.

  8. Affiche le message déchiffré.

  9. Dans les versions 3 à 5, valide le texte chiffré du message à l'aide de la signature numérique.La version 3 n'affiche pas d'avertissements de sécurité car Alice, Bob et Mallory utilisent la même signature.La version 4 affiche des avertissements de sécurité lorsque le texte chiffré d'un message comporte une signature non valide.Cependant, comme seuls Alice et Bob disposent de la version 4, Mallory ne voit jamais d'avertissement.Dans la version 5, les clés de chiffrement dont la signature n'est pas valide provoquent l'arrêt du programme avant que les messages ne soient transmis et validés.

Voir aussi

Concepts

Communication sécurisée Cryptography Next Generation (CNG), exemple

Code source de Communicator.cs (Exemple CNG)

Vue d'ensemble du code source (Exemple CNG)

Échange de clés et de messages étape par étape (Exemple CNG)

Sortie attendue (Exemple CNG)