转义
每种语言都有其关键字和保留字符,这样为了能这些特殊字符能正常显示,就需要转义,如:HTML中的
 
代表空格;Python中的
\n
代表回车换行;\t
代表制表符;\\
代表\
字符本身;\u
代表Unicode;
-
Unicode转义:
string = '杰克' #1. Unicode转义 string_u = string.encode('unicode-escape').decode('utf-8') print(string_u) # \u6770\u514b #2. Unicode转回 string = string_u.encode('utf-8').decode('unicode-escape') print(string) # 杰克
-
HTML转义
import html args='{"e": 5, "f": 6}' # html转义 html.escape(args) # '{"e": 5, "f": 6}' # 转回 html.unescape('{"e": 5, "f": 6}') # '{"e": 5, "f": 6}'
编码
字符编码
不同的编码格式编解码类似,以GBK编码为例如下:
string = "张三"
#1. gbk编码转义
sting_g = string.encode('gbk')
print(sting_g)
# b'\xd5\xc5\xc8\xfd'
#2. gbk解码转回
s = sting_g.decode('gbk')
print(s)
URL编码
请求URL的时候看到以%开头的字符串,这一般是对字符做了URL编码处理,避免中文等特殊字符歧义,编解码如下。
from urllib import parse
#1. 字典对象编码
data = {
"name": "杰克",
"pwd": "123456"
}
text = parse.urlencode(data)
print(text)
# name=%E6%9D%B0%E5%85%8B&pwd=123456
#2. 字符串编码(=、&、中文均会被编码):
string = "name=杰克&pwd=123456"
text = parse.quote(string)
print(text)
# name%3D%E6%9D%B0%E5%85%8B%26pwd%3D123456
#3. 解码
text_enc = "name%3D%E6%9D%B0%E5%85%8B%26pwd%3D123456"
text = parse.unquote(text_enc)
print(text)
# name=杰克&pwd=123456
base64编码
编码和加密的不同在于,编码一般为了传输或者压缩,支持解码。加密后则一般不能反解。base64一般用于在接口中,将图片或媒体变为一种固定长度的字符串形式,方便传输。
import base64
#1. 编码
string = '杰克'
string_enc = string.encode('utf-8')
print(base64.b64encode(string_enc))
# b'5p2w5YWL'
#2. 解码
b = b'5p2w5YWL'
print(base64.b64decode(b).decode('utf-8'))
# 杰克
加密
加密分类&特点
-
不可逆加密:
- SHA256、SHA384、SHA512、HMAC-SHA256、HMAC-SHA384、HMAC-SHA512
-
对称加密:
- AES、3DES
-
非对称加密:
- RSA
加密算法我们整体可以分为:可逆加密(对称加密、非对称加密)和不可逆加密
不可逆加密
常见的不可逆加密算法有MD5,HMAC,SHA1、SHA-224、SHA-256、SHA-384,和SHA-512,其中SHA-224、SHA-256、SHA-384,和SHA-512我们可以统称为SHA2加密算法,SHA加密算法的安全性要比MD5更高,而SHA2加密算法比SHA1的要高。其中SHA后面的数字表示的是加密后的字符串长度,SHA1默认会产生一个160位的信息摘要。
特定:
不可逆加密算法最大的特点就是密钥,由于这些加密都是不可逆的,因此比较常用的场景就是用户密码加密,其验证过程就是通过比较两个加密后的字符串是否一样来确认身份的。
对称加密
对称加密算法是应用比较早的算法,在数据加密和解密的时用的都是同一个密钥,这就造成了密钥管理困难的问题。常见的对称加密算法有DES、3DES、AES128、AES192、AES256 (默认安装的 JDK 尚不支持 AES256,需要安装对应的 jce 补丁进行升级 jce1.7,jce1.8)。其中AES后面的数字代表的是密钥长度。
特点:
对称加密算法的安全性相对较低,比较适用的场景就是内网环境中的加解密。
非对称加密算法
非对称加密算法有两个密钥,这两个密钥完全不同但又完全匹配。只有使用匹配的一对公钥和私钥,才能完成对明文的加密和解密过程。常见的非对称加密有RSA、SM2等。
加密盐
加密盐也是比较常听到的一个概念,盐就是一个随机字符串用来和我们的加密串拼接后进行加密。加盐主要是为了提供加密字符串的安全性。假如有一个加盐后的加密串,黑客通过一定手段这个加密串,他拿到的明文,并不是我们加密前的字符串,而是加密前的字符串和盐组合的字符串,这样相对来说又增加了字符串的安全性。
MD5
简述:
message-digest algorithm 5(信息-摘要算法),其实就是一种算法。可以将一个字符串,或文件,或压缩包,执行md5后,就可以生成一个固定长度为128bit的串。这个串,基本上是唯一的。
不可逆性
压缩性:任意长度的数据,算出的MD5值长度都是固定的。
容易计算:从原数据计算出MD5值很容易。
抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
广泛的用途:
- 加密网站注册用户的密码。
- 网站用户上传图片 / 文件后,计算出MD5值作为文件名。(MD5可以保证唯一性)
- key-value数据库中使用MD5值作为key。
- 比较两个文件是否相同。(大家在下载一些资源的时候,就会发现网站提供了MD5值,就是用来检测文件是否被篡改)
import hashlib
# 待加密信息
str = '中国你好'
# 创建md5对象,
#md5对象,md5不能反解,但是加密是固定的,就是关系是一一对应,所以有缺陷,可以被对撞出来
hl = hashlib.md5()
#要对哪个字符串进行加密,就放这里
# 此处必须声明encode
# 若写法为hl.update(str) 报错为: Unicode-objects must be encoded before hashing
hl.update(str.encode(encoding='utf-8'))
print('MD5加密前为 :' + str)
#hl.hexdigest()) #拿到加密字符串
print('MD5加密后为 :' + hl.hexdigest())
"""
MD5加密前为 :中国你好
MD5加密后为 :560a6b11a85d436acfa4bd7f34462f40
"""
hash3 = hashlib.md5(bytes('abd',encoding='utf-8'))
'''
如果没有参数,所以md5遵守一个规则,生成同一个对应关系,如果加了参数,
就是在原先加密的基础上再加密一层,这样的话参数只有自己知道,防止被撞库,
因为别人永远拿不到这个参数
'''
hash3 .update(bytes("admin",encoding = "utf-8"))
print(hash3.hexdigest()) #9aea3c0a6c51555c1a4d0a5e9b689ded
检测两个文件是否相同时,大文件处理方法:
import hashlib
def get_file_md5(f):
m = hashlib.md5()
while True:
data = f.read(10240)
if not data:
break
m.update(data)
return m.hexdigest()
with open(YOUR_FILE, 'rb') as f:
file_md5 = get_file_md5(f)
SHA1的全称是Secure Hash Algorithm(安全哈希算法) 。SHA1基于MD5,加密后的数据长度更长,它对长度小于264的输入,产生长度为160bit的散列值。比MD5多32位。因此,比MD5更加安全,但SHA1的运算速度就比MD5慢:
import hashlib
str = "中国你好"
a = hashlib.sha1(str.encode("utf-8")).hexdigest()
print("sha1加密前为 :",str)
print("sha1加密前后 :",a)
"""
sha1加密前为 : 中国你好
sha1加密前后 : 3e6c570876775d0031dbf66247ed1054d4ef695e
"""
DES
DES算法为密码体制中的对称密码体制,又被称为美国数据加密标准。
# 导入DES模块
from Cryptodome.Cipher import DES
import binascii
# 这是密钥,此处需要将字符串转为字节
key = b'abcdefgh'
# 需要去生成一个DES对象
def pad(text):
"""
# 加密函数,如果text不是8的倍数【加密文本text必须为8的倍数!】,那就补足为8的倍数
:param text:
:return:
"""
while len(text) % 8 != 0:
text += ' '
return text
# 创建一个DES实例
des = DES.new(key,DES.MODE_ECB)
text ="I'm china!"
padded_text = pad(text)
print(padded_text)
#加密
encrypted_text = des.encrypt(padded_text.encode("utf-8"))
print(encrypted_text)
# rstrip(' ')返回从字符串末尾删除所有字符串的字符串(默认空白字符)的副本
# 解密
plain_text = des.decrypt(encrypted_text).decode().rstrip(' ')
print(plain_text)
"""
I'm china!
b'\xc0`I\x15\x8bo\x00\x00\xb0\xe27\xfe)\xc3\xde,'
I'm china!
"""
from Cryptodome.Cipher import DES
import binascii
# 这是密钥
key = b'abcdefgh'
# 需要去生成一个DES对象
des = DES.new(key, DES.MODE_ECB)
# 需要加密的数据
text = 'python spider!'
text = text + (8 - (len(text) % 8)) * '='
# 加密的过程
encrypto_text = des.encrypt(text.encode())
# 加密过后二进制转化为ASCII
encrypto_text = binascii.b2a_hex(encrypto_text)
print(encrypto_text)
# 解密需要ASCII 先转化为二进制 然后再进行解密
plaint = des.decrypt(binascii.a2b_hex(encrypto_text))
print(plaint)
"""
b'084725d8f5ffafc61814fae0796bfd2f'
b'python spider!=='
"""
(DES其他示例可参考另一文章《DES加解密》)
3DES
3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法。
由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解。3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。
3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),加密算法,其具体实现如下:设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,M代表明文,C代表密文:
3DES加密过程为:C=Ek3(Dk2(Ek1(M)))
3DES解密过程为:M=Dk1(EK2(Dk3©))
AES
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
from Cryptodome.Cipher import AES
from Cryptodome import Random
from binascii import a2b_hex
# 要加密的明文
data = '南来北往'
# 密钥key必须为 16(AES-128), 24(AES-192), 32(AES-256)
key = b'this is a 16 key'
# 生成长度等于AES 块大小的不可重复的密钥向量
iv = Random.new().read(AES.block_size)
print(iv)
# 使用 key 和iv 初始化AES 对象, 使用MODE_CFB模式
mycipher = AES.new(key, AES.MODE_CFB, iv)
print(mycipher)
# 加密的明文长度必须为16的倍数, 如果长度不为16的倍数, 则需要补足为16的倍数
# 将iv(密钥向量)加到加密的密钥开头, 一起传输
ciptext = iv + mycipher.encrypt(data.encode())
# 解密的话需要用key 和iv 生成的AES对象
print(ciptext)
mydecrypt = AES.new(key, AES.MODE_CFB, ciptext[:16])
# 使用新生成的AES 对象, 将加密的密钥解密
decrytext = mydecrypt.decrypt(ciptext[16:])
print(decrytext.decode())
RSA
RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。
该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用,而且,因为RSA加密算法的特性,RSA的公钥私钥都是10进制的,但公钥的值常常保存为16进制的格式,所以需要将其用int()方法转换为10进制格式。
import rsa
# rsa加密
def rsaEncrypt(str):
# 生成公钥、私钥
(pubkey, privkey) = rsa.newkeys(512)
print("pub: ", pubkey)
print("priv: ", privkey)
# 明文编码格式
content = str.encode('utf-8')
# 公钥加密
crypto = rsa.encrypt(content, pubkey)
return (crypto, privkey)
# rsa解密
def rsaDecrypt(str, pk):
# 私钥解密
content = rsa.decrypt(str, pk)
con = content.decode('utf-8')
return con
(a, b) = rsaEncrypt("hello")
print('加密后密文:')
print(a)
content = rsaDecrypt(a, b)
print('解密后明文:')
print(content)
import rsa
import binascii
def rsa_encrypt(rsa_n, rsa_e, message):
key = rsa.PublicKey(rsa_n, rsa_e)
message = rsa.encrypt(message.encode(), key)
message = binascii.b2a_hex(message)
return message.decode()
pubkey_n = '8d7e6949d411ce14d7d233d7160f5b2cc753930caba4d5ad24f923a505253b9c39b09a059732250e56c594d735077cfcb0c3508e9f544f101bdf7e97fe1b0d97f273468264b8b24caaa2a90cd9708a417c51cf8ba35444d37c514a0490441a773ccb121034f29748763c6c4f76eb0303559c57071fd89234d140c8bb965f9725'
pubkey_e = '10001'
rsa_n = int(pubkey_n, 16)
rsa_e = int(pubkey_e, 16)
message = '南北今天很忙'
print("公钥n值长度:", len(pubkey_n))
aa = rsa_encrypt(rsa_n, rsa_e, message)
print(aa)
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_OAEP, PKCS1_v1_5
class MyRSA():
def create_rsa_key(self, password):
"""
创建RSA密钥
步骤说明:
1、从 Crypto.PublicKey 包中导入 RSA,创建一个密码
2、生成 1024/2048 位的 RSA 密钥
3、调用 RSA 密钥实例的 exportKey 方法,传入密码、使用的 PKCS 标准以及加密方案这三个参数。
4、将私钥写入磁盘的文件。
5、使用方法链调用 publickey 和 exportKey 方法生成公钥,写入磁盘上的文件。
"""
key = RSA.generate(1024)
encrypted_key = key.exportKey(passphrase=password.encode("utf-8"), pkcs=8,
protection="scryptAndAES128-CBC")
with open("my_private_rsa_key.bin", "wb") as f:
f.write(encrypted_key)
with open("my_rsa_public.pem", "wb") as f:
f.write(key.publickey().exportKey())
def encrypt(self, plaintext):
# 加载公钥
recipient_key = RSA.import_key(
open("my_rsa_public.pem").read()
)
cipher_rsa = PKCS1_v1_5.new(recipient_key)
en_data = cipher_rsa.encrypt(plaintext.encode("utf-8"))
return en_data
# print(len(en_data), en_data)
def decrypt(self, en_data, password):
# 读取密钥
private_key = RSA.import_key(
open("my_private_rsa_key.bin").read(),
passphrase=password
)
cipher_rsa = PKCS1_v1_5.new(private_key)
data = cipher_rsa.decrypt(en_data, None)
return data
# print(data)
mrsa = MyRSA()
mrsa.create_rsa_key('123456')
e = mrsa.encrypt('hello')
d = mrsa.decrypt(e, '123456')
print(e)
print(d)
部分参考网络。