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