• Microsoft .NET
  • C#.NET
  • Основы, лучшие методы и соглашения реализации событий в C#

Защита данных в .NET

ОГЛАВЛЕНИЕ

Данная статья кратко объясняет распространенные криптосистемы и подробно описывает два самых популярных шифра с закрытым ключом: DES –  наиболее широко используемый, и AES – собирающийся заменить DES.

•    Примеры кода .NET по криптологии [исходник - 38.5 Кб] [демо - 9.96 Кб]
•    Реализация AES и DES на C# [исходник - 35.7 Кб] [демо - 13.1 Кб]

1. Введение

Криптология – область, занимающаяся обеспечением безопасности и конфиденциальности. Эта область включает в себя много криптосистем, каждая из которых состоит из набора алгоритмов, направленных на обеспечение защиты данных. Сейчас криптосистемы широко применяются во всех областях цифровых технологий. Цифровые подписи, электронная почта и интернет-банкинг – лишь несколько приложений, в которых используются криптосистемы. Данная статья кратко объясняет распространенные криптосистемы и подробно описывает два самых популярных шифра с закрытым ключом: DES –  наиболее широко используемый, и AES – собирающийся заменить DES. Следует начать с обзора распространенных криптосистем.

2. Обзор распространенных криптосистем

Три криптосистемы являются основой множества приложений безопасности: симметричные криптосистемы, асимметричные криптосистемы и хеширование.

2.a Симметричные (с закрытым ключом) криптосистемы

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

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

Блок-схема симметричных криптосистем

Открытый текст шифруется закрытым ключом, передается, затем расшифровывается тем же самым закрытым ключом.

//простая операция шифрования закрытым ключом
private void buttonEncrypt_Click(object sender, EventArgs e)
{
    string password = textBoxKey.Text;
    string salt = textBoxSalt.Text;
    string plainText = textBoxInput.Text;
    byte[]plainBytes=Encoding.ASCII.GetBytes(plainText);

    //Rfc2898DeriveBytes: используется для генерации стойких ключей
    Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password,
        Encoding.ASCII.GetBytes(salt));
        //неанглийские алфавиты не будут работать в кодировке ASCII

    SymmetricAlgorithm Alg = GetSelectedAlgorithm();

    Alg.Key = rfc.GetBytes(Alg.KeySize / 8);
    Alg.IV = rfc.GetBytes(Alg.BlockSize / 8);

    MemoryStream strCiphered = new MemoryStream();//для хранения зашифрованных данных

    CryptoStream strCrypto = new CryptoStream(strCiphered,
        Alg.CreateEncryptor(), CryptoStreamMode.Write);

    strCrypto.Write(plainBytes, 0, plainBytes.Length);
    strCrypto.Close();
    textBoxCiphered.Text = Convert.ToBase64String(strCiphered.ToArray());
    strCiphered.Close();
}
       
private SymmetricAlgorithm GetSelectedAlgorithm()
{
    SymmetricAlgorithm Alg = null;
    if (comboBoxAlgorithm.SelectedIndex == 0)
        Alg = new DESCryptoServiceProvider();
    else if (comboBoxAlgorithm.SelectedIndex == 1)
        Alg = new RijndaelManaged();//RijndaelManaged: алгоритм AES в .NET
    else if (comboBoxAlgorithm.SelectedIndex == 2)
        Alg = new TripleDESCryptoServiceProvider();
    else
        Alg = new RC2CryptoServiceProvider();
    return Alg;
}

2.b Асимметричные (с открытым ключом) криптосистемы

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

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

//Генерация открытого и закрытого ключей
Выбрать p,q так, чтобы p и q были двумя разными большими простыми числами
Пусть n=p*q
Пусть m=(p-1)*(q-1)
Выбрать e так, чтобы было 1<e<m и gcd(m,e)=1 (e взаимно-простой с m)
Вычислить такой d, чтобы было (d*e)mod(m) = 1

Открытый ключ: {e,n}
Закрытый ключ:{d,n}

//Шифрование
Открытый текст: M   (M<n)
Шифротекст: C = M<sup>e</sup> Mod(n)

//Расшифровка
Шифротекст: C
Открытый текст: M = C<sup>d</sup> Mod(n)

Блок-схема асимметричных криптосистем

Открытый текст шифруется [Бобом] открытым ключом Алисы, передается, затем расшифровывается [Алисой] закрытым ключом Алисы.

/*
 * В отличие от симметричных шифров, нельзя свободно выбрать
 * пары открытых и закрытых ключей, потому что эти два ключа
 * математически связаны друг с другом. Правильный способ
 * создания этих ключей в .NET - использовать асимметричный класс,
 * генерирующий данные ключи в своем конструкторе.
 */
private void GenerateKeyPairs()
{                       
    //При каждом вызове этого конструктора
    //генерируется другая пара открытого и закрытого ключей.
    rsaCipher = new RSACryptoServiceProvider();

    //извлечь открытые параметры
    textBoxPublicKey.Text = rsaCipher.ToXmlString(false);

    //извлечь закрытые параметры
    textBoxPrivateKey.Text = rsaCipher.ToXmlString(true);
}

private void buttonEncrypt_Click(object sender, EventArgs e)
{
    rsaCipher = new RSACryptoServiceProvider();

    string publicKey = textBoxPublicKey.Text;
    rsaCipher.FromXmlString(publicKey);

    string plainText = textBoxPlain.Text;
    byte[] plainBytes = Encoding.ASCII.GetBytes(plainText);

    byte[] cipheredBytes = rsaCipher.Encrypt(plainBytes, true);
    string cipheredText = Convert.ToBase64String(cipheredBytes);

    textBoxCiphered.Text = cipheredText;
}

2.c Хеширование

Хеширование – операция взятия контрольной суммы данных. Назначение этого метода – сгенерировать уникальных ключ постоянного размера [из входных данных], который не могут дать никакие другие данные, тем самым делая невозможной генерацию данных из ключа. Хеширование очень полезно для систем баз данных. Представьте базу данных, хранящую пароли пользователей. Хранить пароли в открытом виде не так безопасно, как хранить хеш-значения паролей в таблицах. Даже притом что любое хеш-значение содержится в базе данных, невозможно восстановить оригинальный пароль из этого значения. Данный метод обеспечивает такой же функционал для процессов авторизации. Единственное отличие в том, что хеш пароля пользователя сравнивается со значением в базе данных вместо сравнения самого пароля.

//хешировать ввод и отобразить результат
private void buttonComputeHash_Click(object sender, EventArgs e)
{
    byte[] input = Encoding.ASCII.GetBytes(textBoxInput.Text);

    HashAlgorithm Alg = GetSelectedAlgorithm();
    Alg.ComputeHash(input);

    textBoxHash.Text = Convert.ToBase64String(Alg.Hash);
}

private HashAlgorithm GetSelectedAlgorithm()
{
    //только для алгоритмов хеширования с помощью ключей
    Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(textBoxKey.Text,
        Encoding.ASCII.GetBytes(textBoxSalt.Text));

    HashAlgorithm Alg = null;
    if (comboBoxAlgorithm.SelectedIndex == 0)
        Alg = new MD5CryptoServiceProvider();
    else if (comboBoxAlgorithm.SelectedIndex == 1)
        Alg = new RIPEMD160Managed();
    else if (comboBoxAlgorithm.SelectedIndex == 2)
        Alg = new SHA1CryptoServiceProvider();
    else if (comboBoxAlgorithm.SelectedIndex == 3)
        Alg = new SHA256Managed();
    else if (comboBoxAlgorithm.SelectedIndex == 4)
        Alg = new SHA384Managed();          
    else if (comboBoxAlgorithm.SelectedIndex == 5)
        Alg = new  SHA512Managed();
    else if (comboBoxAlgorithm.SelectedIndex == 6)
        Alg = new MACTripleDES(rfc.GetBytes(16));
    else if (comboBoxAlgorithm.SelectedIndex == 7)
        Alg = new HMACSHA1(rfc.GetBytes(29));

    return Alg;
}

2.d Применения цифровой подписи

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

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

Рисунок ниже изображает блок-схему системы цифровой подписи, составленной из двух фаз: подписание документа (левая часть) и проверка подлинности документа (правая часть). Обе фазы используют криптосистему с открытым ключом для шифрования и расшифровки данных. В фазе подписания хеш сообщение шифруется закрытым ключом отправителя. Это значение (зашифрованный хеш) становится подписью и отправляется получателю вместе с оригинальным сообщением. Потом, в фазе проверки подлинности, получатель расшифровывает подпись (зашифрованный хеш) открытым ключом отправителя. Эта операция дает значение хеша, которое отправитель уже вычислил. Получатель тоже вычисляет хеш полученного сообщения и сравнивает его с хешем отправителя. Если два значение хеша идентичны, то подлинность документов подтверждена, в противном случае нет.

Блок-схема применения цифровой подписи