Communicator.cs-Quellcode (CNG-Beispiel)

Die Datei Communicator.cs stellt den Quellcode für die Communicator-Klasse bereit, die im Beispiel für die sichere Kommunikation mit Cryptography Next Generation (CNG) verwendet wird.Inhalt ist der folgende Code.

using System;                           // Required for the IDisposable interface
using System.Collections.Generic;       // Required for the List class
using System.Text;                      // Required for the Encoding class
using System.IO;                        // Required for the MemoryStream class
using System.Diagnostics;               // Required for the Debug.Assert calls               
using System.Security.Cryptography;     // Required for the CNG APIs



public partial class CNG_SecureCommunicationExample
{

    internal sealed class Communicator : IDisposable
        {
        private CngKey m_DSKey;
        private ECDiffieHellmanCng m_ECDH_Cng;
        private string m_ECDH_local_publicKey_XML;
        private ECDiffieHellmanPublicKey m_ECDH_remote_publicKey;

        public ChannelManager ChMgr;

        public Communicator(string mode, string ChannelName)
            {
            m_ECDH_Cng = new ECDiffieHellmanCng(521);
            m_ECDH_local_publicKey_XML = m_ECDH_Cng.ToXmlString(ECKeyXmlFormat.Rfc4050);
            ChMgr = new ChannelManager(mode, ChannelName);
            }

        public void Dispose()
            {
            if (m_ECDH_Cng != null)
               (m_ECDH_Cng as IDisposable).Dispose();
            if (m_ECDH_remote_publicKey != null)
               (m_ECDH_remote_publicKey as IDisposable).Dispose();
            if (ChMgr != null)
               (ChMgr as IDisposable).Dispose();
            }

        public void StoreDSKey(byte[] DSKeyBlob)
            {
            Debug.Assert(DSKeyBlob != null, "DSKeyBlob != null");
            m_DSKey = CngKey.Import(DSKeyBlob,
                                    CngKeyBlobFormat.Pkcs8PrivateBlob);
            }


        public bool Send_or_Receive_PublicCryptoKey(string mode, int color)
            {
            string xmlECDH;
            byte[] signature = null;                                        // Sign the ciphertext with the public signature key

            if ("send" == mode)
                {
                xmlECDH = m_ECDH_local_publicKey_XML;
                Byte[] message = Encoding.ASCII.GetBytes(m_ECDH_local_publicKey_XML);

                if(3 <= Version)
                    {
                    using (ECDsaCng ecdsa = new ECDsaCng(m_DSKey))          // EDCsaCng(CngKey)
                            {
                            ecdsa.HashAlgorithm = CngAlgorithm.Sha512;
                            signature = ecdsa.SignData(message);            // Create a digital signature for the encrypted message
                            }

                    string messageLength = message.Length.ToString();

                    byte[] bLengths = new byte[1];                                  // Create a byte array to hold the three lengths
                    bLengths[0] = (byte)messageLength.Length;

                    List<byte> list1 = new List<byte>(bLengths);                   // Turn all four arrays into List objects
                    List<byte> list2 = new List<byte>(Encoding.ASCII.GetBytes(messageLength));
                    List<byte> list3 = new List<byte>(message);
                    List<byte> list4 = new List<byte>(signature);

                    list1.AddRange(list2);                                  // Concatenate the four arrays
                    list1.AddRange(list3);
                    list1.AddRange(list4);

                    message = list1.ToArray();                              // Create the master output array
                    }
                ChMgr.SendMessage(message);
                }
            else                                                            // Mode = receive
                {
                byte[] input = ChMgr.ReadMessage();

                if (0 == input.Length)                              // Application control for Version 5 to keep Mallory from
                    return false;                                   //  hanging when Alice discovers a bad signature


                if(3 <= Version)
                    {
                    List<byte> list = new List<byte>(input);

                    int iLength = (int)input[0];                                 // The first byte specifies the count of bytes
                                                                                 // required to hold the message length. These
                                                                                 // message length bytes immediately follow the first byte.
                    Byte[] message_Length = new Byte[iLength];                   // Allocate a buffer large enough for the message
                    list.CopyTo(1, message_Length, 0, iLength);                  // Copy the message into the buffer
                    string s_message_Length =
                              Encoding.ASCII.GetString(message_Length);

                    int count = Convert.ToInt32(s_message_Length); 

                    Byte[] TheMessage = new Byte[count];
                    list.CopyTo(4, TheMessage, 0, count);                       // Retrieve the message starting from the byte 4 (0-based)

                    Byte[] TheSignature = new Byte[input.Length - 4 - count];
                    list.CopyTo(4 + count, TheSignature, 0,                     // Retrieve the signature from the input
                                input.Length - 4 - count); 

                    using (ECDsaCng ecdsa = new ECDsaCng(m_DSKey))              // Verify the ciphertext by hashing the ciphertext,
                        {                                                       // and comparing the result with the signature
                        ecdsa.HashAlgorithm = CngAlgorithm.Sha512;
                        if (!ecdsa.VerifyData(TheMessage, TheSignature))
                            {
                            if ("Alice Green" == MyName || "Bob White" == MyName) 
                            if (4 <= Version)   
                                Display(" ========  SECURITY ERROR!!===========\n" +
                                "Cryptographic Key: Failure verifying digital signature.\n" +
                                (5 == Version ? "Contact your security administrator.\n" +
                                               "TERMINATING SESSION\n\n" : "" )+ "\n\n",0) ;
                            if (5 == Version)
                                {
                                System.Threading.Thread.Sleep(2000);
                                return false;                   
                                }
                            }
                        }
                    xmlECDH = Encoding.ASCII.GetString(TheMessage);
                    }

                else xmlECDH = Encoding.ASCII.GetString(input);                 // Cryptographic key is not signed.

                m_ECDH_remote_publicKey = ECDiffieHellmanCngPublicKey.FromXmlString(xmlECDH);
                }

            if (fVerbose)
                {
                Display("Here it is: an ECDH public KeyBlob\n" +
                        "encoded within an XML string:\n\n");
                Display(xmlECDH + "\n\n", color);
                }
            return true;
            }





/*
    public void Store_bArray_ECDH_remotePublicKey(Byte[] bArray)
    {
 //   m_ECDH_remote_publicKey = (ECDiffieHellmanPublicKey)enc.GetBytes(s);
 //   ECDiffieHellmanPublicKey Alice_ECDH_publicKey = Alice.m_ECDH_local_publicKey;

 //   byte[] bArray = enc.GetBytes(s);
 //   m_ECDH_remote_publicKey = new ECDiffieHellmanPublicKey(bArray);           // Abstract Base Class: can't instantiate
 //   m_ECDH_remote_publicKey = ECDiffieHellmanCngPublicKey.FromByteArray(bArray,CngKeyBlobFormat.GenericPublicBlob);
     m_ECDH_remote_publicKey = ECDiffieHellmanCngPublicKey.FromByteArray(bArray,CngKeyBlobFormat.EccPublicBlob);
     }
*/

//-------------------------------------------------------------------------------------------------

        private byte[] iv;
        private byte[] ciphertext;
        private byte[] signature;


        public bool SendMessage(string plainTextMessage, bool fShowMsg)
            {
            Debug.Assert(plainTextMessage != null, "plainTextMessage != null");
            if (fShowMsg)
                Display(":> " + plainTextMessage + "\n", MyColor);

            if (1 != Version)
                if (fVerbose)
                    Display(sep1,1);

            byte[] UnicodeText = Encoding.Unicode.GetBytes(plainTextMessage);// Convert the message string into a Unicode byte array.

            if (1 == Version)
                return ChMgr.SendMessage(UnicodeText);                      // Send the plaintext (unencrypted, unsigned) message.

                                                                            // Generate a shared AES session key with the recipiant.
                                                                            //  This key will be used to encrypt the message.

            byte[] iv     = null;                                           // The AES type will generate a random Initialization
                                                                            //  Vector (IV) for us.
            byte[] aesKey =                                                 // ECDiffieHellmanCng.DeriveKeyMaterial Method.
                     m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey); // Derives the key material that is generated from
                                                                            //  the secret agreement between two parties.

            byte[] ciphertext = null;                                       // Output buffer to hold the encrypted message.


            using (Aes aes = new AesCryptoServiceProvider())                // Do the encryption.
                {
                aes.Key = aesKey;

                using (MemoryStream ms = new MemoryStream())                // Create temporary managed memory for the encrypted string.
                using (CryptoStream cs = new CryptoStream(ms,
                         aes.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                    cs.Write(UnicodeText, 0, UnicodeText.Length);           // Perform the encryption, and write the results to memory.
                    cs.FlushFinalBlock();                                   // Update the temporary memory and clear the cs buffer.

                    iv = aes.IV;                                            // Save the IV and ciphertext.
                    ciphertext = ms.ToArray();
                    }
                }

            byte[] signature = null;                                        // Sign the ciphertext with the public signature key

            if (3 <= Version)
                using (ECDsaCng ecdsa = new ECDsaCng(m_DSKey))              // EDCsaCng(CngKey)
                    {
                    ecdsa.HashAlgorithm = CngAlgorithm.Sha512;                  
                    signature = ecdsa.SignData(ciphertext);                 // Create a digital signature for the encrypted message
                    }


            byte[] bLengths = new byte[3];                                  // Create a byte array to hold the three lengths
            bLengths[0] = (byte)iv.Length;
            bLengths[1] = (byte)ciphertext.Length;
            bLengths[2] = (byte)(3 <= Version?signature.Length:0);          // Add signature length if Version is 3 or 4

            List<byte> list1 = new List<byte> (bLengths);                   // Create four list objects from the arrays
            List<byte> list2 = new List<byte> (iv);
            List<byte> list3 = new List<byte> (ciphertext);
            List<byte> list4 = 3 <= Version?new List<byte>(signature):null;

            list1.AddRange(list2);                                          // Concatenate the four arrays
            list1.AddRange(list3);
            if (3 <= Version)
                list1.AddRange(list4);

            byte[] message = list1.ToArray();                               // Create the master output array

            return ChMgr.SendMessage(message);                              // Send the master output array
            }   // End SendMessage



        public string ReceiveMessage()
            {
            Byte[] byteBuffer;                                      // Utility byte buffer

            byteBuffer =  ChMgr.ReadMessage();                      // Read the message.
            if (0 == byteBuffer.Length)                             // The other party closed the command window
                {                                                   //  with CTRL-C or SYS-EXIT while they had focus
                Display("Connection has been closed\n\n");          //   (while we were waiting to receive a message)
                return "";                               
                }

            if (1 == Version)                                       // Not encrypted
                { 
                string AsciiMessage = Encoding.Unicode.GetString(byteBuffer);
                Display("   " + AsciiMessage + "\n", OtherColor);
                return AsciiMessage;
                }           


            List<byte> list = new List<byte>(byteBuffer);

            try
                {
                                                                    // Create three byte arrays to hold the message
                                                                    //  components. The size of these three byte arrays
                                                                    //  are contained in the first three bytes of the message.
                iv = new Byte[byteBuffer[0]];                       // Storage for the initialization vector. 
                ciphertext = new Byte[byteBuffer[1]];               // Storage for the ciphertext.
                signature = new Byte[byteBuffer[2]];                // Storage for the signature.
                }
            catch (IndexOutOfRangeException e)
                {
                Display("Cryptographic error encountered\n\n");
                Display(e + "Cryptographic error encountered\n\n");
                return "";
                }

            int ndx = 3;
                                                                    // CopyTo: 0-based index in source, destination,
                                                                    //         0-based ndx in destination, elements to copy.
            list.CopyTo(ndx, iv, 0, byteBuffer[0]);                 // Get the initialization vector (IV).
            ndx += byteBuffer[0];
            list.CopyTo(ndx, ciphertext, 0, byteBuffer[1]);         // Get the ciphertext (ciphertext).
            ndx += byteBuffer[1];
            list.CopyTo(ndx, signature, 0, byteBuffer[2]);          // Get the message's digital signature (signature).


            Debug.Assert(iv != null, "iv != null");
            Debug.Assert(ciphertext != null, "ciphertext != null");
            Debug.Assert(signature != null, "signature != null");

            if (fVerbose)
                {
                ASCIIEncoding enc = new ASCIIEncoding();

                string s = enc.GetString(iv); 
                Display("   Incoming Message:\n\n",7);
                Display("   Initialization vector:  ",7);
                Display(s + "\n\n", 7);

                s = enc.GetString(ciphertext);
                Display("   Ciphertext:\n",7);
                Display(s + "\n\n", 7);

                s = enc.GetString(signature);
                if ("" != s)
                    {
                    Display("   Signature:\n",7);
                    Display(s + "\n\n", 7);
                    }
                Display("   Incoming Decoded message:\n\n", 7);
                }

            // Derive the key that will be used to decrypt the message.
            byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey);


            // We've got the key material, now we can decrypt the message.

            byte[] plaintext = null;

            using (Aes aes = new AesCryptoServiceProvider())
                {
                aes.Key = aesKey;
                aes.IV = iv;

                using (MemoryStream ms = new MemoryStream())
                using (CryptoStream cs = new CryptoStream(ms,
                       aes.CreateDecryptor(),
                       CryptoStreamMode.Write))
                    {
                    cs.Write(ciphertext, 0, ciphertext.Length);
                    cs.FlushFinalBlock();
                    plaintext = ms.ToArray();
                    }
                }

            string message = Encoding.Unicode.GetString(plaintext);        // Convert the raw plaintext back to the transmitted message
            Display("   " + message + "\n", OtherColor);

            if (3 <= Version)
                    using (ECDsaCng ecdsa = new ECDsaCng(m_DSKey))          // Verify the ciphertext by hashing the ciphertext,
                        {                                                   // and comparing the result with the signature
                        ecdsa.HashAlgorithm = CngAlgorithm.Sha512;
                        if (!ecdsa.VerifyData(ciphertext, signature))
                            if ("Alice Green" == MyName || "Bob White" == MyName)
                                Display("SECURITY WARNING! "
                                       +"Received signature did not verify.\n\n",0);
                        }
            if (fVerbose)
                Display(sep1,1);
            return message;
            }

//-------------------------------------------------------------------------------------------------

    }   // End Communicator class

}  // End Communicator.cs: public partial class CNG_SecureCommunicationExample

Siehe auch

Aufgaben

Gewusst wie: Erstellen und Ausführen des CNG-Beispiels

Konzepte

Quellcodeübersicht (CNG-Beispiel)

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

Kryptografische Dienste