base编码系列学习
一、base64编码
1.1表
base64码表,“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/”。
1.2原理&分组
将输入的字符串用base64字符表示,其中每3个字符可以用4个base64字符表示,根据字符表示的整数值对应base64码表进行转换。
1.3变化
编码后的数据变更大了,三个字符变四个字符。
注:base64的索引表,base64字符选用了"A-Z、a-z、0-9、+、/" 64个字符。因为一共64个字符,可以用6位二进制位去表示。若剩余的输入字符不足三个,则用2个base64字符表示一个字符,空余的两个字符用“ == ”代替;用3个base64字符表示2个字符,空余的一个base64字符用 “ = ”。
1.4编/解码
import base64
import string
#base64实现
base64_charset = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'
def encode(origin_bytes):
# 将每一位bytes转换为二进制字符串,{:0>8}意思是向右对齐,用0填充,长度为8
base64_bytes = ['{:0>8}'.format(str(bin(b)).replace('0b', '')) for b in origin_bytes]
resp = ''
nums = len(base64_bytes) // 3
remain = len(base64_bytes) % 3
integral_part = base64_bytes[0:3 * nums]
while integral_part:
# 取三个字节,以每6比特,转换为4个整数
tmp_unit = ''.join(integral_part[0:3])
tmp_unit = [int(tmp_unit[x: x + 6], 2) for x in [0, 6, 12, 18]]
# 取对应base64字符
resp += ''.join([base64_charset[i] for i in tmp_unit])
integral_part = integral_part[3:]
if remain:
# 补齐三个字节,每个字节补充 0000 0000
remain_part = ''.join(base64_bytes[3 * nums:]) + (3 - remain) * '0' * 8
# 取三个字节,以每6比特,转换为4个整数
# 剩余1字节可构造2个base64字符,补充==;剩余2字节可构造3个base64字符,补充=
tmp_unit = [int(remain_part[x: x + 6], 2) for x in [0, 6, 12, 18]][:remain + 1]
resp += ''.join([base64_charset[i] for i in tmp_unit]) + (3 - remain) * '='
return resp
def decode(base64_str):
"""
解码base64字符串
:param base64_str:base64字符串
:return:解码后的bytearray;若入参不是合法base64字符串,返回空bytearray
"""
# 对每一个base64字符取下标索引,并转换为6为二进制字符串
base64_bytes = ['{:0>6}'.format(str(bin(base64_charset.index(s))).replace('0b', '')) for s in base64_str if
s != '=']
resp = bytearray()
nums = len(base64_bytes) // 4
remain = len(base64_bytes) % 4
integral_part = base64_bytes[0:4 * nums]
while integral_part:
# 取4个6位base64字符,作为3个字节
tmp_unit = ''.join(integral_part[0:4])
tmp_unit = [int(tmp_unit[x: x + 8], 2) for x in [0, 8, 16]]
for i in tmp_unit:
resp.append(i)
integral_part = integral_part[4:]
if remain:
remain_part = ''.join(base64_bytes[nums * 4:])
tmp_unit = [int(remain_part[i * 8:(i + 1) * 8], 2) for i in range(remain - 1)]
for i in tmp_unit:
resp.append(i)
return resp
if __name__ == '__main__':
s = b'One piece, all Blue'
local_base64 = encode(s)
print('使用本地base64加密:', local_base64)
print('使用本地base64解密:', decode(local_base64).decode())
b_base64 = base64.b64encode(s)
print('使用base64加密:', b_base64)
print('使用base64解密:', base64.b64decode(b_base64).decode())
二、base16 编码
2.1表
base16码表,“0123456789ABCDEF”。
2.2原理&分组
将输入的字符串中的每一个字符拆成两部分,每部分4bit进行编码。
2.3变化
编码后的数据变更大了,一个字符变两个字符。
2.4编/解码
#base16解码 import base64 #输入的数据必须是比特流 s = b'aaaa' enc = base64.b16encode(s) print(base64.b16decode(enc))
三、base24 编码
3.1表
base24码表,“BCDFGHJKMPQRTVWXY2346789”。
3.2原理&分组
将输入的字符串中的每一个字符拆成两部分,每部分4bit进行编码,但是过程与base16有点不同,具体看代码实现。
3.3变化
编码后的数据变更大了,一个字符变两个字符。
3.4编/解码
static const char sel[] = {
'B','C','D','F','G',
'H','J','K','M','P',
'Q','R','T','V','W',
'X','Y','2','3','4',
'6','7','8','9', '\0'};
char *b24e(char *buf, unsigned char *byst, size_t sizeOfBytes)
{
int i = 0;
unsigned char *p = byst;
while ((size_t)(i = (p-byst)) < sizeOfBytes) {
buf[2*i] = sel[((*p) >> 4)];
buf[(2*i)+1] = sel[23 - ((*p) & 0x0f)];
p++;
}
buf[(2*i)+1] = '\0';
return buf;
}
unsigned char *b24d(unsigned char *buf, char *str, size_t countOfChars)
{
size_t i;
char *p = str;
char *loc[2];
unsigned char n[2];
if (countOfChars % 2)
return NULL;
for (i = 0; i < (countOfChars>>1); i++) {
loc[0] = strchr( sel, str[2*i] );
loc[1] = strchr( sel, str[ ( 2*i ) + 1 ] );
if (loc[0] == NULL || loc[1] == NULL)
return NULL;
n[0] = (unsigned char)( loc[0] - sel );
n[1] = 23 - (unsigned char)( loc[1] - sel );
buf[i] = (unsigned char)((n[0] << 4) | n[1]);
}
return buf;
}
四、base32 编码
4.1表
base32码表,“ABCDEFGHIJKLMNOPQRSTUVWXYZ234567”。
4.2原理&分组
以5 bit为一组进行分组,对切分而成的每个组进行编码得到1个可显示字符。
4.3变化
编码后的数据变更大了,每5个字符变8个字符。如果编码的字符串不足5的倍数,那么余下的部分用‘ = ’填充。
4.4编/解码
#base32解码 import base64 #输入的数据必须是比特流 s = b'aaaa' enc = base64.b32encode(s) print(base64.b32decode(enc))
五、base58 编码
5.1表
base58码表,“123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz”。
5.2原理&分组
不再以根据位分组的方式进行编码,而是通过辗转相除法的方式去编码。实质上就是将每个字符变成一个大整数,然后用58进制去表示,然后这个58进制里面每一位进行编码。(注:base62好像也是这样,暂时先放着。)
5.3变化
编码后的数据变更大了,具体变多大还得看编码的数据内容。
5.4编/解码
def b58encode(tmp:str) -> str:
tmp = list(map(ord,tmp))
temp = tmp[0]
base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
for i in range(len(tmp)-1):
temp = temp * 256 + tmp[i+1]
tmp = []
while True:
tmp.insert(0,temp % 58)
temp = temp // 58
if temp == 0:
break
temp = ""
for i in tmp:
temp += base58[i]
return temp
def b58decode(tmp:str) -> str:
import binascii
base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
temp = []
for i in tmp:
temp.append(base58.index(i))
tmp = temp[0]
for i in range(len(temp)-1):
tmp = tmp * 58 + temp[i+1]
return binascii.unhexlify(hex(tmp)[2:].encode("utf-8")).decode("UTF-8")
print(b58encode("ABDCDEFGA"))
print(b58decode("qBLiPgShKjap"))
六、base60 编码
6.1表
base60码表,“0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx”。
6.2原理&分组
未知。

6.3变化
未知。
6.4编/解码
https://github.com/chai2010/base60

浙公网安备 33010602011771号