49688 (Защита персональных данных с помощью алгоритмов шифрования), страница 4
Описание файла
Документ из архива "Защита персональных данных с помощью алгоритмов шифрования", который расположен в категории "". Всё это находится в предмете "информатика" из 1 семестр, которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "курсовые/домашние работы", в предмете "информатика, программирование" в общих файлах.
Онлайн просмотр документа "49688"
Текст 4 страницы из документа "49688"
Только что мы рассмотрели случай, когда для зашифровки и расшифровки сообщения отправитель и получатель использовали пароль, известный только им. Сейчас рассмотрим другой: отправитель генерирует ключ случайно и передает его получателю в зашифрованном виде вместе с сообщением. При этом для шифрования сеансового ключа используется открытый ключ получателя. А где отправитель его возьмет?
Как уже было сказано, при создании ключевого контейнера с помощью функции CryptAcquireContext, ключи в контейнере не создаются, их нужно сгенерировать отдельно. Рассмотрим функцию:
function CryptGenKey(hProv :HCRYPTPROV;
Algid :ALG_ID;
dwFlags :DWORD;
phKey :PHCRYPTKEY) :BOOL; stdcall;
Функция предназначена для генерации случайных сеансовых ключей и ключевых пар. Параметры этой функции аналогичны одноименным параметрам функции CryptDeriveKey, за исключением того, что Algid может также принимать значения AT_KEYEXCHANGE и AT_SIGNATURE. В этом случае будут сгенерированы ключевые пары соответственно для обмена ключами и цифровой подписи. Создание нового ключевого контейнера должно выглядеть примерно так:
uses Wcrypt2;
...
var
Prov: HCRYPTPROV;
ExchangeKey, SignKey: HCRYPTKEY;
begin
CryptAcquireContext(@Prov,'My_Container',nil,PROV_RSA_FULL,CRYPT_NEWKEYSET);
// Создаем ключевые пары
CryptGenKey(Prov,AT_KEYEXCHANGE,0,@ExchangeKey);
CryptGenKey(Prov,AT_SIGNATURE,0,@SignKey);
// Работаем с функциями CryptoAPI
...
// Освобождаем дескрипторы ключевых пар. Сами ключи сохраняются в контейнере
CryptDestroyKey(SignKey);
CryptDestroyKey(ExchangeKey);
CryptReleaseContext(Prov,0);
end;
Созданные таким образом ключевые пары, впоследствии можно извлечь из контейнера, воспользовавшись функцией
function CryptGetUserKey(hProv :HCRYPTPROV;
dwKeySpec :DWORD;
phUserKey :PHCRYPTKEY) :BOOL; stdcall;
Параметр dwKeySpec может принимать два значения: AT_KEYEXCHANGE и AT_SIGNATURE, значения которых очевидны. Дескриптор ключа возвращается в параметре phUserKey.
Теперь ответим на вопрос, как отправитель сможет передать получателю свою открытую часть ключа.
function CryptExportKey(hKey :HCRYPTKEY;
hExpKey :HCRYPTKEY;
dwBlobType :DWORD;
dwFlags :DWORD;
pbData :PBYTE;
pdwDataLen :PDWORD) :BOOL; stdcall;
Функция позволяет экспортировать ключ в двоичный буфер, который впоследствии можно будет сохранить в файл и передать кому-либо. В параметре hKey должен содержаться дескриптор экспортируемого ключа. Экспортировать можно не только открытые ключи, а также ключевые пары целиком и сеансовые ключи. В последних двух случаях, ключи и ключевые пары должны быть созданы функциями CryptGenKey или CryptDeriveKey с параметрами dwFlags равными CRYPT_EXPORTABLE. Открытые же ключи всегда экспортируемы. Сеансовые ключи и ключевые пары экспортируются только в зашифрованном виде. Параметр hExpKey определяет ключ, которым они будут зашифрованы. Если экспортируется открытая часть ключа, то этот параметр следует установить в ноль, если экспортируется ключевая пара целиком, то здесь обычно передают дескриптор сеансового ключа (обычно полученный с помощью CryptDeriveKey), которым пара будет зашифрована, если экспортируется сеансовый ключ, то обычно он шифруется открытым ключом получателя (обычно используется ключ обмена, но никто не запрещает использовать ключ подписи). Параметр dwBlobType определяет тип экспортируемого ключа и может принимать следующие значения: SIMPLEBLOB - сеансовый ключ, PUBLICKEYBLOB - открытый ключ, PRIVATEKEYBLOB - ключевая пара целиком. Существуют и другие значения, но они не поддерживаются стандартным криптопровайдером. Параметр dwFlags для Microsoft Base Cryptographic Provider должен быть равен нулю. pbData - буфер, куда будут скопированы данные, pdwDataLen - размер этого буфера. Если он заранее не известен, то можно указать в качестве параметра pbData nil, и в pdwDataLen будет получен необходимый размер.
Вот пример экспорта открытого ключа:
procedure ExportPublicKey(FileName: TFileName);
var
Prov: HCRYPTPROV;
SignKey: HCRYPTKEY;
Stream: TMemoryStream;
BufSize: DWORD;
begin
CryptAcquireContext(@Prov,'My_Container',nil,PROV_RSA_FULL,0);
CryptGetUserKey(Prov,AT_SIGNATURE,@SignKey);
Stream:=TMemoryStream.Create;
CryptExportKey(SignKey,0,PUBLICKEYBLOB,0,nil,@BufSize);
Stream.SetSize(BufSize);
CryptExportKey(SignKey,0,PUBLICKEYBLOB,0,PByte(Stream.Memory),@BufSize);
Stream.SaveToFile(FileName);
Stream.Free;
CryptDestroyKey(SignKey);
CryptReleaseContext(Prov,0);
end;
Импорт ключа осуществляется с помощью функции
function CryptImportKey(hProv :HCRYPTPROV;
pbData :PBYTE;
dwDataLen :DWORD;
hPubKey :HCRYPTKEY;
dwFlags :DWORD;
phKey :PHCRYPTKEY) :BOOL; stdcall;
В параметре hPubKey необходимо передать дескриптор ключа, которым будет расшифрован импортированный ключ. Если импортируется ключевая пара целиком, то параметр dwFlags можно установить в CRYPT_EXPORTABLE, тогда импортированная пара может быть впоследствии также экспортирована. В параметре phKey вернется дескриптор полученного ключа. Если это ключевая пара, то она будет сохранена в контейнере.
Вот пример импорта открытого ключа:
function ImportPublicKey(FileName: TFileName): HCRYPTKEY;
var
Prov: HCRYPTPROV;
Stream: TMemoryStream;
begin
Stream:=TMemoryStream.Create;
Stream.LoadFromFile(FileName);
CryptImportKey(Prov,PByte(Stream.Memory),Stream.Size,0,0,@Result);
Stream.Free;
end;
Теперь, воспользовавшись этой информацией, мы без труда сможем восстановить пропущенные фрагменты в функции проверки цифровой подписи, описанной ранее.
Итак, как же передать собеседнику зашифрованное сообщение:
-
Получатель экспортирует свой открытый ключ обмена в файл и передает его отправителю сообщения.
-
Отправитель генерирует случайный сеансовый ключ и шифрует им сообщение.
-
Отправитель импортирует открытый ключ обмена получателя, экспортирует сеансовый ключ, шифруя его полученным ключом обмена (ключ обмена в параметре hExpKey).
-
Зашифрованное сообщение передается вместе с зашифрованным сеансовым ключом - так называемый цифровой конверт.
-
Получатель импортирует сеансовый ключ, расшифровывая его своим закрытым ключом обмена (его можно получить, вызвав CryptGetUserKey) и с помощью сеансового ключа расшифровывает сообщение.
Говоря о сеансовых ключах, используемых в Microsoft Base Cryptographic Provider нужно упомянуть об одной неприятности: до начала 2000 года действовал запрет на экспорт программного обеспечения, использующего средства "сильной криптографии" за пределами США и Канады. По этой причине в базовом криптопровайдере не поддерживаются ключи для симметричных алгоритмов длиной более 40 бит. Ключи длиной 56 бит разрешалось использовать только заграничным отделениям американских компаний. Для алгоритмов RC2 и RC4 рекомендуемая длина ключа должна составлять 128 бит, поэтому недостающее количество бит заполняется нулями либо случайными значениями, которые должны передаваться открыто. Надежность защиты из-за этого, разумеется, сильно страдает. В состав Windows XP входит Microsoft Enhanced Cryptographic Provider, в котором этой проблемы нет, но при использовании базового криптопровайдера, необходимо дополнять ключ до нужной длины, используя т.н. солт-значения (salt-values). Сгенерировать salt-value и внести его в ключ можно несколькими способами, но самый простой и очевидный - при вызове CryptGenKey или CryptDeriveKey передать в параметре dwFlags значение CRYPT_CREATE_SALT, примерно так:
CryptGenKey(Prov,CALG_RC2,CRYPT_EXPORTABLE or CRYPT_CREATE_SALT,@Key);
При экспорте ключа солт-значение не сохраняется, о нем должен позаботиться сам программист.
var
SaltLen: DWORD;
Stream: TMemoryStream;
...
begin
...
// Определяем размер буфера для солт-значения
CryptGetKeyParam(Key,KP_SALT,nil,@SaltLen,0);
// Сохраняем его в файл
Stream:=TMemoryStream.Create;
Stream.SetSize(SaltLen);
CryptGetKeyParam(Key,KP_SALT,PByte(Stream.Memory),@SaltLen,0);
Stream.SaveToFile('Salt.dat');
Stream.Free;
...
Сохраненное таким образом солт-значение необходимо передать вместе с сеансовым ключом, а на приемной стороне "вживить" его туда снова.
var
Stream: TMemoryStream;
...
begin
...
Stream:=TMemoryStream.Create;
Stream.LoadFromFile('Salt.dat');
CryptSetKeyParam(Key,KP_SALT,PByte(Stream.Memory),Stream.Size);
Stream.Free;
...
2.5 Постановка задачи
Разработать программу шифрующую и дешифрующую введенный пользователем текст. Обеспечить ввод и вывод информации с помощью файлов. Обеспечить достаточную криптоустойчивость шифра.
2.6 Реализация задачи
2.6.1 Краткая характеристика среды Delphi 7
Среда программирования Delphi 7 позволяет реализовать поставленную задачу со всеми необходимыми требованиями. В среде используется язык Object Pascal. Delphi 7 является объектно-ориентированной средой, что упрощает создание единообразного интерфейса и ввод-вывод информации из файла.
2.6.2 Алгоритм решения задачи
Программа представляет собой шифровщик и дешифровщик одновременно.
Используется метод симметрического кодирования, то есть кодирование и декодирование осуществляется с помощью одного ключа. Для обеспечения криптоустойчивости необходим длинный ключ. Пользователь вводит 30-символьный код. Блоками по 10 цифр. Из них генерируется код следующим образом:
Берутся первые цифры из 1-го, 2-го,3-го блоков, и в зависимости от 3-го блока над ними производятся операции сложения или умножения. Затем берется следующая цифра 3-го блока, после полного завершения цикла по 3-му блоку берется следующая цифра из второго блока и т.д. Гаммирование завершается после прохождения по циклу последней цифры 1-го блока. Результатом является код состоящий из 1000 независимых, неповторяющихся и незакономерных цифр. Шифр возможно вскрыть только полным перебором, что обеспечивает достаточную криптоустойчивость.
Модули программы
Программа имеет несколько стандартных основных модулей: вызов справки, сохранение в файл, открытие файла, генерация произвольного ключа, проверка пароля, которые не будут упоминаться в дальнейшем.
Опишем лишь модули отвечающие непосредственно за шифрование.
Модуль шифровки/дешифровки
s1:=memo1.Text;
k:=length(s);
k1:=length(s1);
k3:=length(s3);
k5:=length(s5);
m:=1;
m3:=1; m5:=1;
for i:=1 to k1 do
begin
q:=false;
i5:=strtoint(s[m]);
i2:=strtoint(s3[m3]);
i3:=strtoint(s5[m5]);
i1:=kod(i5,i2,i3);
if i1=0 then i1:=10;
case s1[i] of
'a'..'z':begin c1:=perevod(s1[i],i1,96,122); q:=true; end;
'A'..'Z':begin c1:=perevod(s1[i],i1,64,90); q:=true; end;
'А'..'Я':begin c1:=perevod(s1[i],i1,191,223); q:=true; end;
'а'..'я':begin c1:=perevod(s1[i],i1,223,255); q:=true; end;
end;
if q=true then
begin
{if ord(s1[i])+i1>255 then }
s2:=s2+c1;
{ else
s2:=s2+chr(ord(s1[i])+i1);}
end
else s2:=s2+s1[i];
q1:=false;
if m5=k5 then begin m5:=1; q1:=true; end
else inc(m5);
q2:=false;
if (q1=true) then
begin
inc(m3);
end;
if m3>=k3 then begin m3:=1; q2:=true end;
if (q2=true) then m:=m+1;
if m>=k then m:=1;
end;
{delete(s2,k1-1,2)}
memo2.Text:=s2;
Процедура кодирования символа
begin
if abs(i1)>y-x+1 then
repeat
i1:=i1 mod (y-x+1);
until i1<(y-x+1);
if ord(c)+i1>y then
perevod:=chr(x+(ord(c)+i1-y))
else
perevod:=chr(ord(c)+i1)
end;
2.6.3 Таблица сообщений
В ходе работы пользователь может получить сообщение:
«Пароль не подтвержден» - следует убедиться в правильности пароля в дублирующих и основных полях.
Заключение
Обоснованный выбор той или иной системы защиты должен опираться на какие-то критерии эффективности. К сожалению, до сих пор не разработаны подходящие методики оценки эффективности криптографических систем.
Наиболее простой критерий такой эффективности - вероятность раскрытия ключа или мощность множества ключей (М). По сути это то же самое, что и кpиптостойкость. Для ее численной оценки можно использовать также и сложность раскрытия шифра путем перебора всех ключей. Однако, этот критерий не учитывает других важных требований к криптосистемам:
-
невозможность раскрытия или осмысленной модификации информации на основе анализа ее структуры,
-
совершенство используемых протоколов защиты,
-
минимальный объем используемой ключевой информации,
-
минимальная сложность реализации (в количестве машинных операций), ее стоимость,
-
высокая оперативность.
В любом случае выбранный комплекс кpиптогpафических методов должен сочетать как удобство, гибкость и оперативность использования, так и надежную защиту от злоумышленников циркулирующей в ИС информации. Поэтому на настоящий момент наиболее оптимальны смешанные криптосиситемы, в которых текст кодируется симметрически, а ключ кодируется ассиметрически и помещается вместе с кодированным текстом.