Рано или поздно разработчику приходится сталкиваться с вопросами защиты информации, обеспечения конфиденциальности и т.д. Мне пришлось столкнуться с этой проблемой сравнительно недавно и, так как я не являюсь специалистом в вопросах криптографии и, тем более, не намереваюсь разрабатывать сверхбыстрый и уникальный компонент для шифрования, то решил выбрать подходящий для меня компонент из уже имеющихся в Сети. Первоначальная задача, которая передо мной была поставлена — обеспечить шифрование файлов с использованием алгоритма AES (Rijndael) перед их отправкой на сервер. И, так как никто меня не ограничивал в выборе компонентов, то я решил начать работу в этой области с компонентов DCPcrypt о которых я рассказывал про расчёт SHA1 в Delphi.
Установка компонентов
- Скачиваем архив с компонентами DCPCrypt с официального сайта (я скачивал DCPcrypt v2 for Delphi 2009/2010)
- Распаковываем архив в любую папку
- Добавляем путь к папке с компонентами и подпапкам Ciphers и Hashes в Tools—>Options—>Library
- Далее, выбираем пакет установки DCPdelphi2009.dpk и устанавливаем компоненты.
После установки на палитре компонентов появятся две новые вкладки: DCPciphers и DCPhashes. После установки компонентов можно приступать к работе.
Демонстрационный проект
Открываем на палитре компонентов вкладку DCPciphers и бросаем на форму компонент TDCP_rijndael. Остальные компоненты берем с вкладок Standard и Dialogs. Окно приложения с помощью которого мы будем учиться использовать компоненты DCPCrypt представлено на рисунке ниже:
С помощью такого нехитрого приложения мы сможем посмотреть как работают компоненты, а, заодно, и оценить затраты времени на шифрование файлов различного размера.
Для начала, напишем две функции для шифрования и расшифровки файла. Первая — шифрование файла:
function TForm2.EncryptFile(Source, Dest, Password: string): Boolean; var SourceStream, DestStream: TFileStream; begin Result := True; try SourceStream := TFileStream.Create(Source, fmOpenRead);//поток для файла, который будем шифровать try DestStream := TFileStream.Create(Dest, fmCreate);//поток файла для зашифрованных данных try DCP_rijndael1.InitStr(Password, TDCP_sha1);//инициализируем ключ (считаем SHA1 для ключа) DCP_rijndael1.EncryptStream(SourceStream, DestStream, SourceStream.Size);//шифруем DCP_rijndael1.Burn;//"сжигаем" данные о ключе finally FreeAndNil(DestStream); end; finally FreeAndNil(SourceStream) end; except Result := False; end; end;
Аналогичным образом выглядит функция и для расшифровки файла:
function TForm2.DecryptFile(Source, Dest, Password: string): Boolean; var SourceStream, DestStream: TFileStream; begin Result := True; try SourceStream := TFileStream.Create(Source, fmOpenRead); try DestStream := TFileStream.Create(Dest, fmCreate); try DCP_rijndael1.InitStr(Password, TDCP_sha1); DCP_rijndael1.DecryptStream(SourceStream, DestStream, SourceStream.Size); DCP_rijndael1.Burn; finally FreeAndNil(DestStream); end; finally FreeAndNil(SourceStream) end; except Result := False; end; end;
Теперь используем эти функции в обработчиках событий OnClick кнопок «Шифровать» и «Расшифровать». Для подсчёта времени, затраченного на проведение операции я воспользовался способом, про который я рассказывал здесь.
//Шифруем файл procedure TForm2.btnEncryptClick(Sender: TObject); var iCounterPerSec: TLargeInteger; T1, T2: TLargeInteger; // значение счётчика ДО и ПОСЛЕ операции SourceStream, DestStream: TFileStream; begin QueryPerformanceFrequency(iCounterPerSec); QueryPerformanceCounter(T1); if EncryptFile(edFile.Text, ExtractFilePath(ParamStr(0)) + 'encrypted' + ExtractFileExt(edFile.Text), edPassword.Text) then begin QueryPerformanceCounter(T2); lbTimer.Caption := FormatFloat('0.0000', (T2 - T1) / iCounterPerSec) + ' сек.'; end else lbTimer.Caption := 'Ошибка!' end; //Расшифровываем файл procedure TForm2.btnDecryptClick(Sender: TObject); var iCounterPerSec: TLargeInteger; T1, T2: TLargeInteger; // значение счётчика ДО и ПОСЛЕ операции SourceStream, DestStream: TFileStream; begin QueryPerformanceFrequency(iCounterPerSec); QueryPerformanceCounter(T1); if DecryptFile(edFile.Text, ExtractFilePath(ParamStr(0)) + 'decrypted' + ExtractFileExt(edFile.Text), edPassword.Text) then begin QueryPerformanceCounter(T2); lbTimer.Caption := FormatFloat('0.0000', (T2 - T1) / iCounterPerSec) + ' сек.'; end else lbTimer.Caption := 'Ошибка!' end;
Теперь проверим работу нашей программы. Для примера, я создал файл с названием «example.txt» и содержащим всего одну строку «Шла Саша по шоссе и сосала чупа-чупс». Запускаем программу, выбираем наш тестовый файл, задаем любой пароль и жмем кнопку «Шифровать». Результат работы программы представлен на рисунке ниже:
При этом, зашифрованный файл стал таким:
Аналогичным образом, если выбрать зашифрованный файл и задать тот же самый ключ, произойдет и обратная операция — расшифровка файла и помещение его содержимого в файл decrypted.
«Безопасность всегда дается ценой производительности»
Конечно, фраза из заголовка относилась не совсем к тому, что я сейчас собираюсь показать, но, тем не менее. Посмотрим, сколько времени затрачивается при использовании DCPCrypt для того, чтобы зашифровать файлы самых различных размеров и с самым различным содержимым.
Размер файла | Тип файла | Время шифрования, с | Время расшифровки, с |
1 Кб | Текст | 0,0052 | 0,0015 |
1 Мб | DLL | 0,0398 | 0,0729 |
11 Мб | EXE | 0,952 | 0,942 |
73 Мб | EXE | 3,5011 | 3,7917 |
1490 Мб | Фильм | 45,5644 | 33,8211 |
В принципе, вполне приемлемый результат, учитывая то, что при предыдущей проверке на производительность эти компоненты показали второй по скорости результат, думаю, что вполне подойдут для дальнейшей работы.
Дополнительно отмечу, что одним из преимуществ этих компонентов, лично для себя, я определил — простоту их использования. С их помощью одинаково просто можно шифровать и строки и целые файлы.
Добрый день, Скачал по указанной вами ссылке dcpcrypt2-2010.zip. Установил библиотеку под Delphi 7.1 (DCPdelphi6.dpk) и Delphi 10 Seattle Update1 (DCPdelphi2009.dpk). Сделал простой пример: DCP_rijndael1.InitStr(‘p100’, TDCP_sha1); ShowMessage(DCP_rijndael1.EncryptString(‘Pass’)); DCP_rijndael1.Burn; Запустил его на D7 и D10. На D10 зашифрованная строка имеет вид: OPIGwVVQnzY= На D7 зашифрованная строка имеет вид: hfTlYw== То есть несмотря на то, что одни и те же данные шифровались с одним и тем же паролем, результат шифрования в D7 и D10 отличается. Провел аналогичный эксперемент с демкой FileEncrypt из состава библиотеки — результат то же самый: зашифрованный файл в D7 и D10 отличаются. Вопрос: Почему ? И что сделать, что… Подробнее »
В Delphi 7 нет поддержки Unicode, в Delphi 10 — есть и по умолчанию там строка UnicodeString. отсюда и различные результаты шифрования
Доброе время суток.
Ссылка на рассмотренный пример не работает
Здравствуйте. Спасибо за сообщение. Действительно, после обновления плагина всё загрузки оказались битые :(
День добрый.
Спасибо за статью, все описано доступно. Скажите, а DCP_rijndael работает только с параметром «MaxKeySize» = 256 ?
Мне надо было использовать ключ длинной 128 бит, установил 128, сбросился параметр в 256, посмотрел в исходниках, а там нет возможности работы с 128 битным ключиком. Есть ли версия сей библиотеки для работы с «MaxKeySize» = 128?
Добрый день!
Нет, для работы со 128-ми битными ключами библиотеки не видел, к сожалению
Здравствуйте.
Спасибо за ответ. Я посмотрел другие библиотеки, так как я являюсь простым любителем, то искал библиотеку под Delphi 7 (ну привык я к ней), нашел TurboPower LockBox 3, релиз 3.4.1 поддерживает мою версию Delphi, то поставил именно её. Правда не нашел хороший хелп для «чайника», теперь разбираюсь.
Vlad, спасибо за ваш сайт, очень интересно читать доступно предоставленную информацию.
Приветствую! Спасибо за отзыв :) Надеюсь, что сможете найти ещё что-либо интересное на сайте