Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Простейшая программа шифрования
Мы рассмотрим основные принципы работы с двоичными файлами на примере программы шифрования файлов. Не надейтесь, что файл, созданный этой программой, не будет взломан хорошим программистом — мы реализуем простейший алгоритм шифрования. Данный пример предназначен лишь для того, чтобы продемонстрировать особенности работы с файлами в двоичном режиме доступа. Шифрование выполняется командой меню Actions > Encrypt, a расшифровка -командой Actions > Decrypt. B обоих случаях вам будет предложено выбрать текстовый файл, с которым будет выполняться операция. 1. Создайте новый проект типа Standard EXE. 2. Активизируйте форму Form1 и задайте ее свойству Name значение frmMain, а свойству Caption — значение Шифрование файлов. 3. Поместите на форму элемент стандартного диалогового окна, задайте его свойству Name значение dlgFile. 4. Откройте редактор меню и создайте в нем следующие объекты:
Меню File:
Команды меню File:
Меню Actions:
Команды меню Action
У вас получится форма, похожая на рис. 8.5.
Рис. 8.5. Форма для программы шифрования
(ПРИМЕЧАНИЕ Следующим шагом должно стать добавление кода формы. Не считая меню, на форме присутствует всего один элемент — стандартное диалоговое окно. Элементы стандартных диалоговых окон предназначены для отображения диалоговых окон Open и Save, а также окон для настройки принтера и выбора шрифта. В нашем примере стандартное диалоговое окно используется только для выбора имени файла.
5. Откройте окно программы и выберите из раскрывающегося списка Object строку mnuFHeExit. 6. Добавьте в процедуру события mnuFileExit_Click() оператор End. 7. Настало время запрограммировать алгоритм шифрования. Откройте секцию (General)(Declarations) и добавьте в нее следующий фрагмент:
Function Encrypt(infile As String) As Boolean Dim fileno1 As Integer Dim fileno2 As Integer Dim outfile As String Dim xpos As Long Dim x As Byte
'Вывести указатель в виде песочных часов MousePointer = vbHourglass
xpos = 4
outfile = " c: \temp.enc"
fileno1 = FreeFile Open infile For Binary As fileno1 fileno2 = FreeFile Open outfile For Binary As fileno2 Put #fileno2, 1, 0 Put #fileno2, 2, 128 Put #fileno2, 3, 0 Put #fileno2, 4, 128
Do While Not EOF(fileno1) xpos = xpos + 1 Get #fileno1, xpos, x Get #fileno2, xpos, x + 128 Loop Close fileno2 Close fileno1
'Удалить исходный файл и заменить его шифрованным Kill infile FileCopy outfile, infile Kill outfile. Encrypt = True
' Восстановить указатель мыши MousePointer = vbNormal End Function
Этот фрагмент стоит рассмотреть подробнее, поскольку именно в нем происходит основная работа программы. Обратите внимание на то, что вместо процедуры Sub используется функция — дело в том, что функция передает вызывающей процедуре код возврата. По нему можно определить, успешно ли произошло шифрование, прежде чем сообщать об этом пользователю или продолжать выполнение программы. Данная функция просто возвращает True, если шифрование прошло успешно, и False в противном случае. Кроме того, функции передается параметр infile. Он содержит полное имя шифруемого файла. Значение infile определяется вызовом функции GetFile(). После стандартного объявления переменных мы превращаем указатель мыши в песочные часы. Это означает, что пользователь должен подождать завершения текущей операции. Дело в том, что побайтовое чтение файла может оказаться довольно долгим процессом.
ПОДСКАЗКА* Если программа выполняет какую-то длительную операцию, отображайте указатель мыши в виде песочных часов. По нему пользователь поймет, что программа работает, а не «висит». Чтобы отобразить песочные часы, задайте свойству MousePointer формы значение vbHourglass.
Как упоминалось ранее, команда FreeFile используется для получения свободного файлового номера. Когда я работал над этим примером, в моей программе рядом стояли два оператора FreeFile. Я поступил так, поскольку стараюсь по возможности группировать логически связанные команды. При запуске программы она постоянно выдавала ошибку «Файл уже открыт». Почему? Я проверил в отладчике значения infile и outfile — они были правильными. Мои файлы не открывались другими приложениями, поэтому они не могли быть заблокированы другой программой. После некоторых размышлений я понял, что файловый номер выделяется программе не в операторе FreeFile, a при открытии файла оператором Open (FreeFile просто сообщает, какие файловые номера доступны в данный момент). В итоге я получал один и тот же номер для fileno1 и fileno2. Как только я переместил команды FreeFile к соответствующим операторам Open, программа заработала. Мораль: старайтесь держать вызов FreeFile как можно ближе к оператору Open, особенно если ваша процедура работает с несколькими файлами. Как видите, даже простейшую программу иногда приходится отлаживать!
ПОДСКАЗКА Если ваша процедура работает с несколькими файлами, старайтесь держать команду FreeFile как можно ближе к команде Open. FreeFile не блокирует файловый номер, а лишь сообщает о его наличии. Самый верный путь — выполнять команду Open сразу же после команды FreeFile.
Перед тем как приступать к непосредственной обработке данных, мы добавляем в начало шифрованного файла некое подобие «электронной подписи». По ней алгоритм расшифровки определяет, действительно ли файл зашифрован. Подпись должна представлять собой последовательность байтов, которая практически никогда не встречается в файлах. В своем примере я использовал четырехбайтовую подпись 0, 128, 0, 128. Именно эту конкретную последовательность байтов будет искать алгоритм дешифровки. Функции Encrypt и Decrypt можно дополнительно усовершенствовать, чтобы электронная подпись генерировалась прямо в них. Обратите внимание — переменная x имеет байтовый, а не целый тип. Причина заключается в том, что ее максимальное значение не должно превышать 255. Если при сложении x с другим числом результат превысит 255, значение x обнуляется, после чего суммирование продолжается. Если сложить 128 и 128, получится 256. Поскольку 256 больше, чем 255, переменная x обнуляется — на этом принципе основан наш алгоритм шифрования. При дешифровке файла тот же алгоритм восстанавливает исходные значения байтов. Если дважды добавить 128 к любому байту, вы получите исходную величину, то есть зашифрованный символ вернется к прежнему состоянию. В конце функции стоят операторы Kill, которые удаляют файлы с диска. После такой последовательности команд файл infile заменяется файлом outfile. B результате у вас остается зашифрованный файл, а временный файл стирается с диска. Тем не менее перед переименованием файла необходимо позаботиться о том, чтобы имя результирующего файла было уникальным, — именно по этой причине мы удаляем infile перед тем, как переименовывать outfile. После успешного переименования outfile удаляется с диска. Шифрование завершено, поэтому мы восстанавливаем прежний вид указателя мыши — пользователь должен понять, что программа готова к работе. Функция Encrypt возвращает значение True, чтобы вызывающая процедура могла нормально продолжаться. 1. Основа программы (функция шифровки) готова. Теперь необходимо создать процедуру, из которой она будет вызываться. Для этого мы воспользуемся процедурой события mnuEncrypt_Click():
Private Sub mnuActEncrypt_Click() Dim filename As String
filename = GetFile() If filename < > " " Then If Encrypt(filename) = False Then MsgBox " Ошибка при шифровании файла! " End If End If
End Sub
2, Перед вызовом функции Encrypt команда меню должна получить имя файла с помощью функции GetFile():
Function GetFile() As String dlgFile.CancelError = True On Error GoTo filerr dlgFile.DialogTitle =" Выберите файл..." dlgFile.DefaultExt = " *.txt" dlgFile.Filter = " Текстовые файлы (*.txt)|*, txt* _ Все файлы (*. *)|*.*" dlgFile.FilterIndex = 1 dlgFile.MaxFileSize = 32767 dlgFile.ShowOpen GetFile = dlgFile.filename Exit Function
filerr: GetFile = " " End Function
Функцию GetFile() тоже следует рассмотреть внимательнее. В основе ее лежит элемент стандартного диалогового окна. Он предоставляет все средства, необходимые для получения имени файла. Возможно, вы уже знаете, что встречающееся во многих приложениях окно Open не открывает файл — оно всего лишь получает и возвращает приложению его имя. Затем другая процедура использует это имя и открывает файл для дальнейшей обработки. Наша программа поступает точно так же. Работа функции GetFile() начинается с того, что свойству CancelError присваивается значение True. В этом случае при нажатии пользователем кнопки Cancel диалоговое окно посылает сообщение об ошибке. Мы перехватываем эту ошибку, чтобы в случае отмены программа не пыталась продолжать шифрование. Процедура шифрования пропускается с помощью команды On Еггог. Из эстетических соображений мы задаем свойству DialogTitle значение " Выберите файл...", что делает нашу программу чуть более наглядной. На самом деле в заголовок диалогового окна можно поместить любой текст. По умолчанию для файлов в диалоговом окне выбирается расширение *.txt. Читатели, знакомые с командами DOS, поймут, что с данным шаблоном в окне будут отображаться лишь файлы с расширением.txt — это помогает сосредоточить внимание пользователя лишь на интересующих его файлах. Если в ваших приложениях используются стандартные диалоговые окна, старайтесь упростить работу пользователя. После шаблона задается фильтр (свойство Filter). Он представляет собой строку, в которой описания чередуются с фактическими значениями фильтра, а в качестве разделителя применяется символ «вертикальная черта» (|). В нашем приложении, как и во многих других, задано несколько фильтров. От вас требуется лишь правильно отделять их друг от друга вертикальной чертой. Доступ к различным фильтрам осуществляется с помощью свойства FilterIndex. FilterIndex — индекс текущего фильтра, отображаемого в диалоговом окне. Первый фильтр имеет индекс 1, второй — 2 и т. д. При задании этого свойства устанавливается лишь начальное значение индекса. Текущий фильтр выбирается в диалоговом окне (рис. 8.6). Рис. 8.6. Стандартное диалоговое окно
Обратите внимание — свойству MaxFileSize задается значение 32 767. Если задать это свойство, в диалоговом окне будут отображаться лишь имена файлов размером 32 К и меньше. Данному свойству можно задать произвольное значение, но необходимо позаботиться о том, чтобы открываемые файлы не выходили за пределы возможностей элементов. Впрочем, в выполняемых нами операциях размер файла нигде не ограничивается, так что для этого приложениясвойство MaxFileSize не имеет особого значения.
ПОДСКАЗКА С помощью свойства MaxFileSize можно фильтровать файлы в стандартном диалоговом окне по размеру. Эта возможность предохраняет от многих ошибок, если используемые вами элементы имеют ограничения по памяти (это относится к текстовым полям).
Наконец, мы задаем свойство ShowOpen, чтобы отобразить диалоговое окно. Если пользователь нажимает кнопку Cancel, диалоговое окно возвращает код ошибки, а работа функции отменяется. В противном случае свойству FileName задается имя файла, выбранного пользователем, и это значение возвращается функцией GetFile(). Если имя файла не выбрано, функция возвращает пустую строку. Давайте напишем алгоритм дешифровки, который будет восстанавливать исходный вид файла:
1. Добавьте следующий фрагмент: Private Function Decrypt(infile As String) As Boolean Dim fileno1 As Integer Dim fileno2 As Integer Dim outfile As String Dim xpos As Long Dim x As Byte Dim t(3) As Byte
'Вывести указатель в виде песочных часов MousePointer = vbHourglass
xpos = 4 outfile = " c: \temp.enc" fileno1 = FreeFile Open infile For Binary As fileno1 fileno2 = FreeFile Get #fileno1, 1, t(0) Get #fileno1, 2, t(1) Get #fileno1, 3, t(2) Get #fileno1, 4, t(3) If (t(0)=0 And t(1)=128 And t(2)=0 And t(3)=128) Then Open outfile For Binary As fileno2 Do While Not EOF(fileno1) xpos = xpos + 1 Get #fileno1, xpos, x Get #fileno2, xpos - 4, x + 128 Loop Close fileno2
Decrypt = True Else Decrypt = False End If
Close fileno1
'Удалить исходный файл и заменить его шифрованным If Decrypt Then Kill infile FileCopy outfile, infile Kill outfile End If
'Восстановить указатель мыши MousePointer = vbNormal
End Function
Обратите внимание на то, что эта функция почти совпадает с функцией шифрования. Перед расшифровкой файла необходимо убедиться, что он начинается с электронной подписи, то есть цепочки байтов 0, 128, 0, 128. В процессе шифрования программа вставляет ее в начало зашифрованного файла. Благодаря подписи приложение определяет, действительно ли файл был зашифрован, перед тем, как пытаться расшифровать его.
2. Добавьте код для вызова функции Decrypt при выборе из меню соответствующей команды:
Private Sub mnuActDecrypt_Click() Dim filename As String
filename = GetFile() If filename < > " " Then If Decrypt(filename) = False Then MsgBox " Ошибка при расшифровке файла! " End If End If End Sub
Программа готова - сохраните и запустите ее. Хотя ничего особенно эффектного не происходит, этот пример наглядно показывает, как происходят запись и чтение файлов с диска. Теперь вы обладаете достаточным опытом работы с файлами и сможете применять их в своих программах.
|