DES 加密解密实现之旅
字数 2437 2025-08-30 06:50:11
DES加密解密实现详解
1. 概述
本文详细讲解如何从渗透测试实战中遇到的DES加密案例出发,分析des.js和login.jsp文件,并最终实现DES加密解密功能的全过程。通过本教程,您将深入理解DES加密算法的实现细节,并掌握在Node.js环境中实现与des.js一致的加密解密功能的方法。
2. DES加密算法基础
DES(Data Encryption Standard)是一种对称密钥加密算法,使用56位密钥对64位数据进行加密。主要特点包括:
- 分组密码:每次处理固定长度的数据块(64位)
- 对称算法:加密和解密使用相同密钥
- 16轮Feistel结构:通过多轮迭代增强安全性
3. 文件分析
3.1 des.js文件分析
des.js文件包含完整的DES加密解密实现,主要函数如下:
核心函数
-
strEnc(str, key) - 字符串加密入口
- 将输入字符串加密为十六进制字符串
- 参数:str(明文), key(密钥)
- 返回值:加密后的十六进制字符串
-
strDec(str, key) - 字符串解密入口
- 将十六进制字符串解密为原始字符串
- 参数:str(密文), key(密钥)
- 返回值:解密后的明文字符串
-
enc(dataByte, keyByte) - 核心加密函数
- 实现DES算法的详细加密步骤
- 参数:dataByte(64位二进制数据), keyByte(密钥二进制)
- 返回值:加密后的64位二进制数据
-
dec(dataByte, keyByte) - 核心解密函数
- 实现DES算法的详细解密步骤
- 参数:dataByte(64位二进制数据), keyByte(密钥二进制)
- 返回值:解密后的64位二进制数据
辅助函数
-
getKeyBytes(key) - 密钥处理
- 将密钥字符串转换为二进制数组
- 处理密钥长度,确保符合DES要求
-
strToBt(str) - 数据转换
- 将字符串转换为64位二进制数组
- 处理输入数据的分块(4字节一组)
-
bt64ToHex(byteData) - 数据格式化
- 将64位二进制数据转换为十六进制字符串
-
generateKeys(keyByte) - 子密钥生成
- 生成DES算法16轮迭代所需的子密钥
算法步骤函数
- initPermute(originalData) - 初始置换(IP)
- expandPermute(rightData) - 扩展置换(E盒)
- xor(byteOne, byteTwo) - 异或运算
- sBoxPermute(expandByte) - S盒置换
- pPermute(sBoxByte) - P盒置换
- finallyPermute(endByte) - 最终置换(IP⁻¹)
3.2 login.jsp文件分析
login.jsp文件展示了DES加密在实际登录系统中的应用:
document.getElementById("password").value = strEnc(password, "PCCW");
关键点:
- 用户提交登录表单时,调用
des.js中的strEnc函数对密码进行加密 - 使用固定密钥"PCCW"进行加密
- 加密后的密码与用户名一起提交到服务器验证
4. 加密解密流程详解
4.1 加密流程
-
输入处理:
- 用户输入明文密码
- 调用
strEnc(password, key)函数
-
数据分块:
- 将密码分割成长度为4字节的数据块
- 每个数据块单独处理
-
核心加密:
- 对每个数据块调用
enc函数:
a. 初始置换(IP)
b. 16轮Feistel结构:- 扩展置换(E盒)
- 与子密钥异或
- S盒置换
- P盒置换
- 左右交换
c. 最终置换(IP⁻¹)
- 对每个数据块调用
-
输出格式化:
- 加密后的二进制数据转换为十六进制字符串
- 合并所有块的加密结果
- 输出最终的加密字符串
4.2 解密流程
-
输入处理:
- 输入加密后的十六进制字符串
- 调用
strDec(encryptedStr, key)函数
-
数据转换:
- 将十六进制字符串转换为二进制数据
- 分割为64位的数据块
-
核心解密:
- 对每个数据块调用
dec函数:
a. 初始置换(IP)
b. 16轮Feistel结构(子密钥逆序使用)
c. 最终置换(IP⁻¹)
- 对每个数据块调用
-
输出处理:
- 解密后的二进制数据转换为原始字符串
- 合并所有块的解密结果
- 输出明文字符串
5. 本地实现方案
5.1 直接使用des.js的方案
由于Python实现DES算法与JavaScript版本存在兼容性问题,推荐直接使用原des.js文件:
- 创建index.js:
const des = require('./des.js');
// 加密示例
const encrypted = des.strEnc("password123", "PCCW");
console.log("加密结果:", encrypted);
// 解密示例
const decrypted = des.strDec(encrypted, "PCCW");
console.log("解密结果:", decrypted);
- 运行方法:
node index.js
5.2 Python实现注意事项
虽然不推荐,但若需Python实现,需注意以下关键点:
-
数据转换问题:
- JavaScript的字符串处理与Python不同
- 特别注意二进制数据的表示方式
-
常见错误解决:
TypeError: can only concatenate list (not "bytes") to list- 解决方案:统一使用列表或bytes类型,不要混用
-
边界条件处理:
- 数据分块大小必须一致
- 填充规则需要与JavaScript版本匹配
6. 关键算法细节
6.1 Feistel结构实现
DES算法的核心是16轮Feistel结构,每轮处理如下:
function feistel(right, subKey) {
// 1. 扩展置换(E盒)
const expanded = expandPermute(right);
// 2. 与子密钥异或
const xored = xor(expanded, subKey);
// 3. S盒置换
const sBoxed = sBoxPermute(xored);
// 4. P盒置换
const pBoxed = pPermute(sBoxed);
return pBoxed;
}
6.2 子密钥生成
function generateKeys(keyByte) {
const keys = [];
let temp = [...keyByte];
// 1. PC-1置换
temp = pc1Permute(temp);
// 2. 分割为C0和D0
let left = temp.slice(0, 28);
let right = temp.slice(28);
// 3. 16轮生成子密钥
for (let i = 0; i < 16; i++) {
// 循环左移
left = leftShift(left, shiftTable[i]);
right = leftShift(right, shiftTable[i]);
// PC-2置换生成子密钥
const combined = left.concat(right);
keys.push(pc2Permute(combined));
}
return keys;
}
6.3 S盒置换实现
function sBoxPermute(expandByte) {
const sBoxByte = new Array(32).fill(0);
let binary = "";
for (let i = 0; i < 8; i++) {
// 计算行和列
const row = expandByte[i * 6] * 2 + expandByte[i * 6 + 5];
const col = expandByte[i * 6 + 1] * 8 + expandByte[i * 6 + 2] * 4
+ expandByte[i * 6 + 3] * 2 + expandByte[i * 6 + 4];
// 从S盒中取值
const val = S_BOX[i][row][col];
// 转换为4位二进制
binary += val.toString(2).padStart(4, '0');
}
// 转换为二进制数组
for (let i = 0; i < 32; i++) {
sBoxByte[i] = parseInt(binary[i]);
}
return sBoxByte;
}
7. 实际应用示例
7.1 加密用户密码
// 前端加密处理
function encryptPassword() {
const password = document.getElementById("passwordInput").value;
const encrypted = strEnc(password, "PCCW");
document.getElementById("password").value = encrypted;
return true;
}
7.2 服务端解密验证
// Node.js后端解密示例
app.post('/login', (req, res) => {
const { username, password } = req.body;
// 解密密码
const decrypted = strDec(password, "PCCW");
// 验证用户
User.findOne({ username, password: decrypted }, (err, user) => {
if (err || !user) {
return res.status(401).send("认证失败");
}
res.send("登录成功");
});
});
8. 总结与注意事项
-
算法选择:
- DES已不再安全,建议在实际项目中使用AES等更安全的算法
- 本教程主要用于学习目的
-
实现要点:
- 确保所有置换表与标准DES一致
- 特别注意数据分块和填充规则
- 密钥管理要安全,避免硬编码
-
兼容性问题:
- 不同语言实现的DES可能存在细微差异
- 跨平台使用时需严格测试
-
安全建议:
- 结合HTTPS使用
- 考虑添加盐值(salt)增强安全性
- 定期更换加密密钥
通过本教程,您应该已经掌握了DES算法的实现原理和实际应用方法,能够在不同环境中实现DES加密解密功能。