Анализ кода класса 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.Он шифрует, добавляет цифровую подпись и отправляет сообщения, выполняя следующие операции.
Отображение сообщения с открытым текстом, если значение fShowMsg равно true.
Преобразование сообщения в массив байтов Юникод с помощью следующего кода:
byte[] UnicodeText = Encoding.Unicode.GetBytes(plainTextMessage);
Проверка, должно ли сообщение отправляться в виде открытого текста.Если запущена версия 1 примера, метод SendMessage завершает работу и отправляет сообщение с помощью следующего кода:
ChMgr.SendMessage(UnicodeText);
Получение материала ключа с помощью метода ECDiffieHellmanCng.DeriveKeyMaterial(ECDiffieHellmanPublicKey):
byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey)
Создание временного объекта Aes:
Aes aes = new AesCryptoServiceProvider()
Инициализация объекта Aes с использованием материала ключа, полученного на шаге 4:
aes.Key = aesKey;
Создание временного объекта MemoryStream для хранения зашифрованной строки.
Создание временного объекта CryptoStream и его использование для зашифровки сообщения и записи в объект MemoryStream.
Сохранение зашифрованного текста и вектора инициализации:
iv = aes.IV ciphertext = ms.ToArray();
Подписывание зашифрованного текста, если запущены версии 3, 4 или 5 примера, следующим образом.
Создание временного объекта ECDsaCng.ECDsaCng(CngKey):
ECDsaCng ecdsa = new ECDsaCng(m_DSKey)
Инициализация свойства HashAlgorithm объекта значением Sha512, соответствующим защищенному хэш-алгоритму:
ecdsa.HashAlgorithm = CngAlgorithm.Sha512
Создание цифровой подписи для зашифрованного текста:
signature = ecdsa.SignData(ciphertext);
Подготовка выходного сообщения следующим образом.
Создание трехбайтового массива для хранения значений длины вектора инициализации сообщения, зашифрованного текста и подписи.
Создание четырех объектов System.Collections.Generic.List<T> для хранения массива из предыдущего шага, вектора инициализации, зашифрованного текста и подписи.
Сцепление четырех объектов System.Collections.Generic.List<T> и их преобразование в один массив байтов выходного сообщения:
byte[] message = list1.ToArray();
Отправка выходного сообщения:
ChMgr.SendMessage(message)
Метод ReceiveMessage
public string ReceiveMessage()
Алиса, Боб и Мэллори вызывают этот метод из своих методов Run.Он служит для получения и расшифровки сообщений, а также для проверки цифровых подписей.
Сообщения не передаются этому методу в качестве параметров.Вместо этого член ChannelManager класса Communicator считывает сообщения, используя для этого следующий код:
byteBuffer = ChMgr.ReadMessage();
Метод ReceiveMessage выполняет следующие действия.
Проверка, было ли сообщение отправлено в виде открытого текста.Если запущена версия 1 примера, то сообщения отправляются в виде открытого текста и расшифровка не требуется.В этом случае сообщение возвращается после преобразования в формат строки ASCII с помощью следующего кода:
AsciiMessage = Encoding.Unicode.GetString(byteBuffer);
Разбивание сообщения на компоненты.В версиях 2–5 сообщение шифруется.В этом случае оно разбивается на три отдельных массива байтов.Первый массив содержит вектор инициализации, второй — зашифрованный текст, а третий — цифровую подпись зашифрованного текста.
Отображение вектора инициализации, зашифрованного текста и подписи в виде текста ASCII, если установлен флаг fVerbose.
Получение материала ключа.Закрытый член m_ECDH_Cng типа ECDiffieHellmanCng класса Communicator получает общий материал ключа с помощью метода ECDiffieHellmanCng.DeriveKeyMaterial, как показано в следующем фрагменте кода:
byte[] aesKey = m_ECDH_Cng.DeriveKeyMaterial(m_ECDH_remote_publicKey);
Создание объекта Aes в виде объекта AesCryptoServiceProvider:
Aes aes = new AesCryptoServiceProvider()
Инициализация объекта Aes с помощью полученных ранее материала ключа и вектора инициализации.
Расшифровка сообщения с помощью объектов System.IO.MemoryStream и System.Security.Cryptography.CryptoStream.
Вывод расшифрованного сообщения на экран.
Проверка цифровой подписи зашифрованного текста в версиях 3–5.В версии 3 предупреждения безопасности не отображаются, поскольку Алиса, Боб и Мэллори используют одну и ту же цифровую подпись.В версии 4 предупреждение безопасности отображается, когда зашифрованный тест содержит неверную подпись.Однако только Алиса и Боб получают программное обеспечение версии 4, поэтому Мэллори не видит никаких предупреждений.В версии 5 при обнаружении ключей шифрования с недействительной подписью программа прекращает работу до передачи и проверки сообщений.
См. также
Основные понятия
Пример защищенного обмена данными с шифрованием CNG
Исходный код файла Communicator.cs (пример CNG)
Общие сведения об исходном коде (пример CNG)
Пошаговое описание процесса обмена ключами и сообщениями (пример CNG)