前端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。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM