引言
高级加密标准(AES, Advanced Encryption Standard),是一种最常见的对称加密算法 。其加密流程如下图所示,发送方通过密钥对明文加密后进行网络传输,接收方用同样的密钥将密文解密。在前后端通讯场景中,可利用AES算法对用户密码进行加密后传输,防止被抓包而造成密码泄露。
为了完成加解密操作,双方需要事先约定好: 秘钥长度,密钥,IV值,加密模式,填充方式共计5项内容。下面以128位密钥长度、CBC加密模式、零填充为例进行实战介绍,更多AES加密算法的细节读者可自行查阅。
前端 JS加解密
前端要实现AES加密,需要安装CryptoJS。 CryptoJS是一个JavaScript的加解密的工具包。它支持多种算法:MD5、SHA1、SHA2、SHA3、RIPEMD-160
的哈希散列,以及进行 AES、DES、Rabbit、RC4、Triple DES
加解密。
npm install --save crypto-js
新建secret.js,将相关操作封装成函数,代码如下:
// 引用AES源码js
const CryptoJS = require('crypto-js');
// 128位的密钥与IV,与后端约定好
let crypt_key = 'OS7kWn9kGLmr7wxD';
let crypt_iv = 'AgBJQGRaHehjSgjT';
// 加密
export function encrypt(data) {
// 将key解析为字节
let aes_key = CryptoJS.enc.Utf8.parse(crypt_key);
// 将iv解析为字节
let new_iv = CryptoJS.enc.Utf8.parse(crypt_iv);
// AES加密 CBC模式 ZeroPadding
let encrypted = CryptoJS.AES.encrypt(data, aes_key, {
iv: new_iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
// 返回字符串
return encrypted.toString();
}
//解密
export function decrypt(data) {
let aes_key = CryptoJS.enc.Utf8.parse(crypt_key);
let aes_iv = CryptoJS.enc.Utf8.parse(crypt_iv);
// 将数据编码成Base64格式
let baseResult=CryptoJS.enc.Base64.parse(data);
let ciphertext=CryptoJS.enc.Base64.stringify(baseResult);
// AES解密 CBC模式 ZeroPadding
let decryptResult = CryptoJS.AES.decrypt(ciphertext, aes_key, {
iv: aes_iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
// 返回字符串
let resData = decryptResult.toString(CryptoJS.enc.Utf8).toString();
return resData;
}
测试前端加解密:
import {encrypt, decrypt} from '@/utils/secret'
let ps = '123456'
let encodePs = encrypt(ps)
let decodePs = decrypt(encodePs)
console.log('encodePs', encodePs)
// 输出:AA2uUXaD4p/s6HcPbX3CGw==
console.log('decodePs', decodePs)
// 输出:123456
后端Python加解密
后端Python要实现AES加密,需要安装 pycryptodome 。文章来源:https://www.toymoban.com/news/detail-760870.html
pip install pycryptodome
新建secret.py,将相关操作封装成函数,代码如下:文章来源地址https://www.toymoban.com/news/detail-760870.html
import base64
import random
from Crypto.Cipher import AES
# 随机生成,用于加解密,与前端约定好
aes_key = 'OS7kWn9kGLmr7wxD'
aes_iv = 'AgBJQGRaHehjSgjT'
# 生成指定长度的16进制字符串
def generateRandomNum(n):
s = ''
valid_s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
for i in range(n):
s += random.choice(valid_s)
return s
# AES-128-CBC 零填充 加解密
class AESCryptor:
def __init__(self, key, iv):
self.key = key.encode('utf-8')
self.iv = iv.encode('utf-8')
def encrypt_string(self, data):
# 编码成字节
data = data.encode('utf-8')
# 填充为16的倍数 采用零填充
while len(data) % 16 != 0:
data += b'\x00'
# 加密 采用CBC模式
my_aes = AES.new(self.key, AES.MODE_CBC, self.iv)
cipher_data = my_aes.encrypt(data)
# 返回base64密文
return base64.b64encode(cipher_data).decode('utf-8')
def decrypt_string(self, data):
# 编码为字节
real_data = base64.b64decode(data)
# 解密
my_aes = AES.new(self.key, AES.MODE_CBC, self.iv)
decrypt_data = my_aes.decrypt(real_data)
# 解密后的数据去除加密前添加的pad,即0
pos = len(decrypt_data)-1
while decrypt_data[pos] == 0:
pos -= 1
decrypt_data = decrypt_data[:pos+1].decode('utf-8')
return decrypt_data
if __name__ == '__main__':
# 随机生成16*8 = 128位的key 和 iv,手动进行前后端同步
# print('aes_key', generateRandomNum(16))
# print('aes_iv', generateRandomNum(16))
# 测试后端加解密
aes = AESCryptor(aes_key, aes_iv)
# 前端传回的加密后的数据
encode_data = 'AA2uUXaD4p/s6HcPbX3CGw=='
msg = aes.decrypt_string(encode_data)
print(msg)
# 输出:123456
print(aes.encrypt_string(msg))
# 输出:AA2uUXaD4p/s6HcPbX3CGw== 与前端加密后的数据相同
参考文献
- 利用POST进行用户登录的安全问题剖析
- 前端AES加密Python后端解密数据
- python实现AES加密解密
到了这里,关于AES对称加密实战——前端js加密后端python解密的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!