Python和vue前后端交互的AES加解密、RSA加解密、MD5校验

背景

有这样一个流程:用户访问login.html准备登陆,login.html的App挂载完毕后,发送axios get到后端,得到了验证码图片、服务器的RSA公钥。用户输入账户密码验证码后点击提交,前端程序在发送的请求体上添加随机生成的AES秘钥数据,用RSA公钥将请求加密后发送axios post到后端,后端验证完成后再返回使用AES秘钥加密的用户数据。
关键词:python、flask、vue.js、typescript、crypto-js、forge.js、node-forge、AES加解密、RSA加解密、MD5校验

实现代码

python

安装相关的包pip install pycryptodome

1. 进行AES加解密的myAES.py

from random import Random
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad


# AES ECB mode without IV
# 默认AES_Key是hello_next_hello
default_AES_key = "hello_next_hello"

def encrypt(key: str = default_AES_key , data: str = '') -> str:
    key = key.encode('utf-8')
    data = pad(data.encode(), AES.block_size)
    cipher = AES.new(key, AES.MODE_ECB)
    rst = base64.b64encode(cipher.encrypt(data))
    return rst.decode("utf-8", 'ignore')


def decrypt(enc: str, key: str = default_AES_key) -> str:
    enc = enc.encode("utf-8")
    enc = base64.b64decode(enc)
    cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
    return unpad(cipher.decrypt(enc), AES.block_size).decode()


def generateAESKey(param_custom_key='') -> str:
    RES = ''
    if len(param_custom_key) < 16:
        RES += create_salt(16 - len(param_custom_key))
    else:
        RES = param_custom_key[0:16]
    return RES


def create_salt(length=4):
    salt = ''
    chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789+-*'
    len_chars = len(chars) - 1
    random = Random()
    for i in range(length):
        # 每次从chars中随机取一位
        salt += chars[random.randint(0, len_chars)]
    return salt


if __name__ == '__main__':
    encrypted = encrypt(setting.security.AES_encryption_key, 'helloworldhelloworld')
    print('[myAES.py][main]encrypted ECB Base64:', encrypted)
    decrypted = decrypt(encrypted)
    print('[myAES.py][main]decrypted data:', decrypted)
    

2. 进行RSA加解密的myRSA.py

import base64, math
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5


def generate_key():
    rsa = RSA.generate(1024)
    private_key = rsa.exportKey()
    publick_key = rsa.publickey().exportKey()
    return private_key.decode(), publick_key.decode()


def rsa_encrypt(public_key: str, message: str) -> list[str]:
    default_length = 96
    content = []
    public_key = RSA.import_key(public_key)
    cipher = PKCS1_v1_5.new(public_key)
    for i in range(0, math.ceil(len(message) / default_length)):
        temp = message[i * default_length: (i + 1) * default_length]
        content.append(base64.b64encode(cipher.encrypt(temp.encode())).decode('utf-8'))
    return content


def rsa_decrypt(private_key: str, message: list[str]) -> str:
    private_key = RSA.import_key(private_key)
    cipher = PKCS1_v1_5.new(private_key)
    result = ''
    for item in message:
        result += cipher.decrypt(base64.b64decode(item), 0).decode('utf-8')
    return result


if __name__ == "__main__":
    pri, pub = generate_key()
    data = '{"username":"hello","password":"hello","password_confirm":"","captcha":"1234","email":"","phone":"","setting":false,"AES_key":"hello_next_hello"}'
    print(f'[main]明文长度:{len(data)}')  # 单片最大长度117,大于这个值会报错,需要切分?
    E = rsa_encrypt(pub, data)
    D = rsa_decrypt(pri, E)
    print(f'[main]加密文本:[分片数量{len(E)}]{E}')
    print(f'[main]解密文本:[文字数量{len(D)}]{D}')

3. 生成MD5的myMD5.py

from random import Random
import hashlib

# 获取由4位随机大小写字母、数字组成的salt值
def create_salt(length: int = 4) -> str:
    salt = ''
    chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789+-*'
    len_chars = len(chars) - 1
    random = Random()
    for i in range(length):
        # 每次从chars中随机取一位
        salt += chars[random.randint(0, len_chars)]
    return salt

# 获取原始密码+salt的md5值
# salt参数留空(""),就可以不加盐
def create_salty_md5(pwd: str, salt: str) -> str:
    md5_obj = hashlib.md5()
    md5_obj.update((pwd + salt).encode("utf-8"))
    return md5_obj.hexdigest()
   
if __name__ == "__main__":
    data = "helloworld"
    md5 = create_salty_md5(data, create_salt())
    print(f"[myMD5.py][main]加盐加密后的数据为{md5}")

Vue(typescript)

安装相关包npm install crypto-js node-forge

1. 进行AES加解密的myAES.ts

import CryptoJS from 'crypto-js';

export function generate_AES_key(length: number = 16) {
    const enabled_char = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    let result = '';
    for (let i = length; i > 0; --i) result += enabled_char[Math.floor(Math.random() * enabled_char.length)];
    return result;
}


export function AES_encryption(data: string) {
	//默认AES_key为hello_next_hello
    const key = CryptoJS.enc.Utf8.parse("hello_next_hello");
    const srcs = CryptoJS.enc.Utf8.parse(data);
    const encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 });
    return encrypted.toString();

}

export function AES_decryption(data: string) {
    //默认AES_key为hello_next_hello
    const AK = "hello_next_hello"
    const key = CryptoJS.enc.Utf8.parse(AK);
    const decrypted = CryptoJS.AES.decrypt(data, key, { mode: CryptoJS.mode.ECB }).toString(CryptoJS.enc.Utf8);
    return decrypted
}

2. 进行RSA加解密的myRSA.ts

import forge from 'node-forge'
//证书秘钥示例,具体长这样↓,实际生产时可以自己生成
const pk = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChMkifsa7UPkkFHFdNvfGYV49b
jdIcJfWIHXqpO5+xPD5GC8/+AzryyoogDj5PFO4AFGO1m3H/ZhF8eYF5hpOes7K5
qqaShQGqQk1ZeJnK3hrrtMAPyH7PJOOeyq7jxL68dVxXISMN5AxG1MNBJ5UalwrZ
ABfoqbINYKtr/5/+WQIDAQAB
-----END PUBLIC KEY-----`
const prik = `-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQChMkifsa7UPkkFHFdNvfGYV49bjdIcJfWIHXqpO5+xPD5GC8/+
AzryyoogDj5PFO4AFGO1m3H/ZhF8eYF5hpOes7K5qqaShQGqQk1ZeJnK3hrrtMAP
yH7PJOOeyq7jxL68dVxXISMN5AxG1MNBJ5UalwrZABfoqbINYKtr/5/+WQIDAQAB
AoGBAJjxIbDLIGrmUdfUhQ0RDDoT0cP3MoRci7LC7Y/GL4U0+IzzRjvnCrYz74vs
l7fmzs4qilRUEXxWdn7Ytjz8r+/gFwHs/CBrOvOWfiA5FKT61jy7OveFS/GXP6Cp
5XgrCrau5J8lrp0tysHaAppO8x477VmHlZXDxnHQdZFT5NSFAkEA3LHHk7p09Gqi
uNkA9SckvVgzUqSV8WY8i2Bv/YDqotGLI5i1XivATxj5lZu41xzP+CijaRTr6iQH
k+5nhG3E9wJBALr72Ua9wIwzH2SoZOrMOxRb+lPfN1uL75opekKTXu6K5myfUMdX
6MqkAFVnrrYhKZGunPCF9urGOccGx17Zky8CQQCFNs6YTnlgO6njWCGq2SjlHgNE
xFI595NeMiUHaTS4eTG6l+gKYvBfDl1BQFEPj7W9PpJ80IMivwLP+Z0Eo9m7AkBJ
8xbASoVfLUzKI2seDT2EVMgQ6aPcGeDd6G+I6v3Ne7Ob2/o3jIXttqTHIiVPtJfb
HOLGoUTBHzp0gzLQSV5TAkAo5UUdZvsQj547rJPruWUKq96N5/rp3wGsnqLund7C
FhDisKhY2DxYsx9veRIpxTED+TVJaR+MdwOqxzXoTWei
-----END RSA PRIVATE KEY-----`


export function RSA_encrypt(data: string): Array<string> {
    const pubKey = pk
    if (pubKey) {
        const publicKey = forge.pki.publicKeyFromPem(pubKey);
        const RSA_config = {
            md: forge.md.sha1.create(),
            mgf: forge.mgf.mgf1.create(forge.md.sha1.create())
        }
        const default_lenght = 96 //实际上好像最长能到117
        const result = [];
        for (let i = 0; i < Math.ceil(data.length / default_lenght); i++) {
            const temp: string = data.substring(i * default_lenght, (i + 1) * default_lenght)
            result.push(forge.util.encode64(
                publicKey.encrypt(temp, 'RSAES-PKCS1-V1_5', RSA_config)
            ))
        }
        return result
    } else {
        console.log("no publicKey found")
        return []
    }
}

export function RSA_decrypt(data: Array<string>): string {
    const priKey = prik
    if (priKey) {
        const privateKey = forge.pki.privateKeyFromPem(priKey);
        let result = "";
        for (let item of data) {
            const b = atob(item)
            result += privateKey.decrypt(b)
        }
        return result
    } else {
        console.log("no publicKey found")
        return "读取不到privateKey"
    }
}


export function generate_RSA_key(): { "public_key": string, "private_key": string } {
    const keys = forge.pki.rsa.generateKeyPair(1024)
    const public_key = forge.pki.publicKeyToPem(keys.publicKey)
    const private_key = forge.pki.privateKeyToPem(keys.privateKey)
    //可以自行找个地方把公钥私钥存起来,如localStorage、sessionStorage、Pinia、等
    return {
        public_key: public_key,
        private_key: private_key
    }
}

3. 生成md5的myMD5.ts

import CryptoJS from "crypto-js";
export function createMD5(data: string): string {
    return CryptoJS.MD5(data).toString()
}

使用方法

到前端项目新建各种文件(myAES.ts、myRSA.ts之类的),
然后再导入(例子)imprt {generate_RSA_key} from "myRSA"
接着调用函数即可(例子)const data:Array<string> = RSA_encrypt("helloworld")

到python后端项目新建各种文件(myAES.py、myRSA.py之类的),
然后再导入(例子)from src.utils import myAES, myMD5, myRSA
接着调用函数即可

#(例子)
data = myRSA.rsa_decrypt(session['RSA_privateKey'], json.loads(request.data.decode()))
# 如上面代码所示,rsa_decrypt第一个参数是字符串形式的私钥,第二个参数是列表形式的已加密数据,返回字符串形式的结果
# json.loads(request.data.decode())在flask中也可以直接写成request.json

参考文章

Python实现AES加密解密
CryptoJS的AES加解密
浏览器端rsa加密方案node-forge
使用node-forge pki进行RSA加密
RSAUtil 前端 JavaScript JSEncrypt 实现 RSA (长文本)加密解密

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值