欢迎光临!
若无相欠,怎会相见

密码学-Base64编码算法Python3实现

前言

前段时间,在看雪看了一篇关于密码学的帖子,把BASE64算法讲的比较清晰,在加上自己对这方面感兴趣,索性就用Python语言实现一番,不过在实现过程中,发现那个帖子有点儿不足,以下我将自己的理解记录下来。基于Python3

BASE64编码原理

BASE64并不是加密算法,只是一种编码算法,类似于摩斯码,只是编码后的结果不利于人类阅读,被很多人误认为是加密算法。该算法的RFC标准可以参看RFC 4648 《The Base16, Base32, and Base64 Data Encodings》。我就不详细讲解了,我只记录下自己的实现:

  1. 将字符串转换为8位二进制
  2. 每三个字节转换为4个 6bit 二进制
  3. 若字符串的字节数不是3的倍数,在最后追加“0”进行补全。例如数字“1”转换为二进制后为:“00110001”(1的ASCII码),它就一个字节,因此需要补全,共需要补16个“0”(两个字节长度)
  4. 计算每 6bit 二进制代表的十进制数,然后从码表中查找这个数代表的字符。
  5. 在最后,添加几个字节的“0”,就需要将最后的几个字符改为“=”。例如“1”,添加了两个字节的0,编码后是MQAA,最终需要将两个A变成‘==’,即“MQ==”

BASE64码表:

BASE64_TABLE = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',    # 此处更正  'G' -> 'J' 2019-12-17 15:54:57
    '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', '+', '/'
]

二进制转换

首先,对需要编码的字符串进行二进制转换,即将字符串转换为“0”和“1”表示的字符串,我的实现如下:

string = string.encode()        # 将字符串编码为byte
ret = ''
bytes_bin = ''
for b in string:
    bytes_bin = bytes_bin + '{:0>8}'.format(str(bin(b))[2:])

encode() 函数可以将转换为bytes,每个字节的数字是16进制的数字;bin() 函数用于将数字转换为二进制数,它的参数必须是一个整型数字,例如:

>>> "中".encode()
b'\xe4\xb8\xad'
>>> bin(5)
'0b101'

以汉字“中”为例,在上述代码中 for b in string: b 并不是单个的“e”或“4”或后面的其他字符,而是“e4”或“b8”或“ad”,因为一个“\x”在Python中代表的是一个字节(byte),也就是8位(bit)二进制。那么这个循环就很简单,把这三个字节分别转换为8位二进制数,再转换为字符串拼接到一块。

'{:0>8}'.format() 的意思很简单,将字符串补齐,如果字符串小于8位,则在左侧补充“0”,详细的解释可以查看Python format()函数用法。

3×8 to 4×6

在计算机中,一个字节是8位二进制,BASE64算法就是将字符串进行转变。我的实现如下:

three_byte_zise = len(bytes_bin) // 24  # 计算一共有多少个3字节组,即按照3字节一组计算
remain_size = len(bytes_bin) % 24       # 计算余数,分组后是否有多余的


three_byte_group = bytes_bin[:24 * three_byte_zise]  # 所有的3字节组

while three_byte_group:
    byte_group = three_byte_group[0:24]    # 取前3字节共24个二进制字符 
    for j in [0, 6, 12, 18]:   # 分成4个6bit组
        ret = ret + BASE64_TABLE[int(byte_group[j:j+6], 2)]  # int(byte_group[j:j+6], 2) 将6位二进制转换成10进制数
    three_byte_group = three_byte_group[24:]


if remain_size:
    remain_part = bytes_bin[24 * three_byte_zise:] + '0' *  (24- remain_size)   # 对余数字节进行补充,
    for j in [0, 6, 12, 18]:
        ret = ret + BASE64_TABLE[int(remain_part[j:j+6], 2)]

有详细注释,不难。接下来,做收尾工作。

if ret[-2] == 'A':
    ret = ret[0:-2] + '=='
elif ret[-1] == 'A':
    ret = ret[:-1] + '='

BASE64编码算法Python3实现

我的完整代码如下:

BASE64_TABLE = [
    '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', '+', '/'
]


def bs64encode(string):
    string = string.encode()        # 将字符串编码为byte
    ret = ''
    bytes_bin = ''
    for b in string:
        bytes_bin = bytes_bin + '{:0>8}'.format(str(bin(b))[2:])

    three_byte_zise = len(bytes_bin) // 24
    remain_size = len(bytes_bin) % 24

    three_byte_group = bytes_bin[:24 * three_byte_zise]

    while three_byte_group:
        byte_group = three_byte_group[0:24]
        for j in [0, 6, 12, 18]:
            ret = ret + BASE64_TABLE[int(byte_group[j:j+6], 2)]
        three_byte_group = three_byte_group[24:]

    if remain_size:
        remain_part = bytes_bin[24 * three_byte_zise:] + '0' * (24- remain_size)
        for j in [0, 6, 12, 18]:
            ret = ret + BASE64_TABLE[int(remain_part[j:j+6], 2)]

    if ret[-2] == 'A':
        ret = ret[0:-2] + '=='
    elif ret[-1] == 'A':
        ret = ret[:-1] + '='

    return ret

经过我的测试,暂时没发现问题

结语

天色已晚,解码算法只能后面再另写一篇文章了。虽说我已经很困了,但轮到做自己喜欢的事,仍然能坚持下来。

不知道有没有疏漏之处,只能先这样了

如有错误,敬请指出,感谢指正!    — 2019-12-16 22:27:50

 

 

赞(0) 打赏
转载请注明:飘零博客 » 密码学-Base64编码算法Python3实现
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

欢迎光临