常见加解密算法的介绍
前言
在 Android 逆向分析中,加解密算法无处不在。无论是 APP 的签名校验、协议加密、还是用户密码的存储,都离不开各类密码学算法。掌握常见加解密算法的原理和特征,是进行算法还原和协议分析的基础功。本文将从对称加密、非对称加密、哈希算法、编码算法以及消息认证码五个维度,系统性地介绍常见加解密算法的原理,并重点讲解如何在逆向分析中快速识别这些算法。
对称加密算法
AES(Advanced Encryption Standard)
AES 是目前应用最广泛的对称加密算法,也是 NIST(美国国家标准与技术研究院)于 2001 年正式发布的加密标准。AES 支持 128/192/256 三种密钥长度,分别对应 10/12/14 轮迭代加密。
AES 的核心结构是 SPN 网络(Substitution-Permutation Network),每一轮包含四个操作:
- SubBytes(字节替换):通过 S-box 进行非线性替换。AES 的 S-box 是一个固定的 256 字节查找表,其构造基于 GF(2^8) 上的乘法逆元和仿射变换。
- ShiftRows(行移位):对状态矩阵的每一行进行循环左移,不同行移位量不同(0/1/2/3)。
- MixColumns(列混合):对状态矩阵的每一列进行 GF(2^8) 上的矩阵乘法运算。
- AddRoundKey(轮密钥加):将当前状态与轮密钥进行异或操作。
AES 加密还需要 密钥扩展(Key Expansion)算法,从原始密钥扩展出所有轮所需的轮密钥。
DES 和 3DES
DES(Data Encryption Standard)采用 Feistel 网络结构,密钥长度 56 位(实际 64 位,其中 8 位为奇偶校验位),共 16 轮迭代。每一轮将数据分成左右两半,右半部分经过轮函数 F 处理后与左半部分异或,然后左右交换。
DES 的轮函数 F 包含:
- 扩展置换(E):将 32 位扩展为 48 位
- S-box 替换:8 个 S-box 将 48 位压缩为 32 位
- P 置换:32 位置换
3DES(Triple DES)是 DES 的增强版本,使用三个密钥进行三次 DES 运算,有效密钥长度提升到 112/168 位,分为 EDE(加密-解密-加密)和 EEE(三次加密)两种模式。
RC4
RC4 是一种 流密码(Stream Cipher),结构极其简洁。它包含两个核心部分:
- KSA(Key Scheduling Algorithm):使用密钥初始化一个 256 字节的 S 数组(S-box),通过一系列交换操作将密钥的随机性注入 S 数组。
- PRGA(Pseudo-Random Generation Algorithm):使用初始化好的 S 数组生成伪随机密钥流,与明文进行异或得到密文。
RC4 的特征非常明显:一个 256 字节的 S-box 数组和两个索引指针 i、j,以及循环中的交换操作。
非对称加密算法
RSA
RSA 基于大整数分解难题,是应用最广泛的非对称加密算法。其密钥生成过程如下:
- 选择两个大素数 p 和 q
- 计算 n = p × q(模数)
- 计算欧拉函数 φ(n) = (p-1)(q-1)
- 选择公钥指数 e(通常为 65537,即 0x10001)
- 计算私钥指数 d,使得 e × d ≡ 1 (mod φ(n))
RSA 的加密和解密都是模幂运算:c = m^e mod n,m = c^d mod n。在 RSA 实现中,模幂运算通常使用 平方-乘算法(Square-and-Multiply)来实现快速计算。
ECC(椭圆曲线加密)
ECC 基于椭圆曲线离散对数问题(ECDLP),在相同安全级别下,ECC 的密钥长度远小于 RSA。例如,256 位的 ECC 密钥安全性相当于 3072 位的 RSA 密钥。
椭圆曲线的一般方程为 y² = x³ + ax + b。ECC 的核心运算包括:
- 点加法:曲线上两点的加法
- 点倍乘:曲线上一点的自加
- 标量乘法:k × P(对点 P 进行 k 次加法)
在 Android 中,ECC 常见于 TLS/SSL 证书、ECDH 密钥交换、ECDSA 数字签名等场景。
哈希算法
MD5
MD5 产生 128 位(16 字节)的哈希值,处理流程如下:
- 消息填充:在消息末尾填充位,使其长度 ≡ 448 (mod 512),然后追加原始消息长度(64 位小端序)
- 初始化链接变量:A=0x67452301, B=0xefcdab89, C=0x98badcfe, D=0x10325476
- 以 512 位(64 字节)为分组处理,每组经过 4 轮、每轮 16 步、共 64 步操作
- 每步操作使用不同的位移量和常量表 T[i],通过循环左移、加法、异或、与、或、非等运算混合数据
MD5 虽然已被证明存在碰撞漏洞,但在很多 APP 中仍然用于完整性校验(而非安全场景)。
SHA1 和 SHA256
SHA1 产生 160 位(20 字节)哈希值,结构类似于 MD5,但有以下区别:
- 初始化常量不同:H0-H4 分别为 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
- 处理 80 步而非 64 步,分为 4 轮各 20 步
- 每步使用的逻辑函数不同
SHA256 属于 SHA-2 家族,产生 256 位哈希值,其处理步骤为 64 轮。SHA256 使用了不同的初始哈希值(前 8 个素数的平方根的小数部分前 32 位),以及 64 个轮常量 K[0…63](前 64 个素数的立方根的小数部分前 32 位)。
SHA256 的轮函数包含:
- Ch 函数:
(x AND y) XOR (NOT x AND z) - Maj 函数:
(x AND y) XOR (x AND z) XOR (y AND z) - Σ0/Σ1:大循环移位运算
- σ0/σ1:小循环移位运算
编码算法
编码算法不是加密算法,但它们在逆向分析中同样常见,经常与加密算法组合使用。
Base64
Base64 将 3 字节(24 位)的输入数据映射为 4 字符的输出。编码表为 A-Z a-z 0-9 +/,共 64 个字符,不足的用 = 填充。
Base64 的识别特征:
- 输出只包含 A-Z、a-z、0-9、+、/、= 这 66 个字符
- 输出长度是 4 的倍数
- 通常以 1-2 个
=结尾
Hex 编码
Hex 编码将每个字节表示为两个十六进制字符(0-9, A-F),是逆向分析中最简单的编码方式。输出长度是输入长度的 2 倍。
URL 编码
URL 编码将特殊字符转换为 %XX 格式(XX 为十六进制 ASCII 值),常见于网络请求参数中。
消息认证码(MAC/HMAC)
MAC(Message Authentication Code)
MAC 用于验证消息的完整性和真实性。常见的 MAC 实现包括基于分组密码的 CMAC 和基于哈希的 HMAC。
HMAC(Hash-based MAC)
HMAC 使用哈希函数(如 SHA1、SHA256)结合密钥来生成消息认证码,其计算公式为:
HMAC(K, m) = H((K' ⊕ opad) || H((K' ⊕ ipad) || m))
其中:
- K’ 是密钥(如果密钥长度大于哈希块大小则先哈希)
- ipad = 0x36 重复填充到块大小
- opad = 0x5C 重复填充到块大小
- || 表示连接
- H 表示哈希函数
在 Android 中,HMAC 常见于 API 请求签名、数据完整性验证等场景。
逆向中识别算法的关键特征
通过常量识别
算法常量是识别加密算法的最直接线索:
| 算法 | 关键常量 |
|---|---|
| MD5 | 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 |
| SHA1 | 上述 4 常量 + 0xC3D2E1F0 |
| SHA256 | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a 等 8 个初始化值 |
| AES S-box | 以 0x63, 0x7c, 0x77, 0x7b 开头的 256 字节表 |
| DES S-box | 8 个固定查找表,每个 4×16 |
| RC4 | 256 字节 S-box 的初始化循环 |
| RSA | 常见公钥指数 0x10001 (65537) |
| HMAC | 0x36 (ipad), 0x5C (opad) |
通过代码结构识别
- 查表操作:大量使用查找表的函数很可能涉及加密算法
- 循环结构:固定轮数的循环(如 10/12/14 轮)暗示 AES,16 轮暗示 DES,64 轮暗示 MD5
- 位运算:循环移位(ROL/ROR)、异或(XOR)、与/或/非操作的密集使用
- 模运算:大数取模操作常见于 RSA
通过函数调用识别
在 Android 逆向中,可以搜索以下特征字符串来定位加密操作:
javax.crypto.Cipher
javax.crypto.spec.SecretKeySpec
javax.crypto.spec.IvParameterSpec
javax.crypto.Mac
java.security.MessageDigest
java.security.Signature
算法在 Android 中的实现方式
Java 层 Cipher API
Android 使用 JCE(Java Cryptography Extension)框架提供加密能力:
// AES 加密示例
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encrypted = cipher.doFinal(plaintext);
BouncyCastle
BouncyCastle 是 Java 平台上功能最全面的密码学库,支持大量非标准算法。在 Android 逆向中,如果发现 org.bouncycastle 包名,说明使用了 BouncyCastle。
// BouncyCastle 提供了更多算法支持
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");
OpenSSL(Native 层)
OpenSSL 是 C/C++ 层最常用的密码学库,在 Android 中通过 SO 文件使用。关键函数名包括:
EVP_EncryptInit_ex/EVP_DecryptInit_exEVP_aes_256_cbc/EVP_aes_128_ecbMD5_Init/MD5_Update/MD5_FinalSHA1_Init/SHA1_Update/SHA1_FinalHMAC_Init_ex/HMAC_Update
总结
| 实现方式 | 位置 | 识别方式 |
|---|---|---|
| Java Cipher | Java 层 | 搜索 “Cipher.getInstance” 字符串 |
| BouncyCastle | Java 层 | 搜索 “BouncyCastle” 字符串 |
| OpenSSL | Native SO | 搜索 “EVP_”、“MD5_”、“SHA1_” 函数 |
| 自实现算法 | Native SO | 通过常量和代码结构特征识别 |
小结
掌握常见加解密算法的原理和特征是逆向分析的基本功。在实际分析中,我们通常不会从零推导算法,而是通过识别算法特征(常量、代码结构、函数调用)来快速判断算法类型,然后结合动态调试和 Hook 技术来提取密钥和参数。在后续的文章中,我们将通过具体案例讲解如何还原这些算法。