加密算法识别
快速判断目标加密算法,是逆向流程的第一步。 搜索以下关键字: MD5 的 JavaScript 特征:在函数内部有大量位运算(>>>, <<, |, ^),以及十六进制常量(如 0x67452301、0xefcdab89)。 判断模式: RSA 加密同一份数据每次结果不同(PKCS1 v1.5 填充随机),可以此区分 AES。 没有明显库特征,通常表现为: 部分网站使用自定义 Base64 字母表(字母表顺序被打乱),密文看起来是 Base64 但标准解码失败。 识别方法:在代码中搜索长度为 64 的字符串常量,即为自定义字母表。 先看输出长度和字符集,
官方文档:https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines
适用场景:通过密文特征、输出长度和关键字快速判断目标使用的加密/哈希算法
快速判断目标加密算法,是逆向流程的第一步。
算法特征对照表
| 算法 | 输出长度 | 字符集 | 其他特征 |
|---|---|---|---|
| MD5 | 32 位(hex)/ 16 位(短版) | [0-9a-f] |
固定长度,无法解密 |
| SHA-1 | 40 位 | [0-9a-f] |
- |
| SHA-256 | 64 位 | [0-9a-f] |
- |
| SHA-512 | 128 位 | [0-9a-f] |
- |
| HMAC | 同对应 SHA | [0-9a-f] |
需要 secret key |
| AES | 变长(16 的倍数字节) | Base64 编码后可见 +/= |
需要 key + iv |
| DES/3DES | 同 AES | Base64 | key 为 8/24 字节 |
| RSA | 128/256/512 字节 | Base64 | 含公私钥,相同明文密文不同 |
| Base64 | 原始长度 × 4/3 | [A-Za-z0-9+/=] |
末尾常有 = 填充,可逆 |
代码层面识别
MD5 / SHA
搜索以下关键字:
md5 sha1 sha256 sha512 CryptoJS.MD5 CryptoJS.SHA256
MD5 的 JavaScript 特征:在函数内部有大量位运算(>>>, <<, |, ^),以及十六进制常量(如 0x67452301、0xefcdab89)。
AES
// CryptoJS 使用特征
CryptoJS.AES.encrypt(message, key, { iv: iv, mode: ... })
CryptoJS.AES.decrypt(...)
// 内置 WebCrypto API
crypto.subtle.encrypt({ name: 'AES-CBC', iv }, key, data)
判断模式:
CBC:需要 IV,最常见ECB:无 IV,相同明文 → 相同密文GCM:带认证标签
RSA
// 特征关键字
new JSEncrypt()
jsencrypt.setPublicKey(...)
forge.pki.publicKeyFromPem(...)
RSA 加密同一份数据每次结果不同(PKCS1 v1.5 填充随机),可以此区分 AES。
自定义加密
没有明显库特征,通常表现为:
- 大量位运算和循环
- 硬编码的字符表(如 Base62、自定义 Base64)
- 函数名经过混淆,只能通过逻辑分析还原
常见加密库特征
| 库名 | 全局变量 / 特征 | 备注 |
|---|---|---|
| CryptoJS | CryptoJS |
最常见,覆盖 MD5/SHA/AES/DES/HMAC |
| jsencrypt | JSEncrypt |
RSA 加密 |
| node-forge | forge |
RSA/AES/证书处理 |
| crypto-js | require('crypto-js') |
Node.js 同款 |
| sjcl | sjcl |
Stanford 出品,轻量 |
| WebCrypto | crypto.subtle |
浏览器原生,异步 |
识别流程
1. 抓包,找到加密参数
2. 观察密文特征(长度、字符集、是否每次变化)
3. 全局搜索加密库关键字
4. 在 Network → Initiator 或 XHR 断点定位调用位置
5. 在 Scope 面板找到 key / iv 的实际值
6. 本地验证还原
Base64 变体识别
部分网站使用自定义 Base64 字母表(字母表顺序被打乱),密文看起来是 Base64 但标准解码失败。
识别方法:在代码中搜索长度为 64 的字符串常量,即为自定义字母表。
// 标准 Base64 字母表
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
// 自定义变体示例(字母表顺序不同)
"ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9876543210+/"
最佳实践
先看输出长度和字符集,再看代码:固定长度十六进制字符串大概率是哈希(32=MD5,40=SHA-1,64=SHA-256);变长含 +/= 是 Base64;变长纯十六进制是对称加密。确定类别后再进 DevTools 搜索,节省时间。
用已知输入验证判断:用 "test" 作为输入测试目标加密函数,然后用 Python 计算各算法对 "test" 的结果并比对,快速定位算法。比靠代码阅读猜测更可靠。
同时识别 JS 库标志:CryptoJS → 找 CryptoJS.AES/MD5/SHA256;forge → 找 forge.cipher;sjcl → 找 sjcl.cipher;jsencrypt → RSA;搜索这些库名比搜算法关键字命中率更高。
国密算法单独建分支识别:发现常规算法(AES/RSA/SHA)对不上时,再搜索国密关键字(sm2、sm3、sm4、gmssl、smCrypto、OSCCA)。国密近年在政府/金融类网站普及率显著上升。
用 魔法数字速查 文档配合 S-Box 搜索:找到疑似的加密函数后,搜索文档中对应算法的特征常量,二次确认识别结果,避免误判。
常见陷阱
陷阱:把 HMAC 输出误认为哈希
现象: 签名参数长度与 SHA-256 输出一致,但用标准 SHA-256 无法复现。
原因: HMAC-SHA256 和 SHA-256 输出同为 64 字符十六进制,区别在于 HMAC 额外使用了密钥。
解决: 搜索代码中是否有密钥参数(key、secret、salt)传入哈希函数;若有,换用 HMAC 计算。
陷阱:Base64 变体被误认为加密
现象: 用标准 Base64 解码后得到乱码,认为有加密。
原因: 自定义字母表 Base64 的字符集与标准不同,直接解码结果错误。
解决: 在代码中搜索长度为 64 的字符串常量(自定义字母表),找到后用 str.maketrans 替换后再 Base64 解码:base64.b64decode(s.translate(str.maketrans(custom_table, standard_table)))。
陷阱:AES-ECB 与 AES-CBC 混淆
现象: 知道是 AES 加密,但用 CBC 解密出乱码;改用 ECB 正常。
原因: ECB 模式不需要 IV,每个块独立加密;若代码中没有 IV 参数或 IV 为全零,通常是 ECB 或 Zero-IV CBC。
解决: 检查 CryptoJS 调用中的 mode 参数(CryptoJS.mode.ECB / CBC);若没有显式指定,查看是否传了 IV 参数。
参见
还原方法:提取字母表,使用标准 Base64 解码时替换字母表即可。