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

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

序言

接上上一篇:密码学-Base64编码算法Python3实现 ,这一篇文章写base64解码算法,同样是使用Python3,Python2已经停止维护了。

base64解码原理

按照编码算法,把它反着进行,就能对其进行解码,一下是个人拙见:

  1. 判断字符串是否是base64编码的结果;
  2. 由字符获取索引,将每个索引转换成6位二进制,并相连;
  3. 在转换成字节码
  4. 后续进一步处理,如去除不可见字符

判断字符串

标准的base64编码,使用的字符如下:

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

因此,只需要判断字符串中的字符长度是否是4的倍数,以及是否是码表中字符即可,但是,有种特殊情况,就是字符串中含有“=”,这种情况只需要将“=”换成“A”,因为“=”代表的是编码前的字符串补了几个字节的“0”,一个“=”就表示编码前字符串追加了“00000000”,所以“=”就表示码表中索引为“0”的字符“A”,我的实现如下:

def if_bstring_valid(b_string):
    if len(b_string) % 4:                # 判断长度
        return False
    if b_string[-2] == '=':              # 判断倒数第二个字符是否是“=”,判断有几个=
        b_string = b_string[:-2] + 'AA'  # 字符串转换
    elif b_string[-1] == '=':            # 同上
        b_string = b_string[:-1] + 'A'
    for s in b_string:
        if s not in BASE64_TABLE:        # 判断字符是否是码表中的字符
            return False
    return True

To Binary

binary = ''
ret = bytearray()
if bs64string[-2] == '=':           # 字符串预处理,去除“=”,上面判断方式也可以采用这种方式
    bs64string = bs64string[:-2]
elif bs64string[-1] == '=':
    bs64string = bs64string[:-1]
for s in bs64string:
    binary = binary + "{:0>6}".format(str(bin(BASE64_TABLE.index(s)))[2:])

BASE64_TABLE.index(s) 获取字符的索引,并由 bin() 函数转换成二进制数,通过 format() 函数转换成6位二进制,通过循环方式获取整个字符串的二进制

To Byte

six_bit_size = len(binary) // 24        # 按照3字节24位分组,分组数
remain = len(binary) % 24               # 分组后剩余的长度,一定是6的倍数,这里应该很容易懂 

six_bit_group = binary[: 24 * six_bit_size] 

while six_bit_group:
    temp = six_bit_group[0:24]
    temp = [int(temp[x:x + 8], 2) for x in [0, 8, 16]]
    for y in temp:
        ret.append(y)
    six_bit_group = six_bit_group[24:]

if remain:
    temp = binary[24 * six_bit_size:]
    temp = [int(temp[i * 8:(i + 1) * 8], 2) for i in range(0, remain // 6)] # 
    for y in temp:
        ret.append(y)
return ret.strip(b'\x00').decode()  # 去除最后多的不可见字符,会导致解码后的长度不一致

代码实现

完整的代码实现如下:

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 bs64decode(bs64string):
    if not if_bstring_valid(bs64string):
        print("WARNING: Base64 String is invivalid")

    else:
        binary = ''
        ret = bytearray()
        if bs64string[-2] == '=':
            bs64string = bs64string[:-2]
        elif bs64string[-1] == '=':
            bs64string = bs64string[:-1]
        for s in bs64string:
            binary = binary + "{:0>6}".format(str(bin(BASE64_TABLE.index(s)))[2:])
        six_bit_size = len(binary) // 24
        remain = len(binary) % 24

        six_bit_group = binary[: 24 * six_bit_size]

        while six_bit_group:
            temp = six_bit_group[0:24]
            temp = [int(temp[x:x + 8], 2) for x in [0, 8, 16]]
            for y in temp:
                ret.append(y)
            six_bit_group = six_bit_group[24:]

        if remain:
            temp = binary[24 * six_bit_size:]
            temp = [int(temp[i * 8:(i + 1) * 8], 2) for i in range(0, remain // 6)]
            for y in temp:
                ret.append(y)
        return ret.strip(b'\x00').decode()


def if_bstring_valid(b_string):
    if len(b_string) % 4:
        return False
    if b_string[-2] == '=':
        b_string = b_string[:-2] + 'AA'
    elif b_string[-1] == '=':
        b_string = b_string[:-1] + 'A'
    for s in b_string:
        if s not in BASE64_TABLE:
            return False
    return True


if __name__ == '__main__':
    string = input("msg>>>")
    print("Base64编码: %s" % bs64encode(string))
    print("Base64解码: %s" % bs64decode(bs64encode(string)))
    print("Base64解码长度: %s" % len(bs64decode(bs64encode(string))))

测试如下:

msg>>>123
Base64编码: MTIz
Base64解码: 123
Base64解码长度: 3

结语

到此结束!

如有错误,敬请指出,感谢指正!   2020-01-12  13:42:07

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

评论 抢沙发

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

欢迎光临