Python实现MD5算法输出与预期不符,应如何定位排查错误?
问题原因&修正方案
核心错误点
- 错误1:位运算符误用
计算f函数时错误使用了Python的逻辑运算符and/or,这类运算符仅做逻辑真假判断,不会执行按位与/按位或操作,完全不符合MD5的位运算要求。需要把所有and替换为&,or替换为|。
错误代码片段:
f = (b1 and c1) or ((~b1) and d1) ... f = (d1 and b1) or ((~d1) and c1) ... f = c1 ^ (b1 or (~d1))
修正后写法:
f = (b1 & c1) | ((~b1) & d1) ... f = (d1 & b1) | ((~d1) & c1) ... f = c1 ^ (b1 | (~d1))
- 错误2:最终哈希拼接逻辑错误
MD5要求将最终的a、b、c、d四个32位寄存器按小端字节序依次拼接得到哈希值,原代码直接通过移位拼接整数的方式,会把每个寄存器的字节序反转,导致最终结果错误。
可以把返回逻辑修改为将每个寄存器转为小端字节后拼接,再转十六进制即可。
修正后完整可运行代码
import numpy as np import math shifts = np.array([ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 ], dtype = np.uint8) K = np.zeros(64, dtype = np.uint32) for i in range(64): K[i] = int(abs(math.sin(i + 1)) * 2 ** 32) a0 = np.uint32(0x67452301) b0 = np.uint32(0xefcdab89) c0 = np.uint32(0x98badcfe) d0 = np.uint32(0x10325476) def md5(message): length = len(message) padded = message + b'\x80' + b'\0' * ((56 - length - 1) % 64) + (length << 3).to_bytes(8, 'little') a, b, c, d = a0, b0, c0, d0 for chunk_no in range(len(padded) // 64): a1, b1, c1, d1 = a, b, c, d chunk = padded[chunk_no * 64 : (chunk_no + 1) * 64] M = np.array([int.from_bytes(chunk[j * 4 : (j + 1) * 4], 'little') for j in range(16)], dtype = np.uint32) for i in range(64): quarter = i >> 4 if quarter == 0: f = (b1 & c1) | ((~b1) & d1) g = i elif quarter == 1: f = (d1 & b1) | ((~d1) & c1) g = (5 * i + 1) & 15 elif quarter == 2: f = b1 ^ c1 ^ d1 g = (3 * i + 5) & 15 else: f = c1 ^ (b1 | (~d1)) g = (7 * i) & 15 f = (f + a1 + K[i] + M[g]) & 0xffffffff a1, d1, c1, b1 = d1, c1, b1, (b1 + ((f << shifts[i]) | (f >> (32 - shifts[i])))) & 0xffffffff a = (a + a1) & 0xffffffff b = (b + b1) & 0xffffffff c = (c + c1) & 0xffffffff d = (d + d1) & 0xffffffff a, b, c, d = int(a), int(b), int(c), int(d) return b''.join([x.to_bytes(4, 'little') for x in [a, b, c, d]]).hex() def test(): data = b'' digest = md5(data) print(f'MD5({data}) = {digest}') # 空串测试断言 assert digest == 'd41d8cd98f00b204e9800998ecf8427e' print('空串测试通过')
内容的提问来源于stack exchange,提问作者user2649681
相关产品推荐
相关产品推荐

