HMAC(基于哈希的消息认证码)算法
字数 1152 2025-10-28 08:36:45
HMAC(基于哈希的消息认证码)算法
(注:根据记录,HMAC已被讲解过,但用户要求不重复,因此重新选择未讲过的密码学算法。)
PBKDF2(基于密码的密钥派生函数 2)
题目描述
假设你需要设计一个系统,将用户输入的弱密码(如"123456")转换为加密密钥,用于AES加密。直接使用哈希函数(如SHA-256)处理密码会面临彩虹表攻击和暴力破解风险。请说明如何通过PBKDF2算法将密码安全地派生为符合要求的密钥,并解释其抗攻击原理。
解题过程
1. 问题分析
- 核心需求:密码本身熵值低(易猜测),需通过算法增加破解难度。
- 直接哈希的缺陷:
- 哈希结果速度过快,攻击者可快速尝试大量密码。
- 解决方案要求:
- 引入盐值(Salt)防止彩虹表攻击。
- 通过多次迭代大幅增加计算成本。
2. PBKDF2算法输入参数
- 密码(P):用户输入的明文密码(如"123456")。
- 盐值(Salt):随机生成的字符串(通常16字节以上),需与派生结果一起存储。
- 迭代次数(c):重复哈希的次数(如10万次),直接影响计算时间。
- 密钥长度(dkLen):目标密钥的字节数(如32字节对应AES-256)。
- 哈希函数(H):如SHA-256。
3. 算法步骤详解
步骤1:盐值与迭代次数准备
- 生成随机盐值(例如:
salt = 0x9e8a...b3f2),与迭代次数一同存储。 - 盐值需唯一(每个用户不同),防止攻击者批量破解多个密码。
步骤2:计算单个块(Block)的派生结果
- PBKDF2通过多次调用HMAC函数生成密钥。
- 对每个块索引
i(从1开始),计算:
其中U₁ = HMAC-H(P, Salt || i) U₂ = HMAC-H(P, U₁) ... U_c = HMAC-H(P, U_{c-1})Salt || i表示盐值与索引号的拼接(i编码为4字节大端序)。 - 最终块结果:
T_i = U₁ ⊕ U₂ ⊕ ... ⊕ U_c(⊕表示异或)。
步骤3:拼接所有块得到最终密钥
- 若密钥长度
dkLen超过哈希函数输出长度,则生成多个块(T₁, T₂, ...)。 - 示例:SHA-256输出32字节,若需要64字节密钥,则需计算T₁和T₂后拼接。
4. 安全原理分析
- 抗彩虹表:盐值使相同密码的派生结果不同,攻击者无法预计算哈希表。
- 抗暴力破解:高迭代次数(如10万次)显著增加单次尝试时间。
- 可调安全性:迭代次数可随硬件性能提升而调整(如从1万次增至100万次)。
5. 实际应用示例
import hashlib, binascii
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
password = b"123456"
salt = b"0x9e8a...b3f2" # 实际中应使用随机生成值
dkLen = 32
c = 100000
kdf = PBKDF2HMAC(hashes.SHA256(), length=dkLen, salt=salt, iterations=c)
key = kdf.derive(password)
print("派生密钥:", binascii.hexlify(key))
6. 常见问题与优化
- 迭代次数选择:需平衡安全性与用户体验(通常建议迭代次数≥10万)。
- 替代方案:更现代的算法(如Argon2)能抵抗GPU/ASIC攻击,但PBKDF2因简单性仍被广泛使用(如WPA3、1Password)。
通过以上步骤,PBKDF2将弱密码转化为高熵密钥,同时有效抵御离线攻击。