Шифрование
47C# и .NET --- Основы .NET --- Шифрование
Конфиденциальные данные должны обязательно защищаться, чтобы их не могли прочитать пользователи, не обладающие необходимыми правами. Это касается как данных, которые пересылаются по сети, так и хранимых данных. Данные можно шифровать с помощью симметричных или асимметричных ключей.
В технологии шифрования с использованием симметричного ключа для шифрования и дешифрации может применяться один и тот же ключ. В технологии шифрования с использованием асимметричного ключа для шифрования и дешифрации применяются два разных ключа: открытый (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;
}