对称加密算法是一种加密技术,其核心特点是加密和解密使用相同的密钥,即发送方用密钥加密明文,接收方用相同密钥解密密文。这类算法速度快、效率高,适合加密大量数据。
常见的对称加密算法有:
-
DES(Data Encryption Standard),翻译为中文称为
数据加密标准。 -
3DES(Triple DES):对数据执行3次DES加密,相对于 DES 更加安全。
-
AES(Advanced Encryption Standard):翻译为中文为
高级加密标准,是 DES 的替代算法。
我们主要讲解 DES 和 AES 加密算法。
4.1 DES
4.1.1 DES 实现
- js 实现
js
// 引用 crypto-js 加密模块
var CryptoJS = require('crypto-js');
// 创建 DES 对象
var DES = {
// 加密方法
encrypt: function (data, key, iv) {
// 转为 UTF-8 格式的 WordArray 对象供 DES 算法使用
var key = CryptoJS.enc.Utf8.parse(key),
iv = CryptoJS.enc.Utf8.parse(iv),
srcs = CryptoJS.enc.Utf8.parse(data),
// 使用 DES 加密
encrypted = CryptoJS.DES.encrypt(srcs, key, {
iv: iv,
// CBC 加密模式,需添加初始向量(IV)增强安全性
mode: CryptoJS.mode.CBC,
// Pkcs7 填充方式,自动补足数据块至 8 字节倍数
padding: CryptoJS.pad.Pkcs7
});
// 输出为 Base64 编码的密文字符串
return encrypted.toString();
},
// 解密方法
decrypt: function (data, key, iv) {
var key = CryptoJS.enc.Utf8.parse(key),
iv = CryptoJS.enc.Utf8.parse(iv),
decrypted = CryptoJS.DES.decrypt(data, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// 转换为明文字符串
return decrypted.toString(CryptoJS.enc.Utf8);
},
}
// 密钥
var desKey = "12345678";
// 初始向量
var desIv = "12345678";
// 明文内容
var text = "123456";
// 加密
var encryptedData = DES.encrypt(text, desKey, desIv);
console.log("加密字符串: ", encryptedData);
// 解密
var decryptedData = DES.decrypt(encryptedData, desKey, desIv);
console.log("解密字符串: ", decryptedData);
- python 实现
python 想要实现 DES 加密算法,需要安装第三方库:pip install pycryptodome
python
# 提供 DES 加密算法
from Crypto.Cipher import DES
# 提供 PKCS#7 填充
from Crypto.Util.Padding import pad, unpad
import base64
class DESCrypto:
def __init__(self, key, iv):
# 接收字节密钥和IV,自动转换为bytes格式
self.key = key if isinstance(key, bytes) else key.encode('utf-8')
self.iv = iv if isinstance(iv, bytes) else iv.encode('utf-8')
def encrypt(self, plaintext):
"""加密明文并返回Base64编码结果"""
# 创建 DES 对象,使用 CBC 模式
cipher = DES.new(self.key, DES.MODE_CBC, self.iv)
# 对明文的处理,使用 PKCS#7 方式填充,确保数据长度是 8 字节的倍数
padded_data = pad(plaintext.encode('utf-8'), DES.block_size)
# 加密
encrypted = cipher.encrypt(padded_data)
# 返回 Base64 字符串
return base64.b64encode(encrypted).decode('utf-8')
def decrypt(self, ciphertext):
"""解密Base64编码的密文"""
# 创建 DES 对象,使用 CBC 模式
cipher = DES.new(self.key, DES.MODE_CBC, self.iv)
# 对明文使用 Base64 解码
encrypted_data = base64.b64decode(ciphertext)
# 解密
decrypted = cipher.decrypt(encrypted_data)
# 移除 PKCS#7 填充并解码为字符串
return unpad(decrypted, DES.block_size).decode('utf-8')
if __name__ == '__main__':
des = DESCrypto("12345678", "12345678")
print(des.encrypt('123456'))
print(des.decrypt('HUX+7VtHgb0='))
不论是 JavaScript 代码实现,还是 python 代码实现,我们都可以看到几个关键词:key(密钥)、iv(初始化向量)、加密模式、填充模式,这些是DES和AES加密中都存在的核心要素,也是对称加密算法的主要特点。
4.1.2 DES 特点
1)iv
当我们使用 CBC 模式实现加密的时候,需要提供一个初始化向量 iv,iv 必须是 8 字节。iv的核心作用是增强加密安全性,避免相同明文和密钥加密出相同密文,具体需结合加密模式理解。
2)加密模式
DES常用两种加密模式,分别是 ECB 和 CBC:
ECB:全称 Electronic Codebook(电子密码本模式),每个数据块独立加密解密,无需iv,实现简单但安全性极低,仅适用于非敏感数据临时加密。
CBC:全称 Cipher Block Chaining(密文分组链接模式),核心是明文分组与前一个密文分组(或iv)异或后再加密,安全性远高于ECB,是主流使用模式。
3)填充模式
DES要求明文按8字节分组,若明文长度不是8字节整数倍,需通过填充补足。常用PKCS#7填充模式,规则为:不足部分填充"需要补充的字节数"。
4)其他特点
- 密文可表现为十六进制或base64格式,日常开发中base64格式更常用;2. 核心关键字:des、key、iv、CBC、ECB、encrypt、decrypt。
4.1.3 案例 - 长安
1)需求:网址https://bqcm0.cavip1.com/,接口https://bqcm0.cavip1.com/wps/session/login,逆向表单参数(整体为密文,无法直接全局搜索定位)。
2)逆向步骤:
① 调用堆栈调试:从调用堆栈中找到login函数(推测为登录相关),打上断点后重新运行程序,可成功断住。
② 查看数据:断点处a的值为明文参数{username: 'z13800138000', password: '123456', captcha: '6'},i的值为密钥相关参数。
③ 分析加密函数:进入utils.desEncrypt函数,可见其使用CryptoJS实现DES加密,且为ECB模式、Pkcs7填充,确认该接口表单参数采用DES-ECB加密。
js
desEncrypt: function(e, t) {
var n = CryptoJS.enc.Utf8.parse(t);
return CryptoJS.DES.encrypt(e, n, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}).toString()
},
4.2 AES
4.2.1 AES 特点
AES是DES的替代算法,安全性更高,实现原理和代码与DES类似,核心区别在于密钥和iv长度:
-
密钥长度可选:128位(16字节)、192位(24字节)、256位(32字节);
-
iv固定为128位(16字节)。
4.2.2 AES 实现
- js 实现
js
// 引用 crypto-js 加密模块
var CryptoJS = require('crypto-js');
var AES = {
encrypt: function (data, key, iv) {
// 转为 UTF-8 格式的 WordArray 对象供 AES 算法使用
var key = CryptoJS.enc.Utf8.parse(key),
iv = CryptoJS.enc.Utf8.parse(iv),
srcs = CryptoJS.enc.Utf8.parse(data),
// 使用 AES 加密
encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
// CBC 加密模式,需添加初始向量(IV)增强安全性
mode: CryptoJS.mode.CBC,
// Pkcs7 填充方式,自动补足数据块至 8 字节倍数
padding: CryptoJS.pad.Pkcs7
});
// 输出为 Base64 编码的密文字符串
return encrypted.toString();
},
decrypt: function (data, key, iv) {
var key = CryptoJS.enc.Utf8.parse(key),
iv = CryptoJS.enc.Utf8.parse(iv),
decrypted = CryptoJS.AES.decrypt(data, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// 转换为明文字符串
return decrypted.toString(CryptoJS.enc.Utf8);
},
}
// 密钥
var aesKey = "0123456789abcdef";
// 初始向量
var aesIv = "0123456789abcdef";
// 明文内容
var text = "123456";
// 加密
var encryptedData = AES.encrypt(text, aesKey, aesIv);
console.log("加密字符串: ", encryptedData);
// 解密
var decryptedData = AES.decrypt(encryptedData, aesKey, aesIv);
console.log("解密字符串: ", decryptedData);
- python 实现
python
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64
class AESCrypto:
def __init__(self, key, iv):
# 接收字节密钥和IV,自动转换为bytes格式
self.key = key if isinstance(key, bytes) else key.encode('utf-8')
self.iv = iv if isinstance(iv, bytes) else iv.encode('utf-8')
def encrypt(self, plaintext):
"""加密明文并返回Base64编码结果"""
# 创建 AES 对象,使用 CBC 模式
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
# 对明文的处理,使用 PKCS#7 方式填充,确保数据长度是 8 字节的倍数
padded_data = pad(plaintext.encode('utf-8'), AES.block_size)
# 加密
encrypted = cipher.encrypt(padded_data)
# 返回 Base64 字符串
return base64.b64encode(encrypted).decode('utf-8')
def decrypt(self, ciphertext):
"""解密Base64编码的密文"""
# 创建 AES 对象,使用 CBC 模式
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
# 对明文使用 Base64 解码
encrypted_data = base64.b64decode(ciphertext)
# 解密
decrypted = cipher.decrypt(encrypted_data)
# 移除 PKCS#7 填充并解码为字符串
return unpad(decrypted, AES.block_size).decode('utf-8')
if __name__ == '__main__':
aes = AESCrypto("0123456789abcdef", "0123456789abcdef")
print(aes.encrypt('123456'))
print(aes.decrypt('AL5riQzgwmMhXZX+5MtU0A=='))
4.2.3 案例 - 学习通
2)逆向步骤:
① 定位加密位置:全局搜索'password':,快速找到password参数的加密位置。
② 分析加密函数:查看encryptByAES函数,可见其使用CryptoJS实现AES加密,采用CBC模式、Pkcs7填充,密钥与iv相同,确认password参数采用AES-CBC加密。
js
function encryptByAES(message, key) {
let CBCOptions = {
iv: CryptoJS.enc.Utf8.parse(key),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
};
let aeskey = CryptoJS.enc.Utf8.parse(key);
let secretData = CryptoJS.enc.Utf8.parse(message);
let encrypted = CryptoJS.AES.encrypt(
secretData,
aeskey,
CBCOptions
);
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}
5 非对称算法 - RSA
非对称加密,使用 一对密钥(公钥和私钥)进行加密和解密。与对称加密不同,非对称加密的加密和解密使用不同的密钥,解决了密钥分发问题,但计算速度较慢,所以一般不会用非对称加密算法对大量数据进行加密。
5.1 RSA 特点
-
长度:rsa 的密文与密钥的长度有关,密钥长度越长,密文长度越长;密钥长度可选择1024位、2048位和4096位。
-
内容:对相同的明文加密,密文都会不同。
-
关键字:key、new RSA、setPublic、encrypt、decrypt。
5.2 RSA 实现
- js 实现(需安装node-jsencrypt库:
npm install node-jsencrypt)
js
const fs = require('fs');
const JSEncrypt = require('node-jsencrypt');
var RSA = {
encrypt: function (data, key) {
// 创建 JSEncrypt 对象
const encryptor = new JSEncrypt();
// 设置公钥
encryptor.setPublicKey(key);
// 加密数据
return encryptor.encrypt(data);
},
decrypt: function (data, key) {
// 创建 JSEncrypt 对象
const decryptor = new JSEncrypt();
// 设置私钥
decryptor.setPrivateKey(key);
// 解密数据
return decryptor.decrypt(data);
}
}
// 加密
const publicKey = fs.readFileSync('public_key.pem', 'utf8');
var encryptedData = RSA.encrypt("123456", publicKey);
console.log(encryptedData);
// 解密
const privateKey = fs.readFileSync('private_key.pem', 'utf8');
var decryptedData = RSA.decrypt(encryptedData, privateKey);
console.log(decryptedData);
- python 实现(需安装rsa库:
pip install rsa)
python
import rsa
import base64
class RSA:
def __init__(self, publicKey, private_key):
self.publicKey = publicKey
self.private_key = private_key
def encrypt(self, t):
"""公钥加密"""
encrypted = rsa.encrypt(t.encode("utf-8"), self.publicKey)
return base64.b64encode(encrypted).decode("utf-8")
def decrypt(self, t):
"""私钥解密"""
return rsa.decrypt(base64.b64decode(t), self.private_key).decode("utf-8")
if __name__ == "__main__":
# 生成公钥、私钥
public_key, private_key = rsa.newkeys(512)
print('公钥:', public_key)
print('私钥:', private_key)
# 创建 rsa 对象
rsa_ = RSA(public_key, private_key)
# 待加密字符串
text = '123456'
encrypted_str = rsa_.encrypt(text)
print('加密字符串:', encrypted_str)
decrypted_str = rsa_.decrypt(encrypted_str)
print('解密字符串:', decrypted_str)
5.3 案例 - 新华保险
1)需求:网址https://tms.newchinalife.com/ex//app/login/login.jsp,接口https://tms.newchinalife.com/ex/j_spring_security_check,逆向j_password参数(密文示例:n4NUSQ479nvK9xjCq5W2MesLXPWfJ/mGdTENn8ptJr666++5C0w5pO1forQOTXOkFdwC1/TdoxQLJXhwGGDZwQg331AIPrjdLJZjTjiWjKVTRUKua8eOIVX4u2421PSjNbXILrALrRxhwKE4LjLwt8VCeFXF2yGA8lMOXOKPNNelbZOUo/eSNSBdIAHEqWZxBQiWCX6s7FAp5T5DH0a/yd+LtgbfRCaprKvH3G7oreW8HzJKJkp3cKrF2o9ntgaws2UJlF+3rTapAa5f8Jo4KJmDHXYH7bY2fSKvjSBZxv26/ZZaPEM4llrCcm3y6+/Kuks+EElCIYf1Sjtg8HQr1A==)。
2)逆向步骤:
① 定位加密位置:全局搜索j_password,结果较少且可找到相关数据,直接定位到加密位置。
② 断点验证:重新发送请求,断点成功断住,查看j_pwd参数为密码明文,推测此处为加密入口。
③ 分析加密函数:进入rasClient.encrypt函数,可见RSAClient对象调用setPublicKey方法,公钥值为PUBLICKEY,确认j_password参数采用RSA加密。
以上就是对称加密(DES、AES)和非对称加密(RSA)的核心内容,包含实现代码、核心特点和真实逆向案例,覆盖日常开发和逆向实操的核心需求,可直接对照代码和案例上手练习。
关注我,解锁更多加密算法、逆向实战技巧!