0x00 Base64编码的用途

在网络传输中,不是所的的内容都是可打印字符,其中绝大多数数据是不可见字符,base64可以基于64个可打印字符来表示这些带有不可打印字符的传输数据。

0x01 Base64映射表

标准的base64有一个映射表,将常用字符和数字对应起来,其中0-25对应这大写的A-Z,26-51对应着小写的a-z,52-61对应着数字0-9,62-63对应着+/字符。

0x02 Base64加密原理过程

将字符串转换成Base64编码的过程:

a.将字符串转成为ascii码对应的十进制数,然后转成8位二进制数

b.将所有字符串的8位二进制数以6位为一个整体进行转换成十进制数

c.根据每个整体转换后的十进制数从Base64映射表中取出对应的字符

以下以Hello!为例,其转换过程如图所示:

在这个转换过程中,如果存在不足则补0,补多少呢?这个可以推算的。base64的编码只需要6位即可,正常的字符是8位,取最小公倍数24即可保留完整的信息,添加最少的附加信息0. 这样一来,就会存在末尾出现二进制数为0,对应十进制ascii码的A,通常这种情况下,标准base64进行编码时,通常用=字符替换这个不带实际信息的附加信息0。解码则是对应最后的两个==字符,直接对应的两个6位的二进制0值,丢掉最后两个6比特二进制0值,不做处理。

0x03 具体python实现

编码阶段

a.将输入字符串进行编码,返回8位二进制数

  1. def encode_step_a(value):
  2. list = []
  3. for t in value:
  4. list.append('0'+bin(ord(t))[2:])
  5. return ''.join(list)

将输入字符串value进行遍历,先通过ord()函数转换成ascii码,然后利用bin转换成二进制数,因为bin()生成的二进制数带有0b字样,所以截取0b后面需要的二进制数,然后在前面补0,凑齐8位,这就需要针对每次遍历的元素取二进制位数后进行长度的判断,是否满足8位二进制数标准,不足则补0. 可行但麻烦,有没有一种可以自动生成8位二进制数,不足自动补齐的函数呢?

应该是有一种类似格式化补齐二进制位的函数的,发现str.format()函数的参数定义如下:

其中对齐参数选项正是想要的:

测试结果如下:

红框中的0自动补齐了。

所以a阶段的方法可以优化为:

  1. def encode_step_a(value):
  2. list = ''.join(["{:0>8b}".format(ord(t)) for t in value])
  3. return list

接下重点就是b阶段了,将以8位为整体的二进制数转换为以6位为整体的二进制数,

重点在于不足24位的二进制数,需要补0来填充满足格式

  1. def encode_step_b(value):
  2. remainder = len(value) % 24
  3. if remainder:
  4. # 存在余数,则需要补充0
  5. padding = '0' * ( 24 - remainder)
  6. value += padding
  7. # 按照每6位为一个,进行切割字符
  8. res = [value[i:i+6] for i in range(0, len(value), 6)]
  9. return res

然后将每6位为一个整体二进制数进行转换为十进制数

  1. def encode_step_c(res):
  2. result = ''
  3. for i in res:
  4. # 全为0则是补充的
  5. if i == '0'*6:
  6. encoding = 65
  7. else:
  8. encoding = 0
  9. for key , v in enumerate(i):
  10. # 进行二进制转十进制
  11. val = int(v) * pow(2, len(i)-1-key)
  12. encoding += val
  13. # 从base64映射表中取值
  14. res_str= base64_dict.get(str(encoding))
  15. result += res_str
  16. return result

设置一个base64_dict映射表

  1. base64_dict= {'0': 'A', '1': 'B', '2': 'C', '3': 'D', '4': 'E',
  2. '5': 'F', '6': 'G', '7': 'H', '8': 'I', '9': 'J',
  3. '10': 'K', '11': 'L', '12': 'M', '13': 'N', '14': 'O',
  4. '15': 'P', '16': 'Q', '17': 'R', '18': 'S', '19': 'T',
  5. '20': 'U', '21': 'V', '22': 'W', '23': 'X', '24': 'Y',
  6. '25': 'Z', '26': 'a', '27': 'b', '28': 'c', '29': 'd',
  7. '30': 'e', '31': 'f', '32': 'g', '33': 'h', '34': 'i',
  8. '35': 'j', '36': 'k', '37': 'l', '38': 'm', '39': 'n',
  9. '40': 'o', '41': 'p', '42': 'q', '43': 'r', '44': 's',
  10. '45': 't', '46': 'u', '47': 'v', '48': 'w', '49': 'x',
  11. '50': 'y', '51': 'z', '52': '0', '53': '1', '54': '2',
  12. '55': '3', '56': '4', '57': '5', '58': '6', '59': '7',
  13. '60': '8', '61': '9', '62': '+', '63': '/', '65': '=',
  14. }

至此,base64的编码过程已经全部手动实现,解码过程也是同样分析,经过优化,封装后的完整代码

  1. class Custom64:
  2. base64_dict = {'0': 'A', '1': 'B', '2': 'C', '3': 'D', '4': 'E',
  3. '5': 'F', '6': 'G', '7': 'H', '8': 'I', '9': 'J',
  4. '10': 'K', '11': 'L', '12': 'M', '13': 'N', '14': 'O',
  5. '15': 'P', '16': 'Q', '17': 'R', '18': 'S', '19': 'T',
  6. '20': 'U', '21': 'V', '22': 'W', '23': 'X', '24': 'Y',
  7. '25': 'Z', '26': 'a', '27': 'b', '28': 'c', '29': 'd',
  8. '30': 'e', '31': 'f', '32': 'g', '33': 'h', '34': 'i',
  9. '35': 'j', '36': 'k', '37': 'l', '38': 'm', '39': 'n',
  10. '40': 'o', '41': 'p', '42': 'q', '43': 'r', '44': 's',
  11. '45': 't', '46': 'u', '47': 'v', '48': 'w', '49': 'x',
  12. '50': 'y', '51': 'z', '52': '0', '53': '1', '54': '2',
  13. '55': '3', '56': '4', '57': '5', '58': '6', '59': '7',
  14. '60': '8', '61': '9', '62': '+', '63': '/', '65': '=',
  15. }
  16.  
  17. def encode(self, value: str, threshold: int = 6) -> str:
  18. # 对传入的字符进行编码,并返回编码结果
  19. value = ''.join(["{:0>8b}".format(ord(t)) for t in value])
  20. inputs = self.shift(value, threshold)
  21. result = ''
  22. for i in inputs:
  23. if i == '0' * threshold:
  24. # 全为0则视为补位
  25. encoding = 65
  26. else:
  27. encoding = 0
  28. for key, v in enumerate(i):
  29. # 二进制数按权相加得到十进制数
  30. val = int(v) * pow(2, len(i) - 1 - key)
  31. encoding += val
  32. # 从对照表中取值
  33. res = self.base64_dict.get(str(encoding))
  34. result += res
  35. return result
  36.  
  37. def decode(self, value: str, threshold: int, group: int = 8) -> str:
  38. """对传入的字符串解码,得到原字符"""
  39. result = []
  40. coder = self.str2binary(value, threshold=threshold)
  41. bins = self.shift(''.join(coder), group)
  42. for i in range(len(bins)):
  43. binary = ''.join(bins)[i * group: (i + 1) * group]
  44. if binary != '0' * group:
  45. # 如果全为0则视为补位,无需处理
  46. result.append(''.join([chr(i) for i in [int(b, 2) for b in binary.split(' ')]]))
  47. return ''.join(result)
  48.  
  49. def str2binary(self, value: str, threshold: int = 6) -> list:
  50. """字符串转十进制再转二进制"""
  51. result = []
  52. values = self.str2decimal(value)
  53. for i in values:
  54. # 判断是否为补位
  55. if i == '65':
  56. val = '0' * threshold
  57. else:
  58. val = '{:0{threshold}b}'.format(int(i), threshold=threshold)
  59. result.append(val)
  60. return result
  61.  
  62. @staticmethod
  63. def shift(value: str, threshold: int, group: int = 24) -> list:
  64. """位数转换"""
  65. remainder = len(value) % group
  66. if remainder:
  67. # 如果有余数,则说明需要用0补位
  68. padding = '0' * (group - remainder)
  69. value += padding
  70. # 按照threshold值切割字符
  71. result = [value[i:i + threshold] for i in range(0, len(value), threshold)]
  72. return result
  73.  
  74. def str2decimal(self, value: str) -> list:
  75. """使用Base64编码表做对照,取出字符串对应的十进制数"""
  76. keys = []
  77. for t in value:
  78. for k, v in self.base64_dict.items():
  79. if v == t:
  80. keys.append(k)
  81. return keys
  1. if __name__ == '__main__':

    cus = Custom64()
    encode_res = cus.encode('hello1!', threshold=6)
    decode_res = cus.decode(encode_res, threshold=6)
    # encode_res = cus.encode(';function transToDict(n,a){res="{name:"+n+",age:"+a+"}";console.log(res);return res};var ss=transToDict("P",20);', threshold=6)
    # encode_res = cus.encode('alert("xss");', threshold=6)
    # decode_res = cus.decode("cz1jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtib2R5LmFwcGVuZENoaWxkKHMpO3Muc3JjPSdodHRwOi8veHNzcHQuY29tL0ZweWpnUz8nK01hdGgucmFuZG9tKCk=", threshold=6)
    print(encode_res)
    print(decode_res

自实现的base64小工具可以定义分组大小(threshold 6位)和任意字典映射表(base64_dict),可以满足内部小团队的加密需求。

当然python3.6 自带有base64库,使用也是极为方便简单

  1. from base64 import b64decode
  2. from base64 import b64encode
  3.  
  4. def code_fun():
  5. code = ['aGVsbG8=', 'aGVsbG8h', "aGVsbG8hIQ=="]
  6. str_list = ["hello", "hello!", "hello!!"]
  7. for c in code:
  8. string = b64decode(c).decode('utf8')
  9. print(string)
  10.  
  11. for str in str_list:
  12. encoded_str = b64encode(bytes(str, 'utf-8'))
  13. print(encoded_str)
  14.  
  15. if __name__ == "__main__":
  16. code_fun()

0x04 安全小想法

base64一般来说在安全界是不作为安全加密算法的,因为过程可逆。业界中密码系统的安全性不应该依靠算法的保密,而是取决于密钥的保密性。真正能做到就算所有人知道系统的运作过程,仍然是安全的。当然不论是标准的base64或者是自实现的加密工具,作为代码混淆,还是可以为安全贡献一份力量的。

python编写自己的base64加解密工具的更多相关文章

  1. QuickBase64 - Android 下拉通知栏快捷base64加解密工具

    Android Quick Setting Tile Base64 Encode/Decode Tool Android 下拉通知栏快捷 base64 加解密,自动将剪切板的内容进行 base64 E ...

  2. 使用jframe编写一个base64加密解密工具

    该工具可以使用exe4j来打包成exe工具(如何打包自己百度) 先上截图功能 运行main方法后,会弹出如下窗口 输入密文 然后点击解密,在点格式化 代码分享 package tools;import ...

  3. RSA加解密工具类RSAUtils.java,实现公钥加密私钥解密和私钥解密公钥解密

    package com.geostar.gfstack.cas.util; import org.apache.commons.codec.binary.Base64; import javax.cr ...

  4. Java中的AES加解密工具类:AESUtils

    本人手写已测试,大家可以参考使用 package com.mirana.frame.utils.encrypt; import com.mirana.frame.constants.SysConsta ...

  5. Java中的RSA加解密工具类:RSAUtils

    本人手写已测试,大家可以参考使用 package com.mirana.frame.utils.encrypt; import com.mirana.frame.utils.log.LogUtils; ...

  6. java base64加解密

    接上篇java Base64算法. 根据之前过程使用base64加解密,所以写成了工具类. 代码示例; public class Base64Util { private static Logger ...

  7. CTF-Tools 一款CTF古典密码加解密工具

    CTF-Tools 一款CTF古典密码加解密工具 工具截图 工具简介 一款CTF编码.解码.加密.解密工具. 支持的编码解码: URL-UTF-8 URL-GB2312 Unicode Escape( ...

  8. vue 核心加解密工具类 方法

    1 /* base64 加解密 2 */ 3 export let Base64 = require('js-base64').Base64 4 5 /* md5 加解密 6 */ 7 export ...

  9. Base64加密解密工具类

    使用Apache commons codec类Base64进行加密解密 maven依赖 <dependency> <groupId>commons-codec</grou ...

随机推荐

  1. Tensorflow+InternalError: Blas GEMM launch failed

    [参考1:]https://stackoverflow.com/questions/37337728/tensorflow-internalerror-blas-sgemm-launch-failed ...

  2. OOP & 模块化, 多态, 封装

    OOP 面向对象编程 (OOP) 是用抽象方式创建基于现实世界模型的一种编程模式.它使用先前建立的范例,包括模块化,多态和封装几种技术. 在 OOP 中,每个对象能够接收消息,处理数据和发送消息给其他 ...

  3. Android Studio & zh-Hans

    Android Studio & zh-Hans https://developer.android.com/studio?hl=zh-cn https://developer.android ...

  4. taro list render bug

    taro list render bug 列表渲染 https://taro-docs.jd.com/taro/docs/list.html not support jsx map 垃圾微信 cons ...

  5. window.locationbar

    window.locationbar demo https://cdn.xgqfrms.xyz/#/operate-tool/select-seat-system/select-detail?temp ...

  6. JULLIAN MURPHY:拥有良好的心态,运气福气便会自来

    JULLIAN MURPHY是星盟全球投资公司的基金预审经理,负责星盟投资项目预审,有着资深的基金管理经验,并且在区块链应用的兴起中投资了多个应用区块链技术的公司. JULLIAN MURPHY认为往 ...

  7. Java中print、printf、println的区别

    Java中print.printf.println的区别 区别 print:标准输出,但不换行,不可以空参: println:标准输出,但会自动换行,可以空参,可以看做:println()相当于pri ...

  8. [转]C++语言的历史和标准化

    转:https://blog.csdn.net/lemonrabbit1987/article/details/48222339 1979年4月,贝尔实验室的Bjarne Stroustrup(本贾尼 ...

  9. linux系统解压命令总结

    原文链接:https://www.cnblogs.com/lhm166/articles/6604852.html tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追 ...

  10. .NET gRPC 核心功能初体验,附Demo源码

    gRPC是高性能的RPC框架, 有效地用于服务通信(不管是数据中心内部还是跨数据中心). 由Google开源,目前是一个Cloud Native Computing Foundation(CNCF)孵 ...