DES 加密解密实现之旅
字数 2437 2025-08-30 06:50:11

DES加密解密实现详解

1. 概述

本文详细讲解如何从渗透测试实战中遇到的DES加密案例出发,分析des.jslogin.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加密解密实现,主要函数如下:

核心函数

  1. strEnc(str, key) - 字符串加密入口

    • 将输入字符串加密为十六进制字符串
    • 参数:str(明文), key(密钥)
    • 返回值:加密后的十六进制字符串
  2. strDec(str, key) - 字符串解密入口

    • 将十六进制字符串解密为原始字符串
    • 参数:str(密文), key(密钥)
    • 返回值:解密后的明文字符串
  3. enc(dataByte, keyByte) - 核心加密函数

    • 实现DES算法的详细加密步骤
    • 参数:dataByte(64位二进制数据), keyByte(密钥二进制)
    • 返回值:加密后的64位二进制数据
  4. dec(dataByte, keyByte) - 核心解密函数

    • 实现DES算法的详细解密步骤
    • 参数:dataByte(64位二进制数据), keyByte(密钥二进制)
    • 返回值:解密后的64位二进制数据

辅助函数

  1. getKeyBytes(key) - 密钥处理

    • 将密钥字符串转换为二进制数组
    • 处理密钥长度,确保符合DES要求
  2. strToBt(str) - 数据转换

    • 将字符串转换为64位二进制数组
    • 处理输入数据的分块(4字节一组)
  3. bt64ToHex(byteData) - 数据格式化

    • 将64位二进制数据转换为十六进制字符串
  4. generateKeys(keyByte) - 子密钥生成

    • 生成DES算法16轮迭代所需的子密钥

算法步骤函数

  1. initPermute(originalData) - 初始置换(IP)
  2. expandPermute(rightData) - 扩展置换(E盒)
  3. xor(byteOne, byteTwo) - 异或运算
  4. sBoxPermute(expandByte) - S盒置换
  5. pPermute(sBoxByte) - P盒置换
  6. finallyPermute(endByte) - 最终置换(IP⁻¹)

3.2 login.jsp文件分析

login.jsp文件展示了DES加密在实际登录系统中的应用:

document.getElementById("password").value = strEnc(password, "PCCW");

关键点:

  • 用户提交登录表单时,调用des.js中的strEnc函数对密码进行加密
  • 使用固定密钥"PCCW"进行加密
  • 加密后的密码与用户名一起提交到服务器验证

4. 加密解密流程详解

4.1 加密流程

  1. 输入处理

    • 用户输入明文密码
    • 调用strEnc(password, key)函数
  2. 数据分块

    • 将密码分割成长度为4字节的数据块
    • 每个数据块单独处理
  3. 核心加密

    • 对每个数据块调用enc函数:
      a. 初始置换(IP)
      b. 16轮Feistel结构:
      • 扩展置换(E盒)
      • 与子密钥异或
      • S盒置换
      • P盒置换
      • 左右交换
        c. 最终置换(IP⁻¹)
  4. 输出格式化

    • 加密后的二进制数据转换为十六进制字符串
    • 合并所有块的加密结果
    • 输出最终的加密字符串

4.2 解密流程

  1. 输入处理

    • 输入加密后的十六进制字符串
    • 调用strDec(encryptedStr, key)函数
  2. 数据转换

    • 将十六进制字符串转换为二进制数据
    • 分割为64位的数据块
  3. 核心解密

    • 对每个数据块调用dec函数:
      a. 初始置换(IP)
      b. 16轮Feistel结构(子密钥逆序使用)
      c. 最终置换(IP⁻¹)
  4. 输出处理

    • 解密后的二进制数据转换为原始字符串
    • 合并所有块的解密结果
    • 输出明文字符串

5. 本地实现方案

5.1 直接使用des.js的方案

由于Python实现DES算法与JavaScript版本存在兼容性问题,推荐直接使用原des.js文件:

  1. 创建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);
  1. 运行方法
node index.js

5.2 Python实现注意事项

虽然不推荐,但若需Python实现,需注意以下关键点:

  1. 数据转换问题

    • JavaScript的字符串处理与Python不同
    • 特别注意二进制数据的表示方式
  2. 常见错误解决

    • TypeError: can only concatenate list (not "bytes") to list
    • 解决方案:统一使用列表或bytes类型,不要混用
  3. 边界条件处理

    • 数据分块大小必须一致
    • 填充规则需要与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. 总结与注意事项

  1. 算法选择

    • DES已不再安全,建议在实际项目中使用AES等更安全的算法
    • 本教程主要用于学习目的
  2. 实现要点

    • 确保所有置换表与标准DES一致
    • 特别注意数据分块和填充规则
    • 密钥管理要安全,避免硬编码
  3. 兼容性问题

    • 不同语言实现的DES可能存在细微差异
    • 跨平台使用时需严格测试
  4. 安全建议

    • 结合HTTPS使用
    • 考虑添加盐值(salt)增强安全性
    • 定期更换加密密钥

通过本教程,您应该已经掌握了DES算法的实现原理和实际应用方法,能够在不同环境中实现DES加密解密功能。

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加密在实际登录系统中的应用: 关键点: 用户提交登录表单时,调用 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 : 运行方法 : 5.2 Python实现注意事项 虽然不推荐,但若需Python实现,需注意以下关键点: 数据转换问题 : JavaScript的字符串处理与Python不同 特别注意二进制数据的表示方式 常见错误解决 : TypeError: can only concatenate list (not "bytes") to list 解决方案:统一使用列表或bytes类型,不要混用 边界条件处理 : 数据分块大小必须一致 填充规则需要与JavaScript版本匹配 6. 关键算法细节 6.1 Feistel结构实现 DES算法的核心是16轮Feistel结构,每轮处理如下: 6.2 子密钥生成 6.3 S盒置换实现 7. 实际应用示例 7.1 加密用户密码 7.2 服务端解密验证 8. 总结与注意事项 算法选择 : DES已不再安全,建议在实际项目中使用AES等更安全的算法 本教程主要用于学习目的 实现要点 : 确保所有置换表与标准DES一致 特别注意数据分块和填充规则 密钥管理要安全,避免硬编码 兼容性问题 : 不同语言实现的DES可能存在细微差异 跨平台使用时需严格测试 安全建议 : 结合HTTPS使用 考虑添加盐值(salt)增强安全性 定期更换加密密钥 通过本教程,您应该已经掌握了DES算法的实现原理和实际应用方法,能够在不同环境中实现DES加密解密功能。