Visual Basic, .NET, ASP, VBScript
 

   
 
Описание для автора не найдено
 
     
   
 


В последнее время вопрос о защите программ и данных стал очень актуальным как для программистов, так и для простых передовых пользователей, а случаи незаконного обращения к личной виртуальной информации человека не единичны. Конечно, существует множество разнообразных криптографических пакетов, но, как правило, они все направлены на защиту текстовой информации, когда как многие, порой даже профессиональные программные продукты, абсолютно лишены какой-либо защиты персональных настроек и данных пользователей, что зачастую для самого юзера создает лишнюю головную боль, а разработчика этого программного обеспечения приводит к потере драгоценных клиентов, а порой и к судебным баталиям.

Конечно, данные проблемы вызывают неприятные ощущения у обеих сторон конфликта. Но конфликт является борьбой двух противоположных убеждений и мнений. Значит, если программист решит написать качественный программный продукт, чтобы не создавать головных болей ни себе, ни своему пользователю, то, возможно, такие бы столкновения и не возникали.

Однако, после продолжительных поисков методов защиты информации на VB я не пришел к подходящему примеру, полностью подходящему для моих условий. Мне самому требовалось защитить записи ini-файлов моего компьютерного администратора, чтобы перед записью строки файл расшифровывался, добавлялась или изменялась сама строка и файл кодировался. Все примеры, которые я находил, были довольно расплывчаты и просты. Мне же требовалась довольно крепкая защита файлов с использованием прочного алгоритма и без создание temp-овых файлов.

Оставалось одно: приступить к написанию собственного метода защиты, чем я позже и занялся. В основе моего "криптопакета" лежали очень интересный пример из книги Microsoft Press "VB 5.0 Мастерская разработчика". Пример состоял из непосредственно класса защиты и функций шифрования-дешифрования.

Для начала рассмотрим основной класс защиты информации. Назовем его "CIPHER":
' Код класса CIPHER
Option Explicit

Private msKeyString As String
Private msText As String

'~~~.KeyString
Public Property Let KeyString(sKeyString As String)
    msKeyString = sKeyString
    Initialize
End Property

'~~~.Text
Public Property Let Text(sText As String)
    msText = sText
End Property
Public Property Get Text() As String
    Text = msText
End Property

'~~~.DoXor
Public Sub DoXor()
    Dim intC As Integer
    Dim intB As Integer
    Dim lngI As Long
    For lngI = 1 To Len(msText)
        intC = Asc(Mid(msText, lngI, 1))
        intB = Int(Rnd * 256)
        Mid(msText, lngI, 1) = Chr(intC Xor intB)
    Next lngI
End Sub

'~~~.Stretch
Public Sub Stretch()
    Dim intC As Integer
    Dim lngI As Long
    Dim lngJ As Long
    Dim intK As Integer
    Dim lngA As Long
    Dim sB As String
    lngA = Len(msText)
    sB = Space(lngA + (lngA + 2) \ 3)
    For lngI = 1 To lngA
        intC = Asc(Mid(msText, lngI, 1))
        lngJ = lngJ + 1
        Mid(sB, lngJ, 1) = Chr((intC And 63) + 59)
        Select Case lngI Mod 3
        Case 1
            intK = intK Or ((intC \ 64) * 16)
        Case 2
            intK = intK Or ((intC \ 64) * 4)
        Case 0
            intK = intK Or (intC \ 64)
            lngJ = lngJ + 1
            Mid(sB, lngJ, 1) = Chr(intK + 59)
            intK = 0
        End Select
    Next lngI
    If lngA Mod 3 Then
        lngJ = lngJ + 1
        Mid(sB, lngJ, 1) = Chr(intK + 59)
    End If
    msText = sB
End Sub

'~~~.Shrink
Public Sub Shrink()
    Dim intC As Integer
    Dim intD As Integer
    Dim intE As Integer
    Dim lngA As Long
    Dim lngB As Long
    Dim lngI As Long
    Dim lngJ As Long
    Dim lngK As Long
    Dim sB As String
    lngA = Len(msText)
    lngB = lngA - 1 - (lngA - 1) \ 4
    sB = Space(lngB)
    For lngI = 1 To lngB
        lngJ = lngJ + 1
        intC = Asc(Mid(msText, lngJ, 1)) - 59
        Select Case lngI Mod 3
        Case 1
            lngK = lngK + 4
            If lngK > lngA Then lngK = lngA
            intE = Asc(Mid(msText, lngK, 1)) - 59
            intD = ((intE \ 16) And 3) * 64
        Case 2
            intD = ((intE \ 4) And 3) * 64
        Case 0
            intD = (intE And 3) * 64
            lngJ = lngJ + 1
        End Select
        Mid(sB, lngI, 1) = Chr(intC Or intD)
    Next lngI
    msText = sB
End Sub

Private Sub Initialize()
    Dim intI As Integer
    Randomize Rnd(-1)
    For intI = 1 To Len(msKeyString)
        Randomize Rnd(-Rnd * Asc(Mid(msKeyString, intI, 1)))
    Next intI
End Sub
Не буду разбирать построчно класс, это все прекрасно описано в самом учебнике по программированию. Да и мне кажется, что это не столь важно начинающим.

Далее нам требуется форма, в которой мы укажем путь к файлу и пароль для шифрования. Само собой, эта форма будет иметь Visible = False и не будет вызываться из других модулей. Назовем ее "Admin". Добавим на нее два Textbox'а: txtFile и txtPassword1 в которых мы разместим путь к файлу и пароль для шифрования:
' Код формы Admin
Option Explicit

Private Sub Form_Load()
' Вставляем в txtFile путь к файлу настроек
txtFile.Text = App.Path + "\" + "options.ini"
End Sub

Private Sub txtFile_Change()
    Dim lFileLen As Long
    Dim sHead As String
    ' Проверяем наличие файла
    On Error Resume Next
    lFileLen = Len(Dir(txtFile.Text))
    ' Проверяем на наличие ошибок в имени файла
    If Err <> 0 Or lFileLen = 0 Or Len(txtFile.Text) = 0 Then
        Exit Sub
    End If
    ' Проверяем по строке [Secret] в начале файла, 
    ' что он зашифрован нашим классом
    Open txtFile.Text For Binary As #1
    sHead = Space(8)
    Get #1, , sHead
    Close #1
End Sub

Sub Encrypt()
    Dim sHead As String
    Dim sT As String
    Dim sA As String
    Dim cphX As New Cipher
    Dim n As Long
    Open txtFile.Text For Binary As #1
    'Load entire file into sA
    sA = Space$(LOF(1))
    Get #1, , sA
    Close #1
    ' Подготовка к шифрованию через функцию Hash
    sT = Hash(Date & Str(Timer))
    sHead = "[Secret]" & sT & Hash(sT & txtPassword1.Text)
    ' Шифрование
    cphX.KeyString = sHead
    cphX.Text = sA
    cphX.DoXor
    cphX.Stretch
    sA = cphX.Text
    ' Запись результатов
    Open txtFile.Text For Output As #1
    Print #1, sHead
    ' Окончание
    n = 1
    Do
        Print #1, Mid(sA, n, 70)
        n = n + 70
    Loop Until n > Len(sA)
    Close #1
End Sub

Sub Decrypt()
    Dim sHead As String
    Dim sA As String
    Dim sT As String
    Dim cphX As New Cipher
    Dim n As Long
    ' Проверяем по строке [Secret] в начале файла, 
    ' что он зашифрован нашим классом
    Open txtFile.Text For Input As #1
    Line Input #1, sHead
    Close #1
    ' Проверяем пароль
    sT = Mid(sHead, 9, 8)
    If InStr(sHead, Hash(sT & txtPassword1.Text)) <> 17 Then
    Beep
        Exit Sub
    End If
    ' Открываем файл
    Open txtFile.Text For Input As #1
    Line Input #1, sHead
    Do Until EOF(1)
        Line Input #1, sT
        sA = sA & sT
    Loop
    Close #1
    ' Дешифрование
    cphX.KeyString = sHead
    cphX.Text = sA
    cphX.Shrink
    cphX.DoXor
    sA = cphX.Text
    ' Удаляем файл
    Kill txtFile.Text
    Open txtFile.Text For Binary As #1
    Put #1, , sA
    Close #1
End Sub

Function Hash(sA As String) As String
    Dim cphHash As New Cipher
    cphHash.KeyString = sA & "123456"
    cphHash.Text = sA & "123456"
    cphHash.DoXor
    cphHash.Stretch
    cphHash.KeyString = cphHash.Text
    cphHash.Text = "123456"
    cphHash.DoXor
    cphHash.Stretch
    Hash = cphHash.Text
End Function

Public Function Code()
    Refresh
    Encrypt
    txtFile_Change
End Function

Public Function DeCode()
    Refresh
    Decrypt
    txtFile_Change
End Function
Думаю тут вы во всем разобрались. Теперь, чтобы зашифровать файл настроек нужно вызвать Call Admin.Code, а чтобы расшифровать - Call Admin.Decode.

Остается нам написать функцию чтения-записи ini-файлов. Создадим модуль и назовем его "modINI" и вставим следующий код:
' Код модуля modINI
' Чтение и запись строк в файлы инициализации
Declare Function GetPrivateProfileString& Lib _
"kernel32" Alias "GetPrivateProfileStringA" (ByVal _
lpszSection$, ByVal lpszKey$, ByVal lpszDefault$, _
ByVal lpszReturnBuffer$, ByVal cchReturnBuffer&, _
ByVal lpszFile$)
Declare Function WritePrivateProfileString Lib _
"kernel32" Alias "WritePrivateProfileStringA" (ByVal _
lpApplicationName As String, ByVal lpKeyName As String, _
ByVal lpString As String, ByVal lplFileName As String) As Long

' Чтение из файла инициализации
Public Function GetINI(INIfile As String, Section As String, _
Key As String, Default As String)
' Дешифруем
Call Admin.DeCode
' Читаем данные
Dim temp As String * 256
Dim length As Integer
temp = Space$(256)
length = GetPrivateProfileString(Section, Key, _
Default, temp, 255, INIfile)
GetINI = Left$(temp, length)
' Шифруем
Call Admin.Code
End Function

' Запись в файл инициализации
Public Sub SetINI(INIfile As String, Section As String, _
Key As String, Value As String)
' Дешифруем
Call Admin.DeCode
' Записываем данные
Dim n As Integer
Dim temp As String
temp = Value
For n = 1 To Len(Value)
If Mid$(Value, n, 1) = vbCr Or Mid$(Value, n, 1) = vbLf _
Then Mid$(Value, n) = ""
Next n
n = WritePrivateProfileString(Section, Key, temp, INIfile)
' Шифруем
Call Admin.Code
End Sub
Для записи в ini-файл используйте строку:
SetINI Admin.txtFile.text, "Option", "Thing", Object
' Пример: SetINI Admin.txtFile.text, "SETUP", "Check1", Check1.Value
Для чтения из ini-файла используйте строку вида:
Object = GetINI(Admin.txtFile.text, "Option", "Thing", "Off")
' Где "Off" это вывод по умолчанию, если данной строки в файле нет 
' Пример: Check1.Value = GetINI(Admin.txtFile.text, "SETUP", "Check1", "0")
Вот и все. Теперь вы можете не беспокоиться о защите настроек своей программы, где вы можете хранить не только сохраненные программные опции но и непосредственно личные пользовательские пароли и электронные ключи.

В дополнение хочу сказать, что данный код можно дополнить некоторыми полезными вставками. Например при первом запуске программы прописываем в реестре строку, которая будет означать, что файл настроек создан и успешно работает. И если же он будет удален, то программа блокируется и требует системного пароля.

Также, если администратору требуется самостоятельно отредактировать файл настроек, можно вставить данный кусок кода и не зубудьте поставить у формы использующей этот код KeyPreview = True:
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Dim lFileLen As Long
Dim sHead As String
On Error Resume Next
lFileLen = Len(Dir(Admin.txtFile.Text))
If Err <> 0 Or lFileLen = 0 Or Len(Admin.txtFile.Text) = 0 Then
Exit Sub
End If
Open Admin.txtFile.Text For Binary As #1
sHead = Space(8)
Get #1, , sHead
Close #1

If KeyCode = vbKeyF12 Then
' Тут мы выключаем все, что записывает информацию
Call Admin.DeCode
Beep
ElseIf KeyCode = vbKeyF11 Then
If sHead <> "[Secret]" Then
' Тут мы обратно включаем запись настроект и шифруем
Call Admin.Code
Beep
End If
Тут как видно из примера при нажатии клавиши F12 информация будет дешифровываться и можно будет отредактировать самостоятельно файл настроек, а при нажатии F11 информация будет переведена в первоначальное состаяние.

Конечно, эти вариации можно продолжать и продолжать, а пока довольствуйтесь предоставленной вам информацией и защищенными электронными данными :).
 
     

   
   
     
  VBNet рекомендует