49688 (Защита персональных данных с помощью алгоритмов шифрования), страница 3
Описание файла
Документ из архива "Защита персональных данных с помощью алгоритмов шифрования", который расположен в категории "". Всё это находится в предмете "информатика" из 1 семестр, которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "курсовые/домашние работы", в предмете "информатика, программирование" в общих файлах.
Онлайн просмотр документа "49688"
Текст 3 страницы из документа "49688"
y = gx mod p
Общедоступными ключами являются y, g и p, а секретным ключом является х. Для подписи сообщения M выбирается случайное число k, которое является простым по отношению к p-1. После этого вычисляется a = gk mod p. Далее из уравнения M = (xa + kb) mod (p-1) находим b. Электронной подписью для сообщения M будет служить пара a и b. Случайное число k следует хранить в секрете. Для верификации подписи необходимо проверить равенство:
yaab mod p = gM mod p.
Пара a и b представляют собой зашифрованный текст. Следует заметить, что зашифрованный текст имеет размер в два раза больше исходного. Для дешифрования производится вычисление:
M = b/ax mod p
2.3 Сравнение cимметричных и аcимметричных алгоритмов шифрования
В асимметричных системах необходимо применять длинные ключи (512 битов и больше). Длинный ключ резко увеличивает время шифрования. Кроме того, генерация ключей весьма длительна. Зато распределять ключи можно по незащищенным каналам.
В симметричных алгоритмах используют более короткие ключи, т. е. шифрование происходит быстрее. Но в таких системах сложно распределение ключей.
Поэтому при проектировании защищенной системы часто применяют и cимметричные, и аcимметричные алгоритмы. Так как система с открытыми ключами позволяет распределять ключи и в симметричных системах, можно объединить в системе передачи защищенной информации асимметричный и симметричный алгоритмы шифрования. С помощью первого рассылать ключи, вторым же - собственно шифровать передаваемую информацию
Обмен информацией можно осуществлять следующим образом:
-
получатель вычисляет открытый и секретный ключи, секретный ключ хранит в тайне, открытый же делает доступным;
-
отправитель, используя открытый ключ получателя, зашифровывает сеансовый ключ, который пересылается получателю по незащищенному каналу;
-
получатель получает сеансовый ключ и расшифровывает его, используя свой секретный ключ;
-
отправитель зашифровывает сообщение сеансовым ключом и пересылает получателю;
-
получатель получает сообщение и расшифровывает его.
Надо заметить, что в правительственных и военных системах связи используют лишь симметричные алгоритмы, так как нет строго математического обоснования стойкости систем с открытыми ключами, как, впрочем, не доказано и обратное.
2.4 Использование инструментов криптографии в Delphi-приложениях
2.4.1 CryptoAPI
Криптографические функции являются частью операционной системы Windows, и обратится к ним можно посредством интерфейса CryptoAPI. Основные возможности доступны еще с Windows 95, но со временем они расширялись. Описание функций CryptoAPI можно найти в MSDN, или в справочном файле к Delphi. Функции содержаться в библиотеках advapi32.dll и crypt32.dll.
2.4.2 Подключение к криптопровайдеру. Контейнеры ключей
Первая функция, которую мы рассмотрим, будет
function CryptAcquireContext(phProv :PHCRYPTPROV;
pszContainer :LPAWSTR;
pszProvider :LPAWSTR;
dwProvType :DWORD;
dwFlags :DWORD) :BOOL; stdcall;
В большинстве случаев, работа с криптографическими возможностями Windows начинается с вызова именно этой функции, которая выполняет подключение к криптопровайдеру и возвращает его дескриптор в параметре phProv. Криптопровайдер представляет собой dll, независимый программный модуль, который фактически исполняет криптографические алгоритмы. Криптопровайдеры бывают различные и отличаются составом функций (например, некоторые криптопровайдеры ограничиваются лишь цифровыми подписями), используемыми алгоритмами (некоторые шифруют алгоритмом RC2, другие - DES) и другими возможностями. В каждой операционной системе свой состав криптопровайдеров, однако в каждой присутствует Microsoft Base Cryptographic Provider v1.0. При вызове функции CryptAcquireContext, необходимо указать имя провайдера и его тип (соответственно в параметрах pszProvider и dwProvType). Тип провайдера определяет состав функций и поддерживаемые криптоалгоритмы, например:
Тип PROV_RSA_FULL
-
Обмен ключами - алгоритм RSA
-
Цифровая подпись - алгоритм RSA
-
Шифрование - алгоритм RC2 и RC4
-
Хэширование - алгоритмы MD5 и SHA
Тип PROV_RSA_SIG
-
Обмен ключами - не поддерживается
-
Цифровая подпись - алгоритм RSA
-
Шифрование - не поддерживается
-
Хэширование - алгоритмы MD5 и SHA
Microsoft Base Cryptographic Provider v1.0 относится к типу PROV_RSA_FULL и для этого типа используется по умолчанию (если в параметре pszProvider указать nil). В параметре pszContainer необходимо указать имя контейнера ключей, который мы собираемся использовать. Дело в том, что каждый криптопровайдер содержит базу данных, в которой хранятся ключи пользователей. Эти ключи группируются в контейнерах. Сохраняются только ключевые пары для асимметричных алгоритмов, сеансовые ключи не сохраняются, так как их не рекомендуют использовать повторно. Таким образом, каждый контейнер имеет имя и содержит по одному ключу (точнее паре открытый-закрытый ключ) для цифровой подписи и обмена ключами. В зависимости от криптопровайдера, база данных может храниться в файлах, реестре или в каких-либо аппаратных средствах, но это не влияет на работу программиста с контейнерами ключей. Если в качестве параметра pszContainer указать nil, то будет использоваться контейнер ключей, название которого совпадает именем пользователя, под которым был осуществлен вход в систему. Но так делать не рекомендуется: дело в том, что если два приложения использует один и тот же контейнер, одно из них может изменить или уничтожить ключи, необходимые для корректной работы другого приложения. Поэтому рекомендуют использовать контейнеры, имена которых совпадает с именем приложения.
Параметр dwFlags может быть нулевым или принимать одно из следующих значений:
CRYPT_VERIFYCONTEXT - этот флаг предназначен для приложений, которые не должны иметь доступ к закрытым ключам контейнера. Такие приложения могут обращаться только к функциям хеширования, проверки цифровой подписи или симметричного шифрования. В этом случае параметр pszContainer должен быть равен nil.
CRYPT_NEWKEYSET - создает новый контейнер ключей, но сами ключи не создаются.
CRYPT_DELETEKEYSET - удаляет контейнер вместе с хранящимися там ключами. Если задан этот флаг, то подключение к криптопровайдеру не происходит и параметр phProv неопределен.
CRYPT_MACHINE_KEYSET - по умолчанию контейнеры ключей сохраняются как пользовательские. Для основных криптопровайдеров это означает, что контейнеры ключей сохраняются в пользовательских профилях. Этот флаг можно устанавливать в комбинации с другими, чтобы указать, что контейнер является машинным, то есть хранится в профиле All Users.
В случае успеха, функция возвращает true, в противном случае - false. GetLastError вернет код ошибки.
function CryptReleaseContext(hProv :HCRYPTPROV;
dwFlags :DWORD) :BOOL; stdcall;
Освобождает контекст криптопровайдера и контейнера ключей. hProv - дескриптор криптопровайдера, полученный при вызове CryptAcquireContext. dwFlags - зарезервирован и должен равняться нулю.
В случае успеха, функция возвращает true, в противном случае - false. GetLastError вернет код ошибки.
Приведем пример работы с этими функциями:
uses Wcrypt2;
...
procedure CryptProc;
var
Prov: HCRYPTPROV;
begin
CryptAcquireContext(@Prov,nil,nil,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT);
// Работаем с функциями CryptoAPI
...
CryptReleaseContext(Prov,0);
end;
2.4.3 Шифрование на основе пользовательских данных или пароля
Для шифрования в CryptoAPI используются симметричные алгоритмы, ключ для которых может быть получен двумя путями: случайным образом или на основе каких-либо пользовательских данных, например пароля. Причем к последнему варианту генерации ключа есть одно важное требование: при использовании одних и тех же паролей должны получаться идентичные ключи. Такая возможность предусмотрена в CryptoAPI.
function CryptDeriveKey(hProv :HCRYPTPROV;
Algid :ALG_ID;
hBaseData :HCRYPTHASH;
dwFlags :DWORD;
phKey :PHCRYPTKEY) :BOOL; stdcall;
В параметре hProv нужно указать дескриптор провайдера, полученный с помощью CryptAcquireContext. Algid - идентификатор алгоритма, для которого генерируется ключ. Для Microsoft Base Cryptographic Provider может принимать следующие значения: CALG_RC2 и CALG_RC4. Пользовательские данные (пароль) предварительно хэшируются и дескриптор хэш-объекта передается в функцию в качестве параметра hBaseData. Старшие 16 бит параметра dwFlags могут содержать размер ключа в битах или быть нулевыми (в этом случае будет создан ключ с размером по умолчанию). Младшие 16 бит могут быть нулевыми или принимать следующие значения или их комбинации: CRYPT_EXPORTABLE, CRYPT_CREATE_SALT, CRYPT_USER_PROTECTED, CRYPT_UPDATE_KEY. К первым двум мы еще вернемся, а со смыслом остальных вы можете ознакомиться самостоятельно. В параметре phKey возвращается дескриптор созданного ключа.
В случае успеха, функция возвращает true, в противном случае - false. GetLastError вернет код ошибки.
Когда ключ есть, можно приступать непосредственно к шифрованию. Для этого нам понадобятся функции CryptEncrypt и CryptDecrypt.
function CryptEncrypt(hKey :HCRYPTKEY;
hHash :HCRYPTHASH;
Final :BOOL;
dwFlags :DWORD;
pbData :PBYTE;
pdwDataLen :PDWORD;
dwBufLen :DWORD) :BOOL; stdcall;
В параметре hKey передается дескриптор ключа, необходимый для шифрования. Этот ключ также определяет алгоритм шифрования. Параметр hHash используется, если данные одновременно шифруются и хэшируются (шифроваться и хэшироваться будут исходные данные). В этом случае в параметре hHash передается дескриптор заранее созданного хэш-объекта. Эту возможность удобно использовать, если необходимо одновременно зашифровать и подписать сообщение. Иначе этот параметр следует установить в ноль. Параметр Final следует установить в true, если переданный в функцию блок данных является единственным или последним. В этом случае он будет дополнен до необходимого размера. Параметр dwFlags не используется в Microsoft Base Cryptographic Provider и на его месте следует указать ноль. pbData - указатель на буфер, в котором содержаться данные для зашифрования. Зашифрованыые данные помещаются в тот же буфер. pdwDataLen - размер данных, которые будут зашифрованы. dwBufLen - размер выходного буфера, для блочных шифров может быть больше, чем pdwDataLen. Узнать необходимый размер, можно передав в параметре pbData nil, в параметре pdwDataLen - размер данных, которые необходимо зашифровать, а в параметре dwBufLen - что угодно, например ноль. После такого вызова, необходимый размер буфера будет содержаться в параметре pdwDataLen (именно pdwDataLen, а не dwBufLen, немного нелогично, ну да ладно). Чтобы не было путаницы, приведем пример:
var
Message: String;
BufLen, DataLen: DWORD;
...
begin
...
Message:='Hello World!';
BufLen:=Length(Message);
DataLen:=Length(Message);
// Вычисляем необходимый размер выходного буфера
CryptEncrypt(Key,0,true,0,nil,@BufLen,0);
// Выделяем память для буфера и шифруем
SetLength(Message,BufLen);
CryptEncrypt(Key,0,true,0,PByte(Message),@DataLen,BufLen);
Теперь, рассмотрим функцию, которая позволяет расшифровать сообщение.
function CryptDecrypt(hKey :HCRYPTKEY;
hHash :HCRYPTHASH;
Final :BOOL;
dwFlags :DWORD;
pbData :PBYTE;
pdwDataLen :PDWORD) :BOOL; stdcall;
В параметр pdwDataLen нужно передать число байт шифротекста, а после вызова в него будет помещена длина открытого сообщения. Если используется параметр hHash, то данные после расшифровки хэшируются. Это удобно использовать, если нужно одновременно расшифровать сообщение и проверить подпись.
После того, как работа с ключом закончена, необходимо освободить дескриптор:
function CryptDestroyKey(hKey :HCRYPTKEY) :BOOL; stdcall;
Если hKey относится к сеансовому ключу или импортированному открытому ключу (об этом ниже), то дескриптор освобождается, а ключ уничтожается. Если hKey относится к паре открытый/закрытый ключ, то дескриптор освобождается, а ключевая пара сохраняется в контейнере ключей.