利用django中pycryptodome模块进行数据加密(不对称加密,即生成公钥和私钥,前台用公钥加密,后台接收到机密数据后利用私钥解密)
注意:pycrypto,pycrytodome和crypto是一个东西,crypto在python上面的名字是pycrypto它是一个第三方库,但是已经停止更新三年了,所以不建议安装这个库;
安装好pycrytodome,可卸载另外两个模块,否则会在代码中导入时发生冲突。
可直接通过pip(pip3) install pycrytodome在线安装,也可去下载pycrytodome安装包进行安装(选择和python对应的版本)
代码示例:
注意:安装的是pycrytodome,在项目中导入的是Crypto
1、后端代码
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto import Random
import base64
from urllib import parse
from django.shortcuts import render
def create_rsa_key():
"""
创建RSA密钥
步骤说明:
1、从 Crypto.PublicKey 包中导入 RSA,创建一个密码
2、生成 1024/2048 位的 RSA 密钥
3、调用 RSA 密钥实例的 exportKey 方法,传入口令、使用的 PKCS 标准以及加密方案这三个参数。
4、将私钥写入磁盘的文件。
5、使用方法链调用 publickey 和 exportKey 方法生成公钥,写入磁盘上的文件。
"""
# 利用伪随机数来生成私钥和公钥
random_generator = Random.new().read
key = RSA.generate(2048,random_generator) #生成 1024/2048 位的 RSA 密钥
encrypted_key = key.exportKey() #私钥
# public_key = key.publickey().exportKey() #公钥
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()) #一般生成的密钥文件会直接生成到项目的根目录下
# 向前台发送公钥
class Public_Key(LoginRequiredMixin, View):
def post(self, request):
public_key = open("/xx/xx/xxxxxxx/my_rsa_public.pem").read()
return HttpResponse(public_key)
2、前端js代码
// 前端js获取公钥,用公钥对传输数据进行加密(需要注意的是要用到一个对应的加密js文件,jsencrypt.min.js,可以在base.html文件导入,jsencrypt.min.js可从网上下载,放到js文件夹下)
var public_key
var encrypt = new JSEncrypt();
// 获取公钥
$.ajax({
url:"/xxx/xxxxxx/",
type:"post",
data:{
'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()
},
success:function(data){
public_key = data
encrypt.setPublicKey(public_key);
}
})
// 对传输数据进行加密(data: {"activetype": encrypt.encrypt("repasd"), "repasd": encrypt.encrypt(repasd), "uid":encrypt.encrypt(puserid.toString()), "msg_code": encrypt.encrypt(msg_code)},)
$.ajax({
type: 'post',
url: "/xxx/xxxxx/",
dataType: "json",
headers: {"X-CSRFtoken": $("[name='csrfmiddlewaretoken']").val()},
data: {
"activetype": encrypt.encrypt("repasd"),
"repasd": encrypt.encrypt(repasd), "uid":encrypt.encrypt(puserid.toString()),
"msg_code": encrypt.encrypt(msg_code)
},
success: function (data) {
// console.log(data)
if (data.code == 0) {
layer.close(index);
layer.open({
content: '' + data.msg + ''
, yes: function (index, layero) {
//do something
layer.close(index); //如果设定了yes回调,需进行手工关闭
// alert({name: ""})
}
}
)
}
},
error: function (xhr, type) {
// layer.close();
layer.open({
content: '' + '系统错误,重置失败' + ''
}
)
}
});
3、后端解密代码
#解密过程,inputdata为前台公钥加密的数据
def decrypt_data(inputdata):
data = parse.unquote(inputdata)
# base64decode
data = base64.b64decode(data)
# 读取密钥
private_key = RSA.import_key(
open("/xx/xxxxxxx/my_private_rsa_key.bin").read()) # 路径需要准确
# 使用 PKCS1_v1_5解密
cipher_rsa = PKCS1_v1_5.new(private_key)
# 当解密失败,会返回 sentinel
sentinel = None
ret = cipher_rsa.decrypt(data, sentinel)
return ret.decode() # 解码
基本流程到此结束。
说几个注意点(本人碰到的坑):
1、前端需要被公钥加密的数据type为字符串,int型需要转为str型。
2、后台无法解密前端加密数据接
(1)首先检查前台是否获取到公钥,数据是否机密成功,可从console打印查看
(2)检查前台接收到的公钥与项目中保存的文件公钥是否一致(这个是常见的,由于后台代码创建密钥的代码位置原因,每次刷新页面创建一次密钥,都会覆盖之前的密钥,使得之前传输到前台的公钥报废,导致后台无法解密成功,个人建议,1、可以将创建密钥代码写到单独一个文件,启动项目时,被运行,这样只要不关闭项目,密钥就不会改变,2、可以将创建密钥代码写到单独一个文件,定时去执行,每隔一段时间刷新一次密钥,3、懒人用法,如果登录后跳转的index页面不需要进行数据加密,可以将创建密钥代码卸载这,每次登陆就去创建一次密钥。)
暂时写到这,后面想到什么再补充
jsencrypt.min.js可自行下载。jsencrypt.min.js 提取码:9kk2