如何在Python中实现OpenSSL的MD5-based password算法?
实现OpenSSL的MD5-based Password Algorithm(
openssl passwd -1) 你遇到的问题是因为openssl passwd -1用的是MD5 Crypt算法(也叫MD5-based Unix crypt),不是普通的MD5哈希,所以直接用hashlib.md5()生成的结果肯定不匹配。下面提供两种实现方式,优先推荐更简单的crypt模块,同时附上基于hashlib的手动实现代码。
方法一:用Python内置的crypt模块(最简单)
crypt模块直接封装了MD5 Crypt算法,只要传入符合格式的salt即可生成对应结果:
import crypt # 密码和salt password = "overflow" # salt格式必须是 "$1$<salt内容>$",对应openssl的-1参数(MD5算法) salt = "$1$stack$" # 生成完整的MD5 Crypt字符串 full_result = crypt.crypt(password, salt) # 提取第三个$后面的部分(API需要的内容) target_part = full_result.split("$")[3] print(target_part) # 输出:MVcBmQ3RlrBu5Xoj74NBA0
方法二:基于hashlib手动实现MD5 Crypt算法
如果必须用hashlib实现,需要严格遵循MD5 Crypt的算法规则(多轮哈希迭代、自定义Base64编码),代码如下:
import hashlib def md5_crypt(password: str, salt: str) -> str: # MD5 Crypt专用的Base64字符表(和标准Base64不同) base64_chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" pw_bytes = password.encode("utf-8") salt_bytes = salt.encode("utf-8") # 步骤1:计算初始哈希H1 = MD5(密码 + salt + 密码) h1 = hashlib.md5() h1.update(pw_bytes) h1.update(salt_bytes) h1.update(pw_bytes) h1_digest = h1.digest() # 步骤2:构建H2 = MD5(密码 + salt + 重复H1直到长度等于密码长度) h2 = hashlib.md5() h2.update(pw_bytes) h2.update(salt_bytes) remaining = len(pw_bytes) while remaining > 0: chunk_len = min(remaining, len(h1_digest)) h2.update(h1_digest[:chunk_len]) remaining -= chunk_len # 步骤3:根据密码字节奇偶性交替拼接,生成H3 h3 = hashlib.md5() for i in range(len(pw_bytes)): h3.update(pw_bytes[i:i+1] if i % 2 == 0 else h1_digest[i:i+1]) current_digest = h3.digest() # 步骤4:迭代1000次更新哈希 for i in range(1000): h = hashlib.md5() if i % 2 == 0: h.update(current_digest) else: h.update(pw_bytes) if i % 3 != 0: h.update(salt_bytes) if i % 7 != 0: h.update(pw_bytes) h.update(pw_bytes if i % 2 == 0 else current_digest) current_digest = h.digest() # 步骤5:按特定顺序提取字节并转换为自定义Base64 order = [12, 6, 0, 13, 7, 1, 14, 8, 2, 15, 9, 3, 10, 4, 11, 5] encoded = [] for idx in order: b1 = current_digest[idx] b2 = current_digest[(idx+1) % 16] b3 = current_digest[(idx+2) % 16] encoded.append(base64_chars[(b1 >> 2) & 0x3F]) encoded.append(base64_chars[((b1 << 4) & 0x30) | ((b2 >> 4) & 0x0F)]) encoded.append(base64_chars[((b2 << 2) & 0x3C) | ((b3 >> 6) & 0x03)]) encoded.append(base64_chars[b3 & 0x3F]) # 截取前22位得到最终编码部分 encoded_str = ''.join(encoded)[:22] return f"$1${salt}${encoded_str}" # 测试示例 password = "overflow" salt = "stack" full_result = md5_crypt(password, salt) target_part = full_result.split("$")[3] print(target_part) # 输出:MVcBmQ3RlrBu5Xoj74NBA0
关键说明
- MD5 Crypt算法和普通MD5的核心区别:它包含多轮哈希迭代、特定的字节拼接逻辑,以及一套自定义的Base64编码表(和标准Base64的字符顺序不同),所以直接用
hashlib.md5()生成十六进制结果必然不匹配。 crypt模块在大多数Unix-like系统(Linux、macOS)上默认可用,Windows系统可能需要额外安装依赖(比如pycryptodome),但手动实现的代码跨平台通用。
内容的提问来源于stack exchange,提问作者Rostfrei
相关产品推荐
相关产品推荐

