Django和vue的RSA加密

一、前言

账号密码等关键信息在传输过程需要加密,我采用强度更高的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类型。

四、前端vue

前端采用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))

你可能感兴趣的:(vue3,Django,python,js,django,vue.js)