账号密码等关键信息在传输过程需要加密,我采用强度更高的RSA加密
后端:Django3.2,python3.9
前端:vue3.05,node14
后端使用pycryptodome这个模块,我试了好多文章的方法,都不管用,不要去管什么版本,什么C++环境,直接安装这个模块就结束了,没那么多事。
pycryptodome官方文档
# 虽然安装的是pycryptodome,但是使用方法都是一样的
# 短文的加密解密
def jiemi(neirong):
# print(neirong,"\n",len(neirong),"长度",type(neirong))
pri_key = RSA.importKey(private_key)
cipher = PKCS1_cipher.new(pri_key)
jieguo = base64.b64decode(neirong)
# print("解码结果",jieguo,len(jieguo))
back_text = cipher.decrypt(jieguo, None)
jieguo2 = back_text.decode('utf-8')
# print("解密结果",jieguo2,type(jieguo2))
return jieguo2
def jiami(neirong):
pub_key = RSA.importKey(public_key)
cipher = PKCS1_cipher.new(pub_key)
rsa_text = base64.b64encode(cipher.encrypt(bytes(neirong.encode("utf8"))))
return rsa_text
# 长文的分段加密解密
def fenduanjiami(msg):
"""
公钥加密
:param msg: 要加密内容
:return: 加密之后的密文
"""
# 获取公钥
publickey = RSA.importKey(public_key)
# 分段加密
pk = PKCS1_cipher.new(publickey)
encrypt_text = []
for i in range(0, len(msg), 30):
cont = msg[i:i + 30]
jiamitext = pk.encrypt(cont.encode("utf8"))
# print(len(jiamitext))
encrypt_text.append(jiamitext)
# 加密完进行拼接
cipher_text = b''.join(encrypt_text)
# base64进行编码
result = base64.b64encode(cipher_text)
return result.decode()
def fenduanjiemi(msg):
"""
私钥进行解密
:param msg: 密文:字符串类型
:return: 解密之后的内容
"""
# base64解码
msg = base64.b64decode(msg)
# 获取私钥
rsakey = RSA.importKey(private_key)
cipher = PKCS1_cipher.new(rsakey)
# 进行解密
text = []
for i in range(0, len(msg), 128):
cont = msg[i:i + 128]
text.append(cipher.decrypt(cont, 1))
text = b''.join(text)
return text.decode("utf8")
我选择在setting.py里面生成公钥和私钥,直接存储在内存里面,每次重启都重新生成,
# setting.py文件
from Crypto import Random
from Crypto.PublicKey import RSA
random_generator = Random.new().read
key = RSA.generate(1024,random_generator)
private_key = key.export_key()
public_key = key.publickey().export_key()
注意:我采用的证书key长度是1024,能加密的内容长度是(1024/8)-11=117,由于一个中文占两个字符,所以我的分段加密长度是30。证书key1024的时候,生成的密文一定是128位,所以解密长度是128.
加密函数的参数text是utf8的字符串,str类型。
解密函数的参数text是byte类型。
前端采用jsencrypt模块,在APP.vue上create生命周期的时候,向后端获取公钥,存储到vuex里面。
// 我将加密和解密方法存放到一个单独的js文件中
import JSEncrypt from 'jsencrypt';
// rsa加密
function jiamiRSA(text){
let encryptStr = new JSEncrypt();
const pubKey = store.state.encryption.publickey // 从vuex里面获取公钥
// console.log(pubKey,"公钥")
encryptStr.setPublicKey(pubKey); // 设置 加密公钥
const jieguo = encryptStr.encrypt(text.toString());
console.log(jieguo,"rsa加密结果")
return jieguo
}
// rsa解密
function jiemiRSA(text){
let encryptStr = new JSEncrypt();
const siyao = "" // 私钥在后端,这个方法没什么用,先放着吧
encryptStr.setPrivateKey(siyao)//解密公钥
return encryptStr.decrypt(text.toString()) //解密
}
注意:这个方法会自动转化base64,所以不用专门转化base64。
aes加密测试了一天也没搞定。前后端加密长度不一致,目前没找到什么办法。
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from OA后端.settings import private_key, public_key
import base64
# 临时使用,过后删除
# from Crypto import Random
# from Crypto.PublicKey import RSA
#
# random_generator = Random.new().read
# key = RSA.generate(1024, random_generator)
# private_key = key.export_key()
# public_key = key.publickey().export_key()
"""
不支持长文的加密和解密
RSA 1024只能加密117字节
RSA N/8-11 就是可加密的字节长度
"""
def jiemi(neirong):
# print(neirong,"\n",len(neirong),"长度",type(neirong))
pri_key = RSA.importKey(private_key)
cipher = PKCS1_cipher.new(pri_key)
jieguo = base64.b64decode(neirong)
# print("解码结果",jieguo,len(jieguo))
back_text = cipher.decrypt(jieguo, None)
jieguo2 = back_text.decode('utf-8')
# print("解密结果",jieguo2,)
return jieguo2
def jiami(neirong):
pub_key = RSA.importKey(public_key)
cipher = PKCS1_cipher.new(pub_key)
rsa_text = base64.b64encode(cipher.encrypt(bytes(neirong.encode("utf8"))))
return rsa_text
"""
对长文的分段加密和分段解密
"""
def fenduanjiami(msg):
"""
公钥加密
:param msg: 要加密内容
:return: 加密之后的密文
"""
# 获取公钥
publickey = RSA.importKey(public_key)
# 分段加密
pk = PKCS1_cipher.new(publickey)
encrypt_text = []
for i in range(0, len(msg), 30):
cont = msg[i:i + 30]
jiamitext = pk.encrypt(cont.encode("utf8"))
# print(len(jiamitext))
encrypt_text.append(jiamitext)
# 加密完进行拼接
cipher_text = b''.join(encrypt_text)
# base64进行编码
result = base64.b64encode(cipher_text)
return result.decode()
def fenduanjiemi(msg):
"""
私钥进行解密
:param msg: 密文:字符串类型
:return: 解密之后的内容
"""
# base64解码
msg = base64.b64decode(msg)
# 获取私钥
rsakey = RSA.importKey(private_key)
cipher = PKCS1_cipher.new(rsakey)
# 进行解密
text = []
for i in range(0, len(msg), 128):
cont = msg[i:i + 128]
text.append(cipher.decrypt(cont, 1))
text = b''.join(text)
return text.decode("utf8")
"""
aes加密的ECB加密模式,ECB没有偏移量
"""
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
def add_to_16(text):
if len(text.encode('utf-8')) % 16:
add = 16 - (len(text.encode('utf-8')) % 16)
else:
add = 0
text = text + ('\0' * add)
return text.encode('utf-8')
# 加密函数
def encrypt(key, text):
# 将key从str转成byte类型
key = key.encode('utf-8')
mode = AES.MODE_ECB
text = add_to_16(text)
# 这部分相当于js模块的 padding: cryptoJS.pad.Pkcs7
# pad = 16 - len(text) % 16
# text = (text + (chr(pad) * pad)).encode("utf-8")
# 这部分相当于js模块的 padding: cryptoJS.pad.Pkcs7
cryptos = AES.new(key, mode)
cipher_text = cryptos.encrypt(text)
jieguo = b2a_hex(cipher_text)
print(jieguo, "加密结果",key,type(jieguo))
return jieguo
# 解密后,去掉补足的空格用strip() 去掉
def decrypt(key, text):
key = key.encode('utf-8')
mode = AES.MODE_ECB
cryptor = AES.new(key, mode)
plain_text = cryptor.decrypt(a2b_hex(text))
return bytes.decode(plain_text).rstrip('\0')
"""
AES加密的CBC模式,需要一个16位的偏移量
"""
from Crypto.Cipher import AES
import base64
# 密钥(key), 密斯偏移量(iv) CBC模式加密
BLOCK_SIZE = 16 # Bytes
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * \
chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]
vi = '0102030405060708'
def AES_Encrypt(key, data):
data = pad(data)
# 字符串补位
cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
encryptedbytes = cipher.encrypt(data.encode('utf8'))
# 加密后得到的是bytes类型的数据,使用Base64进行编码,返回byte字符串
encodestrs = base64.b64encode(encryptedbytes)
# 对byte字符串按utf-8进行解码
enctext = encodestrs.decode('utf8')
return enctext
def AES_Decrypt(key, data):
data = data.encode('utf8')
encodebytes = base64.decodebytes(data)
# 将加密数据转换位bytes类型数据
cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
text_decrypted = cipher.decrypt(encodebytes)
# 去补位
text_decrypted = unpad(text_decrypted)
text_decrypted = text_decrypted.decode('utf8')
# print(text_decrypted)
return text_decrypted
# 解密rsa主要方法
def myjiemirsa(text):
return jiemi(text.encode())
def myjiamirsa(text):
return jiami(text)
def myjiamiaes(key, text):
return encrypt(key, text)
if __name__ == '__main__':
key = '5c44c819appsapi0'
data = '654198519851651'
jieguo = encrypt(key,data)
print(jieguo)
print(decrypt(key,jieguo))