序言
接上上一篇:密码学-Base64编码算法Python3实现 ,这一篇文章写base64解码算法,同样是使用Python3,Python2已经停止维护了。
base64解码原理
按照编码算法,把它反着进行,就能对其进行解码,一下是个人拙见:
- 判断字符串是否是base64编码的结果;
- 由字符获取索引,将每个索引转换成6位二进制,并相连;
- 在转换成字节码
- 后续进一步处理,如去除不可见字符
判断字符串
标准的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
最新评论
这个软件有bug的,客户端windows有些键不能用如逗号、句号
没有收到邮件通知
我的评论通知貌似坏掉了,定位一下问题
测试一下重新部署后的邮件功能
居然看到自己公司的MIB库,诚惶诚恐
那可能是RobotFramework-ride的版本问题。我装的1.7.4.2,有这个限制。我有空再尝试下旧版本吧,感谢回复。
你好!我在python2.7中安装RobotFramework-ride的时候提示wxPython的版本最高是2.18.12,用pip下载的wxPython版本是4.10,而且我在那个路径下没有找到2
真的太好了,太感谢了,在bilibili和CSDN上都找遍了,终于在你这里找到了