Алгоритм
Base64 может использоваться в пользовательских почтовых приложениях, в качестве одного из уровней защиты шифрованием, для хранения двоичных данных и для решения многих других задачах. В большинстве языков высокого уровня используются штатные функции, в Ассемблере приходится все реализовывать самостоятельно.
Алгоритм Base64 использует две функции - кодирования данных и обратного декодирования. Для обеих функций кодирования и декодирования предварительно инициализируются следующие вспомогательные данные:
section '.data' data readable writeable
...
base64_table db "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
db "abcdefghijklmnopqrstuvwxyz"
db "0123456789+/"
decode_table rb 100h
...
А вот сами функции для работы с Base64:
;---------------------------------------------------------------
; Функция кодирования Base64
; Параметры:
; dFrom - указатель на исходные данные
; dTo - указатель на буфер для приема кодированных данных
; dSize - размер исходных данных
; Функция ничего не возвращает
;---------------------------------------------------------------
proc base64_encode dFrom:dword, dTo:dword, dSize:dword
push eax ecx edx esi edi
mov esi,[dFrom]
mov edi,[dTo]
mov ecx,[dSize]
or ecx,ecx
jz .r3
.encode_loop:
lodsd
mov edx,eax
cmp ecx,3
jae .remainder_ok
and edx,0ffffh
cmp ecx,2
jae .remainder_ok
and edx,0ffh
.remainder_ok:
bswap edx
mov eax,edx
shr eax,26
and eax,00111111b
mov al,[base64_table+eax]
stosb
mov eax,edx
shr eax,20
and eax,00111111b
mov al,[base64_table+eax]
stosb
dec ecx
jz .r2
mov eax,edx
shr eax,14
and eax,00111111b
mov al,[base64_table+eax]
stosb
dec ecx
jz .r1
mov eax,edx
shr eax,8
and eax,00111111b
mov al,[base64_table+eax]
stosb
dec esi
dec ecx
jnz .encode_loop
jmp .r3
.r2:
mov al,'='
stosb
.r1:
mov al,'='
stosb
.r3:
xor eax,eax
stosb
pop edi esi edx ecx eax
ret
endp
В этой функции все параметры обязательные. Размер буфера-приемника должен быть примерно в 1,5 раза больше исходных данных, это обусловлено особенностями алгоритма кодирования.
;---------------------------------------------------------------
; Функция декодирования Base64
; Параметры:
; dFrom - указатель на кодированные данные
; dTo - указатель на буфер для приема декодированных данных
; dSize - размер кодированных данных, необязательный параметр
; На выходе:
; EAX - длина декодированных данных
;---------------------------------------------------------------
proc base64_decode dFrom:dword, dTo:dword, dSize:dword
; Если длина строки не указана, то рассчитать
cmp [dSize],0
jnz .len_not_zero
; Штатную функцию API не используем
stdcall _lstrlen,[dFrom]
mov [dSize],eax
cmp eax,0
jnz .len_not_zero
; Если длина нулевая, то вернуть пустую строку
mov byte [dTo],0
xor eax,eax
ret
.len_not_zero:
push ebx ecx edx esi edi
mov ecx,[dSize]
mov esi,[dFrom]
mov edi,[dTo]
xor eax,eax
mov ebx,63
.make_table:
mov al,[base64_table+ebx]
mov [decode_table+eax],bl
dec ebx
jns .make_table
mov [decode_table+'='],0
xor ebx,ebx
.load_dword:
mov edx,[esi]
bswap edx
add esi,4
mov al,dl
mov al,byte[decode_table+eax]
shrd ebx,eax,6
shr edx,8
mov al,dl
mov al,byte[decode_table+eax]
shrd ebx,eax,6
shr edx,8
mov al,dl
mov al,byte[decode_table+eax]
shrd ebx,eax,6
shr edx,8
mov al,dl
mov al,byte[decode_table+eax]
shrd ebx,eax,6
bswap ebx
mov [edi],ebx
add edi,3
sub ecx,4
js .exit_loop
jnz .load_dword
.exit_loop:
mov byte[edi],0
inc edi
mov eax,[dTo]
sub edi,eax
mov eax,edi
dec eax
pop edi esi edx ecx ebx
ret
endp
;---------------------------------------------------------------
; Вспомогательная функция для расчета длины строки
; Параметры:
; lpBuff - указатель на строку в формате ASCIIZ
; На выходе:
; EAX - длина строки
;---------------------------------------------------------------
proc _lstrlen lpBuff:dword
push edi ecx
mov edi,[lpBuff]
xor ecx,ecx
dec ecx
xor eax,eax
repne scasb
not ecx
dec ecx
mov eax,ecx
pop ecx edi
ret
endp
Поскольку данные, закодированные по алгоритму Base64 могут содержать только печатные символы, то в функции декодирования можно не указывать их длину, она будет посчитана автоматически. Но для этого кодированные данные обязательно должны быть записаны в формате ASCIIZ.
Пример использования обеих функций:
section '.data' data readable writeable
...
base64_table db "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
db "abcdefghijklmnopqrstuvwxyz"
db "0123456789+/"
decode_table rb 100h
str1 db 'ManHunter / PCL' ; Строка для кодирования
str2 db 'SGF2ZSBhIE5pY2UgRGF5IQ==',0 ; Закодированная строка
buffer rb 100h ; Буфер-приемник
section '.code' code readable executable
...
; Закодировать строку. Длина строки обязательно указывается
stdcall base64_encode,str1,buff,15
; Теперь buff содержит кодированную строку 'TWFuSHVudGVyIC8gUENM'
...
; Раскодировать строку. Длина рассчитается автоматически
stdcall base64_decode,str2,buff,NULL
; buff содержит раскодированную строку 'Have a Nice Day!'
...