Оглавление Лабораторная работа №1. Работа с криптопровайдерами Microsoft CryptoAPI. ................................................................................................................................... 5 Цель работы ......................................................................................................... 5 Ход работы ........................................................................................................... 5 Описание основных используемых в лабораторной работе функций Microsoft Crypto API............................................................................................ 5 CryptEnumProviderTypes................................................................................. 5 CryptEnumProviders ......................................................................................... 6 CryptGetDefaultProvider .................................................................................. 6 CryptAcquireContext ........................................................................................ 7 CryptGetProvParam .......................................................................................... 8 CryptReleaseContext......................................................................................... 9 Пример программы, использующей основные функции .............................. 10 Пример результата работы программы........................................................... 15 Задание к лабораторной работе ....................................................................... 16 Пример результата работы программы........................................................... 20 Лабораторная работа №2. Генерация ключа симметричного шифрования на основе пароля......................................................................................................... 25 Цель работы ....................................................................................................... 25 Ход работы ......................................................................................................... 25 Описание основных используемых в лабораторной работе функций Microsoft CryptoAPI........................................................................................... 25 CryptCreateHash ............................................................................................. 25 CryptDestroyHash ........................................................................................... 26 CryptHashData ................................................................................................ 26 CryptGetHashParam ....................................................................................... 27 CryptGenRandom ........................................................................................... 27 CryptDeriveKey .............................................................................................. 28 CryptDestroyKey ............................................................................................ 29 CryptGetKeyParam ......................................................................................... 29 CryptSetKeyParam .......................................................................................... 30 Задание к лабораторной работе ....................................................................... 31 Пример результата работы программы........................................................... 36 Лабораторная работа №3. Симметричная криптосистема. Шифрование. ...... 37 Цель работы ....................................................................................................... 37 Ход работы ......................................................................................................... 37 Описание основных используемых в лабораторной работе функций Microsoft CryptoAPI........................................................................................... 37 CryptEncrypt ................................................................................................... 37 CryptDecrypt ................................................................................................... 38 Задание к лабораторной работе ....................................................................... 39 Пример результата работы программы........................................................... 50 Лабораторная работа №4. Симметричная криптосистема. Генерация имитовставки. ........................................................................................................ 51 Цель работы ....................................................................................................... 51 Ход работы ......................................................................................................... 51 Описание основных используемых в лабораторной работе функций Microsoft CryptoAPI........................................................................................... 51 Задание к лабораторной работе ....................................................................... 51 Пример результата работы программы........................................................... 67 Лабораторная работа №5. Выработка и проверка электронной цифровой подписи средствами Microsoft CryptoAPI. ......................................................... 68 Цель работы ....................................................................................................... 68 Ход работы ......................................................................................................... 68 Описание основных используемых в лабораторной работе функций Microsoft CryptoAPI........................................................................................... 68 Задание к лабораторной работе ....................................................................... 70 Пример результата работы программы........................................................... 78 Лабораторная работа № 8. Основные признаки присутствия вредоносных программ и методы по устранению последствий вирусных заражений ......... 78 Цель работы ....................................................................................................... 78 Ход работы ......................................................................................................... 78 Методические указания к лабораторной работе ............................................ 79 Задание........................................................................................................ 85 Контрольные вопросы .......................................................................... 86 Лабораторная работа № 9. Антивирус Касперского 6.0 для Windows Workstations............................................................................................................ 86 Цель работы ....................................................................................................... 86 Ход работы ......................................................................................................... 86 Методические указания к лабораторной работе..................... 86 Задание........................................................................................................ 98 Контрольные вопросы ........................................................................ 100 ЛАБОРАТОРНЫЕ ПРАКТИКУМЫ С ЛАБОРАТОРНЫМИ ЗАДАНИЯМИ И С РЕКОМЕНДАЦИЯМИ ПО ИХ ВЫПОЛНЕНИЮ Структура лабораторного практикума № п/п Наименование лабораторной работы Содержание лабораторной работы 1 Работа с криптопровайдерами Microsoft CryptoAPI 2 Генерация ключа симметричного шифрования на основе пароля 3 Симметричная криптосистема. Шифрование с использованием функций Microsoft CryptoAPI. 4 Симметричная криптосистема. Генерация имитовставки с использованием функций Microsoft CryptoAPI. 5 Выработка и проверка электронной цифровой подписи средствами Microsoft CryptoAPI. 6 Разработка встроенной защиты программного обеспечения от несанкционированного использования. Разработка навесной защиты программного обеспечения от несанкционированного использования. Получение основных навыков инициализации, запроса параметров и завершения работы с криптопровайдерами Microsoft CryptoAPI. Получение основных навыков работы с функциями хеширования, создания ключей и генерации случайных чисел Microsoft CryptoAPI. Получение основных навыков работы с функциями шифрования и расшифровывания. Закрепление навыков использования хешфункций, создания ключей и генерации случайных чисел. Получение основных навыков работы с функциями хеширования с ключом. Закрепление навыков использования функций шифрования и расшифровывания, хеш-функций, создания ключей и генерации случайных чисел. Получение основных навыков работы с функциями создания и проверки электронной цифровой подписи. Закрепление навыков использования хеш-функций. Изучение методов и средств идентификации и аутентификации среды функционирования программного обеспечения. 7 Получение навыков создания программ – протекторов. Количество часов 4 4 4 4 4 4 4 8 Основные признаки присутствия вредоносных программ и методы по устранению последствий вирусных заражений. 9 Антивирус Касперского 6.0 для Windows Workstations ВСЕГО Получение навыков обнаружения на компьютере вредоносных программ, изучение основных методов по устранению последствий вирусных инцидентов без использования антивирусного программного обеспечения. Ознакомление с процессом инсталляции, принципами работы и управлением Антивирусом Касперского для Windows Workstations на операционных системах Microsoft Windows XP Professional или Microsoft Windows 2000 Professional. 4 4 36 Лабораторная работа №1. Работа с криптопровайдерами Microsoft CryptoAPI. Цель работы Получить основные навыки инициализации, запроса параметров и завершения работы с криптопровайдерами Microsoft CryptoAPI. Ход работы Изучить основные функции инициализации и получения параметров при работе с криптопровайдерами Microsoft CryptoAPI. Перенести пример программы, использующий основные функции в среду программирования, запустить на выполнение и проанализировать его работу. Сравнить результаты работы программы с примером результатов, приведенным в лабораторной работе. Перенести задание к лабораторной работе в среду программирования. Восстановить вырезанные фрагменты программы по описаниям и отладить полученную программу. Добавление кода осуществляется непосредственно в месте расположения комментария с описанием действия! Проанализировать работу полученной программы и сравнить результаты работы программы с примером результатов, приведенным в лабораторной работе. Описание основных используемых в лабораторной работе функций Microsoft Crypto API (функции определены в файле wincrypt.h, полное описание находится в MSDN, security.chm, .chi, в разделе Cryptography\CryptoAPI\Using CryptoAPI\CryptoAPI Reference\CryptoAPI Functions\Base CryptoAPI Functions\Service Provider Functions) CryptEnumProviderTypes получает первый или следующий тип поддерживаемых системой криптопровайдеров. Используя ее в цикле можно получить список всех доступных типов криптопровайдеров. BOOL WINAPI CryptEnumProviderTypes( DWORD dwIndex, // [вх] номер следующего перечисляемого типа. DWORD *pdwReserved, //[вх] должен быть NULL. Оставлен для использования в будущем. DWORD dwFlags,//[вх] должен быть 0. Оставлен для использования в будущем. DWORD *pdwProvType, //[вых] адрес значения содержащего перечисляемый тип. LPTSTR pszTypeName, //[вых] указатель на место, куда будет помещена строка с именем типа. Параметр может быть NULL для получения размера памяти необходимого для выделения. DWORD *pcbTypeName //[вх/вых] размер строки, записанной в предыдущий параметр. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула значение ERROR_NO_MORE_ITEMS, то это не ошибка, а сигнал окончания списка типов криптопровайдеров. Таблица кодов остальных ошибок находится в MSDN. CryptEnumProviders получает первый или следующий из поддерживаемых системой криптопровайдеров. Используя ее в цикле можно получить список всех доступных криптопровайдеров. BOOL WINAPI CryptEnumProviders( DWORD dwIndex, // [вх] номер следующего перечисляемого провайдера. DWORD *pdwReserved, //[вх] должен быть NULL. Оставлен для использования в будущем. DWORD dwFlags,//[вх] должен быть 0. Оставлен для использования в будущем. DWORD *pdwProvType, //[вых] адрес значения содержащего тип перечисляемого провайдера. LPTSTR pszProvName, //[вых] указатель на место, куда будет помещена строка с именем провайдера. Параметр может быть NULL для получения размера памяти необходимого для выделения. DWORD *pcbProvName //[вх/вых] размер строки, записанной в предыдущий параметр. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула значение ERROR_NO_MORE_ITEMS, то это не ошибка, а сигнал окончания списка типов криптопровайдеров. Если она вернула ERROR_MORE_DATA, то буфер pszProvName недостаточен для размещения в нем имени. Таблица кодов остальных ошибок находится в MSDN. CryptGetDefaultProvider получает криптопровайдер определенного типа, заданный в системе по умолчанию. BOOL WINAPI CryptGetDefaultProvider( DWORD dwProvType, //[вх] тип провайдера по умолчанию. Может быть одним из следующих: PROV_RSA_FULL, PROV_RSA_SIG, PROV_DSS, PROV_DSS_DH, PROV_DH_SCHANNEL, PROV_FORTEZZA, PROV_MS_EXCHANGE, PROV_RSA_SCHANNEL, PROV_SSL DWORD *pdwReserved, //[вх] должен быть NULL. Оставлен для использования в будущем DWORD dwFlags, //[вх] CRYPT_USER_DEFAULT ищет провайдер по умолчанию для данного пользователя. CRYPT_MACHINE_DEFAULT ищет провайдер по умолчанию системы. LPTSTR pszProvName, //[вых] указатель на место, куда будет помещена строка с именем провайдера. Параметр может быть NULL для получения размера памяти необходимого для выделения DWORD *pcbProvName //[вх/вых] размер строки, записанной в предыдущий параметр. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула ERROR_MORE_DATA, то буфер pszProvName недостаточен для размещения в нем имени. Если она вернула ERROR_INVALID_PARAMETER, значит один из параметров является неправильным. Таблица кодов остальных ошибок находится в MSDN. CryptAcquireContext используется для получения дескриптора некоторого контейнера ключей в некотором криптопровайдере. Полученный дескриптор используется в вызовах функций CryptoAPI использующих выбранный криптопровайдер. Сначала функция пытается найти криптопровайдер с параметрами, описанными в dwProvType и pszProvider. Если криптопровайдер найден, функция пытается найти в нем контейнер ключей с именем, указанным в pszContainer. При заданных настройках dwFlags эта функция может создавать и уничтожать контейнеры ключей, а также обеспечивать доступ к криптопровайдеру с временным контейнером ключей если не требуется доступ к секретному ключу. BOOL WINAPI CryptAcquireContext( HCRYPTPROV *phProv, //[вых] указатель на дескриптор криптопровайдера. LPCTSTR pszContainer, //[вх] заканчивающаяся нулем строка с именем контейнера ключей. Если равен NULL, то используется контейнер по умолчанию. Когда dwFlags установлен в CRYPT_VERIFYCONTEXT, pszContainer должен быть NULL. LPCTSTR pszProvider, //[вх] заканчивающаяся нулем строка с именем криптопровайдера. Если равен NULL, то используется криптопровайдер по умолчанию. DWORD dwProvType, //[вх] задает тип получаемого криптопровайдера. DWORD dwFlags //[вх] значения флагов. Обычно этот параметр равен нулю, но приложения могут устанавливать один или несколько флагов, описанных ниже. ); Значения параметра dwFlags: CRYPT_VERIFYCONTEXT предназначен для приложений не использующих асимметричные ключевые пары, например приложений хеширования или симметричного шифрования. К секретному ключу должны иметь доступ только приложения расшифрования сообщений или создания подписей. Всем остальным приложениям желательно устанавливать этот флаг. В этом случае приложение не имеет доступа к парам открытых/секретных ключей, и pszContainer должен быть установлен в NULL. CRYPT_NEWKEYSET создает новый контейнер ключей с именем заданным в pszContainer. Если последний равен NULL, то создается контейнер с именем по умолчанию. CRYPT_MACHINE_KEYSET может совмещаться с остальными флагами для указания, что контейнер не пользовательский, а системный. По умолчанию же используются пользовательские ключи и контейнеры, а это значит, что доступ к ним может получить только пользователь создавший их или пользователь с администраторскими привилегиями. Права для доступа к системному контейнеру могут быть заданы с использованием CryptSetProvParam. Системные контейнеры полезны, если пользователь работает с ними из службы или не загрузился интерактивно. После создания контейнера большинством криптопровайдеров ключи автоматически не создаются. Их необходимо создать отдельно вызовом CryptGenKey. CRYPT_DELETEKEYSET уничтожает указанный в pszContainer контейнер ключей. Если pszContainer равен NULL, то удаляется контейнер ключей по умолчанию. Все ключевые пары в контейнере также уничтожаются. Если установлен этот флаг, то значение phProv не определено, и вызывать CryptReleaseContext не нужно. CRYPT_SILENT означает требование приложения, чтобы криптопровайдер не выводил ничего для этого контекста на экран. Если криптопровайдер должен выводить информацию для своей работы на экран, то выдается ошибка NTE_SILENT_CONTEXT. Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Некоторые из возможных значений ошибок (таблица кодов остальных ошибок находится в MSDN): ERROR_BUSY: если установлен CRYPT_DELETEKEYSET а другой процесс использует этот контейнер. ERROR_INVALID_PARAMETER: один из параметров является неправильным. NTE_BAD_KEYSET: невозможно открыть контейнер. Скорее всего нет контейнера с таким именем. NTE_SIGNATURE_FILE_BAD, NTE_BAD_SIGNATURE: не прошла проверка подписи DLL провайдера. Либо подпись, либо DLL были подменены. NTE_EXISTS: если установлен CRYPT_NEWKEYSET, а контейнер с таким именем уже существует. NTE_KEYSET_ENTRY_BAD: контейнер найден, но поврежден. NTE_KEYSET_NOT_DEF: не найден провайдер или контейнер с заданным именем. NTE_PROV_TYPE_NO_MATCH: тип провайдера не соответствует найденному криптопровайдеру. Эта ошибка возможна, если pszProvider задает имя конкретного криптопровайдера. CryptGetProvParam получает параметры, управляющие работой криптопровайдера. BOOL WINAPI CryptGetProvParam( HCRYPTPROV hProv, //[вх] дескриптор криптопровайдера, созданный вызовом CryptAcquireContext. DWORD dwParam, //[вх] обозначает предмет запроса (см. ниже) BYTE *pbData, //[вых] указатель на место, куда будет помещена строка с именем провайдера. Параметр может быть NULL для получения размера памяти необходимого для выделения. DWORD *pdwDataLen, //[вх/вых] указатель на размер строки, записанной в предыдущий параметр. Если pdbData равен NULL и запрос PP_ENUMALGS или PP_ENUMALGS_EX, параметр содержит размер максимальной записи из списка. DWORD dwFlags //[вх] флаги (см. ниже). ); Возможные значения dwParam: PP_CONTAINER, PP_UNIQUE_CONTAINER: имя текущего контейнера ключа. PP_ENUMALGS: структура PROV_ENUMALGS, содержащая сокращенную информацию об одном алгоритме, поддерживаемом криптопровайдером. Значения должны запрашиваться последовательно чтобы получить все поддерживаемые алгоритмы. При первом вызове должен быть установлен флаг CRYPT_FIRST в dwFlags. При следующих вызовах dwFlags должен быть установлен в 0. Список окончился, если выдан код ошибки ERROR_NO_MORE_ITEMS. typedef struct _PROV_ENUMALGS { ALG_ID aiAlgid; // идентификатор алгоритма DWORD dwBitLen; // длина ключа DWORD dwNameLen; // длина имени алгоритма CHAR szName[20]; // имя алгоритма } PROV_ENUMALGS; PP_ENUMALGS_EX: расширенная информация об алгоритме (вариант PP_ENUMALGS). typedef struct _PROV_ENUMALGS_EX { ALG_ID aiAlgid; // идентификатор алгоритма DWORD dwDefaultLen; // длина ключа по умолчанию DWORD dwMinLen; // минимальная длина ключа DWORD dwMaxLen; // максимальная длина ключа DWORD dwProtocols; // количество поддерживаемых протоколов DWORD dwNameLen; // длина короткого имени протокола CHAR szName[20]; // строка с именем поддерживаемого протокола DWORD dwLongNameLen; // длина полного имени протокола CHAR szLongName[40]; // строка с длинным именем протокола } PROV_ENUMALGS_EX; PP_ENUMCONTAINERS: строка с именем одного из контейнеров ключей поддерживаемого криптопровайдером. Список получается так же как и с помощью PP_ENUMALGS. PP_IMPTYPE: значение DWORD, означающее вид реализации криптопровайдера. CRYPT_IMPL_HARDWARE – аппаратный, CRYPT_IMPL_SOFTWARE – программный, CRYPT_IMPL_MIXED аппаратно-программный, CRYPT_IMPL_UNKNOWN – неизвестный. PP_NAME: строка с именем криптопровайдера. PP_VERSION: номер версии криптопровайдера. Два младших байта содержат номер версии. PP_SIG_KEYSIZE_INC и PP_KEYX_KEYSIZE_INC: шаг изменения длины ключей подписи и обмена. PP_KEYSET_SEC_DESCR: указатель на дескриптор безопасности контейнера ключей. PP_PROVTYPE: значение DWORD, соответствующее типу криптопровайдера. PP_USE_HARDWARE_RNG: проверяет поддержку аппаратного генератора случайных чисел. Если поддерживается, то функция возвращает TRUE, если нет – FALSE. При использовании этого значения параметр pbData должен быть равен NULL, а dwFlags – 0. PP_KEYSPEC: возвращает информацию о поддерживаемых криптопровайдером спецификаторах ключа. Некоторые возможные значения dwFlags: CRYPT_FIRST используется при получении списка для выдачи первого значения. CRYPT_MACHINE_KEYSET может использоваться совместно с PP_ENUMCONTAINERS для получения списка системных (а не пользовательских) контейнеров ключей. Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула значение ERROR_NO_MORE_ITEMS, то это не ошибка, а сигнал окончания списка. Если она вернула ERROR_MORE_DATA, то буфер pbData недостаточен для размещения в нем информации. Если она вернула ERROR_INVALID_PARAMETER, ERROR_INVALID_HANDLE, NTE_BAD_FLAGS или NTE_BAD_UID, значит один из параметров является неправильным. Таблица кодов остальных ошибок находится в MSDN. CryptReleaseContext освобождает дескриптор криптопровайдера и контейнера ключей. При каждом вызове этой функции счетчик подключений уменьшается на единицу. Когда он достигает нуля, контекст полностью освобождается и не может использоваться никакой функцией приложения. Приложение вызывает эту функцию после окончания использования криптопровайдера. После ее вызова дескриптор провайдера более недействителен. Функция не уничтожает контейнеры ключей или ключевые пары. BOOL WINAPI CryptReleaseContext( HCRYPTPROV hProv, //[вх] дескриптор криптопровайдера, созданный вызовом CryptAcquireContext. DWORD dwFlags //[вх] должен быть 0. Оставлен для использования в будущем. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она вернула ERROR_BUSY, то контекст криптопровайдера в данный момент используется другим процессом. Если она вернула ERROR_INVALID_PARAMETER, ERROR_INVALID_HANDLE, NTE_BAD_FLAGS или NTE_BAD_UID, значит один из параметров является неправильным. Таблица кодов остальных ошибок находится в MSDN. Примечания. После вызова функции сеанс работы криптопровайдера заканчивается и все существующие сеансовые ключи и хеш-объекты созданные с использованием дескриптора hProv становятся недействительными. В практике все эти объекты должны быть уничтожены вызовами CryptDestroyKey и CryptDestroyHash до вызова CryptReleaseContext. Пример программы, использующей основные функции #include "stdafx.h" #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <stdio.h> #include <windows.h> #include <wincrypt.h> void HandleError(char *s) { printf("An error occurred in running the program.\n"); printf("%s\n",s); printf("Error number %x\n.",GetLastError()); printf("Program terminating.\n"); exit(1); } void main() { HCRYPTPROV hProv; // Дескриптор криптопровайдера LPTSTR pszName; DWORD dwType; DWORD cbName; DWORD dwIndex=0; BYTE *ptr; ALG_ID aiAlgid; DWORD dwBits; DWORD dwNameLen; CHAR szName[100]; // Часто выделяется динамически BYTE pbData[1024];// Часто выделяется динамически DWORD cbData=1024; DWORD dwIncrement = sizeof(DWORD); DWORD DWORD CHAR BOOL LPTSTR DWORD dwFlags=CRYPT_FIRST; dwParam = PP_CLIENT_HWND; *pszAlgType = NULL; fMore=TRUE; pbProvName; cbProvName; //-------------------------------------------------------------// Печать заголовка таблицы типов криптопровайдеров. printf("\n printf("Type printf("____ Listing Available Provider Types.\n"); Provider Type Name\n"); ________________________________\n"); // Цикл перечисления типов криптопровайдеров. dwIndex = 0; while(CryptEnumProviderTypes( dwIndex, // вх -- dwIndex NULL, // вх -- pdwReserved- установить NULL 0, // вх -- dwFlags – установить 0 &dwType, // вых -- pdwProvType NULL, // вых -- pszProvName -- NULL при первом вызове &cbName // вх, вых -- pcbProvName )) { //------------------------------------------------------------------// cbName — длина имени следующего типа криптопровайдеров. // Выделяем участок памяти для размещения этого имени. if (!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName))) { HandleError("ERROR - LocalAlloc failed!"); } //------------------------------------------------------------------// Получаем название типа криптопровайдера. if (CryptEnumProviderTypes( dwIndex++, NULL, NULL, &dwType, pszName, &cbName)) { printf ("%4.0d %s\n",dwType, pszName); } else { HandleError("ERROR - CryptEnumProviders"); } LocalFree(pszName); } //-------------------------------------------------------------// Печать заголовка списка криптопровайдеров. printf("\n\n Listing Available Providers.\n"); printf("Type Provider Name\n"); printf("____ ________________________________\n"); //--------------------------------------------------------------// Цикл перечисления криптопровайдеров. dwIndex = 0; while(CryptEnumProviders( dwIndex, // in -- dwIndex NULL, // in -- pdwReserved- установить NULL 0, // in -- dwFlags – установить 0 &dwType, // out -- pdwProvType NULL, // out -- pszProvName -- NULL при первом вызове &cbName // in, out -- pcbProvName )) { //------------------------------------------------------------------// cbName — длина имени следующего криптопровайдера. // Выделяем участок памяти для размещения этого имени. if (!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName))) { HandleError("ERROR - LocalAlloc failed!"); } //------------------------------------------------------------------// Получаем название криптопровайдера. if (CryptEnumProviders( dwIndex++, NULL, 0, &dwType, pszName, &cbName // pcbProvName – размер pszName )) { printf ("%4.0d %s\n",dwType, pszName); } else { HandleError("ERROR - CryptEnumProviders"); } LocalFree(pszName); } // Конец цикла while //---------------------------------------------------------------// Получаем имя провайдера по умолчанию относящегося к PROV_RSA_FULL // //-------------------------------------------------------------// Получаем длину его имени. if (!(CryptGetDefaultProvider( PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, NULL, &cbProvName))) { HandleError("Error getting the length of the default provider name."); } //-------------------------------------------------------------// Выделяем память для размещения имени криптопровайдера по умолчанию if (!(pbProvName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbProvName))) { HandleError("Error during memory allocation for provider name."); } //-------------------------------------------------------------// Получаем имя криптопровайдера типа PROV_RSA_FULL. if (CryptGetDefaultProvider( PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, pbProvName, &cbProvName)) { printf("\n\nThe default provider name is %s\n\n",pbProvName); } else { HandleError("Getting the name of the provider failed."); } //----------------------------------------------------// Получаем криптографический контекст (инициализируем криптопровайдер). if(!CryptAcquireContext( &hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT )) { HandleError("Error during CryptAcquireContext!"); } //-----------------------------------------------------// Получаем список поддерживаемых алгоритмов. //-----------------------------------------------------// Печать заголовка таблицы информации об алгоритмах printf(" Enumerating the supported algorithms\n\n"); printf(" Algid Bits Type Name Algorithm\n"); printf(" Length Name\n"); printf(" ________________________________________________________\n"); while(fMore) { //-----------------------------------------------------// Получение информации об очередном алгоритме. if(CryptGetProvParam(hProv, PP_ENUMALGS, pbData, &cbData, dwFlags)) { //---------------------------------------------------------// Достаем информацию из буфера 'pbData'. dwFlags=0; ptr = pbData; aiAlgid = *(ALG_ID *)ptr; ptr += sizeof(ALG_ID); dwBits = *(DWORD *)ptr; ptr += dwIncrement; dwNameLen = *(DWORD *)ptr; ptr += dwIncrement; strncpy(szName,(char *) ptr, dwNameLen); //-------------------------------------------------------// Определяем тип алгоритма. switch(GET_ALG_CLASS(aiAlgid)) { case ALG_CLASS_DATA_ENCRYPT: pszAlgType = "Encrypt "; break; case ALG_CLASS_HASH: pszAlgType = "Hash "; break; case ALG_CLASS_KEY_EXCHANGE: pszAlgType = "Exchange "; break; case ALG_CLASS_SIGNATURE: pszAlgType = "Signature"; break; default: pszAlgType = "Unknown "; } //----------------------------------------------------------// Печатаем информацию об алгоритме. printf(" %8.8xh %-4d %s %-2d aiAlgid, dwBits, pszAlgType, dwNameLen, szName ); } else fMore=FALSE; } if(GetLastError() == ERROR_NO_MORE_ITEMS) { printf("\nThe program completed without error.\n"); } else { HandleError("Error reading algorithm!"); } } Пример результата работы программы Type ____ 1 3 12 13 18 Listing Available Provider Types. Provider Type Name ________________________________ RSA Full (Signature and Key Exchange) DSS Signature RSA SChannel DSS Signature with Diffie-Hellman Key Exchange Diffie-Hellman SChannel Type Listing Available Providers. Provider Name %s\n", ____ ________________________________ 1 Gemplus GemSAFE Card CSP v1.0 1 Microsoft Base Cryptographic Provider v1.0 13 Microsoft Base DSS and Diffie-Hellman Cryptographic Provider 3 Microsoft Base DSS Cryptographic Provider 18 Microsoft DH SChannel Cryptographic Provider 1 Microsoft Enhanced Cryptographic Provider v1.0 13 Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider 12 Microsoft RSA SChannel Cryptographic Provider 1 Microsoft Strong Cryptographic Provider 1 Schlumberger Cryptographic Service Provider The default provider name is Microsoft Strong Cryptographic Provider Enumerating the supported algorithms Algid Bits Type Name Algorithm Length Name ________________________________________________________ 00006602h 40 Encrypt 4 RC2 00006801h 40 Encrypt 4 RC4 00006601h 56 Encrypt 4 DES 00006609h 112 Encrypt 13 3DES TWO KEY 00006603h 168 Encrypt 5 3DES 00008004h 160 Hash 6 SHA-1 00008001h 128 Hash 4 MD2 00008002h 128 Hash 4 MD4 00008003h 128 Hash 4 MD5 00008008h 288 Hash 12 SSL3 SHAMD5 00008005h 64 Hash 4 MAC 00002400h 512 Signature 9 RSA_SIGN 0000a400h 512 Exchange 9 RSA_KEYX 00008009h 0 Hash 5 HMAC The program completed without error. Задание к лабораторной работе Заполнить указанные пропуски в программе вывода списка криптопровайдеров с параметрами реализуемых в них алгоритмов. #include "stdafx.h" #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <windows.h> #include <stdio.h> /* 1. Вставить заголовочный файл для работы с Microsoft CryptoAPI */ // Определение массива имен типов криптопровайдеров LPTSTR szProvType[]={ NULL, "RSA Full (Signature and Key Exchange)", "RSA Signature", "DSS Signature", "PROV_FORTEZZA", "PROV_MS_EXCHANGE", "PROV_SSL", NULL, NULL, NULL, NULL, NULL, "RSA SChannel", "DSS Signature with Diffie-Hellman Key Exchange", "PROV_EC_ECDSA_SIG", "PROV_EC_ECNRA_SIG", "PROV_EC_ECDSA_FULL", "PROV_EC_ECNRA_FULL", "Diffie-Hellman SChannel", NULL, "PROV_SPYRUS_LYNKS", "PROV_RNG", "PROV_INTEL_SEC"}; // Определение массива имен типов исполнения криптопровайдеров LPTSTR szImpType[]={ NULL, "Hardware", "Software", "Mixed", "Unknown", "Not define", "Not define", "Not define", "Removable", "Type 9", "Type 10", "Type 11"}; // Определение массива имен классов алгоритмов LPTSTR szAlgClass[]={ NULL, "Signature", "Encrypt ", "Encrypt ", "Hash ", "Exchange ", "All "}; // Определение и инициализация переменных HMODULE hDll=0; DWORD dwCount, cbName; DWORD dwDataLen, dwIndex=0; WCHAR swzProvName[100]; CHAR szName[100]; PROV_ENUMALGS AlgInfo; PROV_ENUMALGS_EX AlgInfoEx; CHAR *pszAlgType = NULL; LPWSTR LPWSTR DWORD dwImpType; DWORD HCRYPTPROV DWORD pswzProvName=NULL; pszProvName=NULL; dwProvType, dwCryptError, dwVersion, dwFlags=0; hProv = 0; dwSigKeySizeInc, dwXchKeySizeInc; void main(void) { // Цикл перечисления криптопровайдеров. while (/* 2. Имя функции? */(dwIndex, NULL,0, &dwProvType, NULL, &cbName)){ if (/* 3. Имя функции? */(dwIndex++,NULL,0,&dwProvType,szName, &cbName)){ // Открываем контекст криптопровайдера if (! /* 4. Открыть контекст криптопровайдера не подключаясь к контейнерам ключей. Дескриптор – hProv, имя и тип криптопровайдера получаем из вызова предыдущей функции перечисления криптопровайдеров */ ) { printf("Error:CryptAcquireContext=0x%X.\n",GetLastError()); break; } // Получаем версию криптопровайдера dwDataLen = sizeof(DWORD); if (!CryptGetProvParam( hProv, PP_VERSION, (PBYTE)&dwVersion, &dwDataLen, 0)) { printf("Error:CryptGetProvParam=0x%X.\n",GetLastError()); goto ReleaseResource; } // Получаем тип исполнения криптопровайдера dwDataLen = sizeof(DWORD); if (! /* 5. В переменную dwImpType получить вид реализации криптопровайдера с дескриптором hProv (аппаратный, программный или аппаратнопрограммный) */ ) { printf("Error:CryptGetProvParam=0x%X.\n",GetLastError()); goto ReleaseResource; } // Распечатываем полученную информацию printf("\n\n\nProvider name: %s\n", szName); printf("Provider version: %d.%d\n", HIBYTE(LOWORD(dwVersion)), LOBYTE(LOWORD(dwVersion))); printf("Provider type: %s\n", szProvType[dwProvType]); printf("Provider implementation type: %s\n", szImpType[dwImpType]); // Распечатываем заголовок таблицы алгоритмов printf("\n |Length info (bits)|\n"); printf("AlgId|Type |Def |Max |Min |Name \n"); printf("-----+---------+-----+------+-----+---------------\n"); // Перечисляем алгоритмы криптопровайдера for (dwCount=0 ; ; dwCount++) { // Устанавливаем флаг CRYPT_FIRST // при первом обращении в цикле. if (dwCount == 0) dwFlags = CRYPT_FIRST; else dwFlags = 0; // Получаем информацию об алгоритмах dwDataLen = sizeof(PROV_ENUMALGS_EX); dwCryptError=ERROR_SUCCESS; // Запрашиваем расширенную информацию об алгоритмах if (! /* 6. В переменную AlgInfoEx получить расширенную информацию об алгоритмах криптопровайдера с дескриптором hProv. В переменную dwDataLen получить длину AlgInfoEx. Необходимые значения флагов уже записаны в переменную dwFlags */ ) { dwCryptError=GetLastError(); if (dwCryptError == ERROR_NO_MORE_ITEMS) break; if (dwCryptError == NTE_BAD_FLAGS || dwCryptError== NTE_BAD_TYPE) { dwDataLen = sizeof(PROV_ENUMALGS); // Если криптопровайдер не поддерживает расширенный запрос, то // запрашиваем сокращенную информацию об алгоритмах if (! /* 7. В переменную AlgInfo получить сокращенную информацию об алгоритмах криптопровайдера с дескриптором hProv. В переменную dwDataLen получить длину AlgInfo. Необходимые значения флагов уже записаны в переменную dwFlags */ ) { /* 8. Проанализировать код возникшей ошибки. Если возникла ошибка, показывающая конец списка алгоритмов, то прервать цикл */ printf("Error %x reading algorithm!\n",GetLastError()); goto ReleaseResource; } AlgInfoEx.aiAlgid=AlgInfo.aiAlgid; AlgInfoEx.dwDefaultLen=AlgInfo.dwBitLen; AlgInfoEx.dwMaxLen=0; AlgInfoEx.dwMinLen=0; lstrcpy(AlgInfoEx.szLongName,AlgInfo.szName); } else { printf("Error %x reading algorithm!\n",GetLastError()); goto ReleaseResource; } } // Распечатываем полученную информацию printf( "%4.4xh|%s|%-4d |%-5d |%-4d |%s \n", AlgInfoEx.aiAlgid, szAlgClass[GET_ALG_CLASS(AlgInfoEx.aiAlgid) >> 13], AlgInfoEx.dwDefaultLen, AlgInfoEx.dwMaxLen, AlgInfoEx.dwMinLen, AlgInfoEx.szLongName); } // Окончание работы с криптопровайдером /* 9. Освободить дескриптор криптопровайдера hProv */ hProv=0; } } // Аварийное завершение работы с криптопровайдером ReleaseResource: if (hProv)/* 10. Освободить дескриптор криптопровайдера hProv */ ; return; } Пример результата работы программы Provider name: Gemplus GemSAFE Card CSP v1.0 Provider version: 0.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Type 11 |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8001h|Hash |128 |128 |128 |Message Digest 2 (MD2) 8002h|Hash |128 |128 |128 |Message Digest 4 (MD4) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|1024 |1024 |512 |RSA Signature a400h|Exchange |512 |512 |512 |RSA Key Exchange 8009h|Hash |0 |0 |0 |Hugo's MAC (HMAC) Provider name: Microsoft Base Cryptographic Provider v1.0 Provider version: 2.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |40 |56 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |56 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8001h|Hash |128 |128 |128 |Message Digest 2 (MD2) 8002h|Hash |128 |128 |128 |Message Digest 4 (MD4) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|512 |16384 |384 |RSA Signature a400h|Exchange |512 |1024 |384 |RSA Key Exchange 8009h|Hash |0 |0 |0 |Hugo's MAC (HMAC) Provider name: Microsoft Base DSS and Diffie-Hellman Cryptographic Provider Provider version: 1.0 Provider type: DSS Signature with Diffie-Hellman Key Exchange Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------- 660ch|Encrypt |40 |40 gorithm 6602h|Encrypt |40 |56 6801h|Encrypt |40 |56 6601h|Encrypt |56 |56 (DES) 8004h|Hash |160 |160 8003h|Hash |128 |128 2200h|Signature|1024 |1024 aa01h|Exchange |512 |1024 Algorithm aa02h|Exchange |512 |1024 gorithm |40 |CYLINK Message Encryption Al- |40 |40 |56 |RSA Data Security's RC2 |RSA Data Security's RC4 |Data Encryption Standard |160 |128 |512 |512 |Secure Hash Algorithm (SHA-1) |Message Digest 5 (MD5) |Digital Signature Algorithm |Diffie-Hellman Key Exchange |512 |Diffie-Hellman Ephemeral Al- Provider name: Microsoft Base DSS Cryptographic Provider Provider version: 1.0 Provider type: DSS Signature Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 2200h|Signature|1024 |1024 |512 |Digital Signature Algorithm Provider name: Microsoft DH SChannel Cryptographic Provider Provider version: 1.0 Provider type: Diffie-Hellman SChannel Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------660ch|Encrypt |40 |40 |40 |CYLINK Message Encryption Algorithm 6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 2200h|Signature|1024 |1024 |1024 |Digital Signature Algorithm aa01h|Exchange |512 |4096 |512 |Diffie-Hellman Key Exchange Algorithm aa02h|Exchange |512 |4096 |512 |Diffie-Hellman Ephemeral Algorithm Provider name: Microsoft Enhanced Cryptographic Provider v1.0 Provider version: 2.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |128 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |128 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8001h|Hash |128 |128 |128 |Message Digest 2 (MD2) 8002h|Hash |128 |128 |128 |Message Digest 4 (MD4) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|1024 |16384 |384 |RSA Signature a400h|Exchange |1024 |16384 |384 |RSA Key Exchange 8009h|Hash |0 |0 |0 |Hugo's MAC (HMAC) Provider name: Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider Provider version: 1.0 Provider type: DSS Signature with Diffie-Hellman Key Exchange Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------660ch|Encrypt |40 |40 |40 |CYLINK Message Encryption Algorithm 6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 2200h|Signature|1024 |1024 |512 |Digital Signature Algorithm aa01h|Exchange |512 |4096 |512 |Diffie-Hellman Key Exchange Algorithm aa02h|Exchange |512 |4096 |512 |Diffie-Hellman Ephemeral Algorithm Provider name: Microsoft RSA SChannel Cryptographic Provider Provider version: 2.0 Provider type: RSA SChannel Provider implementation type: Software AlgId|Type |Length info (bits)| |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |128 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |128 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|1024 |16384 |384 |RSA Signature a400h|Exchange |1024 |16384 |384 |RSA Key Exchange 8009h|Hash |0 |0 |0 |Hugo's MAC (HMAC) Provider name: Microsoft Strong Cryptographic Provider Provider version: 2.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Software |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 |160 |Secure Hash Algorithm (SHA-1) 8001h|Hash |128 |128 |128 |Message Digest 2 (MD2) 8002h|Hash |128 |128 |128 |Message Digest 4 (MD4) 8003h|Hash |128 |128 |128 |Message Digest 5 (MD5) 8008h|Hash |288 |288 |288 |SSL3 SHAMD5 8005h|Hash |0 |0 |0 |Message Authentication Code 2400h|Signature|512 |16384 |384 |RSA Signature a400h|Exchange |512 |16384 |384 |RSA Key Exchange 8009h|Hash |0 |0 |0 |Hugo's MAC (HMAC) Provider name: Schlumberger Cryptographic Service Provider Provider version: 5.0 Provider type: RSA Full (Signature and Key Exchange) Provider implementation type: Type 11 |Length info (bits)| AlgId|Type |Def |Max |Min |Name -----+---------+-----+------+-----+---------------6602h|Encrypt |40 |128 |40 |RSA Data Security's RC2 6801h|Encrypt |40 |128 |40 |RSA Data Security's RC4 6601h|Encrypt |56 |56 |56 |Data Encryption Standard (DES) 6609h|Encrypt |112 |112 |112 |Two Key Triple DES 6603h|Encrypt |168 |168 |168 |Three Key Triple DES 8004h|Hash |160 |160 8001h|Hash |128 |128 8002h|Hash |128 |128 8003h|Hash |128 |128 8008h|Hash |288 |288 8005h|Hash |0 |0 2400h|Signature|1024 |1024 a400h|Exchange |1024 |1024 8009h|Hash |0 |0 |160 |Secure Hash Algorithm (SHA-1) |128 |Message Digest 2 (MD2) |128 |Message Digest 4 (MD4) |128 |Message Digest 5 (MD5) |288 |SSL3 SHAMD5 |0 |Message Authentication Code |1024 |RSA Signature |1024 |RSA Key Exchange |0 |Hugo's MAC (HMAC) Лабораторная работа №2. Генерация ключа симметричного шифрования на основе пароля. Цель работы Получить основные навыки работы с функциями хеширования, создания ключей и генерации случайных чисел Microsoft CryptoAPI. Ход работы Изучить функции хеширования, создания ключей и генерации случайных чисел Microsoft CryptoAPI. Перенести задание к лабораторной работе в среду программирования. Восстановить вырезанные фрагменты программы по описаниям и отладить полученную программу. Добавление кода осуществляется непосредственно в месте расположения комментария с описанием действия! Проанализировать работу полученной программы и сравнить результаты работы программы с примером результатов, приведенным в лабораторной работе. Описание основных используемых в лабораторной работе функций Microsoft CryptoAPI (функции определены в файле wincrypt.h, полное описание находится в MSDN, security.chm, .chi, в разделе Cryptography\CryptoAPI\Using CryptoAPI\CryptoAPI Reference\CryptoAPI Functions\Base CryptoAPI Functions) CryptCreateHash Начинает процесс хеширования потока данных. Создает и возвращает вызвавшему приложению дескриптор хеш-объекта криптопровайдера. Этот дескриптор используется в последующих вызовах функций CryptHashData и CryptHashSessionKey для хеширования сеансовых ключей и других потоков данных. BOOL WINAPI CryptCreateHash( HCRYPTPROV hProv, // [вх] дескриптор криптопровайдера, созданный вызовом CryptAcquireContext. ALG_ID Algid, // [вх] идентификатор и другие необходимые параметры хешалгоритма (см. MSDN) HCRYPTKEY hKey, // [вх] для алгоритмов генерации имитовставки (секретного хеша: MAC, HMAC) в этом параметре передается ключ. Для обычных алгоритмов должен быть равен 0. DWORD dwFlags,//[вх] должен быть 0. Оставлен для использования в будущем. HCRYPTHASH *phHash //[вых] адрес, в который функция записывает дескриптор нового хеш-объекта. ); Возможные значения хеш-алгоритмов: CALG_HMAC, CALG_MAC, CALG_MD2, CALG_MD5, CALG_SHA, CALG_SSL3_SHAMD5. Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Таблица кодов ошибок находится в MSDN. Непосредственно вычисление значения хеш-функции происходит в вызовах функций CryptHashData и CryptHashSessionKey, требующих дескриптор хеш-объекта. После того, как к хеш-объекту были добавлены все данные, возможны следующие действия: Получить хеш-значение можно вызовом CryptGetHashParam Сгенерировать сеансовый ключ можно вызовом CryptDeriveKey Подписать полученное значение можно вызовом CryptSignHash Проверить подпись можно вызовом CryptVerifySignature После вызова любой из этих функций дальнейшие вызовы CryptHashData и CryptHashSessionKey невозможны. CryptDestroyHash Уничтожает хеш-объект, на который указывает дескриптор hHash. После уничтожения хеш-объекта дальнейшее его использование невозможно. По соображениям безопасности рекомендуется уничтожать хеш-объекты сразу после их использования. BOOL WINAPI CryptDestroyHash( HCRYPTHASH hHash // [вх] дескриптор уничтожаемого хеш-объекта. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Таблица кодов ошибок находится в MSDN. Для каждого вызова CryptCreateHash должен быть соответствующий вызов CryptDestroyHash. CryptHashData Добавляет данные к указанному хеш-объекту. Эта функция и CryptHashSessionKey могут вызываться несколько раз для вычисления хеша длинного или состоящего из нескольких частей потока данных. Перед вызовом этой функции нужно создать хеш-объект вызовом CryptCreateHash. BOOL WINAPI CryptHashData( HCRYPTHASH hHash, // [вх] дескриптор хеш-объекта. BYTE *pbData, // [вх] указатель на область памяти, содержащую данные, добавляемые к хеш-объекту. DWORD dwDataLen, // [вх] количество байт добавляемых данных. Должно быть равно 0, если установлен флаг CRYPT_USERDATA. DWORD dwFlags // [вх] определено следующее значение: CRYPT_USERDATA. Все криптопровайдеры Microsoft его игнорируют. Если какой-либо криптопровайдер его поддерживает, то он запрашивает данные непосредственно у пользователя минуя приложение (например, PIN-код). ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Таблица кодов ошибок находится в MSDN. CryptGetHashParam Получает параметры, управляющие работой хеш-объекта. Можно также получить и само значение хеш-функции. BOOL WINAPI CryptGetHashParam( HCRYPTHASH hHash, // [вх] дескриптор хеш-объекта. DWORD dwParam, //[вх] обозначает предмет запроса (см. ниже). BYTE *pbData, //[вых] указатель на место, куда будет помещена выходная информация. Параметр может быть NULL для получения размера памяти необходимого для выделения. DWORD *pdwDataLen, //[вх/вых] указатель на размер данных, записанных в предыдущий параметр. DWORD dwFlags //[вх] должен быть 0. Оставлен для использования в будущем. ); Возможные значения dwParam: HP_ALGID: структура типа ALG_ID, содержащая идентификатор алгоритма хеширования, заданного во время создания хеш-объекта. HP_HASHSIZE: значение типа DWORD, равное длине хеш-значения в байтах. Обычно равно 16 или 20 байт в зависимости от алгоритма хеширования. Необходимо запрашивать это значение перед запросом HP_HASHVAL, чтобы выделить необходимую область памяти. HP_HASHVAL: значение хеш-функции, полученное вызовами CryptHashData и CryptHashSessionKey. После вызова этой функции дополнительные данные уже не хешируются. Остается вызвать CryptDestroyHash для уничтожения этого объекта. Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она возвращает ERROR_MORE_DATA, то переданная область памяти мала для размещения результата. Таблица кодов остальных ошибок находится в MSDN. CryptGenRandom Заполняет переданный буфер криптографически случайными байтами. BOOL WINAPI CryptGenRandom( HCRYPTPROV hProv, //[вх] дескриптор криптопровайдера, созданный вызовом CryptAcquireContext. DWORD dwLen, //[вх] количество случайных байт, которое нужно сгенерировать. BYTE *pbBuffer //[вх/вых] область памяти для размещения случайных байт. Должна быть длиной не менее dwLen байт. Перед вызовом можно заполнить необязательным начальным значением для генератора. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Таблица кодов ошибок находится в MSDN. Примечания. Данные, полученные от этой функции гораздо более случайны, чем результат стандартного генератора псевдослучайных чисел, входящего в библиотеки языков программирования. Эта функция часто используется для генерации модификаторов ключа и синхропосылок. Для получения по-настоящему случайного числа, перед вызовом приложение может задать начальное значение, полученное из движений мыши или нажатий клавиатуры, которые затем прибавляются к хранимому начальному значению а также к системной информации. Полученный результат хешируется с алгоритмом SHA-1 и подается на вход алгоритма RC-4 для получения значения результата. CryptDeriveKey Генерирует криптографические сеансовые ключи на основе переданного значения. Функция гарантирует, что при использовании одинаковых криптоалгоритмов ключи получаемые из начальных данных будут одинаковыми. Начальные данные могут быть паролем или другим пользовательским значением. Функция работает аналогично CryptGenKey, но ключи получаются на основе заданного, а не случайного значения. CryptDeriveKey используется только для генерации случайных ключей, и не может применяться для создания пар открытых/секретных ключей. В параметре phKey возвращается дескриптор сеансового ключа, который может использоваться с любыми функциями CryptoAPI, использующими дескриптор ключа. BOOL WINAPI CryptDeriveKey( HCRYPTPROV hProv, //[вх] дескриптор криптопровайдера, созданный вызовом CryptAcquireContext. ALG_ID Algid, // [вх] идентификатор симметричного криптоалгоритма для которого генерируется ключ. В различных криптопровайдерах списки доступных алгоритмов могут различаться. Полный список алгоритмов стандартных криптопровайдеров доступен в MSDN. HCRYPTHASH hBaseData, // [вх] дескриптор хеш-объекта, в который были переданы исходные данные. DWORD dwFlags,// [вх] задает тип генерируемого ключа. (см. ниже). HCRYPTKEY *phKey // [вх/вых] адрес, в который функция копирует дескриптор сгенерированного ключа. ); Возможные значения dwFlags: При генерации сеансового ключа можно задать его размер. Длину ключа в битах записывают в старшие 16 бит этого параметра. Например, для генерации 128-битного ключа, значение 0x00800000 комбинируется с помощью побитовой операции OR с другими флагами. Младшие 16 бит могут быть нулями, или комбинациями (с помощью побитовой операции OR) следующих значений: CRYPT_CREATE_SALT: обычно, когда из хеш-значения создается ключ, остаются неиспользуемые биты. Если этот флаг установлен, то оставшиеся биты используются для модификатора ключа. Это значение можно получить функцией CryptGetKeyParam. Если флаг не установлен, то значение модификатора равно нулю. Когда с помощью CryptExportKey экспортируются ключи с ненулевым модификатором, то модификатор нужно получить отдельно и хранить вместе с выгруженным ключом. CRYPT_NO_SALT: не создавать модификатор для ключа. CRYPT_EXPORTABLE: если установлен этот флаг, то сеансовый ключ впоследствии можно будет экспортировать из криптопровайдера функцией CryptExportKey. Обычно этот флаг должен быть установлен. Если флаг не установлен, то его невозможно экспортировать, и он доступен только в данном сеансе и только создавшему его приложению. CRYPT_UPDATE_KEY: Некоторые криптопровайдеры используют сеансовые ключи, полученные на основе нескольких хеш-значений. В этом случае функция CryptDeriveKey должна вызываться несколько раз. Если установлен этот флаг, то новый ключ не создается, а модифицируется существующий. Специфика работы зависит от криптопровайдера. Криптопровайдеры Microsoft игнорируют этот флаг. Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Таблица кодов ошибок находится в MSDN. Примечания. При создании ключа устанавливается режим шифра CBC. При необходимости его можно изменить вызовом CryptSetKeyParam. После вызова CryptDeriveKey добавить новые данные к указанному в параметре хешобъекту невозможно. CryptDestroyKey Освобождает ключ, на который ссылается дескриптор hKey. После этого работа с данным ключом становится невозможной. Если это был дескриптор сеансового или импортированного с помощью CryptImportKey открытого ключа, то функция уничтожает ключ и освобождает память. Хранящаяся в контейнере пара открытый/секретный ключ не уничтожается. BOOL WINAPI CryptDestroyKey( HCRYPTKEY hKey // [вх] дескриптор уничтожаемого ключа ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Таблица кодов ошибок находится в MSDN. Примечание. По окончанию работы приложение должно уничтожить все ключи для освобождения системной памяти и памяти криптопровайдера. Это особенно важно в случае аппаратных криптопровайдеров с ограниченной памятью для хранения ключа. CryptGetKeyParam Получает параметры, управляющие работой ключа. Если используется криптопровайдер Microsoft, то сам ключ нельзя получить ни этой функцией, ни какой другой. BOOL WINAPI CryptGetKeyParam( HCRYPTKEY hKey, // [вх] дескриптор используемого ключа DWORD dwParam, //[вх] обозначает предмет запроса (см. ниже). BYTE *pbData, //[вых] указатель на место, куда будет помещена выходная информация. Параметр может быть NULL для получения размера памяти необходимого для выделения. DWORD *pdwDataLen, //[вх/вых] указатель на размер данных, записанных в предыдущий параметр. DWORD dwFlags //[вх] должен быть 0. Оставлен для использования в будущем. ); Возможные значения dwParam: KP_ALGID: алгоритм, для которого предназначен ключ. Выходные данные содержат ALG_ID алгоритма, заданного при создании ключа. KP_BLOCKLEN: если hKey указывает на сеансовый ключ, то возвращается длина блока типа DWORD. Для потоковых шифров это значение всегда равно нулю. Для пар открытых/секретных ключей возвращается длина ключа, используемого для зашифрования. Если алгоритм не поддерживает шифрования, то возвращаемое значение не определено. KP_KEYLEN: настоящая длина ключа в битах типа DWORD, на которое указывает pbData. В отличие от длины ключа, возвращаемой функцией CryptGetProvParam, эта длина содержит и биты проверки на четность. KP_SALT: модификатор ключа. pbData содержит массив байт модификатора. Длина модификатора зависит от используемого криптопровайдера и алгоритма. Модификатор не применяется в парах открытых/ секретных ключей. KP_PERMISSIONS: разрешения. Значения DWORD с битами, установленными в соответствии с разрешениями. Криптопровайдеры Microsoft поддерживают только флаг CRYPT_EXPORT. KP_P, KP_Q, KP_G: соответствующие параметры для алгоритма DSS. KP_EFFECTIVE_KEYLEN: эффективная длина ключа алгоритма RC2. KP_IV: вектор инициализации (синхропосылка). pbData содержит массив длиной BLOCK_LEN/8 байт, содержащий синхропосылку. KP_PADDING: используемый режим дополнения неполных блоков. Обычно используется PKCS5_PADDING. KP_MODE: режим блочного шифра. Возможные значения: CRYPT_MODE_CBC, CRYPT_MODE_ECB, CRYPT_MODE_CFB и CRYPT_MODE_OFB KP_MODE_BITS: количество бит обратной связи в режимах OFB и CFB. Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она возвращает ERROR_MORE_DATA, то переданная область памяти мала для размещения результата. Таблица кодов остальных ошибок находится в MSDN. CryptSetKeyParam Позволяет настроить различные параметры использования сеансовых ключей. Устанавливаемые значения влияют только на текущий сеанс и в памяти не сохраняются. BOOL WINAPI CryptSetKeyParam( HCRYPTKEY hKey, // [вх] дескриптор используемого ключа. DWORD dwParam, // [вх] определяет устанавливаемый параметр (см. ниже). BYTE *pbData, // [вх] указатель на область памяти, содержащую устанавливаемое значение. DWORD dwFlags // [вх] используется только когда dwParam = KP_ALGID. Используется для установки длины ключа и других параметров (см. CryptGenKey). ); Возможные значения dwParam: KP_SALT: модификатор ключа заданный массивом байт. Предварительно нужно определить его размер вызовом CryptGetKeyParam. KP_SALT_EX: модификатор ключа, заданный структурой CRYPTOAPI_BLOB. KP_IV: вектор инициализации (синхропосылка), заданная массивом байт. KP_PERMISSIONS, KP_ALGID, KP_P, KP_Q, KP_G, KP_X, KP_PADDING, KP_MODE, KP_MODE_BITS, KP_PADDING: см. описание функции CryptGetKeyParam Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Таблица кодов ошибок находится в MSDN. Задание к лабораторной работе Заполнить указанные пропуски в основной программе и функции генерации симметричного ключа на основе пароля. #include "stdafx.h" #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <windows.h> #include <stdio.h> /* 1. Вставить заголовочный файл для работы с Microsoft CryptoAPI */ // Определение имени и типа рабочего провайдера #define PROV_NAME MS_DEF_PROV #define PROV_TYPE PROV_RSA_FULL // Определение алгоритмов, используемых при получении ключа из пароля #define KDF_HASH_ALG CALG_SHA #define KDF_SALT_LEN 12 #define KDF_HASH_COUNT 1000 // Определение алгоритма шифрования #define CRYPT_ALG CALG_RC2 // Определение длины ключа шифрования и флагов #define CRYPT_KEY_LEN 56 #define CRYPT_KEY_FLAGS 0 // Определение строки пароля #define CRYPT_PASSWORD L"Test password" // Определение прототипа функции CryptPBKDFunction // (Password-based key derivation function) BOOL CryptPBKDFunction( HCRYPTPROV hCryptProv, // дескриптор используемого криптопровайдера ALG_ID aiCryptAlg, // криптоалгоритм, для которого создается ключ DWORD dwKeyFlags, // флаги, используемые при генерации ключа HCRYPTKEY *phPBKey, // результат: сгенерированный на основе пароля ключ PDATA_BLOB pPassword, // пароль, на основе которого генерируется ключ PDATA_BLOB pSalt, // модификатор ключа, генерируется случайно ALG_ID aiHashAlg, // алгоритм, используемый для хеширования пароля DWORD dwHashCount // количество повторов хеширования модификатора ключа ); void main(void) { BOOL Result=TRUE; // тип DATA_BLOB состоит из двух полей: // cbData содержит длину (количество байт) данных, // pbData содержит сами данные. DATA_BLOB Password={wcslen((wchar_t*)CRYPT_PASSWORD)+2,(PBYTE)CRYPT_PASSWORD}; DATA_BLOB Salt={KDF_SALT_LEN,NULL}; ALG_ID aiKDFHashAlg=KDF_HASH_ALG; DWORD dwKDFHashCount=KDF_HASH_COUNT; HCRYPTPROV hCryptProv=0; // дескриптор криптопровайдера HCRYPTKEY hCryptKey=0; // дескриптор ключа DWORD dwKeyFlags=(CRYPT_KEY_LEN << 16) | CRYPT_KEY_FLAGS; // Открываем дескриптор ключевого контейнера отправителя if (! /* 2. Открыть контекст криптопровайдера не подключаясь к контейнерам ключей. Параметры, используемые для вызова функции определены ранее в программе */ ) { printf("Error: CSP init =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The Cryptographic Service Provider context has been initialized.\n"); // На основании пароля и дополнительных параметров создаем ключ шифрования if (!CryptPBKDFunction( hCryptProv, CRYPT_ALG, dwKeyFlags, &hCryptKey, &Password, &Salt, aiKDFHashAlg, dwKDFHashCount)) { Result=FALSE; goto FirstPhaseReleaseResource; } printf("The password-based encryption key has been created.\n"); FirstPhaseReleaseResource: if (hCryptKey) /* 3. Освободить дескриптор ключа */; hCryptKey=0; if (hCryptProv) /* 4. Освободить дескриптор кр.провайдера */; hCryptProv=0; if (Salt.pbData) LocalFree(Salt.pbData); Salt.pbData=NULL; if (!Result) printf("There were ERRORS during the process.\n"); printf("The key generation from password is completed.\n\n"); } // Функция CryptPBKDFunction (Password-based key derivation function) // создает криптографический ключ, указанного алгоритма, на основании // пароля, модификатора ключа и счетчика хеш-функций. BOOL CryptPBKDFunction( HCRYPTPROV hCryptProv, ALG_ID aiCryptAlg, DWORD dwKeyFlags, HCRYPTKEY *phPBKey, PDATA_BLOB pPassword, PDATA_BLOB pSalt, ALG_ID aiHashAlg, DWORD dwHashCount ) { BOOL Result=TRUE; HCRYPTHASH hHash=0; DWORD dwDataLen=0, dwCount=0; DWORD dwKeyLen=0; DATA_BLOB HashVal={0,NULL}, IV={0,NULL}; printf(" Entering the CryptPBKD Function...\n"); // Создаем объект хеш-функции if (! /* 5. Создать хеш-объект. Криптопровайдер и алгоритм хеширования переданы функции через параметр. Результат поместить в переменную hHash. */ ) { printf("Error: Hash object create =0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } printf(" Hash object has been created.\n"); // Если модификатор ключа отсутствует, то вырабатываем его if (!pSalt->pbData) { // Выделяем память для модификатора ключа pSalt->pbData=(unsigned char *)LocalAlloc(LMEM_ZEROINIT,pSalt->cbData); if (!pSalt->pbData) { printf("Error: Out of memory.\n"); Result=FALSE; goto ReleaseResource; } // Генерируем случайное значение модификатора ключа if (! /* 6. Заполнить область памяти модификатора ключа случайными значениями. Память нужного размера уже была выделена выше в программе. */ ) { printf("Error: Salt generation =0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } } printf(" Salt has been generated.\n"); // Хешируем значение пароля if (! /* 7. Произвести хеширования пароля, который был передан в параметрах функции, с помощью созданного хеш-объекта. */ ) { printf("Error: Hash password =0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } printf(" Password has been hashed.\n"); // Цикл хеширования модификатора ключа for (dwCount=1; dwCount <= dwHashCount; dwCount++) { // Хешируем модификатор ключа if (! /* 8. Провести хеширование модификатора ключа, который был создан ранее */ ) { printf("Error: Hash salt =0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } } printf(" Salt has been hashed.\n"); // На основании хеш-функции вырабатываем ключ if (! /* 9. Сгенерировать сеансовый ключ на основе хешированного пароля и поместить его в выходной параметр функции. Все необходимые параметры были переданы в функцию или созданы в ней ранее */ ) { printf("Error: Key generation =0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } printf(" Cryptographic key has been generated.\n"); // Получаем размер ключа dwDataLen=sizeof(DWORD); if (! /* 10. В переменную dwKeyLen получить настоящую длину сгенерированного ключа. (при получении нужно будет привести ее к типу PBYTE). Размер этих данных получить в переменную dwDataLen */ ) { printf("Error: Key size obtaining=0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } dwKeyLen >>= 3; // делим на 8 printf(" Key size has been obtained.\n"); // Получаем размер значения хеш-функции if (!CryptGetHashParam(hHash,HP_HASHVAL,HashVal.pbData,&HashVal.cbData,0)) { printf("Error: Hash value =0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } printf(" Length of hash value has been obtained.\n"); if (dwKeyLen < HashVal.cbData) { // Выделяем память для значения хеш-функции HashVal.pbData=(unsigned char *)LocalAlloc(LMEM_ZEROINIT,HashVal.cbData); if (!HashVal.pbData) { printf("Error: Out of memory.\n"); Result=FALSE; goto ReleaseResource; } // Получаем значение хеш-функции if (! /* 11. В переменную HashVal занести значение вычисленной хешфункции */ ) { printf("Error: Hash value =0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } printf(" Hash value has been obtained.\n"); // Получаем размер блока шифрования dwDataLen=sizeof(DWORD); if (! /* 12. В переменную IV.cbData получить длину синхропосылки (при получении нужно будет привести ее к типу PBYTE). Размер этих данных получить в переменную dwDataLen */ ) { printf("Error: Block size =0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } IV.cbData >>= 3; // делим на 8 printf(" Block size has been obtained.\n"); // Выделяем память для синхропосылки IV.pbData=(unsigned char *)LocalAlloc(LMEM_ZEROINIT,IV.cbData); if (!IV.pbData) { printf("Error: Out of memory.\n"); Result=FALSE; goto ReleaseResource; } // Копируем значение синхропосылки CopyMemory( IV.pbData, HashVal.pbData+dwKeyLen, (HashVal.cbData >= (dwKeyLen+IV.cbData)) ? IV.cbData : (dwKeyLen+IV.cbData)-HashVal.cbData); // Устанавливаем синхропосылку dwDataLen=sizeof(DWORD); if (! /* 13. Установить у сгенерированного ключа значение синхропосылки, заданной в переменной IV.pbData */ ) { printf("Error: Initial vector =0x%X.\n",GetLastError()); Result=FALSE; goto ReleaseResource; } printf(" Initial vector has been set.\n"); } ReleaseResource: if (hHash) /* 14. Уничтожить созданный в функции хеш-объект */; if (IV.pbData) LocalFree(IV.pbData); if (HashVal.pbData) LocalFree(HashVal.pbData); printf(" Exiting the CryptPBKD Function...\n"); return Result; } Пример результата работы программы The Cryptographic Service Provider context has been initialized. Entering the CryptPBKD Function... Hash object has been created. Salt has been generated. Password has been hashed. Salt has been hashed. Cryptographic key has been generated. Key size has been obtained. Length of hash value has been obtained. Hash value has been obtained. Block size has been obtained. Initial vector has been set. Exiting the CryptPBKD Function... The password-based encryption key has been created. The key generation from password is completed. Лабораторная работа №3. Симметричная криптосистема. Шифрование. Цель работы Получить основные навыки работы с функциями шифрования и расшифровывания. Закрепить навыки использования хеш-функций, создания ключей и генерации случайных чисел. Ход работы Изучить функции шифрования и расшифрования Microsoft CryptoAPI. Перенести задание к лабораторной работе в среду программирования. Восстановить вырезанные фрагменты программы по описаниям и отладить полученную программу. Добавление кода осуществляется непосредственно в месте расположения комментария с описанием действия! Проанализировать работу полученной программы и сравнить результаты работы программы с примером результатов, приведенным в лабораторной работе. Разобраться с форматом файла Ciphertext.msg и знать что, какой длины и в каком порядке в него записано. Описание основных используемых в лабораторной работе функций Microsoft CryptoAPI (функции определены в файле wincrypt.h, полное описание находится в MSDN, security.chm, .chi, в разделе Cryptography\CryptoAPI\Using CryptoAPI\CryptoAPI Reference\CryptoAPI Functions\Base CryptoAPI Functions) CryptEncrypt Зашифровывает данные. Алгоритм шифрования определяется параметрами ключа, находящегося в контейнере криптопровайдера и передаваемого в параметре hKey. BOOL WINAPI CryptEncrypt( HCRYPTKEY hKey, // [вх] дескриптор ключа шифрования. HCRYPTHASH hHash, // [вх] Если требуется одновременное шифрование и хеширование данных, в параметре передается дескриптор хеш-объекта. Значение хешфункции изменяется по мере поступления открытого текста. Эта возможность полезна при создании зашифрованного и подписанного текста. Перед вызовом хешобъект должен быть создан функцией CryptCreateHash. После шифрования значение можно получить с помощью CryptGetHashParam или подписать CryptSignHash. Если хешировать не нужно, то этот параметр равен 0. BOOL Final, // [вх] True если шифруется последний или единственный блок, False в остальных случаях. DWORD dwFlags,//[вх] должен быть 0. Оставлен для использования в будущем. BYTE *pbData, //[вх/вых] указатель на область памяти, в которой находятся открытые данные. При шифровании зашифрованные данные замещают открытые. Размер этой области задается в параметре dwBufLen, а количество байт шифруемых данных – в параметре pdwDataLen. Для определения необходимого размера области памяти этот параметр должен быть равен NULL. DWORD *pdwDataLen, // [вх/вых] указатель на значение DWORD, содержащее длину области данных. Перед вызовом функции там должно быть задано количество шифруемых байт, после вызова функции возвращаемое значение содержит количество байт, требуемое для размещения зашифрованных данных. Если область памяти недостаточна для размещения данных, то функция GetLastError возвращает ошибку ERROR_MORE_DATA и сохраняет необходимый размер области памяти в этом параметре. При использовании блочного шифра этот размер должен быть кратен размеру блока, за исключением последнего блока если параметр Final = True. DWORD dwBufLen // [вх/вых] длина области памяти pbData. В зависимости от используемого алгоритма, шифротекст может быть длиннее открытого текста, и размер области должен это учитывать. Как правило, при использовании потокового шифра размер не меняется, а при использовании блочного шифротекст может быть длиннее открытого текста на величину вплоть до размера блока. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она возвращает ERROR_MORE_DATA или NTE_BAD_LEN, то переданная область памяти мала для размещения результата. Если возвращается значение NTE_DOUBLE_ENCRYPT, то была попытка два раза зашифровать одни и те же данные. При значении ошибки NTE_BAD_DATA представленные для шифрования данные некорректны. Например, если используется блочный шифр с параметром Final = False, значение pdwDataLen должно быть кратно длине блока. Таблица кодов остальных ошибок находится в MSDN. Примечания. Если требуется зашифровать большой объем данных, можно последовательно вызывать CryptEncrypt для каждой части. Перед шифрованием последней части параметр Final нужно установить в True. При этом выполняются следующие действия: 1. Если ключ относится к блочному шифру, то данные дополняются до размера блока. Чтобы узнать это значение необходимо вызвать CryptGetKeyParam со зачением KP_BLOCKLEN. 2. Если применяется один из режимов шифрования, то следующий вызов CryptEncrypt устанавливает исходное значение синхропосылки из ключа. 3. Если применяется потоковый шифр, то следующий вызов CryptEncrypt устанавливает его начальное состояние. В ОС Windows 2000 и более поздних возможно непосредственное шифрование открытым ключом RSA. Длина одного блока шифрования равна разрядности ключа минус 11 байт. CryptDecrypt Расшифровывает данные ранее зашифрованные функцией CryptEncrypt. BOOL WINAPI CryptDecrypt( HCRYPTKEY hKey, // [вх] дескриптор ключа шифрования. HCRYPTHASH hHash, // [вх] Если требуется одновременное расшифровывание и хеширование данных, в параметре передается дескриптор хеш-объекта. Значение хешфункции изменяется по мере получения открытого текста. Эта возможность полезна при совместном расшифровывании и проверке подписи. Перед вызовом хеш-объект должен быть создан функцией CryptCreateHash. После шифрования значение можно получить с помощью CryptGetHashParam или проверить подпись с помощью CryptVerifySignature. Если хешировать не нужно, то этот параметр равен 0. BOOL Final, // [вх] True если шифруется последний или единственный блок, False в остальных случаях. DWORD dwFlags,//[вх] должен быть 0. Оставлен для использования в будущем. BYTE *pbData, //[вх/вых] указатель на область памяти, в которой находятся данные, подлежащие расшифровыванию. При расшифровывании открытые данные замещают зашифрованные. Количество байт расшифровываемых данных задается в параметре pdwDataLen. DWORD *pdwDataLen // [вх/вых] указатель на значение DWORD, содержащее длину области данных. Перед вызовом функции там должно быть задано количество расшифровываемых байт, после вызова функции возвращаемое значение содержит количество расшифрованных байт. При использовании блочного шифра этот размер должен быть кратен размеру блока, за исключением последнего блока если параметр Final = True. ); Возвращаемые значения: если все прошло нормально, ненулевое (TRUE), если произошла ошибка, то возвращается нуль (FALSE). Для анализа ошибки нужно вызвать GetLastError. Если она возвращает NTE_BAD_LEN, то переданная область памяти мала для размещения результата. Если возвращается значение NTE_DOUBLE_ENCRYPT, то была попытка два раза расшифровать одни и те же данные. При значении ошибки NTE_BAD_DATA представленные для шифрования данные некорректны. Например, если используется блочный шифр с параметром Final = False, значение pdwDataLen должно быть кратно длине блока. Также возможно, что дополнение последнего блока было некорректно. Таблица кодов остальных ошибок находится в MSDN. Примечания. Если требуется расшифровать большой объем данных, можно последовательно вызывать CryptDecrypt для каждой части. Перед расшифровыванием последней части параметр Final нужно установить в True. В ОС Windows 2000 и более поздних возможно непосредственное расшифровывание секретным ключом RSA. Длина одного блока расшифровывания равна разрядности ключа. Нули в старших разрядах блока также должны подаваться на алгоритм расшифровывания. Задание к лабораторной работе Программа симметричной криптосистемы шифрует файл с именем, указанным в константе ORIGINATOR_PLAINTEXT_FILE и записывает результат в файл с именем, заданным в константе CIPHERTEXT_FILE. Затем его содержимое расшифровывается и записывается в файл c именем, заданным в константе RECIPIENT_PLAINTEXT_FILE. Если исходного файла не существует, он создается и в него записывается текст, заданный в константе CRYPT_MSG. Пароль, на основании которого получается ключ для симметричного криптоалгоритма, задается в константе CRYPT_PASSWORD. Заполнить указанные пропуски в программе симметричной криптосистемы. #include "stdafx.h" #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <windows.h> #include <stdio.h> #include <wincrypt.h> // Определение имени и типа рабочего провайдера #define PROV_NAME MS_DEF_PROV #define PROV_TYPE PROV_RSA_FULL // Определение алгоритмов, используемых при получении ключа из пароля #define KDF_HASH_ALG CALG_SHA #define KDF_SALT_LEN 12 #define KDF_HASH_COUNT 1000 // Определение алгоритмов шифрования и секретного хеша #define CRYPT_ALG CALG_RC2 #define CRYPT_CIPHER_MODE CRYPT_MODE_CBC #define BLOCK_SIZE 160 #define BUFFER_SIZE BLOCK_SIZE+8 // Определение длины ключа шифрования и флагов #define CRYPT_KEY_LEN 56 #define CRYPT_RC2_EFFECTIVE_LEN CRYPT_KEY_LEN #define CRYPT_KEY_FLAGS 0 // Определение строки для шифрования и строки пароля #define CRYPT_MSG "The data that is to be encrypted." #define CRYPT_PASSWORD L"Test password" // Определение имен используемых файлов #define ORIGINATOR_PLAINTEXT_FILE "Plaintext.org" #define CIPHERTEXT_FILE "Ciphertext.msg" #define RECIPIENT_PLAINTEXT_FILE "Plaintext.rcp" // Определение прототипа функции CryptPBKDFunction // (Password-based key derivation function) BOOL CryptPBKDFunction( HCRYPTPROV hCryptProv, ALG_ID aiCryptAlg, DWORD dwKeyFlags, HCRYPTKEY *phPBKey, PDATA_BLOB pPassword, PDATA_BLOB pSalt, ALG_ID aiHashAlg, DWORD dwHashCount ); // Определение прототипа функции WriteFileBlob BOOL WriteFileBlob( FILE *hFile, PDATA_BLOB pDataBlob ); // Определение прототипа функции ReadFileBlob BOOL ReadFileBlob( FILE *hFile, PDATA_BLOB pDataBlob ); void main(void) { BOOL Result=TRUE; FILE *hOriginator=NULL, *hCipher=NULL, *hRecipient=NULL; DWORD Final=0; fpos_t fSavePos=0, fSetPos=0; DATA_BLOB OriginatorMsg={strlen((char*)CRYPT_MSG)+1,(PBYTE)CRYPT_MSG}; DATA_BLOB Password={wcslen((wchar_t*)CRYPT_PASSWORD)+2,(PBYTE)CRYPT_PASSWORD}; DATA_BLOB Salt={KDF_SALT_LEN,NULL}; ALG_ID aiKDFHashAlg=KDF_HASH_ALG; DWORD dwKDFHashCount=KDF_HASH_COUNT; DWORD dwCipherMode=CRYPT_CIPHER_MODE; DWORD dwEffectiveLen=CRYPT_RC2_EFFECTIVE_LEN; DWORD dwDataLen=0; DWORDLONG dwlEncryptDataLen=0, dwlReadDataLen=0; HCRYPTPROV hCryptProv=0; HCRYPTHASH hHash=0, hMAC=0; HCRYPTKEY hCryptKey=0; DWORD dwKeyFlags=(CRYPT_KEY_LEN << 16) | CRYPT_KEY_FLAGS; BYTE DWORD pbBuffer[BUFFER_SIZE]; dwCount; // Первый этап // Отправитель на основании пароля вырабатывает ключи // шифрования и аутентификации, и отправляет зашифрованное // сообщение с аутентифицирующим хешем получателю printf("First phase start.\n"); // Открываем файл с открытым текстом отправителя if ((hOriginator=fopen(ORIGINATOR_PLAINTEXT_FILE,"rb"))==NULL) { if((hOriginator=fopen(ORIGINATOR_PLAINTEXT_FILE,"wb"))==NULL ) { printf("Error: Opening %s file.\n",ORIGINATOR_PLAINTEXT_FILE); Result=FALSE; goto FirstPhaseReleaseResource; } fwrite(OriginatorMsg.pbData, OriginatorMsg.cbData, 1, hOriginator); if (ferror(hOriginator)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } fclose(hOriginator); hOriginator=0; if ((hOriginator=fopen(ORIGINATOR_PLAINTEXT_FILE,"rb"))==NULL) { printf("Error: Opening %s file.\n",ORIGINATOR_PLAINTEXT_FILE); Result=FALSE; goto FirstPhaseReleaseResource; } } printf("The originator plaintext file, %s, is open.\n",ORIGINATOR_PLAINTEXT_FILE); // Открываем файл для записи шифртекста if ((hCipher=fopen(CIPHERTEXT_FILE,"wb"))==NULL) { printf("Error: Opening %s file.\n",CIPHERTEXT_FILE); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The ciphertext file, %s, is open.\n",CIPHERTEXT_FILE); // Инициализируем криптопровайдер отправителя if (! /* 1. Открыть контекст криптопровайдера не подключаясь к контейнерам ключей. Параметры, используемые для вызова функции определены ранее в программе */ ) { printf("Error: CSP Initialization =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } printf("Originator CSP context initialized.\n"); // На основании пароля и дополнительных параметров создаем ключ шифрования if (!CryptPBKDFunction( hCryptProv, CRYPT_ALG, dwKeyFlags, &hCryptKey, &Password, &Salt, aiKDFHashAlg, dwKDFHashCount)) { Result=FALSE; goto FirstPhaseReleaseResource; } printf("The password-based encryption key has been created.\n"); if (CRYPT_ALG == CALG_RC2) { if (! /* 2. Установить эффективную длину ключа для алгоритма RC2, заданную в переменной dwEffectiveLen */ ) { printf("Error: Parameters 1 =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The RC2 encryption key effective length has been set.\n"); } // Устанавливаем режим шифрования ключа шифрования сообщения if (! /* 3. Установить для ключа режим шифрования, заданный в переменной dwCipherMode */ ) { printf("Error: Parameters 2 =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The encryption key cipher mode has been set.\n"); // Сохраняем в файле значение модификатора ключа для ключа шифрования if (!WriteFileBlob(hCipher,&Salt)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The encryption key salt value blob has been written to the file.\n"); // Сохраняем в файле значение счетчика хеш-функций для ключа шифрования fwrite(&dwKDFHashCount,1,sizeof(DWORD),hCipher); if (ferror(hCipher)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The encryption key hash count has been written to the file.\n"); LocalFree(Salt.pbData); Salt.pbData=NULL; // Сохраняем позицию в файле для записи длины // зашифрованных данных fgetpos(hCipher, &fSavePos); if (ferror(hOriginator)) { printf("Error: Get file position.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } // Устанавливаем позицию в файле для записи // зашифрованных данных fseek(hCipher,sizeof(DWORDLONG),SEEK_CUR); if (ferror(hCipher)) { printf("Error: Set file position.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } // Зашифровываем данные из файла отправителя do { // Читаем из файла отправителя данные размером BLOCK_SIZE байт dwCount = fread(pbBuffer, 1, BLOCK_SIZE, hOriginator); if (ferror(hOriginator)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } Final=feof(hOriginator); // Зашифровываем данные if (! /* 4. Зашифровать считанный из файла блок данных. На область памяти, в которой находится открытый текст, указывает pbBuffer, размер этой области задан в константе BUFFER_SIZE, количество шифруемых байт задано в переменной dwCount. В случае окончания файла переменная Final принимает значение True */ ) { printf("Error: Crypt=0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } // Записываем зашифрованные данные в файл fwrite(pbBuffer, 1, dwCount, hCipher); if (ferror(hCipher)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } dwlEncryptDataLen+=dwCount; } while(!Final); printf("The encrypted message has been written to the file.\n"); // Устанавливаем позицию в файле для сохранения // длины зашифрованных данных fsetpos(hCipher, &fSavePos); if (ferror(hCipher)) { printf("Error: Set file position.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } // Сохраняем в файле длину зашифрованных данных fwrite(&dwlEncryptDataLen, 1, sizeof(DWORDLONG), hCipher); if (ferror(hCipher)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } FirstPhaseReleaseResource: // Освобождаем открытые на первом этапе ресурсы и обнуляем переменные if (hCryptKey) /* 5. Освободить дескриптор ключа */; hCryptKey=0; if (hCryptProv) /* 6. Освободить дескриптор кр.провайдера */; hCryptProv=0; if (Salt.pbData) LocalFree(Salt.pbData); Salt.pbData=NULL; if (hCipher) fclose(hCipher); hCipher=0; if (hOriginator) fclose(hOriginator); hOriginator=0; Final=FALSE; if (!Result) return; printf("The first phase is completed.\n\n"); // Второй этап // Получатель на основании пароля вырабатывает ключи // шифрования и аутентификации, зашифровывает // сообщение и проверяет его целостность printf("Second phase start.\n"); // Открываем файл с шифртекстом if ((hCipher=fopen(CIPHERTEXT_FILE,"rb"))==NULL) { printf("Error: Opening %s file.\n",CIPHERTEXT_FILE); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The ciphertext file, %s, is open.\n",CIPHERTEXT_FILE); // Открываем файл для записи открытого текста получателя if ((hRecipient=fopen(RECIPIENT_PLAINTEXT_FILE,"wb"))==NULL) { printf("Error: Opening %s file.\n",RECIPIENT_PLAINTEXT_FILE); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The recipient plaintext file, %s, is open.\n",RECIPIENT_PLAINTEXT_FILE); // Инициализируем криптопровайдер получателя if (! /* 7. Открыть контекст криптопровайдера не подключаясь к контейнерам ключей. Параметры, используемые для вызова функции определены ранее в программе */ ) { Result=FALSE; goto SecondPhaseReleaseResource; } printf("Recipient CSP context initialized.\n"); // Считываем значение модификатора ключа для ключа шифрования сообщения if (!ReadFileBlob(hCipher,&Salt)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The encryption key salt value blob has been read from the file.\n"); // Считываем значение счетчика хеш-функций для ключа шифрования сообщения fread(&dwKDFHashCount,1,sizeof(DWORD),hCipher); if (ferror(hCipher) || feof(hCipher)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The encryption key hash count has been read from the file.\n"); // На основании пароля и дополнительных параметров создаем ключ шифрования if (!CryptPBKDFunction( hCryptProv, CRYPT_ALG, dwKeyFlags, &hCryptKey, &Password, &Salt, aiKDFHashAlg, dwKDFHashCount)) { Result=FALSE; goto SecondPhaseReleaseResource; } printf("The password-based encryption key has been created.\n"); if (CRYPT_ALG == CALG_RC2) { if (! /* 8. Установить эффективную длину ключа для алгоритма RC2, заданную в переменной dwEffectiveLen */ ) { printf("Error: Parameters 3 =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The RC2 encryption key effective length has been set.\n"); } // Устанавливаем режим шифрования ключа шифрования сообщения if (! /* 9. Установить для ключа режим шифрования, заданный в переменной dwCipherMode */ ) { printf("Error: Parameters 4 =0x%X.\n",GetLastError()); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The encryption key cipher mode has been set.\n"); dwlEncryptDataLen = 0; LocalFree(Salt.pbData); Salt.pbData=NULL; // Считываем длину зашифрованных данных fread(&dwlEncryptDataLen,1,sizeof(DWORDLONG),hCipher); if (ferror(hCipher) || feof(hCipher)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } // Расшифровываем файл do { // Считываем из файла блок размером BLOCK_SIZE байт dwCount = fread(pbBuffer,1,BLOCK_SIZE,hCipher); if(ferror(hCipher)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } // Расшифровываем данные и рассчитываем значение секретного хеша dwlReadDataLen+=dwCount; if (dwlReadDataLen >= dwlEncryptDataLen) { Final=TRUE; dwDataLen=dwCount-(DWORD)(dwlReadDataLendwlEncryptDataLen); } else dwDataLen=dwCount; if(! /* 10. Расшифровать считанный из файла блок данных. На область памяти, в которой находится шифротекст, указывает pbBuffer, количество расшифровываемых байт задано в переменной dwDataLen. В случае окончания шифротекста переменная Final принимает значение True */ ) { printf("Error: Crypt =0x%X.\n",GetLastError()); Result=FALSE; goto SecondPhaseReleaseResource; } // Записываем данные в файл получателя сообщения fwrite(pbBuffer,1,dwDataLen,hRecipient); if(ferror(hRecipient)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } } while(!Final); printf("The decrypted message has been written to the file.\n"); SecondPhaseReleaseResource: // Освобождаем открытые на втором этапе ресурсы и обнуляем переменный if (hCryptKey) /* 11. Освободить дескриптор ключа */; if (hCryptProv) /* 12. Освободить дескриптор кр.провайдера */; if (Salt.pbData) LocalFree(Salt.pbData); if (hCipher) fclose(hCipher); if (hRecipient) fclose(hRecipient); if (Result) printf("The second phase is completed.\n\n"); return; } /* 13. Вставить функцию CryptPBKDFunction из лабораторной работы №2 */ // Функция сохраняет в файле, описанном парметром hFile, // структуру DATA_BLOB, описанную параметром pDataBlob. BOOL WriteFileBlob( FILE *hFile, PDATA_BLOB pDataBlob ) { // Сохраняем в файле длину блока данных fwrite(&pDataBlob->cbData, 1, sizeof(DWORD), hFile); if(ferror(hFile)) { return FALSE; } // Сохраняем в файле блок данных длиной pDataBlob->cbData if (pDataBlob->cbData) { fwrite(pDataBlob->pbData,1,pDataBlob->cbData,hFile); if(ferror(hFile)) { return FALSE; } } return TRUE; } // Функция считывает из файла, описанного парметром hFile, // структуру DATA_BLOB, сохраняя ее в по адресу pDataBlob. BOOL ReadFileBlob( FILE *hFile, PDATA_BLOB pDataBlob ) { BOOL Result=TRUE; pDataBlob->cbData=0; pDataBlob->pbData=NULL; // Считаем длину блока данных fread(&pDataBlob->cbData,sizeof(DWORD),1,hFile); if(ferror(hFile) || feof(hFile)) { Result=FALSE; goto ReleaseResource; } // Если длина блока не нулевая, то выделяем блок памяти if (pDataBlob->cbData) pDataBlob->pbData=(unsigned char *)LocalAlloc(LMEM_ZEROINIT,pDataBlob->cbData); else goto ReleaseResource; if (!pDataBlob->pbData) { printf("Error: Out of memory.\n"); Result=FALSE; goto ReleaseResource; } // Считываем блок данных в выделенный буфер fread(pDataBlob->pbData,1,pDataBlob->cbData,hFile); if(ferror(hFile) || feof(hFile)) { Result=FALSE; goto ReleaseResource; } ReleaseResource: if (!Result) // Освобождаем выделенный буфер if (pDataBlob->pbData) LocalFree(pDataBlob->pbData); return Result; } Пример результата работы программы First phase start. The originator plaintext file, Plaintext.org, is open. The ciphertext file, Ciphertext.msg, is open. Originator CSP context initialized. The password-based encryption key has been created. The RC2 encryption key effective length has been set. The encryption key cipher mode has been set. The encryption key salt value blob has been written to the file. The encryption key hash count has been written to the file. The encrypted message has been written to the file. The first phase is completed. Second phase start. The ciphertext file, Ciphertext.msg, is open. The recipient plaintext file, Plaintext.rcp, is open. Recipient CSP context initialized. The encryption key salt value blob has been read from the file. The encryption key hash count has been read from the file. The password-based encryption key has been created. The RC2 encryption key effective length has been set. The encryption key cipher mode has been set. The decrypted message has been written to the file. The second phase is completed. Помимо диагностических сообщений программа ищет в текущем каталоге файл Plaintext.org, и если не находит его, то создает новый и записывает в него тестовую фразу. После работы первой части программы создается файл Ciphertext.msg, содержащий некоторые параметры алгоритма и зашифрованный файл Plaintext.org. После работы второй части программы создается файл Plaintext.rcp, содержащий расшифрованную информа- цию из файла Ciphertext.msg. Его длина и содержимое должно быть идентично файлу Plaintext.org. Лабораторная работа №4. Симметричная криптосистема. Генерация имитовставки. Цель работы Получить основные навыки работы с функциями хеширования с ключом. Закрепить навыки использования функций шифрования и расшифровывания, хеш-функций, создания ключей и генерации случайных чисел. Ход работы Повторить материал по функциям шифрования, расшифровывания и хеширования Microsoft CryptoAPI. Перенести задание к лабораторной работе в среду программирования. Восстановить вырезанные фрагменты программы по описаниям и отладить полученную программу. Добавление кода осуществляется непосредственно в месте расположения комментария с описанием действия! Исходный код работы частично повторяет исходный код лабораторной работы №3. Сначала необходимо снова заполнить пропущенные фрагменты вида /* 1. … */ фрагментами кода из лабораторной работы №3. Внимание! Нумерация одинаковых фрагментов в работах №3 и №4 не всегда совпадает! Новые участки программы, введенные в данной работе, для облегчения понимания находятся внутри комментариев /* … */. После заполнения предыдущих пропусков, эти комментарии нужно снять и продолжить заполнение пропусков, помеченных как **** 4. Заполнение этих пропусков и составляет задачу данной лабораторной работы. Проанализировать работу полученной программы и сравнить результаты работы программы с примером результатов, приведенным в лабораторной работе. Разобраться с форматом файла Ciphertext.msg и знать что, какой длины и в каком порядке в него записано. Формат файла отличается от того, что был использован в лабораторной работе №3. Описание основных используемых в лабораторной работе функций Microsoft CryptoAPI (функции определены в файле wincrypt.h, полное описание находится в MSDN, security.chm, .chi, в разделе Cryptography\CryptoAPI\Using CryptoAPI\CryptoAPI Reference\CryptoAPI Functions\Base CryptoAPI Functions) В данной работе не используется новых функций Microsoft CryptoAPI. Задание к лабораторной работе Программа симметричной криптосистемы шифрует файл с именем, указанным в константе ORIGINATOR_PLAINTEXT_FILE и записывает результат в файл с именем, заданным в константе CIPHERTEXT_FILE. Затем его содержимое расшифровывается и записывается в файл c именем, заданным в константе RECIPIENT_PLAINTEXT_FILE. Если исходного файла не существует, он создается и в него записывается текст, заданный в константе CRYPT_MSG. Пароль, на основании которого получается ключ для симметричного криптоалгоритма, задается в константе CRYPT_PASSWORD. Заполнить указанные пропуски в программе симметричной криптосистемы. #include "stdafx.h" #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <windows.h> #include <stdio.h> #include <wincrypt.h> // Определение имени и типа рабочего провайдера #define PROV_NAME MS_DEF_PROV #define PROV_TYPE PROV_RSA_FULL // Определение алгоритмов, используемых при получении ключа из пароля #define KDF_HASH_ALG CALG_SHA #define KDF_SALT_LEN 12 #define KDF_HASH_COUNT 1000 // Определение алгоритмов шифрования и секретного хеша #define CRYPT_ALG CALG_RC2 #define CRYPT_CIPHER_MODE CRYPT_MODE_CBC #define BLOCK_SIZE 160 #define BUFFER_SIZE BLOCK_SIZE+8 /*#define MAC_ALG CALG_HMAC #define HMAC_HASH_ALG CALG_MD5 */ // Определение длины ключа шифрования и флагов #define CRYPT_KEY_LEN 56 #define CRYPT_RC2_EFFECTIVE_LEN CRYPT_KEY_LEN #define CRYPT_KEY_FLAGS 0 // Определение строки для шифрования и строки пароля #define CRYPT_MSG "The data that is to be encrypted and MAC'ed." #define CRYPT_PASSWORD L"Test password" // Определение имен используемых файлов #define ORIGINATOR_PLAINTEXT_FILE "Plaintext.org" #define CIPHERTEXT_FILE "Ciphertext.msg" #define RECIPIENT_PLAINTEXT_FILE "Plaintext.rcp" // Определение прототипа функции CryptPBKDFunction // (Password-based key derivation function) BOOL CryptPBKDFunction( HCRYPTPROV hCryptProv, ALG_ID aiCryptAlg, DWORD dwKeyFlags, HCRYPTKEY *phPBKey, PDATA_BLOB pPassword, PDATA_BLOB pSalt, ALG_ID aiHashAlg, DWORD dwHashCount ); // Определение прототипа функции WriteFileBlob BOOL WriteFileBlob( FILE *hFile, PDATA_BLOB ); pDataBlob // Определение прототипа функции ReadFileBlob BOOL ReadFileBlob( FILE *hFile, PDATA_BLOB pDataBlob ); void main(void) { BOOL FILE *hRecipient=NULL; DWORD fpos_t Result=TRUE; *hOriginator=NULL, *hCipher=NULL, Final=0; fSavePos=0, fSetPos=0; DATA_BLOB OriginatorMsg={strlen((char*)CRYPT_MSG)+1,(PBYTE)CRYPT_MSG}; DATA_BLOB Password={wcslen((wchar_t*)CRYPT_PASSWORD)+2,(PBYTE)CRYPT_PASSWORD}; DATA_BLOB Salt={KDF_SALT_LEN,NULL}; /* DATA_BLOB MACVal={0,NULL}; DATA_BLOB MACValChecked={0,NULL}; HMAC_INFO HMACInfo={HMAC_HASH_ALG,NULL,0,NULL,0}; */ ALG_ID aiKDFHashAlg=KDF_HASH_ALG; DWORD dwKDFHashCount=KDF_HASH_COUNT; DWORD dwCipherMode=CRYPT_CIPHER_MODE; DWORD dwEffectiveLen=CRYPT_RC2_EFFECTIVE_LEN; DWORD DWORDLONG HCRYPTPROV HCRYPTHASH HCRYPTKEY DWORD CRYPT_KEY_FLAGS; BYTE DWORD dwDataLen=0; dwlEncryptDataLen=0, dwlReadDataLen=0; hCryptProv=0; hHash=0, hMAC=0; hCryptKey=0 /*, hMACKey=0*/; dwKeyFlags=(CRYPT_KEY_LEN << 16) | pbBuffer[BUFFER_SIZE]; dwCount; // Первый этап // Отправитель на основании пароля вырабатывает ключи // шифрования и аутентификации, и отправляет зашифрованное // сообщение с аутентифицирующим хешем получателю printf("First phase start.\n"); // Открываем файл с открытым текстом отправителя if ((hOriginator=fopen(ORIGINATOR_PLAINTEXT_FILE,"rb"))==NULL) { if((hOriginator=fopen(ORIGINATOR_PLAINTEXT_FILE,"wb"))==NULL) { printf("Error: Opening %s file.\n",ORIGINATOR_PLAINTEXT_FILE); Result=FALSE; goto FirstPhaseReleaseResource; } fwrite(OriginatorMsg.pbData, OriginatorMsg.cbData, 1, hOriginator); if (ferror(hOriginator)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } fclose(hOriginator); hOriginator=0; if ((hOriginator=fopen(ORIGINATOR_PLAINTEXT_FILE,"rb"))==NULL) { printf("Error: Opening %s file.\n",ORIGINATOR_PLAINTEXT_FILE); Result=FALSE; goto FirstPhaseReleaseResource; } } printf("The originator plaintext file, %s, is open.\n",ORIGINATOR_PLAINTEXT_FILE); // Открываем файл для записи шифртекста if ((hCipher=fopen(CIPHERTEXT_FILE,"wb"))==NULL) { printf("Error: Opening %s file.\n",CIPHERTEXT_FILE); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The ciphertext file, %s, is open.\n",CIPHERTEXT_FILE); // Открываем дескриптор ключевого контейнера отправителя if (!/* 1. Открыть контекст криптопровайдера не подключаясь к контейнерам ключей. Параметры, используемые для вызова функции определены ранее в программе */) { printf("Error: CSP Initialization =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } printf("Originator CSP context initialized.\n"); // На основании пароля и дополнительных параметров создаем ключ шифрования if (!CryptPBKDFunction( hCryptProv, CRYPT_ALG, dwKeyFlags, &hCryptKey, &Password, &Salt, aiKDFHashAlg, dwKDFHashCount)) { Result=FALSE; goto FirstPhaseReleaseResource; } printf("The password-based encryption key has been created.\n"); if (CRYPT_ALG == CALG_RC2) { if (!/* 2. Установить эффективную длину ключа для алгоритма RC2, заданную в переменной dwEffectiveLen */) { printf("Error: Parameters 1 =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The RC2 encryption key effective length has been set.\n"); } // Устанавливаем режим шифрования ключа шифрования сообщения if (! /* 3. Установить для ключа режим шифрования, заданный в переменной dwCipherMode */) { printf("Error: Parameters 2 =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The encryption key cipher mode has been set.\n"); // Сохраняем в файле значение модификатора ключа для ключа шифрования if (!WriteFileBlob(hCipher,&Salt)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The encryption key salt value blob has been written to the file.\n"); // Сохраняем в файле значение счетчика хеш-функций для ключа шифрования fwrite(&dwKDFHashCount,1,sizeof(DWORD),hCipher); if (ferror(hCipher)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The encryption key hash count has been written to the file.\n"); LocalFree(Salt.pbData); Salt.pbData=NULL; /* // На основании пароля и дополнительных параметров создаем ключ секретного хеша if (!CryptPBKDFunction( hCryptProv, CRYPT_ALG, dwKeyFlags, &hMACKey, &Password, &Salt, aiKDFHashAlg, dwKDFHashCount)) { Result=FALSE; goto FirstPhaseReleaseResource; } printf("The password-based MAC key has been created.\n"); // Вырабатываем секретный хеш // Создаем объект хеш-функции для алгоритма MAC_ALG if (! **** 4. Создать хеш-объект. Криптопровайдер hCryptProv, алгоритм хеширования MAC_ALG. Ключ секретного хеша – hMACKey. Результат поместить в переменную hMAC.) { printf("Error: Hash=0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } if (MAC_ALG == CALG_HMAC) { // Устанавливаем параметры алгоритма HMAC if (! **** 5. вопрос удален CryptSetHashParam(hMAC,HP_HMAC_INFO,(PBYTE)&HMACInfo,0)) { printf("Error: Parameters 3=0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } } printf("MAC object created.\n"); */ // Сохраняем позицию в файле для записи длины // зашифрованных данных fgetpos(hCipher, &fSavePos); if (ferror(hOriginator)) { printf("Error: Get file position.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } // Устанавливаем позицию в файле для записи // зашифрованных данных fseek(hCipher,sizeof(DWORDLONG),SEEK_CUR); if (ferror(hCipher)) { printf("Error: Set file position.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } // Зашифровываем данные из файла отправителя do { // Читаем из файла отправителя данные размером BLOCK_SIZE байт dwCount = fread(pbBuffer, 1, BLOCK_SIZE, hOriginator); if (ferror(hOriginator)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } Final=feof(hOriginator); // Зашифровываем данные и рассчитываем значение секретного хеша if (! /* 6. Зашифровать считанный из файла блок данных. На область памяти, в которой находится открытый текст, указывает pbBuffer, размер этой области задан в константе BUFFER_SIZE, количество шифруемых байт задано в переменной dwCount. В случае окончания файла переменная Final принимает значение True. Параллельно с шифрованием вычислить значение хеш-функции hMАС */) { printf("Error: Crypt=0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } // Записываем зашифрованные данные в файл fwrite(pbBuffer, 1, dwCount, hCipher); if (ferror(hCipher)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } dwlEncryptDataLen+=dwCount; } while(!Final); printf("The encrypted message has been written to the file.\n"); /* // Запрашиваем размер значения хеш-функции if (! **** 7. В переменную MACVal.cbData получить размер памяти, необходимый для размещения значения хеш-функции. Для этого вызов функции должен выглядеть как в вопросе 8, но третий параметр должен быть равен NULL) { printf("Error: Parameters 4 =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } // Выделяем память для значения хеш-функции MACVal.pbData=(unsigned char *)LocalAlloc(LMEM_ZEROINIT,MACVal.cbData); if (!MACVal.pbData) { printf("Error: Out of memory.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } // Запрашиваем значение хеш-функции if (! **** 8. В переменную MACVal.pbData получить значение хеш-функции hMAC. Размер этого значения получить в переменную MACVal.cbData) { printf("Error: Parameters 5=0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } // Сохраняем в файле значение модификатора ключа для секретного хеша if (!WriteFileBlob(hCipher,&Salt)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The MAC salt value blob has been written to the file.\n"); // Сохраняем в файле значение счетчика хеш-функций для секретного хеша fwrite(&dwKDFHashCount,1,sizeof(DWORD),hCipher); if (ferror(hCipher)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The MAC hash count has been written to the file.\n"); // Сохраняем в файле значение секретного хеша if (!WriteFileBlob(hCipher,&MACVal)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The MAC value blob has been written to the file.\n"); */ // Устанавливаем позицию в файле для сохранения // длины зашифрованных данных fsetpos(hCipher, &fSavePos); if (ferror(hCipher)) { printf("Error: Set file position.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } // Сохраняем в файле длину зашифрованных данных fwrite(&dwlEncryptDataLen, 1, sizeof(DWORDLONG), hCipher); if (ferror(hCipher)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto FirstPhaseReleaseResource; } FirstPhaseReleaseResource: // Освобождаем открытые на первом этапе ресурсы и обнуляем переменный /* if (hMAC) **** 9. Уничтожить хеш-объект hMAC; hMAC=0; if (hMACKey) **** 10. Уничтожить ключ hMACKey; hMACKey=0; */ if (hCryptKey) /* 11. Освободить дескриптор ключа */; hCryptKey=0; if (hCryptProv) /* 12. Освободить дескриптор кр.провайдера */; hCryptProv=0; /* if (MACVal.pbData) LocalFree(MACVal.pbData); MACVal.pbData=NULL; */ if (Salt.pbData) LocalFree(Salt.pbData); Salt.pbData=NULL; if (hCipher) fclose(hCipher); hCipher=0; if (hOriginator) fclose(hOriginator); hOriginator=0; Final=FALSE; if (!Result) return; printf("The first phase is completed.\n\n"); // Второй этап // Получатель на основании пароля вырабатывает ключи // шифрования и аутентификации, зашифровывает // сообщение и проверяет его целостность printf("Second phase start.\n"); // Открываем файл с шифртекстом if ((hCipher=fopen(CIPHERTEXT_FILE,"rb"))==NULL) { printf("Error: Opening %s file.\n",CIPHERTEXT_FILE); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The ciphertext file, %s, is open.\n",CIPHERTEXT_FILE); // Открываем файл для записи открытого текста получателя if ((hRecipient=fopen(RECIPIENT_PLAINTEXT_FILE,"wb"))==NULL) { printf("Error: Opening %s file.\n",RECIPIENT_PLAINTEXT_FILE); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The recipient plaintext file, %s, is open.\n",RECIPIENT_PLAINTEXT_FILE); // Открываем дескриптор ключевого контейнера получателя if (! /* 13. Открыть контекст криптопровайдера не подключаясь к контейнерам ключей. Параметры, используемые для вызова функции определены ранее в программе */) { Result=FALSE; goto SecondPhaseReleaseResource; } printf("Recipient CSP context initialized.\n"); // Считываем значение модификатора ключа для ключа шифрования сообщения if (!ReadFileBlob(hCipher,&Salt)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The encryption key salt value blob has been read from the file.\n"); // Считываем значение счетчика хеш-функций для ключа шифрования сообщения fread(&dwKDFHashCount,1,sizeof(DWORD),hCipher); if (ferror(hCipher) || feof(hCipher)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The encryption key hash count has been read from the file.\n"); // На основании пароля и дополнительных параметров создаем ключ шифрования if (!CryptPBKDFunction( hCryptProv, CRYPT_ALG, dwKeyFlags, &hCryptKey, &Password, &Salt, aiKDFHashAlg, dwKDFHashCount)) { Result=FALSE; goto SecondPhaseReleaseResource; } printf("The password-based encryption key has been created.\n"); if (CRYPT_ALG == CALG_RC2) { if (! /* 14. Установить эффективную длину ключа для алгоритма RC2, заданную в переменной dwEffectiveLen */) { printf("Error: Parameters =0x%X.\n",GetLastError()); Result=FALSE; goto FirstPhaseReleaseResource; } printf("The RC2 encryption key effective length has been set.\n"); } // Устанавливаем режим шифрования ключа шифрования сообщения if (! /* 15. Установить для ключа режим шифрования, заданный в переменной dwCipherMode */) { printf("Error: Parameters=0x%X.\n",GetLastError()); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The encryption key cipher mode has been set.\n"); dwlEncryptDataLen = 0; LocalFree(Salt.pbData); Salt.pbData=NULL; // Считываем длину зашифрованных данных fread(&dwlEncryptDataLen,1,sizeof(DWORDLONG),hCipher); if (ferror(hCipher) || feof(hCipher)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } // Сохраняем позицию в файле для считывания // зашифрованных данных fgetpos(hCipher, &fSavePos); if (ferror(hCipher)) { printf("Error: Get file position.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } /* // Устанавливаем позицию в файле для считывания // параметров секретного хеша fSetPos=fSavePos+dwlEncryptDataLen; fsetpos(hCipher, &fSetPos); if (ferror(hCipher)) { printf("Error: Set file position.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } // Считываем значение модификатора ключа для ключа секретного хеша if (!ReadFileBlob(hCipher,&Salt)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The MAC key salt value blob has been read from the file.\n"); // Считываем значение счетчика хеш-функций для ключа секретного хеша fread(&dwKDFHashCount,1,sizeof(DWORD),hCipher); if (ferror(hCipher) || feof(hCipher)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The MAC key hash count has been read from the file.\n"); // На основании пароля и дополнительных параметров создаем ключ секретного хеша if (!CryptPBKDFunction( hCryptProv, CRYPT_ALG, dwKeyFlags, &hMACKey, &Password, &Salt, aiKDFHashAlg, dwKDFHashCount)) { Result=FALSE; goto SecondPhaseReleaseResource; } printf("The password-based MAC key has been created.\n"); // Вырабатываем секретный хеш // Создаем объект хеш-функции для алгоритма MAC_ALG if (! **** 16. Создать хеш-объект. Криптопровайдер hCryptProv, алгоритм хеширования MAC_ALG. Ключ секретного хеша – hMACKey. Результат поместить в переменную hMAC.) { printf("Error: Hash=0x%X.\n",GetLastError()); Result=FALSE; goto SecondPhaseReleaseResource; } if (MAC_ALG == CALG_HMAC) { // Устанавливаем параметры алгоритма HMAC if (! **** 17. вопрос удален CryptSetHashParam(hMAC,HP_HMAC_INFO,(PBYTE)&HMACInfo,0)) { printf("Error: Parameters=0x%X.\n",GetLastError()); Result=FALSE; goto SecondPhaseReleaseResource; } } printf("MAC object created.\n"); // Считываем значение хеш-функции вычисленной отправителем if (!ReadFileBlob(hCipher,&MACVal)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } printf("The originator MAC value blob has been read from the file.\n"); */ // Устанавливаем позицию в файле для считывания // зашифрованных данных fsetpos(hCipher, &fSavePos); if (ferror(hCipher)) { printf("Error: Set file position.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } // Расшифровываем файл do { // Считываем из файла блок размером BLOCK_SIZE байт dwCount = fread(pbBuffer,1,BLOCK_SIZE,hCipher); if(ferror(hCipher)) { printf("Error: Reading data from file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } // Расшифровываем данные и рассчитываем значение секретного хеша dwlReadDataLen+=dwCount; if (dwlReadDataLen >= dwlEncryptDataLen) { Final=TRUE; dwDataLen=dwCount(DWORD)(dwlReadDataLen-dwlEncryptDataLen); } else dwDataLen=dwCount; if(! /* 18. Расшифровать считанный из файла блок данных. На область памяти, в которой находится шифротекст, указывает pbBuffer, количество расшифровываемых байт задано в переменной dwDataLen. В случае окончания шифротекста переменная Final принимает значение True. Параллельно с расшифровыванием вычислить значение хеш-функции hMАС */) { printf("Error: Crypt=0x%X.\n",GetLastError()); Result=FALSE; goto SecondPhaseReleaseResource; } // Записываем данные в файл получателя сообщения fwrite(pbBuffer,1,dwDataLen,hRecipient); if(ferror(hRecipient)) { printf("Error: Writing data to file.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } } while(!Final); printf("The decrypted message has been written to the file.\n"); /* // Запрашиваем размер значения хеш-функции if (! **** 19. В переменную MACValChecked.cbData получить размер памяти, необходимый для размещения значения хешфункции. Для этого вызов функции должен выглядеть как в вопросе 20, но третий параметр должен быть равен NULL) { printf("Error: Parameters=0x%X.\n",GetLastError()); Result=FALSE; goto SecondPhaseReleaseResource; } // Выделяем память для рассчитываемой хеш-функции MACValChecked.pbData=(unsigned char *)LocalAlloc(LMEM_ZEROINIT,MACValChecked.cbData); if (!MACValChecked.pbData) { printf("Error: Out of memory.\n"); Result=FALSE; goto SecondPhaseReleaseResource; } // Считываем значение хеш-функции if (! **** 20. В переменную MACValChecked.pbData получить значение хеш-функции hMAC. Размер этого значения получить в переменную MACValChecked.cbData) { printf("Error: Parameters=0x%X.\n",GetLastError()); Result=FALSE; goto SecondPhaseReleaseResource; } // Сравниваем размеры хеш-функций if (MACVal.cbData != MACValChecked.cbData) { printf("File MAC failed to validate!\n"); Result=FALSE; goto SecondPhaseReleaseResource; } // Сравниваем значение хеш-функций отправителя и получателя if (memcmp(MACVal.pbData,MACValChecked.pbData,MACValChecked.cbData) ) { printf("File MAC failed to validate!\n"); Result=FALSE; goto SecondPhaseReleaseResource; } printf("File MAC validated Ok!\n"); */ SecondPhaseReleaseResource: // Освобождаем открытые на втором этапе ресурсы и обнуляем переменный /* if (hMAC) **** 21. Уничтожить хеш-объект hMAC; if (hMACKey) **** 22. Уничтожить ключ hMACKey; */ if (hCryptKey) /* 23. Освободить дескриптор ключа */; if (hCryptProv) /* 24. Освободить дескриптор кр.провайдера */; /* if (MACValChecked.pbData) LocalFree(MACValChecked.pbData); if (MACVal.pbData) LocalFree(MACVal.pbData); */ if (Salt.pbData) LocalFree(Salt.pbData); if (hCipher) fclose(hCipher); if (hRecipient) fclose(hRecipient); if (Result) printf("The second phase is completed.\n\n"); return; } /* 25. Вставить функцию CryptPBKDFunction из лабораторной работы №2 */ // Функция сохраняет в файле, описанном парметром hFile, // структуру DATA_BLOB, описанную параметром pDataBlob. BOOL WriteFileBlob( FILE *hFile, PDATA_BLOB pDataBlob ) { // Сохраняем в файле длину блока данных fwrite(&pDataBlob->cbData, 1, sizeof(DWORD), hFile); if(ferror(hFile)) { return FALSE; } // Сохраняем в файле блок данных длиной pDataBlob>cbData if (pDataBlob->cbData) { fwrite(pDataBlob->pbData,1,pDataBlob>cbData,hFile); if(ferror(hFile)) { return FALSE; } } return TRUE; } // Функция считывает из файла, описанного парметром hFile, // структуру DATA_BLOB, сохраняя ее в по адресу pDataBlob. BOOL ReadFileBlob( FILE *hFile, PDATA_BLOB pDataBlob ) { BOOL Result=TRUE; pDataBlob->cbData=0; pDataBlob->pbData=NULL; // Считаем длину блока данных fread(&pDataBlob->cbData,sizeof(DWORD),1,hFile); if(ferror(hFile) || feof(hFile)) { Result=FALSE; goto ReleaseResource; } // Если длина блока не нулевая, то выделяем блок памяти if (pDataBlob->cbData) pDataBlob->pbData=(unsigned char *)LocalAlloc(LMEM_ZEROINIT,pDataBlob->cbData); else goto ReleaseResource; if (!pDataBlob->pbData) { printf("Error: Out of memory.\n"); Result=FALSE; goto ReleaseResource; } // Считываем блок данных в выделенный буфер fread(pDataBlob->pbData,1,pDataBlob->cbData,hFile); if(ferror(hFile) || feof(hFile)) { Result=FALSE; goto ReleaseResource; } ReleaseResource: if (!Result) // Освобождаем выделенный буфер if (pDataBlob->pbData) LocalFree(pDataBlob>pbData); return Result; } Пример результата работы программы First phase start. The originator plaintext file, Plaintext.org, is open. The ciphertext file, Ciphertext.msg, is open. Originator verify CSP context initialized. The password-based encryption key has been created. The RC2 encryption key effective length has been set. The encryption key cipher mode has been set. The encryption key salt value blob has been written to the file. The encryption key hash count has been written to the file. The password-based MAC key has been created. MAC object created. The encrypted message has been written to the file. The MAC salt value blob has been written to the file. The MAC hash count has been written to the file. The MAC value blob has been written to the file. The first phase is completed. Second phase start. The ciphertext file, Ciphertext.msg, is open. The recipient plaintext file, Plaintext.rcp, is open. Recipient verify CSP context initialized. The encryption key salt value blob has been read from the file. The encryption key hash count has been read from the file. The password-based encryption key has been created. The RC2 encryption key effective length has been set. The encryption key cipher mode has been set. The MAC key salt value blob has been read from the file. The MAC key hash count has been read from the file. The password-based MAC key has been created. MAC object created. The originator MAC value blob has been read from the file. The decrypted message has been written to the file. File MAC validated Ok! The second phase is completed. Помимо диагностических сообщений программа ищет в текущем каталоге файл Plaintext.org, и если не находит его, то создает новый и записывает в него тестовую фразу. После работы первой части программы создается файл Ciphertext.msg, содержащий некоторые параметры алгоритма, зашифрованный файл Plaintext.org и значение секретного хеша (имитовставку). После работы второй части программы создается файл Plaintext.rcp, содержащий расшифрованную информацию из файла Ciphertext.msg. Его длина и содержимое должно быть идентично файлу Plaintext.org. Параллельно с расшифровкой происходит расчет значения секретного хеша и проверка целостности сообщения. Лабораторная работа №5. Выработка и проверка электронной цифровой подписи средствами Microsoft CryptoAPI. Цель работы Получить основные навыки работы с функциями создания и проверки электронной цифровой подписи. Закрепление навыков использования хеш-функций. Ход работы Повторить материал по функциям управления контекстом криптопровайдеров и хеширования Microsoft CryptoAPI. Перенести задание к лабораторной работе в среду программирования. Восстановить вырезанные фрагменты программы по описаниям и отладить полученную программу. Добавление кода осуществляется непосредственно в месте расположения комментария с описанием действия! Проанализировать работу полученной программы и сравнить результаты работы программы с примером результатов, приведенным в лабораторной работе. Разобраться с форматом файла электронной цифровой подписи и знать что, какой длины и в каком порядке в него записано. Описание основных используемых в лабораторной работе функций Microsoft CryptoAPI (функции определены в файле wincrypt.h, полное описание находится в MSDN, security.chm, .chi, в разделе Cryptography\CryptoAPI\Using CryptoAPI\CryptoAPI Reference\CryptoAPI Functions\Base CryptoAPI Functions\Service Provider Functions) Функция CryptSignHash вычисляет значение ЭЦП от значения хеша, определенного дескриптором объекта хеш-функции hHash. BOOL WINAPI CryptSignHash( HCRYPTHASH hHash, DWORD dwKeySpec, LPCSTR szDescription, DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen); Параметры hHash [in] - Дескриптор объекта хеш-функции, для которого вычисляется ЭЦП. dwKeySpec [in] - Параметр идентифицирует секретный ключ, который будет использоваться для ЭЦП. Возможные значения параметра: AT_SIGNATURE или AT_KEYEXCHANGE. szDescription [in] - Строка, описывающая подписываемые данные. Текст описания добавляется к хешу перед тем, как будет произведена подпись. Всякий раз, когда подпись проверяется, в функцию CryptVerifySignature должна передаваться та же самая строка. Это гарантирует, что и подписывающая сторона и проверяющая знают то, что подписывается или проверяется. Если строка описания не включается в подпись, этот параметр может быть равен NULL. В настоящее время этот параметр поддерживается для совместимости с предыдущими версиями криптопровайдеров. Использование его не рекомендуется, так как это снижает безопасность системы. dwFlags [in] - Значения флагов. В настоящее время определено одно значение флага: CRYPT_NOHASHOID - Используется с криптопровайдерами RSA. В случае установки данного флага подписывается непосредственно значение хеш-функции. По умолчанию, если флаг не устанавливается, подписывается структура DigestInfo, определенная к стандарте PKCS #7. pbSignature [out] - Адрес буфера, в который копируется значение подписи. Этот параметр может быть равен NULL, если необходимо только определить размер буфера, требуемый для размещения подписи. pdwSigLen [in/out] - Указатель назначение типа DWORD, содержащее размер в байтах буфера pbSignature. После завершения функции DWORD показывает число байт, переданных в буфер. При выполнении функции могут произойти ошибки: ERROR_INVALID_HANDLE, ERROR_INVALID_PARAMETER, ERROR_MORE_DATA, NTE_BAD_ALGID, NTE_BAD_FLAGS, NTE_BAD_HASH, NTE_BAD_UID, NTE_NO_KEY, NTE_NO_MEMORY. Перед вызовом этой функции дескриптор объекта хеш-функции следует получить через вызов функции CryptCreateHash. Далее для хеширования данных или сессионных ключей используется функция CryptHashData или CryptHashSessionKey. Функция CryptSignHash выполняет следующие операции: объект хеш-функции «закрывается» и значение хеша извлекается; значение хеша дополняется, как это требуется алгоритмом подписи; вычисляется значение подписи. После того как значение хеша подписано, приложение не может добавлять новые данные к объекту хеш-функции. Приложение должно уничтожить объект хеш-функции, вызвав функцию CryptDestroyHash. Функция CryptVerifуSignature осуществляет проверку подписи, соответствующей объекту хеш-функции hHash. BOOL WINAPI CryptVerifySignatureA( HCRYPTHASH hHash, CONST BYTE *pbSignature, DWORD dwSigLen, HCRYPTKEY hPubKey, LPCSTR szDescription, DWORD dwFlags); Параметры hHash [in] - Дескриптор объекта хеш-функции, подпись которого проверяется. pbSignature [in] - Буфер, содержащий значение проверяемой подписи. dwSigLen [in] - Длина в байтах, значения подписи, содержащейся в буфере pbSignature. hPubKey [in] - Дескриптор открытого ключа, который используется для проверки подписи. Этот открытый ключ должен соответствовать ключевой паре, на которой вычислялось значение подписи. szDescripfion [in] - Строка описания подписанных данных. Она должна быть точно такой, что использовалась в функции CryptSignHash при вычислении подписи. Если она не соответствует использованной в функции CryptSignHash, проверка подписи вернет отрицательный результат. В настоящее время этот параметр поддерживается для совместимости с предыдущими версиями криптопровайдеров. Использование его не рекомендуется, так как это снижает безопасность системы. dwFlags [in] - Значения флагов. В настоящее время определено одно значение флага CRYPT_NOHASHOID. Используется с криптопровайдерами RSA. При проверке подписи проверяется только значение хеш-функции. По умолчанию, если флаг не устанавливается, проверяется подпись для структуры Digestlnfo, определенной в стандарте PKCS #7. При выполнении функции могут произойти ошибки: ERROR_INVALID_HANDLE, ERROR_INVALID_PARAMETER, NTE_BAD_FLAGS, NTE_BAD_HASH, NTE_BAD_KEY, NTE_BAD_SIGNATURE, NTE_BAD_UID, NTE_NO_MEMORY. Функция CryptVerifySignature выполняет следующие операции: если параметр описания szDescription определен, он добавляется к хешу; объект хеш-функции «закрывается» и значение хеша извлекается; значение хеша дополняется, как это требуется алгоритмом подписи; осуществляется проверка подписи на открытом ключе hPubKey. Если подпись, переданная через буфер pbSignature, неверна, то функция возвращает FALSE с кодом ошибки NTE_BAD_SIGNATURE. После выполнения проверки подписи приложение не может добавлять новые данные к объекту хеш-функции. Приложение должно уничтожить объект хеш-функции через вызов функции CryptDestroyHash. Задание к лабораторной работе Программа выработки и проверки ЭЦП создает файл подписи для входного файл, имя которого вводится с клавиатуры. Имя файла подписи создается путем присоединения к имени входного файла расширения ".sig". При создании файла подписи необходимо указывать имя владельца (автора) исходного файла. Заполнить указанные пропуски в программе выработки и проверки ЭЦП. // FileSign.h: interface for the CFileSign class. ////////////////////////////////////////////////////////////////////// #if !defined(_FILESIGN_H_) #define _FILESIGN_H_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <windows.h> #include <wincrypt.h> #include <stdio.h> #include <conio.h> #define SHOW_CON 1 #define SHOW_WIN 2 void ShowErrMes(DWORD dwErrCode,DWORD dwFlag=SHOW_WIN); #define BUF_LEN 1024 struct FileSignParam{ DWORD dwProvType; // Тип криптопровайдера ALG_ID HashAlgid; // Идентификатор алгоритма хеширования DWORD dwDescrLen; // Длина строки описания DWORD dwBlobLen; // Длина ключевого блоба DWORD dwSigLen; // Длина подписи }; class CFileSign{ private: HCRYPTPROV hProv; // Дескриптор крипторовайдера HCRYPTKEY hKey; // Дескриптор открытого ключа HCRYPTHASH hHash; // Дескриптор объекта хеширования HANDLE hFile; // Дескриптор входного файла HANDLE hSignFile; // Дескриптор файла подписи LPSTR pszSignFileName; // Указатель на имя файла подписи LPSTR pszDescription; // Указатель на на строку описания LPBYTE pbKeyBlob; // Указатель на ключевой BLOB LPBYTE pbSignature; // Указатель на ЭЦП LPBYTE pbBuf; // Указатель на буфер чтения входного файла void CreateSignFileName(LPCSTR pszFileName); // Создание имени файла подписи void ReleaseResource(); // Освобождение ресурсов public: CFileSign(): hProv(0),hKey(0),hHash(0),hFile(0),hSignFile(0),pszSignFileName(NULL), pszDescription(NULL),pbKeyBlob(NULL),pbSignature(NULL),pbBuf(NULL){} virtual ~CFileSign(); // Создание файла подписи void CreateFileSignature( LPCSTR pszFileName, // Указатель на имя входного файла LPCSTR pszUserName, // Указатель на имя автора подписи // (имя ключевого контейнера) LPCSTR pszProvider, // Указатель на имя криптопровайдера DWORD dwProvType, // Тип криптопровайдера ALG_ID HashAlgid // Идентификатор алгоритма хеширования ); // Проверка файла подписи LPSTR VerifyFileSignature( LPCSTR pszFileName // Указатель на имя входного файла ); }; #endif // !defined(_FILESIGN_H_) // FileSign.cpp: implementation of the CFileSign class. ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "FileSign.h" #include <iostream.h> // Отображение сообщения об ошибке void ShowErrMes(DWORD dwErrCode,DWORD dwFlag){ LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); switch(dwFlag){ case SHOW_CON: CharToOem(LPCTSTR(lpMsgBuf),LPSTR(lpMsgBuf)); printf("GetLastError: %s\nPress any key to continue...\n",(char*)lpMsgBuf); getch(); break; case SHOW_WIN: MessageBox(NULL, LPCTSTR(lpMsgBuf), "GetLastError", MB_OK|MB_ICONINFORMATION ); break; } LocalFree( lpMsgBuf ); } // Деструктор CFileSign::~CFileSign( ){ ReleaseResource( ); if(pszDescription) delete[ ] pszDescription, pszDescription=NULL; } // Освобождение ресурсов void CFileSign::ReleaseResource( ){ if(pszSignFileName) delete[ ] pszSignFileName, pszSignFileName=NULL; if(pbKeyBlob) delete[ ] pbKeyBlob, pbKeyBlob=NULL; if(pbSignature) delete[ ] pbSignature, pbSignature=NULL; if(pbBuf) delete[ ] pbBuf, pbBuf=NULL; if(hFile) CloseHandle(hFile), hFile=0; if(hSignFile) CloseHandle(hSignFile), hSignFile=0; if(hKey) CryptDestroyKey(hKey), hKey=0; if(hHash) CryptDestroyHash(hHash), hHash=0; if(hProv) CryptReleaseContext(hProv,0), hProv=0; } // Создание имени файла подписи // путем присоединения к имени входного файла расширения ".sig" void CFileSign::CreateSignFileName(LPCSTR pszFileName){ pszSignFileName=(LPSTR)new char[strlen(pszFileName)+5]; if(pszSignFileName==NULL) throw DWORD(ERROR_NOT_ENOUGH_MEMORY); strcpy(pszSignFileName,pszFileName); strcat(pszSignFileName,".sig"); } // Создание файла подписи void CFileSign::CreateFileSignature(LPCSTR pszFileName,LPCSTR pszUserName, LPCSTR pszProvider,DWORD dwProvType, ALG_ID HashAlgid){ // Переменная для хранения количества реально прочитанных или записанных байт DWORD nBytes; // Освобождаем память под строку описания if(pszDescription) delete[ ] pszDescription, pszDescription=NULL; // Подготавливаем структуру для хранения параметров ЭЦП FileSignParam fsp; fsp.dwProvType=dwProvType; fsp.HashAlgid=HashAlgid; // Пытаемся открыть контекст криптопровайдера if(!CryptAcquireContext(&hProv,pszUserName,pszProvider,dwProvType,0)) // Если контекст не может быть открыт // по причине отсутствия контейнера ключей, то пытаемся создать контейнер if(GetLastError( )==NTE_BAD_KEYSET){ if(!CryptAcquireContext(&hProv,pszUserName,pszProvider,dwProvType, CRYPT_NEWKEYSET)) throw GetLastError( ); } else throw GetLastError(); // Пытаемся получить десриптор ключа подписи if(!CryptGetUserKey(hProv,AT_SIGNATURE,&hKey)) // Если ключ подписи отсутствует, то пытаемся создать его if(!CryptGenKey(hProv,AT_SIGNATURE,CRYPT_EXPORTABLE,&hKey)) ReleaseResource(), throw GetLastError( ); // Получаем системное время и формируем строку " dd.mm.yyyy hh:mm.ss" SYSTEMTIME st; GetSystemTime(&st); char FormatDate[21]; wsprintf(FormatDate," %02d.%02d.%02d %02d:%02d:%02d", st.wDay,st.wMonth,st.wYear,st.wHour,st.wMinute,st.wSecond); // Формируем строку описания fsp.dwDescrLen=strlen(pszFileName)+strlen(pszUserName)+strlen(FormatDate)+17; pszDescription=(LPSTR)new char[fsp.dwDescrLen]; if(pszDescription==NULL) ReleaseResource(), throw DWORD(ERROR_NOT_ENOUGH_MEMORY); strcpy(pszDescription,"File "); strcat(pszDescription,pszFileName); strcat(pszDescription," signed by "); strcat(pszDescription,pszUserName); strcat(pszDescription,FormatDate); // Пытаемся открыть входной файл для чтения hFile=CreateFile(pszFileName,GENERIC_READ,0,NULL,OPEN_EXISTING,0,0); if(hFile==INVALID_HANDLE_VALUE) ReleaseResource(), throw GetLastError(); // Пытаемся создать объект хеширования if(!CryptCreateHash(hProv,HashAlgid,0,0,&hHash)) ReleaseResource(), throw GetLastError(); // Отводим память под буфер для чтения из входного файла pbBuf=(LPBYTE)new BYTE[BUF_LEN]; if(pbBuf==NULL) ReleaseResource(), throw DWORD(ERROR_NOT_ENOUGH_MEMORY); // Читем данные из входного файла и добавляем их к объекту хеширования do{ ReadFile(hFile,pbBuf,BUF_LEN,&nBytes,NULL); if(nBytes) if(!CryptHashData(hHash,pbBuf,nBytes,0)) ReleaseResource( ), throw GetLastError( ); }while(nBytes==BUF_LEN); // Закрываем входной файл CloseHandle(hFile); hFile=0; // Определяем объем памяти необходимый для хранения ЭЦП if(!CryptSignHash(hHash,AT_SIGNATURE, (LPCSTR)pszDescription,0,NULL,&fsp.dwSigLen)) ReleaseResource( ), throw GetLastError( ); pbSignature=(LPBYTE)new BYTE[fsp.dwSigLen]; if(pbSignature==NULL) ReleaseResource(), throw DWORD(ERROR_NOT_ENOUGH_MEMORY); // Получаем ЭЦП if(!CryptSignHash(hHash,AT_SIGNATURE, (LPCSTR)pszDescription,0,pbSignature,&fsp.dwSigLen)) ReleaseResource(), throw GetLastError( ); // Освобождаем объект хеширования CryptDestroyHash(hHash); hHash=0; // Определяем объем памяти необходимый // для хранения блоба открытого ключа подписи if(!CryptExportKey(hKey,0,PUBLICKEYBLOB,0,NULL,&fsp.dwBlobLen)) ReleaseResource( ), throw GetLastError( ); pbKeyBlob=(LPBYTE)new BYTE[fsp.dwBlobLen]; if(pbKeyBlob==NULL) ReleaseResource( ), throw DWORD(ERROR_NOT_ENOUGH_MEMORY); // Получаем блоб открытого ключа if(!CryptExportKey(hKey,0,PUBLICKEYBLOB,0,pbKeyBlob,&fsp.dwBlobLen)) ReleaseResource( ), throw GetLastError( ); // Пытаемся создать имя файла подписи try{ CreateSignFileName(pszFileName); } catch(DWORD dwError){ ReleaseResource(); throw dwError; } // Пытаемся создать файл подписи для записи hSignFile=CreateFile(pszSignFileName, GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,0); if(hSignFile==INVALID_HANDLE_VALUE) ReleaseResource(), throw GetLastError(); // Пишем в файл подписи параметры ЭЦП WriteFile(hSignFile,&fsp,sizeof(FileSignParam),&nBytes,NULL); // Пишем в файл подписи строку описания WriteFile(hSignFile,pszDescription,fsp.dwDescrLen,&nBytes,NULL); // Пишем в файл подписи ключевой блоб WriteFile(hSignFile,pbKeyBlob,fsp.dwBlobLen,&nBytes,NULL); // Пишем в файл подписи ЭЦП WriteFile(hSignFile,pbSignature,fsp.dwSigLen,&nBytes,NULL); // Освобождаем ресурсы ReleaseResource(); // Освобождаем память под строку описания if(pszDescription) delete[] pszDescription, pszDescription=NULL; } // Проверка файла подписи LPSTR CFileSign::VerifyFileSignature(LPCSTR pszFileName){ // Переменная для хранения количества реально прочитанных или записанных байт DWORD nBytes; // Освобождаем память под строку описания if(pszDescription) delete[] pszDescription, pszDescription=NULL; // Подготавливаем структуру для хранения параметров ЭЦП FileSignParam fsp; // Пытаемся создать имя файла подписи try{ CreateSignFileName(pszFileName); } catch(DWORD dwError){ ReleaseResource(); throw dwError; } // Пытаемся открыть файл подписи для чтения hSignFile=CreateFile(pszSignFileName, GENERIC_READ,0,NULL,OPEN_EXISTING,0,0); if(hSignFile==INVALID_HANDLE_VALUE) ReleaseResource(), throw GetLastError(); // Читаем параметры ЭЦП ReadFile(hSignFile,&fsp,sizeof(FileSignParam),&nBytes,NULL); // Читем строку описания pszDescription=(LPSTR)new char[fsp.dwDescrLen]; if(pszDescription==NULL) ReleaseResource(), throw DWORD(ERROR_NOT_ENOUGH_MEMORY); ReadFile(hSignFile,pszDescription,fsp.dwDescrLen,&nBytes,NULL); // Читаем ключевой блоб pbKeyBlob=(LPBYTE)new BYTE[fsp.dwBlobLen]; if(pbKeyBlob==NULL) ReleaseResource(), throw DWORD(ERROR_NOT_ENOUGH_MEMORY); ReadFile(hSignFile,pbKeyBlob,fsp.dwBlobLen,&nBytes,NULL); // Читаем ЭЦП pbSignature=(LPBYTE)new BYTE[fsp.dwSigLen]; if(pbSignature==NULL) ReleaseResource(), throw DWORD(ERROR_NOT_ENOUGH_MEMORY); ReadFile(hSignFile,pbSignature,fsp.dwSigLen,&nBytes,NULL); // Закрываем файл подписи CloseHandle(hSignFile); hSignFile=0; // Пытаемся открыть контекст криптопровайдера if(!CryptAcquireContext(&hProv,NULL,NULL, fsp.dwProvType,CRYPT_VERIFYCONTEXT)) ReleaseResource( ), throw GetLastError( ); // Пытаемся импортировать в криптопровайдер открытый ключ подписи if(!CryptImportKey(hProv,pbKeyBlob,fsp.dwBlobLen,0,0,&hKey)) ReleaseResource( ), throw GetLastError( ); // Пытаемся открыть входной файл для чтения hFile=CreateFile(pszFileName,GENERIC_READ,0,NULL,OPEN_EXISTING,0,0); if(hFile==INVALID_HANDLE_VALUE) ReleaseResource( ), throw GetLastError( ); // Пытаемся создать объект хеширования if(!CryptCreateHash(hProv,fsp.HashAlgid,0,0,&hHash)) ReleaseResource( ), throw GetLastError( ); // Отводим память под буфер для чтения из входного файла pbBuf=(LPBYTE)new BYTE[BUF_LEN]; if(pbBuf==NULL) ReleaseResource( ), throw DWORD(ERROR_NOT_ENOUGH_MEMORY); // Читем данные из входного файла и добовляем их к объекту хэширования do{ ReadFile(hFile,pbBuf,BUF_LEN,&nBytes,NULL); if(nBytes) if(!CryptHashData(hHash,pbBuf,nBytes,0)) ReleaseResource(), throw GetLastError(); }while(nBytes==BUF_LEN); // Закрываем входной файл CloseHandle(hFile); hFile=0; // Проверяем ЭЦП if(!CryptVerifySignature(hHash,pbSignature, fsp.dwSigLen,hKey,(LPCSTR)pszDescription,0)) if(GetLastError()==NTE_BAD_SIGNATURE){ ReleaseResource(); // Освобождаем память под строку описания if(pszDescription) delete[] pszDescription, pszDescription=NULL; return NULL; } else ReleaseResource(), throw GetLastError(); // Освобождаем ресурсы ReleaseResource(); return pszDescription; } // CreateFileSign.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream.h> #include "FileSign.h" int main(int argc, char* argv[]) { char FileName[256],UserName[256]; cout<<"Enter user name: "; cin>>UserName; cout<<"Enter file name: "; cin>>FileName; CFileSign fs; char* Descr=NULL; try{ fs.CreateFileSignature((LPCSTR)FileName,(LPCSTR)UserName, NULL,PROV_RSA_FULL,CALG_SHA); Descr=fs.VerifyFileSignature((LPCSTR)FileName); } catch(DWORD dwError){ ShowErrMes(dwError); } if(Descr!=NULL) cout<<"SIGNATURE VALIDATED OK!"<<endl<<Descr<<endl; else cout<<"SIGNATURE FAILED TO VALIDATE!"<<endl; return 0; } Пример результата работы программы Лабораторная работа № 8. Основные признаки присутствия вредоносных программ и методы по устранению последствий вирусных заражений Цель работы Получить навыки обнаружения на компьютере вредоносных программ, изучить основные методы по устранению последствий вирусных инцидентов без использования антивирусного программного обеспечения. Ход работы Ознакомиться с определением вируса и вредоносных программ Ознакомиться с типами вредоносных программ и их описанием Ознакомиться с жизненными циклами различных типов вредоносных программ Ознакомиться с действиями червей при заражении компьютера Ознакомиться с возможностями лечения компьютеров без использования антивирусного программного обеспечения 6. Выполнить задания к лабораторной работе 7. Защитить лабораторную работу, ответив на контрольные вопросы 1. 2. 3. 4. 5. Методические указания к лабораторной работе Определения компьютерного вируса - исторически проблемный вопрос, поскольку достаточно сложно дать четкое определение вируса, очертив при этом свойства, присущие только вирусам и не характерные для других программ. Наоборот, давая жесткое определение вируса как программы, обладающей определенными свойствами практически сразу же можно найти пример вируса, таковыми свойствами не обладающего. Приведем определение вируса согласно ГОСТ P 51198-98: Вирус - программа, способная создавать свои копии (необязательно совпадающие с оригиналом) и внедрять их в файлы, системные области компьютера, компьютерных сетей, а также осуществлять иные деструктивные действия. При этом копии сохраняют способность дальнейшего распространения. Компьютерный вирус относится к вредоносным программам. Еще одна проблема, связанная с определением компьютерного вируса кроется в том, что сегодня под вирусом чаще всего понимается не "традиционный" вирус, а практически любая вредоносная программа. Это приводит к путанице в терминологии, осложненной еще и тем, что сегодня практически любой антивирус способен выявлять все типы вредоносных программ, таким образом ассоциация "вредоносная программа-вирус" становится все более устойчивой. Вредоносная программа - компьютерная программа или переносной код, предназначенный для реализации угроз информации, хранящейся в компьютерной системе (КС), либо для скрытого нецелевого использования ресурсов КС, либо иного воздействия, препятствующего нормальному функционированию КС. К вредоносным программам относятся компьютерные вирусы, трояны, сетевые черви и др. Вирусы К вирусам относятся: Загрузочные вирусы - вирусы, заражающие загрузочные сектора постоянных и сменных носителей Файловые вирусы - вирусы, заражающие файлы Макровирусы - вирусы, написанные на языке макрокоманд и исполняемые в среде какого-либо приложения. В подавляющем большинстве случаев речь идет о макросах в документах Microsoft Office Скрипт-вирусы - вирусы, исполняемые в среде определенной командной оболочки: раньше - bat-файлы в командной оболочке DOS, сейчас чаще VBS- и Javaскрипты в командной оболочке Windows Scripting Host (WSH) Отдельно стоит сказать пару слов о макровирусах. Большинство электронных документов создаются и обрабатываются в формате MS Office, инструмент VBA (Visual Basic for Application), который можно использовать для создания макровирусов поставляется вместе с приложением MS Office. Такое положение дел приводит к тому, что на сегодняшний день макровирусы - наиболее часто встречающийся тип вирусов. Однако борьба с ними не вызывает особых проблем и сводится к изучению тела вредоносного макроса с помощью того же VBA на предмет выполняемых операций, контролю стартовых макросов AutoOpen, AutoClose, AutoSave, глобальных макросов FileOpen, FileSaveAs, FileSave, FileClose и ряда стандартных операций, таких как вызов API-функций, выполнения команд Shell и т. д. Процедура лечение макровирусов сводится к удалению тела макроса из документов и шаблонов MS Office. Сетевые черви Червь (сетевой червь) - тип вредоносных программ, распространяющихся по сетевым каналам, способных к автономному преодолению систем защиты автоматизированных и компьютерных систем, а также к созданию и дальнейшему распространению своих копий, не всегда совпадающих с оригиналом, осуществлению иного вредоносного воздействия В зависимости от путей проникновения в операционную систему черви делятся на: Почтовые черви (Mail-Worm) - черви, распространяющиеся в формате сообщений электронной почты IM черви (IM-Worm) - черви, использующие Интернет-пейджеры P2P черви (P2P-Worm) - черви, распространяющееся при помощи пиринговых (peer-to-peer) файлообменных сетей Сетевые черви (Net-Worm) - прочие сетевые черви, среди которых имеет смысл дополнительно выделить Интернет-черви и LAN-черви o Интернет черви - черви, использующие для распространения протоколы Интернет. Преимущественно этот тип червей распространяется с использованием неправильной обработки некоторыми приложениями базовых пакетов стека протоколов tcp/ip o LAN черви - черви, распространяющиеся по протоколам локальных сетей Трояны Троян (троянский конь) - тип вредоносных программ, основной целью которых является вредоносное воздействие по отношению к компьютерной системе. Трояны отличаются отсутствием механизма создания собственных копий Некоторые трояны способны к автономному преодолению систем защиты КС, с целью проникновения и заражения системы. В общем случае, троян попадает в систему вместе с вирусом либо червем, в результате неосмотрительных действий пользователя или же активных действий злоумышленника. Наиболее распространены следующие виды троянов: Клавиатурные шпионы (Trojan-SPY) - трояны, постоянно находящиеся в памяти и сохраняющие все данные поступающие от клавиатуры с целью последующей передачи этих данных злоумышленнику. Обычно таким образом злоумышленник пытается узнать пароли или другую конфиденциальную информацию Похитители паролей (Trojan-PSW) - трояны, также предназначенные для получения паролей, но не использующие слежение за клавиатурой. Обычно в таких троянах реализованы способы извлечения паролей из файлов, в которых эти пароли хранятся различными приложениями Утилиты удаленного управления (Backdoor) - трояны, обеспечивающие полный удаленный контроль над компьютером пользователя. Существуют легальные утилиты такого же свойства, но они отличаются тем, что сообщают о своем назначении при установке или же снабжены документацией, в которой описаны их функции. Троянские утилиты удаленного управления, напротив, никак не выдают своего реального назначения, так что пользователь и не подозревает о том, что его компьютер подконтролен злоумышленнику. Наиболее популярная утилита удаленного управления - Back Orifice Анонимные smtp-сервера и прокси (Trojan-Proxy) - трояны, выполняющие функции почтовых серверов или прокси и использующиеся в первом случае для спамрассылок, а во втором для заметания следов хакерами Модификаторы настроек браузера (Trojan-Cliker) - трояны, которые меняют стартовую страницу в браузере, страницу поиска или еще какие-либо настройки, для организации несанкционированных обращений к Интернет-ресурсам Инсталляторы прочих вредоносных программ (Trojan-Dropper) - трояны, представляющие возможность злоумышленнику производить скрытую установку других программ Загрузчики вредоносных программ (Trojan Downloader) - трояны, предназначенные для загрузки на компьютер-жертву новых версий вредоносных программ, или рекламных систем Уведомители об успешной атаке (Trojan-Notifier) - трояны данного типа предназначены для сообщения своему "хозяину" о зараженном компьютере "Бомбы" в архивах (ARCBomb) - трояны, представляющие собой архивы, специально оформленные таким образом, чтобы вызывать нештатное поведение архиваторов при попытке разархивировать данные - зависание или существенное замедление работы компьютера, заполнение диска большим количеством "пустых" данных Логические бомбы - чаще не столько трояны, сколько троянские составляющие червей и вирусов, суть работы которых состоит в том, чтобы при определенных условиях (дата, время суток, действия пользователя, команда извне) произвести определенное действие: например, уничтожение данных Утилиты дозвона - сравнительно новый тип троянов, представляющий собой утилиты dial-up доступа в Интернет через платные почтовые службы. Такие трояны прописываются в системе как утилиты дозвона по умолчанию и влекут за собой крупные счета за пользование Интернетом Жизненный цикл вредоносных программ Процесс размножения вирусов может быть условно разделен на несколько стадий: 1. 2. 3. 4. Активация вируса Поиск объектов для заражения Подготовка вирусных копий Внедрение вирусных копий Так же как для вирусов, жизненный цикл червей можно разделить на определенные стадии: 1. 2. 3. 4. 5. Проникновение в систему Активация Поиск "жертв" Подготовка копий Распространение копий У троянов вследствие отсутствия функций размножения и распространения, их жизненный цикл меньше чем у вирусов - всего три стадии: 1. Проникновение на компьютер 2. Активация 3. Выполнение заложенных функций Это, само собой, не означает малого времени жизни троянов. Напротив, троян может незаметно находиться в памяти компьютера длительное время, никак не выдавая своего присутствия, до тех пор, пока не выполнит свою вредоносную функцию будет обнаружен антивирусными средствами. ции Основные пути проникновения в систему и актива- Существует утверждение - любую вредоносную программу пользователь может победить самостоятельно, т. е. не прибегая к использованию антивирусных программ. Это действительно так, за успешными действия любой антивирусной программы стоит труд вирусных аналитиков, которые по сути дела вручную разбираются с алгоритмами работы новых вирусов, выделяют сигнатуры, описывают алгоритм работы вируса. Сигнатура вируса - в широком смысле, информация, позволяющая однозначно определить наличие данного вируса в файле или ином коде Примерами сигнатур являются: уникальная последовательность байт, присутствующая в данном вирусе и не встречающаяся в других программах; контрольная сумма такой последовательности Таким образом, антивирусную программу можно рассматривать как средство автоматизации борьбы с вирусами. Следует заметить, что анализ вирусов требует от пользователя владения большим объемом специфических знаний в области программирования, работы операционных систем и т. д. Современные вредоносные программы используют сложные технологии маскировки и защиты своих копий, которые обуславливают необходимость применение специальных средств для их анализа. Процесс подготовки вредоносной программой своих копий для распространения может существенно отличаться от простого копирования. Авторы наиболее сложных в технологическом плане вирусов стараются сделать разные копии максимально непохожими для усложнения их обнаружения антивирусными средствами. Как следствие, составление сигнатуры для такого вируса крайне затруднено. При создании копий для маскировки могут применяться следующие технологии: Шифрование - вирус состоит из двух функциональных блоков: собственно вируса и шифратора. Каждая копия вируса состоит из шифратора, случайного ключа и вирусного блока, зашифрованного этим ключом Метаморфизм - создание различных копий вируса путем замены групп команд на эквивалентные, перестановки местами блоков кода, вставки между значащими кусками кода "мусорных" команд, которые практически ничего не делают Сочетание этих двух технологий приводит к появлению следующих типов вирусов. Шифрованный вирус - вирус, использующий простое шифрование со случайным ключом и неизменный шифратор. Такие вирусы легко обнаруживаются по сигнатуре шифратора Метаморфный вирус - вирус, применяющий метаморфизм ко всему своему телу для создания новых копий Полиморфный вирус - вирус, использующий метаморфный шифратор для шифрования основного тела вируса со случайным ключом. При этом часть информации, используемой для получения новых копий шифратора также может быть зашифрована. Например, вирус может реализовывать несколько алгоритмов шифрования и при создании новой копии менять не только команды шифратора, но и сам алгоритм Рассматривая современные вирусные угрозы необходимо отметить, что более 90% процентов вирусных угроз в последнее время связаны с червями. Наиболее многочисленную группу в этом классе вредоносных программ составляют почтовые черви. Интернет-черви также являются заметным явлением, но не столько из-за количества, сколько из-за качества: эпидемии, вызванные Интернет-червями зачастую отличаются высокой скоростью распространения и большими масштабами. IRC и P2P черви встречаются достаточно редко, чаще IRC и P2P служат альтернативными каналами распространения для почтовых и Интернет-червей. Распространение через LAN также используется преимущественно как дополнительный способ распространения. Кроме того, на этапе активации червей можно разделить на две большие группы отличающиеся как по технологиям активации, так и по срокам жизни: Для активации необходимо активное участие пользователя Для активации участие пользователя не требуется вовсе либо достаточно лишь пассивного участия Активация сетевого червя без участия пользователя всегда означает, что червь использует бреши в безопасности программного обеспечении компьютера. Это приводит к очень быстрому распространению червя внутри корпоративной сети с большим числом станций, существенно увеличивает загрузку каналов связи и может полностью парализовать сеть. Именно этот метод активации использовали черви Lovesan и Sasser. Под пассивным участием пользователя понимается, например, просмотр писем в почтовом клиенте, при котором пользователь не открывает вложенные файлы, но его компьютер тем не менее оказывается зараженным. Активное участие пользователя в активации червя означает, что пользователь был введен в заблуждение методами социальной инженерии. В большинстве случаев основным фактором служит форма подачи инфицированного сообщения: оно может имитировать письмо от знакомого человека (включая электронный адрес, если знакомый уже заражен), служебное сообщение от почтовой системы или же что-либо подобное, столь же часто встречающееся в потоке обычной корреспонденции. При заражении компьютера черви обычно производят следующие действия: Создают исполняемый файл с расширением .exe с произвольным именем или именем очень похожим на имя системных файлов Windows. В некоторых червях могут использоваться технологии присущие вирусам, в таком случае черви инфицируют уже существующий файл приложения (например WSOCK32.DLL) или заменяют его на свой файл (например I-Worm.MTX записывает одну из своих процедур в файл WSOCK32.DLL таким образом, что она перехватывает отсылку данных в Интернет (процедура send). В результате червь в зараженной библиотеке WSOCK32.DLL получал управление каждый раз, когда данные отправляются в Интернет). Кроме этого, вместе с добавлением в систему исполняемых файлов, в ряде случаев черви помещают в систему файлы библиотек, которые обычно выполняют функции Backdoor компонентов (например один из клонов червя MyDoom - IWorm.Mydoom.aa создавал системном каталоге Windows файл tcp5424.dll, являющийся Backdoor-компонентом и регистрировал его в системном реестре: HKCR\CLSID\{E6FB5E20-DE35-11CF-9C87-00AA005127ED}\InProcServer32 {Default} = "%SysDir%\tcp5424.dll") Вредоносная программа может вносить изменения в системные файлы win.ini и system.ini. Например Email-Worm.Win32.Toil при установке в заражаемой системе копирует себя в папку Windows со случайным именем и записывает в файл system.ini следующие значения: [boot] shell=Explorer.exe %имя червя% что обеспечивает ему автозапуск при каждой перезагрузке Windows (но только под Win9x/Me). Email-Worm.Win32.Atak.h в процессе инсталляции копирует себя с именем dec25.exe в системный каталог Windows и модифицирует файл win.ini для своего последующего запуска - добавляет полный путь к файлу dec25.exe в ключ run секции [windows]: [windows] run=%SystemDir%\dec25.exe) Следует так же отметить, что в файле system.ini кроме секции [boot] вредоносные программы могут использовать секцию [Drivers] Вредоносные программы могут вносить изменения в следующие ветки реестра: o HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion в ключи Run, RunOnce, RunOnceEx, RunServices, RunServicesOnce - для того чтобы система запускала созданные червем файлы o HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion в ключ Run. Например, Email-Worm.Win32.Bagle.ax после запуска копирует себя в системный каталог Windows, после чего регистрирует в реестре скопированный файл: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run "Sysformat"="%System%\sysformat.exe o HKEY_CLASSES_ROOT\exefile\shell\open\command Например вирус I-Worm.Navidad. вносил следующие изменения: HKEY_CLASSES_ROOT\exefile\shell\open\command {Default} = %SystemDir%\wintask.exe %1 %*) Таким образом запуск всех ехе-файлов проходил через обращение к инфицированному файлу wintask.exe. В результате, если файл wintask.exe удалялся до правки реестра, операционная система теряла возможность запускать файлы с расширением .exe. o HKEY_CLASSES_ROOT\txtfile\shell\open\command Например Email-Worm.Win32.LovGate.ad изменяет ключ системного реестра HKCR\txtfile\shell\open\command {default}="Update_OB.exe %1", таким образом, чтобы при открытии текстовых файлов получать управление. Кроме выше перечисленных ветвей и ключей реестра вредоносные программы могут вносить изменения и в другие ветки и ключи реестра, например: o o o o o o HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WOW\boot HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\WinLogon HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug Устранение последствий заражения В связи с тем что, что черви практически не используют технологии шифрования и метаморфизма для маскировки своих копий, борьба с ним вручную несколько упрощается и сводится к следующему алгоритму действий: 1. Анализ и выявление с помощью Диспетчера задач Windows подозрительных процессов 2. Анализ открытых портов с помощью команды Netstat 3. Выгрузка подозрительных процессов 4. Анализ реестра с помощью утилиты Regedit.exe в выше перечисленных ветках и ключах 5. Восстановление и правка ключей реестра 6. Поиск инфицированных файлов по имени на основе данных анализа процессов операционной системы и данных анализа реестра 7. Удаления или замена инфицированных файлов 8. Перегрузка системы Контрольный анализ процессов, ключей реестра, открытых портов. Если подозрительных процессов не обнаружено, ключи реестра не изменились, значит, процедуру дезинфекции компьютера можно считать успешной, в противном случае алгоритм придется повторить. Тем не менее, учитывая тот факт, что современные черви могут использовать технологии присущие вирусам, устанавливать backdoor-компоненты, затрудняя, тем самым, процедуру анализа и обнаружения своих файлов, для полной уверенности компьютер после дезинфекции вручную настоятельно рекомендуется осуществить проверку антивирусным средством. Следует также отметить, что бороться вручную с вредоносными программами можно только постфактум - после того, как они поразили компьютер, в то же время использование антивирусного программного обеспечения в подавляющем большинстве случаев не допустит активации вредоносной программы на компьютере. Задание 1. Запустите Диспетчер задач Windows и проанализируйте список запущенных процессов, нагрузку, которую они оказывают на ЦП. Запишите в протокол лабораторной работы название подозрительных процессов. Объясните, на основании чего были сделаны такие выводы. 2. Используя Диспетчер задач Windows выгрузите подозрительные процессы. 3. Запустите интерфейс командной строки Windows. Ознакомьтесь с ключами команды netstat. Получите статистку текущих сетевых подключений Вашего компьютера с параметрами отображение всех подключений и ожидающих портов, отображение последовательности компонентов участвующих в создании подключения, отображение исполняемого файла, участвующего в создании каждого подключения, или слушающего порт. Сохраните статистику в файл с названием netstat.log. Запишите протокол лабораторной работы формат команды для этого действия. Проанализирует данные netstat.log. Запишите в протокол лабораторной работы подозрительные открытые порты и приложения их использующие. Объясните, на основании чего были сделаны такие выводы. 4. Запустите утилиту работы с реестром Windows. Проанализируйте содержимое перечисленных в теоретической части веток и ключей реестра. 5. При необходимости внесите изменения в параметры ключей с целью удалить подозрительные записи, созданные вредоносной программой. Запишите в протокол лабораторной работы все внесенные изменения. 6. Проанализируйте содержание файла win.ini на предмет подозрительных записей. При необходимости внесите корректировки в файл win.ini. Запишите в протокол лабораторной работы вносимые корректировки. 7. Проанализируйте файл system.ini на предмет подозрительных записей. При необходимости внесите корректировки в файл system.ini. Запишите в протокол лабораторной работы вносимые корректировки 8. Используя стандартные средства поиска, найдите файлы, которые порождали подозрительные процессы и удалите их. Запишите в протокол лабораторной работы имена этих файлов. 9. Перегрузите компьютер, выполните пункты 1-6, чтобы убедиться, что удаление вредоносной программы прошло успешно, в оперативной памяти нет подозрительных процессов, ключи реестра не изменились, на компьютере отсутствуют подозрительно открытые порты. Контрольные вопросы 1. Объясните в чем разница между шифрованным и полиморфным вирусом? 2. Достаточно ли для защиты от заражения вредоносной программой установить файлам разрешения только для чтения? Обоснуйте ответ. 3. Объясните в чем отличие понятий вирус и вредоносная программа. Лабораторная работа № 9. Антивирус Касперского 6.0 для Windows Workstations Цель работы Ознакомиться с процессом инсталляции, принципами работы и управлением Антивирусом Касперского для Windows Workstations на операционных системах Microsoft Windows XP Professional или Microsoft Windows 2000 Professional. Ход работы 1. Изучить процесс установки Антивируса Касперского 6.0 для Windows Workstations 2. Ознакомиться с назначением Антивируса Касперского 6.0 для Windows Workstations и функциями данного приложения 3. Ознакомиться с основными принципами работы приложения Антивирус Касперского 6.0 для Windows Workstations (компонентами защиты, задачами) 4. Ознакомиться с интерфейсом Антивируса Касперского 6.0 для Windows 5. Выполнить задания к лабораторной работе 6. Защитить лабораторную работу, ответив на контрольные вопросы Методические указания к лабораторной работе Антивирус Касперского для Windows Workstations - это программный продукт, предназначенный для комплексной защиты рабочей станции от угроз связанных с работой в локальных вычислительных сетях и в интернет. Продукт предназначен для защиты рабочих станций в корпоративной сети под управлением Kaspersky Administration Kit. При необходимости, Антивирус Касперского для Windows Workstations может работать автономно, в отсутствие сервера управления, без ограничения функций защиты. Продукт объединяет функциональность антивируса, брандмауэра, антиспама и антибаннера и обеспечивает защиту компьютера пользователя от следующих угроз: Вирусов Вредоносных и потенциально опасных программ Сетевых атак Интернет мошенничества Нежелательной интернет рекламы Спама Для выполнения поставленных задач, в продукте реализованы следующие функции: Защита файловой системы в режиме реального времени - перехватываются все операции с файлами на жестких, сменных и сетевых дисках. Объекты, с которыми выполняются операции, проверяются на наличие вредоносного кода Защита электронной почты в режиме реального времени - проверяются все входящие и исходящие электронные письма по протоколам POP3, SMTP, IMAP, NNTP; обеспечивается защита от нежелательных почтовых сообщений (спама) Защита при работе в интернет - проверка ННТР трафика, блокировка выполнения опасных скриптов (при помощи поведенческого блокиратора), блокировка рекламных баннеров и всплывающих окон, защита от фишинг-атак Контроль активности приложений - поведенческий блокиратор позволяющий противодействовать заражению и распространению еще не внесенных в базы вирусов и других вредоносных программ. Дополнительно обеспечивается защита системного реестра, контроль целостности приложений и блокировка опасных VBA скриптов Контроль сетевых соединений - Антивирус Касперского для Windows Workstations выполняет функции персонального брандмауэра, позволяет контролировать все сетевые соединения и фильтровать сетевые пакеты согласно установленным пользователем правилам Защита от сетевых атак - ведется постоянный мониторинг и анализ сетевой активности компьютера пользователя. В случае выявления сетевой активности классифицируемой как атака, атакующий компьютер блокируется на определенный период времени Поиск вирусов - приложение позволяет по требованию пользователя или по расписанию осуществлять поиск вирусов среди стандартных, или указанных пользователем объектов на жестких, сменных и сетевых дисках, а также в оперативной памяти компьютера Обновление сигнатур угроз - для обеспечения эффективной защиты от новых типов вирусов производится регулярное обновлений антивирусных баз, адресов потенциально опасных интернет ресурсов и сигнатур сетевых атак. Новая технология позволяет существенно уменьшить размер обновлений и тем самым уменьшить время их загрузки Аварийная проверка системы - Антивирус Касперского для Windows Workstations предоставляет возможность создавать диски аварийной проверки, которые, в случае потери работоспособности системы в результате вирусной атаки, позволяют выполнить проверку и лечение компьютера Установка Перед началом установки необходимо убедиться, что параметры операционной системы соответствуют системным требованиям Антивируса Касперского для Windows Workstations и установка производится под учетной записью обладающей правами администратора. В случае невыполнения этих условий мастер установки выдает сообщение об ошибке, и установка прерывается. Одновременная работа Антивируса Касперского для Windows Workstations c другими антивирусами и брандмауэрами может привести к возникновению ошибок, снижению производительности или полной потере работоспособности операционной системы. Дистрибутив продукта доступен в виде инсталляционного файла в формате Microsoft installer - например, kav6ws.ru.msi. Где "kav" - аббревиатура названия продукта Kaspersky Anti-Virus, "6" - версия, "ws" - тип систем, для которых предназначен продукт (Workstations), "ru" - язык интерфейса. При исполнении файла kav6ws.ru.msi, запускается мастер установки приложения, и появляется окно приветствия. Для продолжения установки нужно нажать кнопку Далее. При нажатии кнопки Отмена установка будет прервана. В случае если установка выполняется на компьютер под управлением Microsoft Windows ХР Service Pack 2 с включенным брандмауэром Windows, необходимо выбрать режим взаимодействия Антивируса Касперского для Windows Workstations с брандмауэром: Отключить сетевой экран Microsoft Windows - при выборе этого пункта брандмауэр Windows будет автоматически отключен, и контроль всех сетевых соединений будет выполняться средствами Антивируса Касперского для Windows Workstations Использовать сетевой экран Microsoft Windows - в этом режиме контроль сетевых соединений выполняется брандмауэром Windows. При этом по умолчанию компонент Анти-Хакер будет отключен После окончания копирования файлов открывается окно с сообщением об успешном завершении установки. Далее необходимо произвести предварительную настройку установленного продукта. Для перехода к этапу предварительной настройки следует нажать кнопку Далее. Результат установки После успешно завершенной установки на компьютере пользователя появляется папка Program Files\Kaspersky Lab\Kaspersky Ati-Virus for Windows Workstations\, - которая содержит файлы и программные модули антивируса, а также используемые файлы графической оболочки (каталог Skin) и каталог с сопутствующей документацией (Doc) Также в процессе установки создается папка: Documents and Settings\All Users\Application Data\Kaspersky Lab\AVP6\ для Microsoft Windows 2000/XP Windows\All Users\Application Data\Kaspersky Lab\AVP6\ для Microsoft Windows 98/ME WINNT\All Users\Application Data\Kaspersky Lab\AVP6\ для Microsoft Windows NT с подкаталогами, в которых хранятся: файлы, помещенные в Резервное хранилище (каталог Backup) антивирусные базы (Bases) пользовательские настройки (каталог Data) служебные файлы компонента Проактивная защита (PdmHist) файлы Карантина (Quarantine) отчеты (Reports) служебные файлы компонентов продукта (Dskm) В реестр Windows в процессе установки Антивируса Касперского для Windows Workstations вносится ветвь HKLM\SOFTWARE\KasperskyLab\. В каталог операционной системы Windows\System32\drivers\ (или Winnt\System32\drivers\) устанавливаются драйвера: kl1.sys - отвечает за перехват сетевого трафика klick.sys - вспомогательный драйвер kl1.sys, обеспечивает перехват пакетов сетевого уровня klin.sys - вспомогательный драйвер kl1.sys, обеспечивает перехват пакетов транспортного уровня klop.sys - вспомогательный драйвер kl1.sys, отслеживает использование лицензионных ключей в локальной сети klif.sys - осуществляет перехват файловых операций Для Microsoft Windows NT-подобных операционных систем дополнительно в реестр вносятся ветви, отвечающие за параметры запуска службы Kaspersky Anti-Virus 6.0 и драйверов kl1.sys и klif.sys. Одноименные ветви создаются в HKLM\SYSTEM\CurrentControlSet\Services. Также в реестре в список программ автозапуска добавляется ключ AVP со значением C:\Program Files\Kaspersky Lab\Kaspersky Anti-Virus 6.0 for Workstation\avp.exe. В список локальных служб добавляется служба Kaspersky Anti-Virus 6.0 запускаемая автоматически под системной учетной записью. Исполняемый файл службы avp.exe с ключом -r При запуске продукта запускается два процесса avp.exe. Один из них запущен от имени системы и отвечает службе Kaspersky Anti-Virus 6.0, второй от имени пользователя это процесс интерфейса. В контекстном меню файлов и папок появляется пункт Проверить на вирусы, с помощью которого можно запустить задачу проверки по требованию выбранного объекта. В главное меню Windows в раздел Программы добавляется папка Антивирус Касперского для Windows Workstations, в которой находятся: Ярлык для запуска продукта Ярлык для запуска мастера установки Антивируса Касперского для Windows Workstations Ярлык для доступа к справочной системе Антивируса Касперского для Windows Workstations Ссылка на лицензионное соглашение Ссылка на официальный сайт Лаборатории Касперского На системной панели Windows появляется значок антивируса, с помощью которого пользователь может открыть графический интерфейс продукта. Значок также является индикатором состояния Антивируса Касперского для Windows Workstations. Также надпись Антивирус Касперского 6.0 и значок продукта отображаются в правом верхнем углу экрана при запуске системы, показывая, что система находится под защитой Антивируса Касперского для Windows Workstations. Принципы работы программы Антивирус Касперского для Windows Workstations - это новое программное решение, объединяющее опыт всех предыдущих разработок Лаборатории Касперского. Продукт состоит из базового модуля, который выполняет функции антивирусного сканера, и набора опциональных компонентов, обеспечивающих всю остальную функциональность продукта. Базовый модуль устанавливается в любой конфигурации и состоит из антивирусного сканера и модуля загрузки приложений. Компоненты антивируса являются независимыми единицами и могут быть установлены в произвольных сочетаниях. С точки зрения выполняемых функций, компоненты Антивирус Касперского для Windows Workstations обеспечивают защиту компьютера в режиме реального времени. Компоненты Файловый Aнтивирус - обеспечивает защиту файловой системы путем перехвата файловых операций и проверки содержимого файлов, к которым происходит обращение Почтовый Aнтивирус - осуществляет проверку входящих и исходящих сообщений электронной почты Веб-Антивирус - осуществляет проверку НТТР трафика и контроль запускаемых скриптов при помощи поведенческого блокиратора Проактивная защита - поведенческий блокиратор, осуществляющий контроль активности приложений, проверку запускаемых VBA-макросов, защиту реестра и контроль целостности приложений В совокупности с задачами проверки по требованию и обновления Файловый Антивирус, Почтовый Антивирус, Веб-Антивирус и Проактивная защита обеспечивают антивирусную защиту компьютера Анти-Шпион - обеспечивает защиту от фишинг-атак, несанкционированного подключения к платным сайтам и блокирование нежелательной рекламной информации при работе в интернет Анти-Хакер - персональный брандмауэр, контролирует сетевые соединения согласно установленным пользователем правилам, обнаруживает и блокирует сетевые атаки Анти-Спам - обеспечивает защиту от нежелательной электронной почты Каждому компоненту соответствует отдельная группа настроек, согласно которым компонент функционирует. Параметры общие для всех компонентов вынесены в группу настроек Защита. Распределение функций компонентов защиты по информационным потокам выглядит следующим образом: Поток Компонент Гибкие носители Файловый Антивирус Сетевые ресурсы Файловый Антивирус Анти-Хакер Электронная почта Почтовый Антивирус Анти-Спам Интернет Файловый Антивирус Веб-Антивирус Анти-Шпион Анти-Хакер Дополнительно Проактивная защита и Файловый Антивирус обеспечивают контроль активности приложений и проверку всех файлов, к которым происходит обращение. Задачи Инструментом для реализации функций базового модуля являются задачи двух типов: Задачи проверки по требованию - служат для поиска и обнаружения вирусов на жестких, сменных и сетевых дисках Задачи обновления - выполняют загрузку сигнатур угроз (в частности антивирусных баз) и обновление модулей приложения с серверов Лаборатории Касперского Задачи, которые создаются при установке приложения, называются системными, и не могут быть переименованы или удалены пользователем. Созданные дополнительно задачи называются пользовательскими. Системные задачи проверки по требованию (5 задач) Поиск вирусов - задача-шаблон, используемая для создания пользовательских задач проверки по требованию Критические области - задача проверки системной памяти, загрузочных секторов дисков, объектов автозапуска, а также наиболее критичных областей операционной системы Мой компьютер - задача полной проверки компьютера Объекты автозапуска - задача проверки системной памяти, объектов автозапуска и загрузочных секторов дисков. Выполняется сразу после загрузки операционной системы Проверка карантина - задача проверки объектов находящихся на карантине, проводится после обновления антивирусных баз для уточнения статуса подозрительных объектов Все системные задачи проверки по требованию выполняют одну и ту же функцию проверки объектов при помощи сигнатурного и эвристического анализа. Системные задачи обновления Обновление сигнатур угроз и модулей приложения - задача, выполняющая загрузку новых версий антивирусных баз, антиспамовых баз, списков потенциально опасных интернет ресурсов, сигнатур сетевых атак и модулей приложения с серверов обновления Лаборатории Касперского. Может выполнять копирование сигнатур угроз и модулей приложения в указанный локальный или сетевой каталог для ретрансляции обновлений в пределах локальной сети. Откат обновления - задача отката к предыдущей версии сигнатур угроз. Используется в случае, если новая версия сигнатур приводит к сбоям в работе приложения или ложным срабатываниям Пользовательские задачи Пользователь может дополнительно создать до четырех задач проверки по требованию, а также не более двух задач обновления. Пользовательские задачи обновления, могут быть только задачами обновления сигнатур угроз и модулей приложения. Пользовательскую задачу отката обновлений создать нельзя. Проверка по требованию Задачи проверки по требованию используются для проверки объектов находящихся на жестких, сменных и сетевых дисках, а также в оперативной памяти компьютера. Целью таких проверок является обезвреживание вирусов и других вредоносных программ, которые каким либо образом были занесены в память компьютера (например, в то время как компоненты защиты были отключены). Выявление вирусов, при проверке по требованию, осуществляется с помощью сигнатурного и эвристического анализа. Системные задачи проверки по требованию не могут быть удалены или переименованы пользователем. Пользовательские задачи ограничений в настройке не имеют. Всего существует пять системных задач проверки по требованию: Поиск вирусов - задача шаблон предназначена для создания пользовательских задач проверки по требованию Критические области - задача проверки оперативной памяти, объектов автозапуска, загрузочных секторов, а также наиболее критичных областей операционной системы Мой компьютер - задача полной проверки компьютера Объекты автозапуска - задача проверки системной памяти, объектов автозапуска и загрузочных секторов дисков Проверка карантина - задача проверки объектов находящихся на карантине, проводится после обновления антивирусных баз для окончательного определения статуса подозрительных объектов Файловый антивирус Файловый Антивирус является наиболее важным из компонентов антивирусной защиты. Этот компонент обеспечивает перехват всех файловых операций и проверку содержимого файлов, к которым происходит обращение в режиме реального времени. Проверка файлов осуществляется так же, как при работе задач проверки по требованию - с помощью сигнатурного и эвристического анализа. Для уменьшения загрузки системы в работе Файлового Антивируса также используются технологии iSwift и iChecker. Почтовый антивирус Почтовый Антивирус это компонент обеспечивающий проверку входящих и исходящих сообщений электронной почты. Почтовый Антивирус перехватывает и проверяет все письма, которые принимает или отправляет пользователь по протоколам POP3, SMTP, IMAP и NNTP. Объектами проверки Почтового Антивируса являются тело письма и вложенные в письмо файлы. Также как и Файловый Антивирус, Почтовый Антивирус для проверки письма на наличие вирусов использует сигнатурный и эвристический анализ. Веб-Антивирус Компонент Веб-Антивирус обеспечивает антивирусную защиту компьютера пользователя во время работы в интернет. Веб-Антивирус состоит из двух элементов: Проверка НТТР трафика - обеспечивает перехват, буферизацию и проверка загружаемой информации (файлов, НТML-страниц) по НТТР протоколу на наличие вирусов с помощью сигнатурного и эвристического анализа Проверка скриптов - поведенческий блокиратор. При передаче скриптов на выполнение Windows Scripting Host, элемент Проверка скриптов автоматически проверяет скрипты, принимает решение об опасности того или иного скрипта, и блокирует выполнение опасных Проактивная защита Проактивная защита - это средство противодействия еще не внесенным в базы вредоносным программам. Механизм действия Проактивной Защиты опирается на анализ последовательности действий выполняемых приложениями и процессами. По каждому выполняемому действию, на основе разрешающих и запрещающих правил, принимается решение о том, является ли действие приложения опасным. Опасные действия в соответствии с настройками Проактивной защиты могут быть заблокированы или предоставлены на рассмотрение пользователю. Кроме блокирования, Проактивная защита позволяет откатить некоторые из действий приложений (например, изменение значений системного реестра, создание и изменение файлов). Помимо анализа поведения приложений и процессов Проактивная защита контролирует исполнение VBA-макросов. В зависимости от настроек опасные VBA-макросы блокируются, или открывается всплывающее окно, запрашивающее действие у пользователя. Компонент Проактивная защита реализован в виде четырех независимых элементов, остановка и запуск которых может выполняться отдельно: Анализ активности приложений Контроль целостности приложений Мониторинг реестра Проверка VBA-макросов Для операционных систем Microsoft Windows 98/Me доступен только один элемент Проактивной защиты - Проверка VBA-макросов Анти-Шпион Анти-Шпион - это компонент, который обеспечивает блокирование нежелательной рекламной информации при работе в интернет (баннеры, всплывающие окна), защиту от фишинговых атак и несанкционированного подключения к платным интернет ресурсам. Анти-Шпион состоит из четырех независимых элементов: Анти-Фишинг - обеспечивает защиту от фишинговых атак Анти-Реклама - блокирует всплывающие окна Анти-Баннер - блокирует рекламные баннеры Анти-Дозвон - блокирует попытки дозвона на платные номера Для операционных систем Microsoft Windows 98/Me элемент Анти-Дозвон будет недоступен Анти-Хакер Компонент Анти-Хакер - это персональный брандмауэр. В его функции входит контроль сетевых соединений в соответствии с установленными правилами и защита от сетевых атак. Анти-Хакер состоит из двух элементов: Сетевой экран - обеспечивает контроль сетевых соединений Система обнаружения вторжений - отвечает за обнаружение и защиту от сетевых атак Анти-Спам Анти-Спам - это компонент, который служит для защиты пользователя от нежелательной электронной почты, т.е. от спама. Анти-Спам проверяет все входящие письма и, на основе комплексного критерия, определяет, является ли письмо спамом. В результате работы Анти-Спама письму может быть присвоен статус: Спам - письма, которые наверняка являются спамом Потенциальный спам - письма вероятно являющиеся спамом Не спам - письма не являющиеся спамом Для определения статуса письма, используются следующие критерии в перечисленном порядке: Проверка на основе "белых" списков. Если отправитель письма содержится в списке разрешенных адресов, или в тексте письма содержится хотя бы одна разрешенная фраза, письмо получает статус не спам, независимо от других критериев Проверка на основе "черных" списков. Если отправитель письма содержится в списке запрещенных отправителей, или в тексте письма содержится определенное количество запрещенных фраз, письмо получает статус спам После проверки на основе списков, выполняется проверка на фишинг. Если текст письма содержит ссылки на фишинг сайты, письму присваивается статус спам (более подробно понятие фишинг-атак было рассмотрено в разделе "АнтиШпион") Далее применяются такие технологии фильтрации как самообучающийся алгоритм Байеса (анализ текста письма), анализ изображений и анализ заголовков. На последнем этапе используются дополнительные критерии определения спама по структуре почтового сообщения Технологии iChecker(tm) и iSwift(tm) Технологии iChecker и iSwift используются для уменьшения времени проверки файлов на наличие вредоносного кода, без снижения эффективности проверки. Сокращение времени проверки достигается за счет того, что файлы, которые не изменились с момента последней проверки, в течение некоторого времени не подвергаются повторной проверке. Период времени, в который файл не будет проверяться, вычисляется по специальному алгоритму, разработанному в Лаборатории Касперского. В некотором приближении, можно говорить, что время исключения файла из проверки пропорционально времени наблюдения файла (т.е. времени между первой и последней его проверками). Разница между технологиями iChecker и iSwift заключается в способе определения, изменялся ли данный файл с момента последней проверки или нет: При первой проверке файла, iChecker записывает в специальную базу данных время выпуска сигнатур угроз использовавшихся при проверке и контрольную сумму проверенного файла. Технология iSwift, также использует другую базу, при создании которой используются особенности файловой системе NTFS (соответственно iSwift работает только на NT-подобных операционных системах) Обновления сигнатур угроз и модулей приложения Сигнатурные методы обнаружения вирусов являются наиболее точными и эффективными, однако, для поддержания этой эффективности, крайне необходимо наличие актуальных антивирусных баз. Поэтому обновление антивирусных баз является одной из самых критичных задач обеспечения антивирусной безопасности. Учитывая частоту появления новых вирусов и высокую скорость их распространения, действительно эффективным сигнатурный метод становится только в случае оперативного выпуска сигнатур этих вирусов и доставки сигнатур на защищаемые компьютеры. Кроме сигнатур могут доставляться также измененные модули антивирусных продуктов: для исправления критических ошибок, для внедрения новых алгоритмов обнаружения и т.д. Именно этот процесс доставки и установки сигнатур и модулей называется обновлением. Обновление - это мероприятие по загрузке и установке наиболее свежих версий антивирусных баз и модулей приложений Интервал между появлением нового вируса и доставкой на клиентские компьютеры сигнатуры этого вируса зависит от двух факторов: Времени реакции на появление вируса компании-разработчика Параметров работы системы обновления В отношении реакции на появление новых вирусов Лаборатория Касперского является одним из лидеров в антивирусной индустрии, что выражается в ежечасном размещении на серверах компании обновлений сигнатур угроз. Веб-Антивирус, Проактивная защита, Анти-Шпион, Анти-Спам и Система обнаружения вторжений также используют специальные базы при осуществлении функций защиты. Все базы данных Антивируса Касперского для Windows Workstations, используемые для выявления опасных объектов, объединены в единую базу - сигнатуры угроз. Лаборатория Касперского выпускает три набора сигнатур угроз (антивирусных баз): Стандартный - набор антивирусных баз, достаточный для обнаружения и лечения (в тех случаях, когда это возможно) всех известных на момент выпуска вредоносных программ (вирусов, троянов, червей) Расширенный - включает в себя стандартный набор, а также базы для обнаружения таких потенциально нежелательных программ, как рекламные (adware), шпионские (spyware) и другие модули Параноидальный - по сравнению с расширенным набором содержит также базы для обнаружения хакерских утилит Стандартный набор используется всегда, дополнительные базы расширенного набора используются при включении опции Шпионское, рекламное ПО, программы скрытого дозвона, а параноидальный - при дополнительном включении опции Потенциально опасное ПО (riskware). Задачи обновления делятся на два типа: Задачи обновления сигнатур угроз и модулей приложения - назначение задачи следует из ее названия - обновление сигнатур угроз, для обеспечения эффективной работы Антивируса Касперского для Windows Workstations, а также обновление модулей продукта, для устранения ошибок и расширения функционала Откат обновления - задача отката к предыдущей версии сигнатур угроз. Используется в случае, если новая версия сигнатур приводит к сбоям в работе приложения или ложным срабатываниям Сами антивирусные базы хранятся в папке Documents and Settings\All Users\Application Data\Kaspersky Lab\AVP6\Bases. Источник обновлений Источником обновлений могут выступать: Сервера обновлений Лаборатории Касперского - в этом случае обновление происходит по протоколам HTTP/FTP Сервер Администрирования - в качестве источника обновления выступает Сервер администрирования, само обновление осуществляется средствами Агента администрирования HTTP-, FTP-сервер или сетевой каталог - источником является задаваемый сетевой ресурс, HTTP, FTP либо UNC Настроить параметры доступа к сетевым HTTP/FTP ресурсам можно, нажав кнопку Параметры LAN. По нажатию открывается окно Настройка параметров LAN, в котором предлагается указать режим доступа к FTP-ресурсам (пассивный либо активный), тайм-аут соединения (промежуток ожидания ответа на запрос к серверу), а также задать параметры настройки доступа к прокси-серверу. Обновляемые компоненты Ниже приведена таблица с описанием баз, которые используются различными компонентами Антивируса Касперского для Windows Workstations . Компонент Поиск вирусов Файловый Антивирус Почтовый Антивирус Используемая база Антивирусная база - предназначена для проверки файлов с помощью сигнатурного анализа. Включает сигнатуры угроз вирусов, троянских и других вредоносных программ Веб-Антивирус (при проверке с буферизацией) Веб-Антивирус (при пото- Специальная сокращенная антивирусная база, содержащая ковой проверке) сигнатуры вредоносных программ предназначенные для потоковой проверки. Проактивная защита (Анализ активности приложений) Критерии выявления опасной и подозрительной активности, а также подозрительных значений в реестре Анти-Шпион (АнтиФишинг) Список адресов фишинг-сайтов Анти-Шпион (АнтиБаннер) Список масок запрещенных баннеров Анти-Хакер (Система обнаружения вторжений) Сигнатуры сетевых угроз Анти-Спам База контрольных сумм изображений, которые являются спамом. При выполнении задачи обновления, новая версия сигнатур может быть загружена с серверов Лаборатории Касперского или из локального каталога. Новая технология обновления сигнатур угроз используемая в Антивирусе Касперского для Windows Workstations позволяет существенно уменьшить объем загружаемой информации. Уменьшение объема обновления достигнуто за счет того, что при обновлении загружается не полный набор сигнатур угроз, а разница между сигнатурами угроз на компьютере пользователя, и на сервере обновления Откат обновления антивирусных баз Откат обновления антивирусных баз необходим в двух случаях. Во-первых, если новые базы и обновления сканирующего ядра вызывают сбои в работе Антивируса Касперского или всей системы в целом. Во-вторых, если с новыми базами заведомо чистая программа обнаруживается как вирус. Работа с инфицированными и подозрительными объектами Во избежание потери важной информации, перед выполнением каких бы то ни было действий с зараженными объектами, будь то попытка лечения или удаление, они помещаются в специальное Резервное хранилище, откуда по необходимости могут быть извлечены. Отдельный статус подозрительных объектов - не зараженных, а лишь подозреваемых в инфицировании, предполагает выделение для них отдельного хранилища - Карантина и периодических проверок этого хранилища с целью определения окончательного статуса файлов при помощи новых наборов антивирусных баз. Во избежание заражения инфицированными и подозрительными объектами, все помещаемые на Карантин и в Резервное хранилище файлы шифруются и, таким образом, перестают быть запускаемыми, в таком же виде объекты отправляются на исследование в Лабораторию Касперского. Задание 1. Установите локально Антивирус Касперского 6.0 для Windows Workstations на рабочую станцию. Место расположения дистрибутива и ключевого файла уточните у преподавателя. 2. Убедитесь, что установка Антивируса Касперского 6.0 для Windows Workstations прошла успешно, а компоненты защиты автоматически запустились при старте операционной системы. Запишите в протокол лабораторной работы, какие службы добавились, и какие процессы и задачи запускаются при старте Антивируса Касперского 6.0 для Windows Workstations. 3. Откройте интерфейс Антивируса Касперского 6.0 для Windows Workstations и ознакомьтесь с интерфейсом. 4. В корне диска С: создайте папку test_virus и скопируйте в нее содержимое аналогичной папки с компьютера преподавателя. Убедитесь, что зараженные объекты (вирус EICAR) блокируются. 5. Удалите содержимое папки test_virus на вашем компьютере, включите проверку архивов Файловым антивирусом и повторите копирование. Убедитесь в том, что зараженные архивы также не могут быть скопированы. 6. Протестируйте работу Доверенной зоны. Для этого отключите проверку Сетевых дисков в Файловом антивирусе, затем внесите папку c:\test_virus в Доверенную зону и повторите копирование зараженных файлов с сетевого ресурса. Убедитесь, что копирование прошло успешно. 7. Изучите работу Проактивной защиты. Для этого откройте соответствующее окно настроек Антивируса Касперского, нажмите Настройка в разделе Анализ активности приложений и включите отслеживание запуска браузера с параметром. 8. Нажмите Пуск, Выполнить, в строке Открыть введите "%SystemDrive%\Program Files\Internet Explorer\IEXPLORE.EXE" www.kaspersky.ru и нажмите кнопку ОК, для имитации запуска браузера с параметром сторонним приложением. Запишите результаты в протокол лабораторной работы 9. Включите Мониторинг системного реестра, и проверьте работу правил, отвечающих за автоматический запуск программ при загрузке операционной системы. Такой контроль позволяет заблокировать автозапуск вредоносных программ при старте системы, путем внесения соответствующего ключа в реестр. 10. Откройте редактор реестра regedit, и найдите ветвь HKLM\Software\Microsoft\Windows\CurrentVersion\Run\AVP6. Попробуйте уда- лить ветвь и убедитесь, что это невозможно. Внесите в протокол работы полученные сообщения 11. Откройте и самостоятельно изучите интерфейс компонента Анти-Хакер. 12. Протестируйте работу Системы обнаружения вторжений с помощью утилиты kltps.exe. Для продолжения лабораторной работы разбейтесь по парам. Сначала первые номера будут имитировать сетевую атаку компьютеров вторых номеров, затем атаку на компьютеры первых номеров выполнят вторые номера. 13. Первые номера. Создайте в корне диска С:\ папку test и скопируйте в нее утилиту kltps.exe (местоположение утилиты уточните у преподавателя). В главном окне интерфейса Антивируса Касперского для Windows Workstations обратите внимание на секцию статус на панели результатов Анти-Хакера. Убедитесь, что Система обнаружения вторжений работает 14. В окне настройки Анти-Хакера в секции Система обнаружения вторжений уберите отметку с пункта Включить систему обнаружения вторжений и нажмите Применить. Нажмите Пуск, Выполнить. Наберите строку C:\test\kltps.exe 192.168.0.1 80 (здесь следует указать, IP адрес компьютера второго номера Вашей пары ) в поле Открыть окна Запуск программы и нажмите ОК. 15. Вторые номера. Убедитесь, что попытка атаки, выполненная с компьютера первого номера Вашей пары, зарегистрирована системой обнаружения вторжений на Вашем компьютере, открылось всплывающее окно с сообщением о блокировании атаки 16. Вернитесь к окну интерфейса Антивируса Касперского для Windows Workstations. Убедитесь, что счетчик заблокированных атак в блоке Статистика равен 1 17. Поменяйтесь местами и повторите действия, начиная с п.13. 18. Настройте задачу Обновление для обновления из источника, указанного преподавателем и запустите ее. Опишите в протоколе лабораторной работы, какие изменения произошли в папке Documents and Settings\All Users\Application Data\Kaspersky Lab\AVP6\Bases после успешного завершения задачи обновления. 19. Выполните задачу Откат обновления антивирусных баз. Опишите в протоколе лабораторной работы, какие изменения произошли в папке Documents and Settings\All Users\Application Data\Kaspersky Lab\AVP6\Bases после успешного завершения задачи Откат обновления антивирусных баз. 20. Создайте задачу проверки по требованию папки Program Files с включенными технологиями iChecker(tm) и iSwift(tm). Выполните созданную задачу 3 раза подряд, каждый раз фиксируя время выполнения в таблице. 21. Создайте пользовательскую задачу проверки по требованию папки Program Files с выключенными технологиями iChecker(tm) и iSwift(tm). Выполните созданную задачу 3 раза подряд, каждый раз фиксируя время выполнения в таблице. 22. Проанализируйте полученные результаты. Есть ли разница? В чем она заключается? Как можно ее объяснить? 23. Создайте на своем компьютере папку test_virus1. Скопируйте в нее по одному файлу содержимое папки test_virus (ее местоположение уточните у преподавателя), не отключая системную Файловый Антивирус. Перечислите в протоколе лабораторной работы, какие файлы удалось скопировать и объясните почему. 24. Создайте на диске C: своего компьютера папку с названием test_virus4. Скопируйте в нее содержимое папки test_virus2, не отключая постоянную защиту. Месторасположение папки test_virus2 уточните у преподавателя. Опишите в протоколе лабораторной работы, какие изменения необходимо произвести в настройках Файлового Антивируса, для того чтобы скопировать все файлы, которые содержатся в папке test_virus2, без изменений в папку test_virus4. 25. Создайте пользовательскую задачу проверки по требованию папки test_virus2 и запустите ее. В окне Пожалуйста, введите пароль в поле Пароль введите "1" и нажмите ОК. По окончании проверки произведите обработку обнаруженных зараженных объектов. Ознакомьтесь с отчетом выполненной задачи, содержимым карантина и резервного хранилища. Опишите, по каким признакам найденные инфицированные и подозрительные файлы помещаются в карантин и в резервное хранилище, перечислите в протоколе лабораторной работы, какие действия возможны над объектами, помещенными в карантин, и над объектами, помещенными в резервное хранилище. 26. Экспортируйте отчет задачи проверки по требованию папки test_virus2 в файл, ознакомьтесь с получившимся файлом. Перечислите в протоколе лабораторной работы, в файлах каких форматов может быть сохранен файл отчета. 27. Не останавливая службу Антивируса Касперского 6.0 для Windows Workstations, измените системную дату на своем компьютере на 2 года вперед. Опишите в протоколе лабораторной работы, какие изменения произойдут с Антивирусом Касперского 6.0 для Windows Workstations после изменения системной даты и истечения срока действия лицензионного ключа. Контрольные вопросы 1. Какие варианты установки лицензионного ключа существуют в Антивирусе Касперского 6.0 для Windows Workstations? 2. Объясните принципы работы компонента Анти-Хакер. 3. Опишите приоритезацию правил в Анти-Хакере. 4. Что такое доверенная зона? Чем она отличается от Локальной сети? 5. Какие компоненты защиты будут установлены в Антивирусе Касперского 6.0 для Windows Workstations по умолчанию? 6. Существует ли в Антивирусе Касперского для Windows Workstations возможность защиты настроек от изменения пользователем? Если да, то каким образом? 7. Какое количество резервных копий антивирусных баз сохраняется в Антивирусе Касперского 6.0 для Windows Workstations? 8. В чем разница между технологиями iChecker(tm) и iSwift(tm)? 9. Какие типы архивов проверяются Файловым антивирусом? 10. Какие модули содержит компонент Проактивная защита? Каково их назначение? 11. Какие модули содержит компонент Анти-Шпион? Какого их назначение? 12. Какие протоколы поддерживаются Почтовым антивирусом? 13. Какие типы архивов могут проверяться и лечиться задачей проверки по требованию? 14. Какими правами необходимо обладать, что бы иметь возможность восстанавливать файлы из карантина? 15. У Вас имеется архив содержащий три файла, неизлечимый файл, файл подающийся лечению и чистый файл. Что произойдет с данным архивом при проверке его по запросу пользователя? Какие объекты будут помещены на карантин, какие в резервное хранилище?