python3下常用编解码与加解密

字符编解码

Python3相对于Python2的一大改变就是,对默认字符类型进行了修改。Python2中定义字符串默认为二进制字符串,强制加前缀u的才是unicode字符串;而Python3中字符串默认为unicode,强制加前缀b的才是二进制字符串。(也就是刚好反过来了)

这里的二进制字符串:指的是进行过编码后的字符串。即utf8、gbk、ascii等编码后的串都是二进制的。存放到文件的时候也必须是二进制的内容。

unicode字符串:是一种在内存中存在的编码规范,它可以和任意其它类型的编码进行转换。比如:utf-8、gbk、ascii等。并且其它编码在进行互相转换时,都必须通过unicode来中转。该字符串只在内存中存在,没有具体的编码实现。

以"中国"为例,来看下各种编码方式下的表示形式:

"中国" unicode:\u4e2d\u56fd utf8:\xe4\xb8\xad\xe5\x9b\xbd gbk:\xd6\xd0\xb9\xfa

可以看到同样的字符串,在不同的编码中其对应的值是不一样的。但是不管哪种编码都可以转成unicode,unicode也可以转成任意其它的编码。(unicode被称为万国码,是世界上最大的字符集,可以支持编码全球的语言,但目前在编的并不是全部)

1、编码

python3中字符编码很简单。直接通过encode方法即可。(该方法只有unicode字符对象才有,Python3中unicode是str对象)

s = '中国' # => unicode print(type(s)) # => str s2 = s.encode('utf8') # => utf8 print(type(s2)) # => byte s3 = s.encode('gbk') # => gbk print(type(s3)) # => byte

2、解码

Python3中解码用的是decode方法。(该方法只有byte对象才有)

b = b'中国' # => 具体编码编程环境的默认编码而定,通常为utf8 print(type(b)) # => byte b1 = b.decode('utf8') # => unicode print(type(b1)) # => str

URL编解码

1、解析URL字符串

from urllib import parse url = 'https://www.baidu.com/s?wd=python3%20url编码' parsed = parse.urlparse(url) print(parsed)

urlparse会把完整的URL串解析成各个部分,方便我们直接提取特定内容。其执行结果如下:

ParseResult(scheme='https', netloc='www.baidu.com', path='/s', params='', query='wd=python3%20url编码', fragment='')

即解析后分解为:协议,域名、路径、参数、查询字符串等。我们可以直接使用对应的属性名来获取。比如:获取query内容。

print(parsed.query) # => wd=python3%20url编码

2、query参数编码

由于query参数对应的是GET请求时,附件在URL路径后的查询参数。为了避免浏览器解析到特殊字符而导致不可预知的问题,所以通常需要对其内容进行编码,称为URLEncode。Python3中编码的方式如下:

d = { 'name': '陈霸天', 'sex': 'male', 'age': 18 } query = parse.urlencode(d) print(query) # => name=%E9%99%88%E9%9C%B8%E5%A4%A9&sex=male&age=18

使用urlencode方法,可以很方便的对一个给定的字典对象的键值内容进行编码,并串联成一个有效格式的query字符串。可以直接附件到URL路径后来使用。(中间需要?链接)

3、query参数解码

有编码就有对应的解码方法,python3中其对应的解码方法不是urldecode,而是parse_qs方法。具体如下:

query = 'name=%E9%99%88%E9%9C%B8%E5%A4%A9&sex=male&age=18' d = parse.parse_qs(query) print(d) # => {'name': ['陈霸天'], 'sex': ['male'], 'age': ['18']}

注意返回的字典中,其value值都是list对象。这是因为有些键可能有多个值的情况。(正常可能会发生的情况)

4、纯字符串URL编码

上面方法是对字典对象进行的编码,如果只需对单个字符串内容编码, 则可以使用quote方法。

s = '中国' print(parse.quote(s)) # => %E4%B8%AD%E5%9B%BD

5、纯字符串URL解码

字符串的解码方法是和编码方法对应的叫unquote。使用方式如下:

s = '%E4%B8%AD%E5%9B%BD' print(parse.unquote(s)) # => 中国

BASE64编解码

1、BASE64编码

BASE64是一种对二进制进行编码的一种方式;之所以叫BASE64编码是因为经过这个算法进行编码之后,其内容只在规定的64个可打印字符之内。(0-9、a-z、A-Z、+、/)。python3中对字符进行BASE64编码的方式如下:

import base64 src = '中国'.encode('utf8') print("明文:", src) enc = base64.b64encode(src) print("密文:", enc)

这段代码运行后的结果:

明文: b'\xe4\xb8\xad\xe5\x9b\xbd' 密文: b'5Lit5Zu9'

可以看到b64encode方法接收的是一个二进制类型的字符串,返回的也是一个二进制类型的字符串。

2、BASE64解码

同编码相反的就是解码了,BASE64的解码也很简单。

import base64 enc = b'5Lit5Zu9' print("密文:", enc) src = base64.b64decode(enc) print("明文:", src) print("unicode:", src.decode('utf8'))

执行后的代码如下:

密文: b'5Lit5Zu9' 明文: b'\xe4\xb8\xad\xe5\x9b\xbd' unicode: 中国

3、BASE16编解码

base64库除了可以进行BASE64编码外,还可以支持BASE16编解码码。其使用方式如下:

import base64 src = '中国'.encode('utf8') print("明文:", src) enc = base64.b16encode(src) print("密文:", enc) src = base64.b16decode(enc) print("明文:", src) print("unicode:", src.decode('utf8')) 执行结果如下: 明文: b'\xe4\xb8\xad\xe5\x9b\xbd' 密文: b'E4B8ADE59BBD' 明文: b'\xe4\xb8\xad\xe5\x9b\xbd' unicode: 中国

与BASE64编码后的内容不同,BASE16的编码后内容其实是有规律的。仔细看下明文和密文,可以发现其实是一种对应关系。比如:明文中的\xe4,对应的是密文中的E4;以此类推。即BASE16只是把二进制在内存中的数值使用16进制字符串来表示而已。

AES加解密

1、AES加密

AES(Advanced Encryption Standard)是一种加密技术和标准。其实DES(Data Encryption Standard)加密的升级版。该加密算法是一种对称加密,即使用相同的key来进行加密和解密。Python3中进行AES加密的方式如下:

import base64 from Crypto.Cipher import AES def ensure_to_16(value): pad = 16 - len(value) % 16 return value + b'\x00' * pad if pad != 16 else value key = b'123456' iv = b'ABCD' src = '中国'.encode('utf8') # AES ECB encrypt aes = AES.new(ensure_to_16(key), AES.MODE_ECB) print('src:', src) enc = aes.encrypt(ensure_to_16(src)) print('enc:', enc) base_str = base64.encodebytes(enc) print('base_str:', base_str) # AES CBC encrypt, need iv arg aes = AES.new(ensure_to_16(key), AES.MODE_CBC, iv=ensure_to_16(iv)) print('src:', src) enc = aes.encrypt(ensure_to_16(src)) print('enc:', enc) base_str = base64.encodebytes(enc) print('base_str:', base_str)

上面的代码中需要说明的是,ensure_to_16主要作用是把key、iv、src等内容的长度补齐到16的整数倍。这个AES加密的标准要求,其中key、iv还可以是32、48等的整数倍,而src只能是16的整数倍。

另外,上面演示了2种加密类型,第一种是ECB,第二种CBC。其中第一种为不需要iv,第二种需要iv(初始化向量,俗称盐)参数。

代码执行效果如下:

src: b'\xe4\xb8\xad\xe5\x9b\xbd' enc: b'3+z@P4\x98\x0c\x1d\x9a\xce#F\xdf\xec\x1d' base_str: b'Myt6QFA0mAwdms4jRt/sHQ==\n' src: b'\xe4\xb8\xad\xe5\x9b\xbd' enc: b'4\xd7\xa42U:Yz\xc7>\xba\\\xb2\x96\x81\n' base_str: b'NNekMlU6WXrHPrpcspaBCg==\n'

2、AES解密

AES解码时需要使用相同的key、iv和模式,有一个不一致都会导致解密失败。具体代码如下:

import base64 from Crypto.Cipher import AES def ensure_to_16(value): pad = 16 - len(value) % 16 return value + b'\x00' * pad if pad != 16 else value key = b'123456' iv = b'ABCD' b64_str = b'NNekMlU6WXrHPrpcspaBCg==\n' # AES CBC decrypt, need iv arg aes = AES.new(ensure_to_16(key), AES.MODE_CBC, iv=ensure_to_16(iv)) print('b64_str:', b64_str) enc = base64.decodebytes(b64_str) print('enc:', enc) src = aes.decrypt(enc) print('src:', src)

上面代码以CBC模式为例,对密文进行了解密。其执行的结果如下:

b64_str: b'NNekMlU6WXrHPrpcspaBCg==\n' enc: b'4\xd7\xa42U:Yz\xc7>\xba\\\xb2\x96\x81\n' src: b'\xe4\xb8\xad\xe5\x9b\xbd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

可以看到明文src中的内容是以\x00补齐的,具体操作时还需要对其进行处理。比如:

src = b'\xe4\xb8\xad\xe5\x9b\xbd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' print(src.strip(b'\x00').decode('utf8')) # => 中国

本文分享自微信公众号 - TestQA(testqna)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-11-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户3029758的专栏

阶段02JavaWeb基础day01html&css

HTML 基础 概念 全写: HyperText Mark-up Language

9930
来自专栏AI研习社

实践是最好的老师:给中级 Python 开发人员的 13 个项目构想

学习 python 的基础知识是一种美妙的体验。但是,学习的喜悦可以被对实践项目的渴望所取代。想要建立项目是正常的,因此需要对项目的构想。

10510
来自专栏杰的记事本

HTML5 download属性无效的问题

如果url指向第三方资源,download会失效,表现和不使用download时一致——浏览器能打开的文件,浏览器会直接打开,不能打开的文件,会直接下载。浏览器...

31830
来自专栏用户3029758的专栏

Linux环境搭建:CentOs + Apache + MySQL + PHP

声明:本文为原创,作者为 对弈,转载时请保留本声明及附带文章链接:http://www.duiyi.xyz/c%e5%ae%9e%e7%8e%b0%e9%9b%...

31510
来自专栏PHP饭米粒

聊聊细节 - 你知道缓存的正确打开方式么?(1)

大的架构设计,各种高大上的概念层出不穷,相信很多人也或多或少的了解过,但其实,我们真的要把一个系统做强壮,做好,打磨细节才是根本,有句老话:细节是魔鬼,所以会来...

9820
来自专栏web秀

关于 ES6 中 Promise 的面试题

最近在复习 Promise 的知识,所以就做了一些题,这里挑出几道题,大家一起看看吧。

6820
来自专栏杰的记事本

注意IE下Ajax Get缓存的问题

​ 常见的是ajax请求过一次以后,以后的相同url的get请求会存在下面这种情况:

11620
来自专栏杰的记事本

img标签不同设备加载不同尺寸的图片的几种方法

一般来说,桌面端显示的是大尺寸的图像,文件体积较大。手机的屏幕较小,只需要小尺寸的图像,可以节省带宽,加速网页渲染。

27210
来自专栏杰的记事本

SVG 图标在React项目中的优化

官方文档:https://webpack.docschina.org/loaders/url-loader/

14310
来自专栏杰的记事本

CSS实线边框渐变以及虚线边框渐变

给border-image加linear-gradient不难理解,但是如果单纯使用border-image,会发现效果是这样的:

41120

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励