常见加解密算法的介绍

前言

在 Android 逆向分析中,加解密算法无处不在。无论是 APP 的签名校验、协议加密、还是用户密码的存储,都离不开各类密码学算法。掌握常见加解密算法的原理和特征,是进行算法还原和协议分析的基础功。本文将从对称加密、非对称加密、哈希算法、编码算法以及消息认证码五个维度,系统性地介绍常见加解密算法的原理,并重点讲解如何在逆向分析中快速识别这些算法。

对称加密算法

AES(Advanced Encryption Standard)

AES 是目前应用最广泛的对称加密算法,也是 NIST(美国国家标准与技术研究院)于 2001 年正式发布的加密标准。AES 支持 128/192/256 三种密钥长度,分别对应 10/12/14 轮迭代加密。

AES 的核心结构是 SPN 网络(Substitution-Permutation Network),每一轮包含四个操作:

  1. SubBytes(字节替换):通过 S-box 进行非线性替换。AES 的 S-box 是一个固定的 256 字节查找表,其构造基于 GF(2^8) 上的乘法逆元和仿射变换。
  2. ShiftRows(行移位):对状态矩阵的每一行进行循环左移,不同行移位量不同(0/1/2/3)。
  3. MixColumns(列混合):对状态矩阵的每一列进行 GF(2^8) 上的矩阵乘法运算。
  4. 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),结构极其简洁。它包含两个核心部分:

  1. KSA(Key Scheduling Algorithm):使用密钥初始化一个 256 字节的 S 数组(S-box),通过一系列交换操作将密钥的随机性注入 S 数组。
  2. PRGA(Pseudo-Random Generation Algorithm):使用初始化好的 S 数组生成伪随机密钥流,与明文进行异或得到密文。

RC4 的特征非常明显:一个 256 字节的 S-box 数组和两个索引指针 ij,以及循环中的交换操作。

非对称加密算法

RSA

RSA 基于大整数分解难题,是应用最广泛的非对称加密算法。其密钥生成过程如下:

  1. 选择两个大素数 p 和 q
  2. 计算 n = p × q(模数)
  3. 计算欧拉函数 φ(n) = (p-1)(q-1)
  4. 选择公钥指数 e(通常为 65537,即 0x10001)
  5. 计算私钥指数 d,使得 e × d ≡ 1 (mod φ(n))

RSA 的加密和解密都是模幂运算:c = m^e mod nm = 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 字节)的哈希值,处理流程如下:

  1. 消息填充:在消息末尾填充位,使其长度 ≡ 448 (mod 512),然后追加原始消息长度(64 位小端序)
  2. 初始化链接变量:A=0x67452301, B=0xefcdab89, C=0x98badcfe, D=0x10325476
  3. 以 512 位(64 字节)为分组处理,每组经过 4 轮、每轮 16 步、共 64 步操作
  4. 每步操作使用不同的位移量和常量表 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_ex
  • EVP_aes_256_cbc / EVP_aes_128_ecb
  • MD5_Init / MD5_Update / MD5_Final
  • SHA1_Init / SHA1_Update / SHA1_Final
  • HMAC_Init_ex / HMAC_Update

总结

实现方式 位置 识别方式
Java Cipher Java 层 搜索 “Cipher.getInstance” 字符串
BouncyCastle Java 层 搜索 “BouncyCastle” 字符串
OpenSSL Native SO 搜索 “EVP_”、“MD5_”、“SHA1_” 函数
自实现算法 Native SO 通过常量和代码结构特征识别

小结

掌握常见加解密算法的原理和特征是逆向分析的基本功。在实际分析中,我们通常不会从零推导算法,而是通过识别算法特征(常量、代码结构、函数调用)来快速判断算法类型,然后结合动态调试和 Hook 技术来提取密钥和参数。在后续的文章中,我们将通过具体案例讲解如何还原这些算法。