Чтобы удостовериться, посмотрите на следующий код, где вызываются функции CryptoAPI:* RCTest.cpp *. #define MAX_ 50 bPlainText,MAX_.; bPlainText,MAX_.; bCipherText,MAX_.; ГЛАВА 8 Подводные камни криптографии 245 bCipherText,MAX_.; bKeyStream,MAX_.; bKey,MAX_.; Исходные параметры записать в память 2 фрагмента открытого текста и ключ шифрования. void Setup() ZeroMemory(bPlainText, MAX_); ZeroMemory(bPlainText, MAX_); ZeroMemory(bCipherText, MAX_); ZeroMemory(bCipherText, MAX_); ZeroMemory(bKeyStream, MAX_); ZeroMemory(bKey, MAX_); strncpy(reinterpret_castchar*(bPlainText), "Фродо, встречаемся у горы Заверть в 6 вечера.", MAX_! 1); strncpy(reinterpret_castchar*(bPlainText), "Саруман захватил меня и держит в плену в замке Ортханк.", MAX_! 1); strncpy(reinterpret_castchar*(bKey), GetKeyFromUser(), MAX_! 1); Внешняя функция. } Encrypt шифрует двоичный блок данных по алгоритму RC. void Encrypt(bKey, bPlaintext, bCipherText, dwHowMuch) hProv; hKey; hHash; * Работает это так: Получаем описатель криптопровайдера. Создаем пустой объект "хеш". Хешируем ключ, переданный в объект! хеш. Используем полученный на этапе 3 ключ для получения криптографического ключа. Этот ключ также содержит название алгоритма шифрования. Используем полученный на этапе 4 ключ для шифрования открытого текста. * dwBuff = dwHowMuch; CopyMemory(bCipherText, bPlaintext, dwHowMuch); if (! CryptAcquireContext(&hProv, _RSA_, _)) throw; 246 Часть II Методы безопасного кодирования if (! CryptCreateHash(hProv, _MD, 0, 0, &hHash)) throw; if (! CryptHashData(hHash, bKey, MAX_, 0)) throw; if (! CryptDeriveKey(hProv, _RC, hHash, _, &hKey)) throw; if (! CryptEncrypt(hKey, 0, 0, bCipherText, &dwBuff, dwHowMuch)) throw; if (hKey) CryptDestroyKey(hKey); if (hHash) CryptDestroyHash(hHash); if (hProv) CryptReleaseContext(hProv, 0); } void main() Setup(); Шифруем два фрагмента текста ключом bKey. try Encrypt(bKey, bPlainText, bCipherText, MAX_); Encrypt(bKey, bPlainText, bCipherText, MAX_); } catch (), printf("Ошибка ! %d", GetLastError()); return; Теперь слегка "поколдуем". Получить все байты уже известного зашифрованного или открытого текста. for (inti=0;i MAX_; i++) c = bCipherText,i.; Байты первого зашифрованного фрагмента p = bPlainText,i.; Байты первого открытого фрагмента k = c ^ p; Получаем байты ключевого потока. p = k ^ bCipherText,i.; Байты второго открытого фрагмента Выводим все байты второго сообщения. printf("%c", p); } } Этот пример есть в папке Secureco\Chapter. При запуске такого кода на исполнение вы увидите открытый текст второго сообщения несмотря на то, что нам известно содержимое только первого сообщения! В действительности можно атаковать используемые таким образом поточные шифры, даже вообще не видя открытого текста. Если у вас есть два зашифрованных фрагмента, вы можете выполнить над ними операцию XOR, чтобы получить XOR-результат двух открытых фрагментов. Далее все просто: статистический анализ ГЛАВА 8 Подводные камни криптографии 247 позволяет расшифровать текст. В любом языке буквы повторяются с вполне определенной частотой. Например, в английском языке наиболее популярны E, T и A. Располагая достаточным временем, хакер сможет получить текст одного (или даже обоих) сообщений. (Впрочем, одного достаточно, чтобы узнать второй.) Примечание Будьте аккуратнее и никогда не используйте один и тот же ключ шифрования в любом из симметричных алгоритмов, в том числе блочных (DES и DES). Шифротексты двух одинаковых фрагментов исходного текста совпадают. Хакер может не знать открытого текста, но иногда совпадения разных фрагментов (или их частей) достаточно. Часто хоть какой-то фрагмент исходного кода взломщику известен. Например, у файлов многих типов есть стандартные заголовки, место которых в шифротексте хакер может вычислить, анализируя частоту и характер зашифрованного текста. Что делать, когда необходимо использовать лишь один ключ Первое, что приходит в голову: такая ситуация вызвана неудачным проектом приложения, поэтому его придется пересмотреть! То есть, если вы обязаны использовать один ключ во всех операциях потокового шифрования, вам следует использовать модификатор и присоединять его к зашифрованным данным.