Простейшая программа шифрования
Мы рассмотрим основные принципы работы с двоичными файлами на примере программы шифрования файлов. Не надейтесь, что файл, созданный этой программой, не будет взломан хорошим программистом — мы реализуем простейший алгоритм шифрования. Данный пример предназначен лишь для того, чтобы продемонстрировать особенности работы с файлами в двоичном режиме доступа. Шифрование выполняется командой меню Actions > Encrypt, a расшифровка -командой Actions > Decrypt. B обоих случаях вам будет предложено выбрать текстовый файл, с которым будет выполняться операция.
1. Создайте новый проект типа Standard EXE.
2. Активизируйте форму Form1 и задайте ее свойству Name значение frmMain, а свойству Caption — значение Шифрование файлов.
3. Поместите на форму элемент стандартного диалогового окна, задайте его свойству Name значение dlgFile.
4. Откройте редактор меню и создайте в нем следующие объекты:
Меню File:
Caption: | Name: |
&File | mnuFile |
Команды меню File:
Caption: | Name: |
&Exit | mnuFileExit |
Меню Actions:
Caption: | Name: |
&Actions | mnuAct |
Команды меню Action
Caption: | Name: |
&Encrypt | mnuActEncrypt |
&Decrypt | mnuActDecrypt |
У вас получится форма, похожая на рис. 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
Программа готова - сохраните и запустите ее. Хотя ничего особенно эффектного не происходит, этот пример наглядно показывает, как происходят запись и чтение файлов с диска. Теперь вы обладаете достаточным опытом работы с файлами и сможете применять их в своих программах.
Элементы данных
Многие программисты на Visual Basic предпочитают хранить данные в таблицах Microsoft Access или других баз данных, псскольку Visual Basic позволяет относительно легко работать с ними. Достаточно поместить элементы на форму, задать значения нескольких свойств — и можно работать практически с любой базой данных! Вы можете убедиться в этом на примере базы данных Biblio.mdb, входящей в комплект Visual Basic, — по умолчанию она находится в каталоге VB98. Эта база данных (и входящие в нее таблицы) была спроектирована заранее, но вам, вероятно, захочется создавать свои собственные базы данных. Для создания базы данных Access можно жестко закодировать все определения таблиц, полей и индексов, но это не всегда удобно. Существует пара других вариантов:
О Если на вашем компьютере установлен Microsoft Access, вы можете легко создать базу данных, с которой будет работать Visual Basic. Это самый быстрый и эффективный, но не единственный способ создания базы данных.
О Если у вас нет Access, воспользуйтесь специальной надстройкой Visual Basic Visual Data Manager (рис. 8.7). Она запускается командой Add-Ins > Data Manager.
Рис. 8.7. VisualData Manager
Создав базу данных, следует выбрать способ работы с ней в Visual Basic. Существует несколько вариантов:
О Самостоятельно запрограммировать все необходимые действия и работать с базой данных через DAO (Data Access Objects - объекты для обращения к базам данных), RDO (Remote Database Objects - объекты дистанционных баз данных) или ADO (ActiveX Data Objects - объекты данных ActiveX). Bce перечисленные объекты позволяют работать с записями, таблицами и запросами из программы. Объекты ADO появились только в Visual Basic версии 6-с их помощью можно обращаться к разным базам данных через общий унивео-сальный интерфейс.
О Поручить всю черновую работу специальному мастеру - Visual Basic Data Form Designer. Чтобы установить его, выполните команду Add-Ins > Add-In Manager и выберите мастера из предложенного списка. После этого мастер появится в меню Add-Ins и останется там до тех пор, пока не будет удален из Add-In Manager.
О Воспользоваться элементами данных, входящими в состав Visual Basic. Именно этот способ будет рассматриваться в следующем разделе.