Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:


Реализация алгоритма BASE64 на VB

Поиск:
Реализация алгоритма BASE64 на VB

Введение
Случилось мне прорываться сквозь заслон авторизующего proxy-сервера. Чтобы осуществить соединение через эту штуку, нужно в HTTP запросе передать закодированную в BASE64 строку "login:password". Прорывался я с помощью VB, поэтому для меня стало актуальным раздобыть либо описание алгоритма, либо какую-нибудь его реализацию на VB. Так как я предпочитаю не связываться с ActiveX компонентами по пустякам, то все варианты реализации этих компонентов были мною исключены из поисков. Остались лишь реализации на VB и методы, использующие WinAPI. Метод, задействующий CryptoAPI меня тоже не вдохновил, так как там есть серьезные ограничения на тип ОС. Осталось отыскать реализацию кода.

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

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

Алгоритм BASE64
Зачем нужно BASE64 кодирование
Все началось с того, что на белом свете существуют каналы, передающие данные в 7 битовом формате. Мало того - существуют терминалы, которые отображают только 7 битовую информацию. Так вот для того, чтобы передать по таким каналам и терминалам 8 битную информацию и были придуманы методы кодирования.

Суть методов проста - нужно разбить 8 битные данные на порции, меньшие 7 бит, и передавать эти данные по каналам и быть уверенным, что эти данные успешно преодолеют всевозможные барьеры. Одной из таких реализаций является BASE64 кодирование.

Разбор алгоритма
Пусть мы хотим закодировать в BASE64 следующий набор символов: "ядрена bugs". В HEX эта строка символов выглядит так: FF E4 F0 E5 ED E0 20 62 75 67 73, а в бинарном формате так:
11111111 11100100 11110000
11100101 11101101 11100000
00100000 01100010 01110101
01100111 01110011

Алгоритм разбивает эту последовательность бит на группы по 6 бит, а если бит не хватает, то дописывает в конец нули. В нашем случае есть 88 бит, которые не делятся на 6 без остатка, поэтому нужно будет дописать 2 нуля в конец этой последовательности. Последовательность по 6 бит выглядит так:
111111 111110 010011 110000
111001 011110 110111 100000
001000 000110 001001 110101
011001 110111 001100

Если преобразовать эту последовательность в числа, то получим индексы символов из последовательности: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".
Так как 3 восьмибитных символа преобразуются в 4 шестибитных символа, было принято решение дополнять любую последовательность до числа символов, кратных 4, а вместо недостающих символов дописывать знак "=".

Реализация алгоритма
В этом алгоритме очень удобно работать с 24 битовыми последовательностями (3 байта или 4 шестибитовые последовательности). Преобразовывать в символы ничего не будем !!! Будем работать с типом LONG, в котором можно манипулировать без проблем 31 битом ( если манипулировать 32 битами, то возникают проблемы, связанные с тем, что тип LONG имеет знак, выставляемый в крайнем левом бите).

Тип LONG в битовом представленнии выглядит так: 00000000 00000000 00000000 00000000. Первые 3 символа в этот тип нужно записать так: 00000000 11111111 11100100 11110000. Но как это сделать? А очень просто - вспомним, что чтобы "сдвинуть" биты в числе на n позиций влево, нужно умножить это число на 2^n. Вот так-то smile

Поэтому 3 буквы "ядр" в типе Long разместятся так:
l = 255*2^16 + 228*2^8 + 240 = 16770288 = 00000000 11111111 11100100 11110000

С обратным преобразованием тоже нет никаких проблем - в VB есть операторы целочисленного деления "\" и получения остатка от деления "mod". поэтому 6 битовую последовательность можно получить так:
b1 = l\(2^18)
b2 = l\(2^12) mod 2^6
b3 = l\(2^6) mod 2^6
b4 = l mod 2^6

Стоит отметить, что для преобразования очень длинных 8 битных последовательностей, стоит разделить алгоритм на 2 части. Первая будет работать с 3 символьными последовательностями очень быстро, а вторая будет разбираться с остатками символов как придется (это чтобы исключить из цикла проверку на достижение конца строкиsmile

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

Использовать класс можно так:
Код
Dim b64 as New BASE64
dstStr = b64.cBASE64(srcStr)

Реализация класса BASE64:
Код
Option Explicit

Const Base64Table As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

Private b64(63) As String
Private b256(255) As Long

Private Sub Class_Initialize()
Dim i As Long
For i = 0 To 63 Step 1
   b64(i) = Mid$(Base64Table, i + 1, 1)
   b256(AscB(b64(i))) = i
Next
End Sub

' Кодирует данные в кодировку BASE64
Public Function cBASE64(s As String) As String
Dim lenStr, endPos, lastChars, l, i As Long
lenStr = Len(s)
lastChars = lenStr Mod 3
endPos = lenStr - lastChars

For i = 1 To endPos Step 3
   l = CLng(AscB(Mid$(s, i, 1))) * 65536 + CLng(AscB(Mid$(s, i + 1, 1))) * 256 + CLng(AscB(Mid$(s, i + 2, 1)))
   cBASE64 = cBASE64 & b64(l \ 262144) & b64((l \ 4096) Mod 64) & _
   b64((l \ 64) Mod 64) & b64(l Mod 64)
Next

Select Case lastChars
   Case 1
       l = CLng(AscB(Right(s, 1))) * 16
       cBASE64 = cBASE64 & b64((l \ 64) Mod 64) & b64(l Mod 64) & "=="
   Case 2
       l = CLng(AscB(Mid$(s, lenStr - 1, 1))) * 1024 + CLng(AscB(Right$(s, 1))) * 4
       cBASE64 = cBASE64 & b64((l \ 4096) Mod 64) & _
       b64((l \ 64) Mod 64) & b64(l Mod 64) & "="
End Select
End Function

' ДеКодирует данные из кодировки BASE64
Public Function eBASE64(s As String) As String
Dim lenStr, endPos, lastChars, l, i As Long
lenStr = Len(s)
If Right(s, 2) = "==" Then
   lenStr = lenStr - 2
Else
   If Right(s, 1) = "=" Then lenStr = lenStr - 1
End If

lastChars = lenStr Mod 4
endPos = lenStr - lastChars
For i = 1 To endPos Step 4
   l = b256(AscB(Mid$(s, i, 1))) * 262144 + b256(AscB(Mid$(s, i + 1, 1))) * 4096 + b256(AscB(Mid$(s, i + 2, 1))) * 64 + b256(AscB(Mid$(s, i + 3, 1)))
   eBASE64 = eBASE64 & Chr(l \ 65536) & Chr((l \ 256) Mod 256) & _
   Chr(l Mod 256)
Next

Select Case lastChars
   Case 2
       l = b256(AscB(Mid$(s, lenStr - 1, 1))) * 1024 + b256(AscB(Mid$(s, lenStr, 1))) * 16
       eBASE64 = eBASE64 & Chr(l \ 256)
   Case 3
       l = (b256(AscB(Mid$(s, lenStr - 2, 1))) * 4096 + b256(AscB(Mid$(s, lenStr - 1, 1))) * 64 + b256(AscB(Mid$(s, lenStr, 1)))) \ 4
       eBASE64 = eBASE64 & Chr(l \ 256) & Chr(l Mod 256)
End Select
End Function

Автор статьи: Илья Винокуров
Статья взята на: www.w3m.ru

Вот еще один пример использования класса:
Код
Private Sub Form_Load()
Dim StringToEncode As String
Dim b64 As New BASE64
Dim srcStr As String
srcStr = "To be or not to be?"
Debug.Print b64.cBASE64(srcStr)
Debug.Print b64.eBASE64(b64.cBASE64(srcStr))
End Sub


У этого класса есть только один недостаток: с помощью него нельзя зашифровать русский текст. Эта проблема решается одним хитрым способом, на который я как-то раз наткнулся. smile
В модуль:
Код
Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Public Function Encode(ByVal iStr As String) As String
Dim iXml As New MSXML2.DOMDocument30
Dim iArray() As Byte

   With iXml.createElement("Encoder")
       .dataType = "bin.base64"
       ReDim iArray(LenB(iStr))
       CopyMemory iArray(0), ByVal StrPtr(iStr), LenB(iStr)

       .nodeTypedValue = iArray()
       Encode = .Text
   End With
   
End Function


Public Function Decode(ByVal iStrbase64 As String) As Byte()
Dim strXML As String

   strXML = "<DECODER xmlns:dt=" & Chr(34) & "urn:schemas-microsoft-com:datatypes" & Chr(34) & " dt:dt=" & Chr(34) & "bin.base64" & Chr(34) & ">" & iStrbase64 & "</DECODER>"
   With New MSXML2.DOMDocument30
       .loadXML strXML
       Decode = .selectSingleNode("DECODER").nodeTypedValue
   End With
   
End Function

Не забудьте подключить msxml3.dll (возможно у вас есть другая версия этой библиотеки). Она должна быть в вашей системной директории.

Вот пример использования:
Код
Private Sub Form_Load()
Dim StringToEncode As String
StringToEncode = "Быть или не быть?"
Debug.Print Encode(StringToEncode)
Debug.Print Decode(Encode(StringToEncode))
End Sub
Автор: cardinal
Сайт: http://






Просмотров: 9649

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную