• 前端AES加密Python后端解密数据


    前言:账号密码一直对我们来说真的非常非常重要,但大多数人不是很重视,比如日常工作中,员工会经常登录到不同网站去查数据或者完成自己的工作,但是账号密码他们不一定会保存,经常会忘了。或者他们的密码都是名字拼音或者简单的数字,员工忘记密码管理员可以帮忙修改,但是密码在网上泄露那么会造成无可挽回的损失。自己平常也有很多站点的账号密码,以前是放在记事本,也试过放在gitee,感觉太危险了,万一丢了,或者忘了在哪就太麻烦了。为了方便自己,后来写了一个密码管理系统,用到了AES加密相关知识,对自己帮助挺大的,分享一下这块技术。

    一、什么是AES
    高级加密标准(AES,Advanced Encryption Standard),是一种最常见的对称加密算法,AES在世界各地的软件和硬件中实施加密敏感数据。

    AES的加密流程介绍

    1.明文P:没有经历加密的数据
    2.密钥K:用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。
    密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,
    然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。
    3.AES加密函数
    经加密函数处理后的数据
    4.AES解密函数
    设AES解密函数为D,则 P = D(K, C),其中C为密文,K为密钥,P为明文。也就是说,把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。

    AES基本的结构

    AES为分组密码,分组密码就是把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文。在AES标准规范中,分组长度只能是128位,也就是说每个分组为16个字节(每个字节8位)。
    AES 包括三种分组密码:AES-128、AES-192 和 AES-256。
    AES-128使用128位密钥长度来加密和解密消息块
    AES-192使用192位密钥长度来加密和解密消息块
    AES-256使用256位密钥长度来加密和解密消息块

    AES加密的模式
    AES分为几种模式,比如ECB,CBC,CFB等等,这些模式除了ECB由于没有使用IV而不太安全,其他模式差别并没有太明显,大部分的区别在IV和KEY来计算密文的方法略有区别。

    AES加密中IV的作用
    IV称为初始向量,不同的IV加密后的字符串是不同的,加密和解密需要相同的IV,既然IV看起来和key一样,却还要多一个IV的目的,对于每个块来说,key是不变的,但是只有第一个块的IV是用户提供的,其他块IV都是自动生成。
    IV的长度为16字节。超过或者不足,可能实现的库都会进行补齐或截断。但是由于块的长度是16字节,所以一般可以认为需要的IV是16字节。

    AES加密中PADDING的作用
    PADDING是用来填充最后一块使得变成一整块,所以对于加密解密两端需要使用同一的PADDING模式,大部分PADDING模式为PKCS5, PKCS7, NOPADDING。

    AES加密和解密端
    对于加密端,应该包括:加密秘钥长度,密钥,IV值,加密模式,PADDING方式。
    对于解密端,应该包括:解密秘钥长度,密钥,IV值,解密模式,PADDING方式。

    二、前端实现AES加密解密功能
    前端要实现AES加密,需要下载crypto-js.js,crypto-js是一个纯javascript写的加密算法类库,可以非常方便地在javascript进行 MD5、SHA1、SHA2、SHA3、RIPEMD-160 哈希散列,进行 AES、DES、Rabbit、RC4、Triple DES 加解密

    下载链接如下:

    https://github.com/brix/crypto-js/releases
    

    前端代码如下:

    crypt_key = 'l36DoqKUYQP0N7e1';
    crypt_iv = '131b0c8a7a6e072e';
    
    //加密
    function encrypt(data) {
        let aes_key = CryptoJS.enc.Utf8.parse(crypt_key);  //解析后的key
        let new_iv = CryptoJS.enc.Utf8.parse(crypt_iv); //解析后的iv
        encrypted = CryptoJS.AES.encrypt(data, aes_key, { //AES加密
            iv: new_iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.ZeroPadding
        });
        return encrypted.toString()
    }
    
    //解密
    function decrypt(data) {
        let aes_key = CryptoJS.enc.Utf8.parse(crypt_key);  // 解析后的key
        let aes_iv = CryptoJS.enc.Utf8.parse(crypt_iv);   // 解析后的iv
        let baseResult=CryptoJS.enc.Base64.parse(data);   // Base64解密
        let ciphertext=CryptoJS.enc.Base64.stringify(baseResult);     // Base64解密
        let decryptResult = CryptoJS.AES.decrypt(ciphertext,aes_key, {    // AES解密
            iv: aes_iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.ZeroPadding
        });
    
        resData = decryptResult.toString(CryptoJS.enc.Utf8).toString();
        return resData;
    }
    

    测试下前端代码

    console.log(encrypt('456')); 加密
    console.log(decrypt('aCbhraRUHLvqxdoG5amBNQ==')); 解密
    

    查看结果:

    三、后端实现AES加密解密功能 

    import base64
    import hashlib
    from Crypto.Cipher import AES, DES
    from binascii import b2a_hex, a2b_hex
    
    
    class DeAesCrypt:
        """
        AES-128-CBC解密
        """
        def __init__(self, data, key, pad='zero'):
            """
            :param data: 加密后的字符串
            :param key: 随机的16位字符
            :param pad: 填充方式
            """
            self.key = key
            self.data = data
            self.pad = pad.lower()
    
    
            hash_obj = hashlib.md5()  # 构造md5对象
            hash_obj.update(key.encode())  # 进行md5加密,md5只能对byte类型进行加密
            res_md5 = hash_obj.hexdigest()  # 获取加密后的字符串数据
            self.iv = res_md5[:16]
    
        @property
        def decrypt_aes(self):
            """AES-128-CBC解密"""
            real_data = base64.b64decode(self.data)
            my_aes = AES.new(self.key, AES.MODE_CBC, self.iv)
            decrypt_data = my_aes.decrypt(real_data)
            return self.get_str(decrypt_data)
    
    
        def add_to_16(self,text):
            pad = 16 - len(text.encode('utf-8')) % 16
            text = text + pad * chr(pad)
            return text.encode('utf-8')
    
    
        def encrypt(self):
            """AES-128-CBC加密"""
            # 预处理,填充明文为16的倍数
            text = self.add_to_16(self.data)
            cryptor = AES.new(self.key,AES.MODE_CBC, self.iv)
    
            cipher_text = cryptor.encrypt(text)
    
            base = 16
    
            if base == 16:
                # 返回16进制密文
                return b2a_hex(cipher_text).decode('utf-8')
            elif base == 64:
                # 返回base64密文
                return base64.b64encode(cipher_text).decode('utf-8')
    
    
        def get_str(self, bd):
            """解密后的数据去除加密前添加的数据"""
            if self.pad == "zero":  # 去掉数据在转化前不足16位长度时添加的ASCII码为0编号的二进制字符
                return ''.join([chr(i) for i in bd if i != 0])
    
            elif self.pad == "pkcs7":  # 去掉pkcs7模式中添加后面的字符
                return ''.join([chr(i) for i in bd if i > 32])
    
            else:
                return "不存在此种数据填充方式"

    四、效果展示  

    前端添加用户名test,密码为123456

    查看传送的数据是否加密,可以看到账号密码都已经加密过了

     后端检查解密数据是否正确

    username=DeAesCrypt(data=info_data.get('username'),key=info_data.get('aes_key')).decrypt_aes
    password=DeAesCrypt(data=info_data.get('password'),key=info_data.get('aes_key')).decrypt_aes
    {'username': 'test', 'password': '123456'}
    

      

    详细AES加密知识可以查看下面链接

    https://blog.csdn.net/qq_28205153/article/details/55798628
    

    补充:

    由于 PyCrypto 已经超过三年无人维护,因此 Github 上的开发者 Varbin 在该项目的 Github issue 里呼吁开发们不要再使用 PyCrypto ,而应该将 PyCrypto 替换为 PyCryptodome。
    对于使用 PyCrypto 的已有项目而言,PyCryptodome 保持了与 PyCrypto 相当高的兼容性并且处于良好的维护状态,因此便于更换。对于要使用 Python 加密库的新项目,建议开发者使用 PyCryptodome 或者 cryptography。

     

  • 相关阅读:
    C#面向对象三大特性:多态
    C#面向对象三大特性:继承
    C#面向对象三大特性:封装
    C# 函数
    SQL常用语句和函数
    NuGet 常用命令
    SQL Server不同服务器不同数据库间的操作
    C# 面试编程算法题
    C# 冒泡排序
    域名和URL各部分组成
  • 原文地址:https://www.cnblogs.com/lucktomato/p/15157475.html
Copyright © 2020-2023  润新知