加密算法基础概念

对称加密中用于加密和解密的秘密字符串。密钥长度决定安全强度。 用于对称加密中引入随机性。每次加密使用不同的 IV,即使明文和密钥相同,密文也不同。 分组密码要求明文长度必须是块大小的整数倍(AES 块大小为 16 字节)。填充用于将不足的部分补齐。 决定分组密码如何处理连续的数据块。 加密后的二进制数据通常需要编码为字符串传输: 逆向中常见的数据类型转换: Python 中:str.encode('utf-8') → bytes JavaScript 中:new TextEncoder().encode(str) → Uint8Array 逆向前先判断算

分享

官方文档: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 的 WordArrayUint8ArrayArrayBuffer、字符串之间的转换频繁出现。固定一套转换工具(如 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
SHA
HMAC
RSA
Base64与编码
魔法数字速查

阅读更多

Web 安全基础

1. HTML 转义(服务端渲染必须): 2. CSP(Content Security Policy): 3. HttpOnly Cookie:防止 JS 读取会话 Cookie: 4. 前端框架防护: 攻击者在第三方网站构造一个表单,诱导已登录用户提交,浏览器会自动携带目标站的 Cookie。 触发条件: 1. 用户已登录目标网站(Cookie 有效) 2. 目标 API 仅凭 Cookie 识别用户身份 3. 请求来源未验证 1. CSRF Token(推荐): 2. SameSite Cookie: 3. 验证 Origin/Referer 头:

By yellowdog

HTTP 协议深度指南

HTTP(HyperText Transfer Protocol)是 Web 的基础传输协议,基于 TCP/IP,采用请求/响应模型。 相关文档:Web安全基础(/web-an-quan-ji-chu/) FastAPI完全指南(/fastapi-wan-quan-zhi-nan/) Nginx完全指南(/nginx-wan-quan-zhi-nan/) 幂等性:多次执行相同请求,服务器状态结果相同。PUT /users/1 多次执行结果一致;POST /users 每次创建新资源,非幂等。 浏览器直接从本地缓存读取,不向服务器发送请求。 缓存命中时,状

By yellowdog

系统设计基础

SLA 对照表: 选择建议:无状态服务(Web 层、API 层)优先水平扩展;数据库初期垂直扩展,达到瓶颈后考虑分库分表或读写分离。 缓存穿透(查询不存在的 key,每次都打到 DB): 缓存击穿(热点 key 过期,瞬间大量请求打到 DB): 缓存雪崩(大量 key 同时过期,或缓存服务宕机): 令牌桶 Python 实现: Redis 实现分布式限流(滑动窗口): URL 命名规则: Cursor 分页响应格式: 雪花算法结构(64 bit): 定义:分布式系统不能同时满足以下三个特性: 在分布式环境中 P 是必须保证的,所以实际是 CP vs AP

By yellowdog

算法思路与模板

二分查找要求序列有序,每次将搜索范围缩减一半,时间复杂度 O(log n)。 两个指针从两端向中间收缩,常用于有序数组。 滑动窗口维护一个满足条件的区间 left, right,right 不断向右扩张,条件不满足时收缩 left。 滑动窗口通用框架: 1. 确定"子问题":原问题可以分解为哪些规模更小的同类问题 2. 定义 dpi 或 dpij 的含义,要足够清晰 3. 推导状态转移方程 4. 确定初始状态(边界条件) 5. 确定计算顺序(确保依赖的子问题先计算) 每件物品最多选一次。dpj = 容量为 j 时的最大价值,逆序遍历容量防止重复选取。 每

By yellowdog