zoukankan      html  css  js  c++  java
  • 奇妙的Base64编码

    各位看官应该都是资深的网虫了,小弟斗胆在此问问大家,平时上网时,除了泡MM、到论坛灌水、扔版砖……之外,进行的最多的是什么活动?对了,你一定会说:是收发电子邮件!(谁敢说自己没收/发过电子邮件的?拉出去枪毙了!!) 收/发E-mail的时候有一个安全性的问题--假想一下,你花了一整天时间给系花写的情书,在发送的过程中被隔壁宿舍张三那小子截获了(难道他是黑客??), 更糟的是他是你的情敌啊……天,后果不堪设想!!因此,我们必须有一种比较可靠的加密方法,能够对电子邮件的明文进行转换,至少要得出一个无法被别人一眼 就看出内容来的东西,而且编码/解码的速度还要足够快。(这时你可以再假想一下啦,张三那家伙截获了你的肉麻情书,可是他一看:“咦?怎么乱七八糟的?垃 圾邮件!!”--这样一来你不就逃过大难了?!) Base64就是在这种背景下产生的加密方法。它的特点是:1、速度非常快。2、能够将字符串A转换成字符串B,而且如果你光看字符串B,是绝对猜不出字符串A的内容来的。不信吗?让我们来看看下面这串东西: xOO6w6Osu7bTrbniwdnAz8LetcTnzbfXzOy12KOh 呵呵,是什么啊?猜出来了吗?其实它就是下面这段文字经过Base64编码产生的东东: 你好,欢迎光临老罗的缤纷天地! 介绍说完啦,让我们开始探讨实质性的东西。 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。 Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。 这样说会不会太抽象了?不怕,我们来看一个例子: 转换前 aaaaaabb ccccdddd eeffffff 转换后 00aaaaaa 00bbcccc 00ddddee 00ffffff 应该很清楚了吧?上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。 转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:(摘自RFC2045) Table 1: The Base64 Alphabet value Encoding value Encoding value Encoding value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y 让我们再来看一个实际的例子,加深印象! 转换前 10101101 10111010 01110110 转换后 00101011 00011011 00101001 00110110 十进制 43 27 42 54 对应码表中的值 r b q 2 所以上面的24位编码,编码后的Base64值为 rbq2 解码同理,把 rbq2 的二进制位连接上再重组得到三个8位值,得出原码。 (解码只是编码的逆过程,在此我就不多说了,另外有关MIME的RFC还是有很多的,如果需要详细情况请自行查找。) 用更接近于编程的思维来说,编码的过程是这样的: 第一个字符通过右移2位获得第一个目标字符的Base64表位置,根据这个数值取到表上相应的字符,就是第一个目标字符。 然后将第一个字符左移6位加上第二个字符右移4位,即获得第二个目标字符。 再将第二个字符左移4位加上第三个字符右移6位,获得第三个目标字符。 最后取第三个字符的右6位即获得第四个目标字符. So easy! That’s all!!! 可是等等……聪明的你可能会问到,原文的字节数量应该是3的倍数啊,如果这个条件不能满足的话,那该怎么办呢? 我们的解决办法是这样的:原文的字节不够的地方可以用全0来补足,转换时Base64编码用=号来代替。这就是为什么有些Base64编码会以一个或两个等号结束的原因,但等号最多只有两个。因为: 余数 = 原文字节数 MOD 3 所以余数任何情况下都只可能是0,1,2这三个数中的一个。如果余数是0的话,就表示原文字节数正好是3的倍数(最理想的情况啦)。如果是1的话,为了让Base64编码是4的倍数,就要补2个等号;同理,如果是2的话,就要补1个等号。 讲到这里,大伙儿应该全明白了吧?如果还有不清楚的话就返回去再仔细看看,其实不难理解的。 下面我给出一个演示Base64编码/解码的程序,希望能对您有用。同时也希望您帮我完善它,利用它做出更多的用途,到时别忘了通知我一声啊!(我现在太忙了) DLL的源代码:Base64Dll.asm ;*********************************************** ;程序名称:演示Base64编码/解码原理 ;作者:罗聪 ;日期:2002-9-14 ;出处:http://laoluoc.yeah.net(老罗的缤纷天地) ;注意事项:如欲转载,请保持本程序的完整,并注明: ;转载自“老罗的缤纷天地”(http://laoluoc.yeah.net) ;*********************************************** .386 .model flat, stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib DllEntry proto :HINSTANCE, WORD, WORD Base64Encode proto WORD, WORD Base64Decode proto WORD, WORD .data ;Base64 -> ASCII mapping table base64_alphabet db "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ;ASCII -> Base64 mapping table base64table db 43 dup (255) db 62,255,255,255,63,52,53,54,55,56,57,58,59,60,61,255 db 255,255,0,255,255,255,0,1,2,3,4,5,6,7,8,9,10,11,12,13 db 14,15,16,17,18,19,20,21,22,23,24,25,255,255,255,255 db 255,255,26,27,28,29,30,31,32,33,34,35,36,37,38 db 39,40,41,42,43,44,45,46,47,48,49,50,51 db 132 dup (255) .code DllEntry proc hInst: HINSTANCE, reason: DWORD, reserved1: DWORD mov eax, TRUE ret DllEntry endp ;********************************************************** ;函数功能:进行Base64编码 ;参数: ; source = 传入的字符串 ; destination = 返回的编码 ;********************************************************** Base64Encode proc uses ebx edi esi sourceWORD, destinationWORD LOCAL sourcelenWORD invoke lstrlen, source mov sourcelen, eax mov esi, source mov edi, destination @@base64loop: xor eax, eax .if sourcelen == 1 lodsb ;source ptr + 1 mov ecx, 2 ;bytes to output = 2 mov edx, 03D3Dh ;padding = 2 byte dec sourcelen ;length - 1 .elseif sourcelen == 2 lodsw ;source ptr + 2 mov ecx, 3 ;bytes to output = 3 mov edx, 03Dh ;padding = 1 byte sub sourcelen, 2 ;length - 2 .else lodsd mov ecx, 4 ;bytes to output = 4 xor edx, edx ;padding = 0 byte dec esi ;source ptr + 3 (+4-1) sub sourcelen, 3 ;length - 3 .endif xchg al,ah ;flip eax completely rol eax, 16 ;can this be done faster xchg al,ah @@: push eax and eax, 0FC000000h ;get the last 6 high bits rol eax, 6 ;rotate them into al mov al, byte ptr [offset base64_alphabet + eax] ;get encode character stosb ;write to destination pop eax shl eax, 6 ;shift left 6 bits dec ecx jnz @B ;loop cmp sourcelen, 0 jnz @@base64loop ;main loop mov eax, edx ;add padding and null terminate stosd ret Base64Encode endp ;********************************************************** ;函数功能:进行Base64解码 ;参数: ; source = 传入的编码 ; destination = 返回的字符串 ;********************************************************** Base64Decode proc uses ebx edi esi sourceWORD, destinationWORD LOCAL sourcelenWORD invoke lstrlen, source mov sourcelen, eax mov esi, source ;esi <- source mov edi, destination ;edi <- destination mov ecx, sourcelen shr ecx, 2 cld ;-------------[decoding part]--------------- @@outer_loop: push ecx mov ecx, 4 xor ebx, ebx lodsd @@inner_loop: push eax and eax, 0ffh mov al, byte ptr [offset base64table + eax] cmp al, 255 je @@invalid_char shl ebx, 6 or bl, al pop eax shr eax, 8 dec ecx jnz @@inner_loop mov eax, ebx shl eax, 8 xchg ah, al ror eax, 16 xchg ah, al stosd dec edi pop ecx dec ecx jnz @@outer_loop xor eax, eax jmp @@decode_done ;------------------------------------------- @@invalid_char: mov eax, -1 @@decode_done: ret Base64Decode ENDP end DllEntry ;******************** over ******************** ;by LC -------------------------------------------------------------------------------- 测试程序:base64.asm ;*********************************************** ;程序名称:演示Base64编码/解码原理 ;作者:罗聪 ;日期:2002-9-14 ;出处:http://laoluoc.yeah.net(老罗的缤纷天地) ;注意事项:如欲转载,请保持本程序的完整,并注明: ;转载自“老罗的缤纷天地”(http://laoluoc.yeah.net) ;*********************************************** .386 .model flat, stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc include Base64Dll.inc includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib includelib Base64Dll.lib WndProc proto WORD, WORD, WORD, WORD .const IDC_BUTTON_ENCODE equ 3000 IDC_BUTTON_DECODE equ 3001 IDC_EDIT_INPUT equ 3002 MAXSIZE equ 260 .data szDlgName db "lc_dialog", 0 szCaption db "BASE64 demo by LC", 0 szBuffer db 255 dup(0) szText db 340 dup(0) szMsg db 450 dup(0) szTemplate_Encode db "字符串 ""%s"" 的Base64编码是:", 13, 10, 13, 10, "%s", 0 szTemplate_Decode db "编码 ""%s"" 经过Base64还原后的字符串是:", 13, 10, 13, 10, "%s", 0 .code main: invoke GetModuleHandle, NULL invoke DialogBoxParam, eax, offset szDlgName, 0, WndProc, 0 invoke ExitProcess, eax WndProc proc uses edi hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM LOCAL hEdit: HWND .if uMsg == WM_CLOSE invoke EndDialog, hWnd, 0 .elseif uMsg == WM_COMMAND mov eax, wParam mov edx, eax shr edx, 16 movzx eax, ax .if edx == BN_CLICKED .if eax == IDCANCEL invoke EndDialog, hWnd, NULL .elseif eax == IDC_BUTTON_ENCODE || eax == IDOK ;取得用户输入的字符串: invoke GetDlgItemText, hWnd, IDC_EDIT_INPUT, addr szBuffer, 255 ;进行 ASCII->Base64 转换: invoke Base64Encode, addr szBuffer, addr szText ;格式化输出: invoke wsprintf, addr szMsg, addr szTemplate_Encode, addr szBuffer, addr szText ;显示结果: invoke MessageBox, hWnd, addr szMsg, addr szCaption, MB_OK .elseif eax == IDC_BUTTON_DECODE ;取得用户输入的字符串: invoke GetDlgItemText, hWnd, IDC_EDIT_INPUT, addr szBuffer, 255 ;进行 Base64->ASCII 转换: invoke Base64Decode, addr szBuffer, addr szText ;格式化输出: invoke wsprintf, addr szMsg, addr szTemplate_Decode, addr szBuffer, addr szText ;显示结果: invoke MessageBox, hWnd, addr szMsg, addr szCaption, MB_OK .endif ;全选edit里面的内容: invoke GetDlgItem, hWnd, IDC_EDIT_INPUT invoke SendMessage, eax, EM_SETSEL, 0, -1 .endif .else mov eax, FALSE ret .endif mov eax, TRUE ret WndProc endp end main ;******************** over ******************** ;by LC -------------------------------------------------------------------------------- 测试程序的资源文件:base64.rc #include "resource.h" #define IDC_BUTTON_ENCODE 3000 #define IDC_BUTTON_DECODE 3001 #define IDC_EDIT_INPUT 3002 #define IDC_STATIC -1 LC_DIALOG DIALOGEX 10, 10, 195, 60 style DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Base64 demo by LC" FONT 9, "宋体", 0, 0, 0x0 BEGIN LTEXT "请输入字符串:", IDC_STATIC, 11, 7, 130, 10 EDITTEXT IDC_EDIT_INPUT, 11, 20, 173, 12, ES_AUTOHSCROLL DEFPUSHBUTTON "编码(&E)", IDC_BUTTON_ENCODE, 38, 39, 52, 15 PUSHBUTTON "解码(&D)", IDC_BUTTON_DECODE, 104, 39, 52, 15 END 如果你发现了有bug,一定要告诉我啊,并请来信讨论!lcother@163.net 最后给大家留下一个小小的习题,你知道下面这串Base64编码的原文是什么吗? :) 0LvQu8T6xM3XxdDU19O/tM3qztK1xEJhc2U2NL3Ms8yjoSCjuqOp
  • 相关阅读:
    6-Python爬虫-分布式爬虫/Redis
    ES 查询时 排序报错(fielddata is disabled on text fileds by default ... )解决方法
    Intellij Idea webstorm 激活
    Intellij Idea 配置jdk
    java 获取(格式化)日期格式
    js 跳转 XSS漏洞 预防
    CSS去掉背景颜色
    js对象无法当成参数传递 解决方法
    Elasticsearch java api
    java多条件查询SQL语句拼接的小技巧
  • 原文地址:https://www.cnblogs.com/adodo1/p/4327786.html
Copyright © 2011-2022 走看看