zoukankan      html  css  js  c++  java
  • Base64编码和解码原理

    Base64常用于对电子邮件、短信、URL等进行编码和传输,在Python和Mysql中都有实现方式

    但这里要说的是它编码的基本原理和步骤。

    1. 首先相信大家都会看到这个表:Base64对应的字符表,一共64个字符,包括26个字母的大小写、10个阿拉伯数字、+号和/号;附:(还有一个' =' 号一般用于后缀)。

    2. Base64并不加密信息,因为它属于编码方式,不属于加密系统;可以随时对其信息进行解码。

    3. Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64是一种基于上述64个可打印ASCII字符来表示二进制字节流数据的方法,还有' =' 号用于后缀。

    Base64编码是一种从二进制到字符的过程,解码则相反。

    4. 其编码规则主要有:

    • 把3个字节变成4个字节。
    • 每76个字符加一个换行符。
    • 结束符也要进行处理。

    5. 编码步骤

    (1)对原始数据,分字节,求二进制字符串;

    (2)对二进制串,6位为一组进行分组,不足末尾补0;

    (3)在各分组前面补2个0成8位,求各分组的十进制值,根据十进制对应上表找编码字符;

    (4)字节数对3取余数,余数为0,不加等号;余数为1,在上述编码符号串的末尾加2个等号;余数为2,末尾加1个等号。

    6. 编码示例

    (1)原始数据是英文字符,sss = 'SE'

    流程:

    首先,求取 'SE' 的二进制编码(utf-8和ASCII等在英文时一致),sss.encode('utf-8') = b 'SE',b表示bytes类型,'SE'只是打印出来的符号,实际上其二进制是ASCII码的大写'S'和'E'的编码连接而成:01010011(二进制,其十进制是83,'S'),01000101(二进制,其十进制是69,'E')—— 即,将输入字符串按字节切分,取得每个字节对应的二进制值(若不足8比特则高位补0)

    其次,将该二进制字符串:01010011 01000101,按照6位一组进行切分(因为2的6次方刚好是64,在Base64的编码范围内),最后一组如果不足6位则末尾补0;于是得到:010100 110100 010100 的3组二进制串。

    然后,各自在前面补2个0得到:00010100 00110100 00010100,转化成十进制为:20,52,20;对应到上面的表中得到:'U0U',注意中间这个是0。

    最后,将N字节的原始数据,每个字节8位,按照6位一组进行划分,(而6和8的最小公倍数为24),所以要划分的二进制位数必须是24的倍数(或者字节数是3的倍数),而这里的 'SE' 原始数据只有2个字节,2%3=2,所以在结尾需要补上1个等号 '='。

    综合以上得到:'U0U='

    :由于某字节数M%3的值,(即M除以3的余数)只有0,1,2共三种情形,0表示整除(不用加等号 '=');那么余数为1,则要加上2个等号 '=';余数为2则要加上1个等号 '='

    (2)原始数据是中英文,sss='线?' ,这里的问号是英文

    流程:

    同理,首先求取sss字符串的二进制编码,sss.encode('utf-8') = b'xe7xbaxbf?',b表示bytes字节流类型,x表示十六进制,写的清楚一点就是:e7 ba bf ?

    则该字符串的二进制数据(进制转换)为:11100111(e7)10111010(ba)10111111(bf)00111111(英文?的ASCII码,二进制);

    其次,将上述字符串6位一组进行划分,不足补0,得到:111001 111011 101010 111111 001111 110000;

    然后各自在前面补2个0得到:00111001 00111011 00101010 00111111 00001111 00110000,十进制值也就是:57,59,42,63,15,48;对应上表也就是:'57q/Pw'

    最后,原始数据共4个字节,4%3=1,所以加上两个等号 '='。

    综合以上得到:'57q/Pw=='

    import base64
    
    sss = 'SE'
    aaa = base64.b64encode(sss.encode('utf-8'))   #base64编码前,需要把数据变成字节流bytes
    print('aaa:',aaa)
    
    bbb = base64.b64decode(aaa)  #解码
    print('bbb:',bbb)

    7. 解码

    解码就是编码的逆过程:

    (1)先去掉等号;

    (2)再根据编码表,找编码字符对应的编码值;

    (3)取各编码值的8位二进制值,去掉每个二进制的前2位的0值,然后连接形成二进制串;

    (4)对上述二进制串,从前到后,每8位构成一个字节的数据;多余的末尾0值去掉;

    (5)此时得到的就是原始数据的二进制编码;再根据编码方式(例如 utf-8)等进行解码。

    8. 解码示例

    对于上述编码的 'U0U=':

    首先,去掉等号 '=',得到 'U0U';

    其次,根据编码表,找到对应的编码值:20,52,20;

    然后,取8位二进制值为:00010100 00110100 00010100;每一个去掉前面2位的0,得到:010100 110100 010100;

    最后,从前到后,每8位构成一个字节数据,去掉末尾多余的0:010100 110100 010100;所以末尾2个0去掉,此时得到的就是原始数据的二进制编码,可以继续utf-8解码形成原始数据;

    9. Base64编码的python代码

    # python 实现base64编码
    def base64_func(str_):   # str_为原始字符串
        oldstr = ''
        newstr = []
        base_str = ''
        base64_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 
                       'K', 'L', 'M', 'N', 'O', 'P','Q', 'R', 'S', 'T', 
                       'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 
                       'e', 'f','g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 
                       'o', 'p', 'q', 'r', 's', 't', 'u', 'v','w', 'x', 
                       'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', 
                       '8', '9', '+', '/']
        
        # 首先将原始字符串转化为二进制字节流,这里用的是 utf-8编码,也可以用bytes函数实现
        byte_str = str_.encode('utf-8')  #会形成一个或多个字节的二进制字节流,是可以遍历的(可迭代),并且遍历的结果是以十进制显示的
        for ii in byte_str:
            oldstr = oldstr + '{:08}'.format(int(bin(ii).replace('0b', '')))  #用bin转换后是0b开头的,所以先把0b去掉;int将字符串转化成数值型,然后再在前面补0补齐成8位字符串{:08},并各字节进行连接
        #把转换后且连接的二进制按照6位一组分组,最后一组不足6位的末尾补0
        for jj in range(0, len(oldstr), 6):   #第三位6相当于步长
            newstr.append('{:0<6}'.format(oldstr[jj:jj + 6]))  #{:0<6}中的<表示左对齐,0表示填充0;oldstr[jj:jj + 6]中,如果jj+6超出字符串长度,则会直接取到末尾,列表也是
        #在base_list中找到对应的字符,拼接
        for ss in range(len(newstr)):
            base_str += base64_list[int(newstr[ss], 2)]   #二进制先转十进制,查找
        #判断base_str字符串结尾补几个等号‘=’
        if len(str_) % 3 == 1:
            base_str += '=='
        elif len(str_) % 3 == 2:
            base_str += '='
        return  bytes(base_str,'utf-8')   # 也可直接返回:base_str
    
    ss = base64_func('线?')
    print(ss)

    # 欢迎交流

    参考:

    https://blog.csdn.net/u013412497/article/details/51552335

    https://baike.baidu.com/item/base64/8545775?fr=aladdin

  • 相关阅读:
    ava新手入门详细介绍
    FreeRTOS源代码的编程标准与命名约定
    Java基础学习笔记
    如何提高单片机C语言代码效率
    java三大框架介绍
    Java代码优化六大原则
    单片机C语言基础编程源码六则2
    单片机C语言基础编程源码六则
    Java编程代码性能优化总结
    SAP ALV报表模板
  • 原文地址:https://www.cnblogs.com/qi-yuan-008/p/12940018.html
Copyright © 2011-2022 走看看