> ## 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.

# 加密算法基础概念
- URL: https://blog.vercanti.com/jia-mi-suan-fa-ji-chu-gai-nian/
- Published: 2026-08-28T14:35:06.000Z
- Updated: 2026-08-28T14:58:03.000Z
- Description: 对称加密中用于加密和解密的秘密字符串。密钥长度决定安全强度。 用于对称加密中引入随机性。每次加密使用不同的 IV，即使明文和密钥相同，密文也不同。 分组密码要求明文长度必须是块大小的整数倍（AES 块大小为 16 字节）。填充用于将不足的部分补齐。 决定分组密码如何处理连续的数据块。 加密后的二进制数据通常需要编码为字符串传输： 逆向中常见的数据类型转换： Python 中：str.encode('utf-8') → bytes JavaScript 中：new TextEncoder().encode(str) → Uint8Array 逆向前先判断算
- Author: yellowdog
- Tags: js逆向, 加密算法

> 官方文档：<https://csrc.nist.gov/publications/fips>  
> 适用场景：JS 逆向前的算法识别基础，理解对称/非对称/哈希的核心差异

---

## 算法分类

```
加密算法
├── 哈希算法（单向，不可逆）
│   ├── MD5
│   ├── SHA-1 / SHA-224 / SHA-256 / SHA-384 / SHA-512
│   └── HMAC（带密钥的哈希）
│
├── 对称加密（加解密用同一密钥）
│   ├── AES（Advanced Encryption Standard）
│   ├── DES / 3DES（已不推荐）
│   └── RC4（流密码，已不推荐）
│
├── 非对称加密（公钥加密，私钥解密）
│   └── RSA
│
└── 编码（非加密，可逆）
    ├── Base64
    └── URL Encode

```

---

## 核心概念

### 密钥（Key）

对称加密中用于加密和解密的秘密字符串。密钥长度决定安全强度。

| 算法   | 常见密钥长度                             |
| ---- | ---------------------------------- |
| AES  | 128 / 192 / 256 位（16 / 24 / 32 字节） |
| DES  | 64 位（8 字节，实际有效 56 位）               |
| 3DES | 128 / 192 位                        |

### 初始化向量（IV，Initialization Vector）

用于对称加密中引入随机性。每次加密使用不同的 IV，即使明文和密钥相同，密文也不同。

- **CBC 模式必须有 IV**，长度通常与块大小相同（AES 为 16 字节）
- ECB 模式不使用 IV（因此不安全，相同明文 → 相同密文）
- IV 通常随密文一起传输（拼接在密文头部或作为单独字段）

### 填充（Padding）

分组密码要求明文长度必须是块大小的整数倍（AES 块大小为 16 字节）。填充用于将不足的部分补齐。

| 填充方式            | 说明               | 示例（块大小16，数据13字节，需填3字节） |
| --------------- | ---------------- | ---------------------- |
| PKCS#5 / PKCS#7 | 填充值等于填充字节数       | \\x03\\x03\\x03        |
| ZeroPadding     | 填充 \\x00         | \\x00\\x00\\x00        |
| NoPadding       | 不填充（明文必须恰好对齐）    | —                      |
| ISO 10126       | 随机字节 + 最后一字节为填充数 | \\xXX\\xXX\\x03        |

> PKCS#7 是最常见的填充方式，CryptoJS 默认使用 PKCS#7。

### 加密模式（Mode）

决定分组密码如何处理连续的数据块。

| 模式  | 全称                    | 需要 IV    | 特点                  |
| --- | --------------------- | -------- | ------------------- |
| ECB | Electronic Codebook   | 否        | 最简单，不安全（相同块 → 相同密文） |
| CBC | Cipher Block Chaining | 是        | 最常用，前一块密文作为下一块输入    |
| CFB | Cipher Feedback       | 是        | 流模式，可处理任意长度数据       |
| OFB | Output Feedback       | 是        | 流模式，错误不传播           |
| CTR | Counter               | 是（Nonce） | 流模式，可并行，现代推荐        |
| GCM | Galois/Counter Mode   | 是        | CTR + 认证标签，AEAD 模式  |

### 编码格式

加密后的二进制数据通常需要编码为字符串传输：

| 格式        | 说明                           | 示例         |
| --------- | ---------------------------- | ---------- |
| Hex       | 十六进制字符串                      | 48656c6c6f |
| Base64    | 64字符编码                       | SGVsbG8=   |
| Base64URL | URL安全的Base64（+→\-, /→\_，无\=） | SGVsbG8    |

---

## 字节与字符串

逆向中常见的数据类型转换：

```
字符串  →  字节数组  →  加密运算  →  字节数组  →  Hex/Base64 字符串
"hello" →  [72,101,...] →  AES/MD5  →  [...]   →  "48656c..."

```

Python 中：`str.encode('utf-8')` → `bytes`  
JavaScript 中：`new TextEncoder().encode(str)` → `Uint8Array`

---

## 最佳实践

**逆向前先判断算法类别**：看密文长度和格式——固定长度 32/40/64 字符十六进制 = 哈希（MD5/SHA-1/SHA-256）；变长且带 `=` 结尾 = 对称加密 Base64 输出；超长字符串（256\~512 字符）= RSA。快速分类后再定位具体算法。

**哈希类算法不需要密钥，对称类必须找密钥**：理清这一点后可以针对性搜索——哈希直接搜函数名，对称加密（AES/DES）需要同时找密钥和 IV，非对称（RSA）需要找公钥。

**编码和加密要分开处理**：先解码（Base64/Hex/URL 解码）再解密；加密时先加密再编码。混淆后的代码常将编码层和加密层嵌套，逐层剥离比整体还原更高效。

**数据类型转换是逆向的核心难点**：JS 的 `WordArray`、`Uint8Array`、`ArrayBuffer`、字符串之间的转换频繁出现。固定一套转换工具（如 CryptoJS Encoder 系列），不要每次手写转换代码。

**Python 还原时用 `pycryptodome` 统一处理**：`pycryptodome` 支持 AES/DES/3DES/RSA，API 风格统一，比用多个库更容易维护。

---

## 常见陷阱

### 陷阱：把哈希算法的输出误认为加密数据

**现象：** 尝试对 32 字符十六进制字符串解密，始终无法还原明文。  
**原因：** MD5/SHA 等哈希是单向函数，数学上不可逆（只能碰撞/彩虹表），不能"解密"。  
**解决：** 确认该字段是哈希还是加密：哈希固定长度且相同输入永远得到相同输出；对称加密密文长度随明文变化。若是哈希，考虑查彩虹表或破解方案，而非解密。

### 陷阱：忽略字符编码导致前后端不一致

**现象：** Python 和 JS 用相同密钥和 IV 加密同一字符串，结果不同。  
**原因：** JS `String` 默认 UTF-16，Python `str.encode()` 默认 UTF-8；含非 ASCII 字符时两者字节表示不同。  
**解决：** 在 JS 中用 `new TextEncoder().encode(str)` 明确转 UTF-8 字节后再传入加密函数；Python 用 `str.encode('utf-8')` 保持一致。

### 陷阱：忘记区分 padding 方案

**现象：** AES 解密后末尾有多余字节或报 `ValueError: PKCS#7 padding is incorrect`。  
**原因：** 加密时使用 PKCS#7（CryptoJS 默认），解密时 `unpad` 方案不匹配，或密文末尾被截断。  
**解决：** 确认 JS 侧的 padding 配置（`CryptoJS.pad.Pkcs7` 是默认，`CryptoJS.pad.NoPadding` 表示不填充），Python 侧用 `Crypto.Util.Padding.unpad(data, block_size, style='pkcs7')` 对应。

---

## 参见

[MD5](https://blog.vercanti.com/md5/)  
[SHA](https://blog.vercanti.com/sha-xi-lie/)  
[HMAC](https://blog.vercanti.com/hmac/)  
[RSA](https://blog.vercanti.com/rsa/)  
[Base64与编码](https://blog.vercanti.com/base64-yu-bian-ma/)  
[魔法数字速查](https://blog.vercanti.com/jia-mi-suan-fa-mo-fa-shu-zi-su-cha/)