Поделиться через


Анализ кода класса Communicator (пример CNG)

Файл Communicator.cs инкапсулирует методы шифрования и расшифровки, используемые в примере защищенного обмена данными с шифрованием CNG.Файл состоит из единственного класса, который называется Communicator.Этот класс содержит члены и методы, описанные в следующих подразделах.

  • Члены класса

  • Конструктор класса

  • Метод Dispose

  • Метод StoreDSKey

  • Метод Send_or_Receive_PublicCryptoKey

  • Метод SendMessage

  • Метод ReceiveMessage

Общие сведения о примере и описание упомянутых в этом разделе версий см. в разделе Пример защищенного обмена данными с шифрованием CNG.

Члены класса

Класс Communicator содержит следующие закрытые члены.

  • CngKey m_DSKey

    Этот член используется методом Communicator.StoreDSKey для хранения ключа цифровой подписи.

  • ECDiffieHellmanCng m_ECDH_Cng

    Этот член используется конструктором для хранения экземпляра класса ECDiffieHellmanCng.Методы ReceiveMessage и SendMessage используют этот член для получения материала ключа.

  • string m_ECDH_local_publicKey_XML

    Этот член используется конструктором для хранения строкового XML-представления локального открытого ключа шифрования ECDH.Алиса, Боб и Мэллори используют для передачи этой XML-строки метод Send_or_Receive_PublicCryptoKey.

  • ECDiffieHellmanPublicKey m_ECDH_remote_publicKey

    Этот член используется методом Send_or_Receive_PublicCryptoKey для хранения удаленного открытого ключа шифрования ECDH.

Класс Communicator также содержит следующие открытые члены.

  • ChannelManager ChMgr

    Этот член используется Алисой, Бобом и Мэллори для обеспечения работы именованных каналов.

Конструктор класса

public Communicator(string mode, string ChannelName)

Этот конструктор создает следующие три объекта.

  • Экземпляр класса ECDiffieHellmanCng со случайной парой ключей и длиной ключа 521 бита:

    m_ECDH_Cng = new ECDiffieHellmanCng(521)
    

    Полученный объект присваивается закрытому члену класса Communicator.Каждый объект Communicator создает только один экземпляр данного класса.

    Алиса и Боб создают по одному объекту Communicator и могут работать с одним членом m_ECDH_Cng каждый.Мэллори создает два объекта Communicator: первый — для взаимодействия с Алисой, второй — для взаимодействия с Бобом.Поэтому Мэллори может работать с двумя членами m_ECDH_Cng.

  • Открытый ключ ECDH в виде закрытой XML-строки:

    m_ECDH_XmlString = m_ECDH_CryptoKey.ToXmlString(ECKeyXmlFormat.Rfc4050)
    

    Метод ECDiffieHellmanCng.ToXmlString сериализует открытый ключ ECDH, используя формат ECKeyXmlFormat.Rfc4050.

    В версиях 2–5 примера Алиса отправляет полученную XML-строку Бобу в своем методе Run, используя для этого следующий код:

    Alice.Send_or_Receive_PublicCryptoKey("send", MyColor);
    
  • Открытый экземпляр класса ChannelManager:

    ChMgr = new ChannelManager(mode, ChannelName)
    

    Конструктор принимает следующие два параметра.

    • mode: строка, указывающая на режим создания именованного канала.Этот параметр принимает значение "server" или "client".

    • ChannelName: строка, задающая имя для идентификации нового именованного канала.

Метод Dispose

public void Dispose()

Класс Communicator наследует интерфейсу IDisposable и содержит метод Dispose для мгновенного удаления важных сведений.К таким сведениям относится содержимое объектов m_ECDH_Cng, m_ECDH_local_publicKey_XML и ChMgr.

Каждый объект создается внутри оператора C# using, чтобы объект удалялся сразу после его выхода из области действия.

Метод StoreDSKey

public void StoreDSKey(byte[] DSKeyBlob)

Этот метод принимает большой двоичный объект, который содержится в массиве байтов.С помощью метода CngKey.Import(array<Byte[], CngKeyBlobFormat) он извлекает из большого двоичного объекта ключ цифровой подписи.Затем ключ сохраняется при помощи следующего кода:

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

Метод StoreDSKey вызывается Алисой, Бобом и Мэллори в их методах Run в следующих версиях.

  • В версиях 3–5 Алиса, Боб и Мэллори используют этот метод для сохранения одного и того же передаваемого по открытому каналу ключа.

  • В версиях 4 и 5 Алиса и Боб вызывают этот метод еще раз и перезаписывают член m_DSKey, используя ключ, передаваемый по закрытому каналу.

Метод Send_or_Receive_PublicCryptoKey

Send_or_Receive_PublicCryptoKey(string mode, int color)

Этот метод принимает два параметра.

  • mode: строка, которая определяет режим — создание сервера канала для отправки ключа или создание клиента канала для получения ключа.Этот параметр принимает значение "server" или "client".

  • color: целое значение, обозначающее цвет, которым будет выводиться ключ.

Метод Send_or_Receive_PublicCryptoKey похож на методы CommunicatorReceiveMessage и SendMessage за тем исключением, что он отправляет и принимает незашифрованные ключи шифрования, а не зашифрованные сообщения.Методы ReceiveMessage и SendMessage нельзя использовать для ключей шифрования, поскольку они будут пытаться зашифровать и расшифровать ключи.

После обмена ключами в версиях 3–5 выполняется проверка цифровых подписей ключей.В версии 3 используется цифровая подпись, которая передается по именованному каналу PublicChannel.Мэллори перехватывает эту подпись и использует ее для подписывания поддельных ключей и сообщений, которые он отправляет Алисе и Бобу.В версии 3 проверка подписи всегда проходит успешно, поскольку Алиса, Боб и Мэллори используют один и тот же ключ цифровой подписи.

Примечание

В версиях 4 и 5 для подписывания ключей и сообщения используется закрытая цифровая подпись. Кроме того, в этих версиях отображаются предупреждения безопасности.Программное обеспечение этих версий получают только Алиса и Боб.Поэтому Мэллори не знает, что его вмешательство в обмен сообщениями обнаруживается.

Метод SendMessage

public bool SendMessage(string plainTextMessage, bool fShowMsg)

Алиса, Боб и Мэллори вызывают этот метод из своих методов Run.Он шифрует, добавляет цифровую подпись и отправляет сообщения, выполняя следующие операции.

  1. Отображение сообщения с открытым текстом, если значение fShowMsg равно true.

  2. Преобразование сообщения в массив байтов Юникод с помощью следующего кода:

    byte[] UnicodeText = Encoding.Unicode.GetBytes(plainTextMessage);
    
  3. Проверка, должно ли сообщение отправляться в виде открытого текста.Если запущена версия 1 примера, метод SendMessage завершает работу и отправляет сообщение с помощью следующего кода:

    ChMgr.SendMessage(UnicodeText);
    
  4. Получение материала ключа с помощью метода ECDiffieHellmanCng.DeriveKeyMaterial(ECDiffieHellmanPublicKey):

    byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey)
    
  5. Создание временного объекта Aes:

    Aes aes = new AesCryptoServiceProvider()
    
  6. Инициализация объекта Aes с использованием материала ключа, полученного на шаге 4:

    aes.Key = aesKey;
    
  7. Создание временного объекта MemoryStream для хранения зашифрованной строки.

  8. Создание временного объекта CryptoStream и его использование для зашифровки сообщения и записи в объект MemoryStream.

  9. Сохранение зашифрованного текста и вектора инициализации:

    iv = aes.IV
    ciphertext = ms.ToArray();
    
  10. Подписывание зашифрованного текста, если запущены версии 3, 4 или 5 примера, следующим образом.

    • Создание временного объекта ECDsaCng.ECDsaCng(CngKey):

      ECDsaCng ecdsa = new ECDsaCng(m_DSKey)
      
    • Инициализация свойства HashAlgorithm объекта значением Sha512, соответствующим защищенному хэш-алгоритму:

      ecdsa.HashAlgorithm = CngAlgorithm.Sha512
      
    • Создание цифровой подписи для зашифрованного текста:

      signature = ecdsa.SignData(ciphertext);
      
  11. Подготовка выходного сообщения следующим образом.

    • Создание трехбайтового массива для хранения значений длины вектора инициализации сообщения, зашифрованного текста и подписи.

    • Создание четырех объектов System.Collections.Generic.List<T> для хранения массива из предыдущего шага, вектора инициализации, зашифрованного текста и подписи.

    • Сцепление четырех объектов System.Collections.Generic.List<T> и их преобразование в один массив байтов выходного сообщения:

      byte[] message = list1.ToArray();
      
  12. Отправка выходного сообщения:

    ChMgr.SendMessage(message)
    

Метод ReceiveMessage

public string ReceiveMessage()

Алиса, Боб и Мэллори вызывают этот метод из своих методов Run.Он служит для получения и расшифровки сообщений, а также для проверки цифровых подписей.

Сообщения не передаются этому методу в качестве параметров.Вместо этого член ChannelManager класса Communicator считывает сообщения, используя для этого следующий код:

byteBuffer = ChMgr.ReadMessage();

Метод ReceiveMessage выполняет следующие действия.

  1. Проверка, было ли сообщение отправлено в виде открытого текста.Если запущена версия 1 примера, то сообщения отправляются в виде открытого текста и расшифровка не требуется.В этом случае сообщение возвращается после преобразования в формат строки ASCII с помощью следующего кода:

    AsciiMessage = Encoding.Unicode.GetString(byteBuffer);
    
  2. Разбивание сообщения на компоненты.В версиях 2–5 сообщение шифруется.В этом случае оно разбивается на три отдельных массива байтов.Первый массив содержит вектор инициализации, второй — зашифрованный текст, а третий — цифровую подпись зашифрованного текста.

  3. Отображение вектора инициализации, зашифрованного текста и подписи в виде текста ASCII, если установлен флаг fVerbose.

  4. Получение материала ключа.Закрытый член m_ECDH_Cng типа ECDiffieHellmanCng класса Communicator получает общий материал ключа с помощью метода ECDiffieHellmanCng.DeriveKeyMaterial, как показано в следующем фрагменте кода:

    byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey);
    
  5. Создание объекта Aes в виде объекта AesCryptoServiceProvider:

    Aes aes = new AesCryptoServiceProvider()
    
  6. Инициализация объекта Aes с помощью полученных ранее материала ключа и вектора инициализации.

  7. Расшифровка сообщения с помощью объектов System.IO.MemoryStream и System.Security.Cryptography.CryptoStream.

  8. Вывод расшифрованного сообщения на экран.

  9. Проверка цифровой подписи зашифрованного текста в версиях 3–5.В версии 3 предупреждения безопасности не отображаются, поскольку Алиса, Боб и Мэллори используют одну и ту же цифровую подпись.В версии 4 предупреждение безопасности отображается, когда зашифрованный тест содержит неверную подпись.Однако только Алиса и Боб получают программное обеспечение версии 4, поэтому Мэллори не видит никаких предупреждений.В версии 5 при обнаружении ключей шифрования с недействительной подписью программа прекращает работу до передачи и проверки сообщений.

См. также

Основные понятия

Пример защищенного обмена данными с шифрованием CNG

Исходный код файла Communicator.cs (пример CNG)

Общие сведения об исходном коде (пример CNG)

Пошаговое описание процесса обмена ключами и сообщениями (пример CNG)

Ожидаемый выводимый результат (пример CNG)