Шифрование

47

Конфиденциальные данные должны обязательно защищаться, чтобы их не могли прочитать пользователи, не обладающие необходимыми правами. Это касается как данных, которые пересылаются по сети, так и хранимых данных. Данные можно шифровать с помощью симметричных или асимметричных ключей.

В технологии шифрования с использованием симметричного ключа для шифрования и дешифрации может применяться один и тот же ключ. В технологии шифрования с использованием асимметричного ключа для шифрования и дешифрации применяются два разных ключа: открытый (public key) и секретный (private key). Данные, зашифрованные с помощью открытого ключа, могут быть расшифрованы с помощью соответствующего секретного ключа. Данные, зашифрованные с помощью секретного ключа, могут расшифровываться с использованием соответствующего секретного ключа, но не открытого.

Открытые и секретные ключи всегда создаются парами. Открытый ключ может делаться доступным для всех и даже размещаться на веб-сайте, но секретный ключ должен всегда храниться в безопасном и недоступном для посторонних месте. Ниже для объяснения процесса шифрования приводится несколько примеров применения открытого и секретного ключей.

Предположим, что Алиса отправляет сообщение Бобу (как показано на рисунке) и для обеспечения уверенности в том, что никто кроме Боба не сможет его прочитать, использует открытый ключ Боба. В результате сообщение шифруется с помощью открытого ключа Боба.

Отправка сообщения с использованием открытого ключа

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

Однако остается одна проблема: Боб не может быть уверенным в том, что почтовое сообщение ему отправила именно Алиса. Например, Ева могла использовать открытый ключ Боба и выдать себя за Алису. Помочь устранить эту проблему может расширение принципа применения открытых и секретных ключей.

Давайте снова вернемся к тому моменту, когда Алиса отправляет почтовое сообщение Бобу. Прежде чем шифровать сообщение с помощью открытого ключа Боба, Алиса может добавить свою подпись и зашифровать ее с помощью собственного секретного ключа, и только после этого зашифровать сообщение с использованием открытого ключа Боба, тем самым обеспечив гарантию того, что его сможет прочитать только Боб. При получении и расшифровке сообщения Боб тогда, соответственно, обнаружит зашифрованную подпись, которую он сможет расшифровать с помощью открытого ключа Алисы. Получить доступ к этому ключу для него не будет проблемой, потому что он является открытым. Расшифровав подпись, Боб сможет быть уверенным в том, что сообщение ему отправила именно Алиса.

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

В случае передаваемых по сети данных такая безопасность может обеспечиваться путем применения сначала асимметричных ключей для обмена ключами, а затем уже симметричных — для непосредственно шифрования передаваемых данных.

В .NET Framework классы для шифрования находятся в пространстве имен System.Security.Cryptography и реализуют несколько симметричных и асимметричных алгоритмов. Здесь можно найти разные классы алгоритмов для множества различных целей.

Некоторые из классов, которые были добавлены в .NET 3.5, имеют префикс или суффикс Cng, который представляет собой сокращение от Cryptography Next Generation (Криптография следующего поколения; CNG) и может применяться, начиная с Windows Vista и Windows Server 2008 и далее. Такой API-интерфейс позволяет писать не зависящие от алгоритма программы за счет применения модели, основанной на поставщиках.

В случае, если целевой платформой является Windows Server 2003, то выбору классов для шифрования необходимо уделять особое внимание. Ниже приведен перечень всех доступных в пространстве имен System.Security.Cryptography классов для шифрования с краткими описаниями их назначения:

Категория Классы Описание
Хеш-шифрование MD5, MD5Cng, SHA1, SHA1Managed, SHA1Cng, SHA256, SHA256Managed, SHA256Cng, SHA384, SHA384Managed, SHA384Cng, SHA512, SHA512Managed, SHA512Cng Задачей хеш-алгоритмов является создание хеш-значения фиксированной длины из двоичных строк произвольной длины. Эти алгоритмы применяются для создания цифровых подписей и для обеспечения целостности данных. В случае повторного хеширования той же бинарной строки возвращается такой же результат.

MD5 (Message Digest Algorithm 5) был разработан в RSA Laboratories и работает быстрее, чем SHA1. Алгоритм SHA1 является более устойчивым к атакам с применением методов грубой силы. Алгоритмы SHA разрабатывались в NSA (National Security Agency — Агентство национальной безопасности). В MD5 размер хеш-значения составляет 128 бит, а в SHA1 — 160 бит. В других алгоритмах SHA размер хеш-значения указан прямо в названии. Алгоритм SHA512 является самым надежным из всех, потому что подразумевает использование хеш-значения размером 512 бит, но при этом, конечно же, и работает медленнее всех остальных.
Симметричное шифрование DES, DESCryptoServiceProvider, TripleDES, TripleDESCryptoServiceProvider, Aes, AesCryptoServiceProvider, AesManaged, RC2, RC2CryptoServiceProvider, Rijandel, RijandelManaged Алгоритмы шифрования с помощью симметричного ключа предусматривают использование одного и того же ключа как для шифрования, так и для дешифрации данных. Алгоритм DES (Data Encryption Standard — стандарт шифрования данных) теперь считается небезопасным, поскольку основан на применении для ключа значения размером всего лишь 56 бит, которое может быть взломано меньше, чем за 24 часа.

Алгоритм Triple-DES является следующей версией DES и предусматривает использование ключей размером 168 бит, но эффективно обеспечивает безопасность только при 112 битах. Алгоритм AES (Advanced Encryption Standard — усовершенствованный стандарт шифрования) поддерживает ключи размером 128,192 и 256 бит.

Алгоритм Rijandel очень похож на AES, но просто предлагает больше вариантов для размеров ключей. Алгоритм AES был утвержден правительством США в качестве стандартного алгоритма для шифрования.
Ассиметричное шифрование DSA, DSACryptoServiceProvider, ECDsa, ECDsaCng, ECDiffieHellman, ECDiffieHellmanCng, RSA, RSACryptoServiceProvider Ассиметричные алгоритмы предусматривают применение для шифрования и дешифрации разных ключей. RSA (Rivest, Shamir, Adleman — Райвест, Шамир, Адлеман) был первым алгоритмом, который применялся для добавления подписей, а также шифрования. Он и по сей день широко используется в протоколах, связанных с областью электронной коммерции.

DSA (Digital Signature Algorithm — алгоритмцифровой подписи) является утвержденным федеральным правительством США стандартом для цифровых подписей.

ECDSA (Elliptic Curve DSA) и ECDiffieHellman используют алгоритмы, основанные на группах эллиптических кривых. Эти алгоритмы обеспечивают большую безопасность в случае применения более коротких ключей. Например, использование ключа длиной 1024 бита для DSA по уровню безопасности аналогично применению ключа длиной 160 бита для ECDSA. В результате получается, что ECDSA будет работать гораздо быстрее. ECDiffieHellman — это алгоритм, который применяется для обеспечения безопасного обмена секретными ключами по открытому каналу.

Классы без суффикса Cng, Managed и CryptoServiceProvider, такие как MD5, являются абстрактными базовыми. Суффикс Managed означает, что данный алгоритм реализуется с помощью управляемого кода; другие классы могут служить оболочкой для вызовов собственного кода из API-интерфейса Windows. Суффикс CryptoServiceProvider присутствует в именах тех классов, которые реализуют абстрактный базовый класс, а суффикс Cng - в тех, которые предусматривают применение нового API-интерфейса Cryptography CNG.

Теперь давайте рассмотрим примеры того, как эти алгоритмы могут использоваться программно.

Подпись

В первом примере демонстрируется создание подписи с использованием алгоритма ECDSA. В этом примере Алиса создает подпись, которая шифруется с помощью ее секретного ключа и может быть расшифрована с применением ее открытого ключа. Такой подход гарантирует, что подпись действительно принадлежит Алисе.

Сначала давайте посмотрим, как выглядят главные шаги в методе Main(): первым делом создаются ключи Алисы, далее производится подписание строки "Alice" и, наконец, осуществляется проверка того, действительно ли подпись принадлежит Алисе, за счет применения открытого ключа. Затем подписанное сообщение с помощью класса Encoding преобразуется в массив байтов. После этого для вывода зашифрованной подписи в окне консоли массив байтов, содержащий подпись, преобразуется в строку с помощью метода Convert.ToBase64String():

using System;
using System.Security.Cryptography;
using System.Text;

namespace SecurityCSharp
{
    class Program
    {
        internal static CngKey aliceKeySignature;
        internal static byte[] alicePubKeyBlob;

        static void Main()
        {
            CreateKeys();

            byte[] aliceData = Encoding.UTF8.GetBytes("Alice");
            byte[] aliceSignature = CreateSignature(aliceData, aliceKeySignature);
            Console.WriteLine("Alice created signature: {0}",
                  Convert.ToBase64String(aliceSignature));

            if (VerifySignature(aliceData, aliceSignature, alicePubKeyBlob))
            {
                Console.WriteLine("Подпись Алисы была успешно проверена");
            }
        }
    ...

Новая пара ключей для Алисы создается с помощью метода CreateKeys(). Эта пара ключей сохраняется в статическом поле, чтобы к ней можно было получать доступ из других методов. Метод Create() класса CngKey в качестве аргумента получает алгоритм. С помощью метода Export() из пары ключей экспортируется открытый ключ. Этот открытый ключ может быть предоставлен Бобу, чтобы он мог проверять действительность подписи.

Секретный ключ остается у Алисы. Вместо того чтобы создавать пары ключей с помощью класса CngKey, можно также открыть существующие ключи из специального хранилища ключей. В реальных условия у Алисы, скорее всего, имеется сертификат, содержащий пару ключей и хранящийся в ее личном хранилище, к которому можно получить доступ с помощью метода CngKey.Open():

static void CreateKeys()
        {
            aliceKeySignature = CngKey.Create(CngAlgorithm.ECDsaP256);
            alicePubKeyBlob = aliceKeySignature.Export(CngKeyBlobFormat.GenericPublicBlob);
        }

Имея в распоряжении пару ключей, Алиса может создать подпись с помощью класса ECDsaCng. Конструктор этого класса принимает объект CngKey, в котором содержится открытый и секретный ключи. Далее этот секретный ключ используется для подписания данных вызовом метода SignData():

static byte[] CreateSignature(byte[] data, CngKey key)
        {
            byte[] signature;
            var signingAlg = new ECDsaCng(key);
            signature = signingAlg.SignData(data);
            signingAlg.Clear();
            return signature;
        }

Для проверки, действительно ли подпись принадлежит Алисе, Боб извлекает ее с применением полученного от Алисы открытого ключа. Для этого сначала массив байтов, содержащий этот открытый ключ, импортируется в объект CngKey с помощью статического метода Import(), а затем для верификации подписи вызывается метод VerifyData() класса ECDsaCng:

static bool VerifySignature(byte[] data, byte[] signature, byte[] pubKey)
        {
            bool retValue = false;
            using (CngKey key = CngKey.Import(pubKey, CngKeyBlobFormat.GenericPublicBlob))
            {
                var signingAlg = new ECDsaCng(key);
                retValue = signingAlg.VerifyData(data, signature);
                signingAlg.Clear();
            }
            return retValue;
        }
Пройди тесты
Лучший чат для C# программистов