> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# DES / 3DES
- URL: https://blog.vercanti.com/des-3des/
- Published: 2026-08-28T14:35:03.000Z
- Updated: 2026-08-28T14:57:56.000Z
- Description: DES（Data Encryption Standard）和 3DES（Triple DES）是比 AES 更老的对称加密算法。目前在新系统中已基本被 AES 取代，但在一些老接口逆向中仍会遇到。 搜索关键字：CryptoJS.DES、CryptoJS.TripleDES、des-cbc、TripleDES、3DES 特征：块大小为 8 字节（填充后密文长度是 8 的倍数）；密钥长度为 8 / 16 / 24 字节。 块大小是关键区分指标：DES/3DES 块大小为 8 字节，AES 为 16 字节。若解密后密文长度是 8 的倍数而非 16，优先怀疑 D
- Author: yellowdog
- Tags: js逆向, 加密算法

> 官方文档：<https://csrc.nist.gov/publications/detail/sp/800/67/rev2/final>  
> 适用场景：JS 逆向中识别和还原老接口中的 DES/3DES 加密参数

DES（Data Encryption Standard）和 3DES（Triple DES）是比 AES 更老的对称加密算法。目前在新系统中已基本被 AES 取代，但在一些老接口逆向中仍会遇到。

---

## 对比

| 算法   | 密钥长度                    | 块大小   | 安全性    |
| ---- | ----------------------- | ----- | ------ |
| DES  | 64 位（有效 56 位，8 字节）      | 8 字节  | 已不安全   |
| 3DES | 128 / 192 位（16 / 24 字节） | 8 字节  | 较弱，不推荐 |
| AES  | 128 / 192 / 256 位       | 16 字节 | 安全，推荐  |

---

## Python 实现

```python
from Crypto.Cipher import DES, DES3
from Crypto.Util.Padding import pad, unpad
import base64

# ── DES ──────────────────────────────────────────────────────

def des_cbc_encrypt(plaintext: str, key: str, iv: str) -> str:
    """DES-CBC 加密，key 和 iv 均为 8 字节"""
    key_b  = key.encode('utf-8')  # 必须是 8 字节
    iv_b   = iv.encode('utf-8')   # 必须是 8 字节
    cipher = DES.new(key_b, DES.MODE_CBC, iv_b)
    return base64.b64encode(cipher.encrypt(pad(plaintext.encode(), DES.block_size))).decode()

def des_cbc_decrypt(ciphertext_b64: str, key: str, iv: str) -> str:
    key_b  = key.encode('utf-8')
    iv_b   = iv.encode('utf-8')
    data   = base64.b64decode(ciphertext_b64)
    cipher = DES.new(key_b, DES.MODE_CBC, iv_b)
    return unpad(cipher.decrypt(data), DES.block_size).decode('utf-8')

def des_ecb_encrypt(plaintext: str, key: str) -> str:
    key_b  = key.encode('utf-8')
    cipher = DES.new(key_b, DES.MODE_ECB)
    return base64.b64encode(cipher.encrypt(pad(plaintext.encode(), DES.block_size))).decode()

def des_ecb_decrypt(ciphertext_b64: str, key: str) -> str:
    key_b  = key.encode('utf-8')
    cipher = DES.new(key_b, DES.MODE_ECB)
    return unpad(cipher.decrypt(base64.b64decode(ciphertext_b64)), DES.block_size).decode()

# ── 3DES ─────────────────────────────────────────────────────

def des3_cbc_encrypt(plaintext: str, key: str, iv: str) -> str:
    """3DES-CBC 加密，key 为 16 或 24 字节，iv 为 8 字节"""
    key_b  = key.encode('utf-8')  # 16 或 24 字节
    iv_b   = iv.encode('utf-8')   # 8 字节
    cipher = DES3.new(key_b, DES3.MODE_CBC, iv_b)
    return base64.b64encode(cipher.encrypt(pad(plaintext.encode(), DES3.block_size))).decode()

def des3_cbc_decrypt(ciphertext_b64: str, key: str, iv: str) -> str:
    key_b  = key.encode('utf-8')
    iv_b   = iv.encode('utf-8')
    data   = base64.b64decode(ciphertext_b64)
    cipher = DES3.new(key_b, DES3.MODE_CBC, iv_b)
    return unpad(cipher.decrypt(data), DES3.block_size).decode('utf-8')

def des3_ecb_encrypt(plaintext: str, key: str) -> str:
    key_b  = key.encode('utf-8')
    cipher = DES3.new(key_b, DES3.MODE_ECB)
    return base64.b64encode(cipher.encrypt(pad(plaintext.encode(), DES3.block_size))).decode()

# 使用示例
key8  = '12345678'          # 8 字节 DES key
iv8   = '87654321'          # 8 字节 IV
key24 = '123456789012345678901234'  # 24 字节 3DES key

ct  = des_cbc_encrypt('hello world', key8, iv8)
pt  = des_cbc_decrypt(ct, key8, iv8)
ct3 = des3_cbc_encrypt('hello world', key24, iv8)
pt3 = des3_cbc_decrypt(ct3, key24, iv8)

```

---

## JavaScript 实现

### 使用 CryptoJS

```javascript
const CryptoJS = require('crypto-js');

// ── DES-CBC ──────────────────────────────────────────────────

function desEncrypt(plaintext, key, iv) {
    const keyWA = CryptoJS.enc.Utf8.parse(key);  // 8 字节
    const ivWA  = CryptoJS.enc.Utf8.parse(iv);   // 8 字节
    return CryptoJS.DES.encrypt(plaintext, keyWA, {
        iv:      ivWA,
        mode:    CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }).toString();
}

function desDecrypt(ciphertext, key, iv) {
    const keyWA = CryptoJS.enc.Utf8.parse(key);
    const ivWA  = CryptoJS.enc.Utf8.parse(iv);
    return CryptoJS.DES.decrypt(ciphertext, keyWA, {
        iv:      ivWA,
        mode:    CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }).toString(CryptoJS.enc.Utf8);
}

// ── DES-ECB ──────────────────────────────────────────────────

function desEcbEncrypt(plaintext, key) {
    const keyWA = CryptoJS.enc.Utf8.parse(key);
    return CryptoJS.DES.encrypt(plaintext, keyWA, {
        mode:    CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    }).toString();
}

// ── 3DES-CBC ─────────────────────────────────────────────────

function tripleDesEncrypt(plaintext, key, iv) {
    const keyWA = CryptoJS.enc.Utf8.parse(key);  // 16 或 24 字节
    const ivWA  = CryptoJS.enc.Utf8.parse(iv);   // 8 字节
    return CryptoJS.TripleDES.encrypt(plaintext, keyWA, {
        iv:      ivWA,
        mode:    CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }).toString();
}

function tripleDesDecrypt(ciphertext, key, iv) {
    const keyWA = CryptoJS.enc.Utf8.parse(key);
    const ivWA  = CryptoJS.enc.Utf8.parse(iv);
    return CryptoJS.TripleDES.decrypt(ciphertext, keyWA, {
        iv:      ivWA,
        mode:    CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }).toString(CryptoJS.enc.Utf8);
}

// 使用示例
const key8  = '12345678';
const iv8   = '87654321';
const key16 = '1234567890abcdef';

console.log(desEncrypt('hello', key8, iv8));
console.log(tripleDesEncrypt('hello', key16, iv8));

```

### 使用 Node.js 内置 crypto

```javascript
const crypto = require('crypto');

function desEncrypt(plaintext, key, iv) {
    const cipher  = crypto.createCipheriv('des-cbc',
        Buffer.from(key, 'utf8'),
        Buffer.from(iv,  'utf8')
    );
    return cipher.update(plaintext, 'utf8', 'base64') + cipher.final('base64');
}

function des3Encrypt(plaintext, key, iv) {
    // Node.js 中 3DES 算法名：des-ede3-cbc（24字节key）或 des-ede-cbc（16字节key）
    const algo   = key.length === 24 ? 'des-ede3-cbc' : 'des-ede-cbc';
    const cipher = crypto.createCipheriv(algo,
        Buffer.from(key, 'utf8'),
        Buffer.from(iv,  'utf8')
    );
    return cipher.update(plaintext, 'utf8', 'base64') + cipher.final('base64');
}

// Node.js 支持的 DES 算法名
// des-cbc       : DES CBC
// des-ecb       : DES ECB
// des-ede3-cbc  : 3DES CBC（24字节key）
// des-ede-cbc   : 3DES CBC（16字节key，k1=k3）

```

---

## 识别特征

搜索关键字：`CryptoJS.DES`、`CryptoJS.TripleDES`、`des-cbc`、`TripleDES`、`3DES`  
特征：块大小为 8 字节（填充后密文长度是 8 的倍数）；密钥长度为 8 / 16 / 24 字节。

---

## 最佳实践

**块大小是关键区分指标**：DES/3DES 块大小为 8 字节，AES 为 16 字节。若解密后密文长度是 8 的倍数而非 16，优先怀疑 DES/3DES；再配合密钥长度（8/16/24 字节）确认。

**3DES 的三种密钥模式**：3DES 密钥长度决定安全强度：24 字节（3 个独立密钥）= 最安全；16 字节（K1=K3）= 最常用；8 字节（K1=K2=K3）= 退化为 DES。逆向时要准确提取密钥长度。

**Python 还原用 `pycryptodome` 而非 `pyDes`**：`pyDes` 库老旧且速度慢，推荐 `from Crypto.Cipher import DES, DES3`，API 与 AES 一致，迁移成本低。

```python
from Crypto.Cipher import DES3
from Crypto.Util.Padding import unpad

cipher = DES3.new(key, DES3.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext), DES3.block_size)

```

**JS 侧的 `CryptoJS.DES` 默认 CBC + PKCS7**：还原时先假设 CBC 模式，若结果不对再尝试 ECB（无 IV）。

**3DES EDE 与 EEE 模式**：JS 逆向中几乎全是 EDE（加-解-加）模式；EEE（加-加-加）极少见，若 EDE 不对可尝试 EEE。

---

## 常见陷阱

### 陷阱：3DES 密钥长度判断错误

**现象：** 用提取的 24 字节密钥解密失败，改为 16 字节正常。  
**原因：** 代码中密钥字符串长度为 24 字符，但每个字符是十六进制（2 字符 = 1 字节），实际 12 字节；或密钥是 Base64 编码，需先解码。  
**解决：** 确认密钥的编码格式（原始字节 / Hex / Base64）后再计算实际长度；`key.length` 是字符数不是字节数。

### 陷阱：ECB 和 CBC 模式混淆

**现象：** 提取了 IV 用 CBC 解密失败；去掉 IV 用 ECB 也不对。  
**原因：** 部分实现虽然代码里写了 `MODE_CBC` 但 IV 全为零字节（`\x00` \* 8），与不用 IV 的 ECB 行为不同。  
**解决：** 检查 JS 中 IV 的实际值；若 IV 是空字符串或空 WordArray，CryptoJS 可能默认使用全零 IV，Python 侧对应 `iv = b'\x00' * 8`。

### 陷阱：DES 密钥奇偶校验位被修改

**现象：** 复制了 8 字节密钥但解密失败，用其他工具解密正常。  
**原因：** DES 规范要求密钥每字节最低位为奇偶校验位，部分实现会自动调整这些位，导致实际密钥与提取值有细微差异。  
**解决：** `pycryptodome` 默认忽略校验位；若使用 `pyDes`，需注意其是否校验密钥合法性。

---

## 参见

[魔法数字速查](https://blog.vercanti.com/jia-mi-suan-fa-mo-fa-shu-zi-su-cha/)  
[Base64与编码](https://blog.vercanti.com/base64-yu-bian-ma/)  
[代码片段大全](https://blog.vercanti.com/js-ni-xiang-hook-yu-dai-ma-pian-duan-da-quan/)