MD5实现代码输出与预期不符,请求排查问题原因
MD5实现结果不符问题
我按照维基百科的MD5算法伪代码实现了一一对应的Python版本,但输出结果与预期不符。我尝试了所有可能的方法修复,但结果仍不正确。请问这是否是由于编码系统不同导致的?恳请提供帮助。
代码实现
#This Code has one to one correspondance with https://en.wikipedia.org/wiki/MD5#Algorithm psuedocode #-------------Globals Start ----------------------# from math import sin , floor import math S = [ 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 ] K = [floor(abs(math.sin(i + 1)) * (2 ** 32)) & 0xFFFFFFFF for i in range(64)] rotate = lambda x,n:((x << n) | (x >> (32 - n))) & 0xFFFFFFFF #-------------Globals End------------------------# def md5(text): a0 = 0x67452301 b0 = 0xefcdab89 c0 = 0x98badcfe d0 = 0x10325476 length = len(text) text = text + b'\x80' text += (b'\x00' * (512 - (len(text) * 8 % 512))) text = text + length.to_bytes(8, 'little') for i in range(0, len(text), 64): chunk = text[i:i+64] M = [int.from_bytes(chunk[j:j+4], 'little') for j in range(0, 64, 4)] A = a0 B = b0 C = c0 D = d0 for j in range(64): if 0 <= j <= 15: F = (B & C) | ((~B) & D) g = j elif 16 <= j <= 31: F = (D & B) | ((~D) & C) g = ((5 * j) + 1) % 16 elif 32 <= j <= 47: F = B ^ C ^ D g = ((3 * j) + 5) % 16 elif 48 <= j <= 63: F = C ^ (B | (~D)) g = (7 * j) % 16 F = (F + A + K[j] + M[g]) & 0xFFFFFFFF A, D, C, B = D, C, B, (B + rotate(F, S[j])) & 0xFFFFFFFF a0 = (a0 + A) & 0xFFFFFFFF b0 = (b0 + B) & 0xFFFFFFFF c0 = (c0 + C) & 0xFFFFFFFF d0 = (d0 + D) & 0xFFFFFFFF result = (a0.to_bytes(4, 'little') + b0.to_bytes(4, 'little') + c0.to_bytes(4, 'little') + d0.to_bytes(4, 'little')) return result.hex() text = 'The quick brown fox jumps over the lazy dog'.encode("utf-8") print(md5(text))
输出对比
- 实际输出:
171e495fea830541b8542c338e388a97
- 预期输出:
9e107d9d372bb6826bd81d3542a419d6
问题分析与修复
问题不是编码系统导致的,而是代码中的填充逻辑错误和寄存器更新顺序错误导致结果不符,具体修正点如下:
1. 填充逻辑错误
MD5的填充规则要求:在原始数据后添加0x80,再添加若干0x00,使得总长度(以比特为单位)模512等于448,最后添加原始数据长度的64位小端表示。
你的代码中填充0x00的计算方式错误,直接将比特数当作字节数使用,正确的计算应该是先算出需要填充的比特数,再转换为字节数:
# 替换错误的填充代码 original_length_bits = len(text) * 8 text += b'\x80' pad_bits = (448 - ((original_length_bits + 8) % 512)) % 512 text += b'\x00' * (pad_bits // 8) text += original_length_bits.to_bytes(8, 'little')
2. 寄存器更新顺序错误
维基百科伪代码中寄存器的更新顺序是先保存原始D的值,再依次更新D、C、B,最后将原始D赋值给A。你的代码中并行赋值的顺序错误,导致A被错误覆盖,正确的更新逻辑应为:
# 替换错误的寄存器赋值代码 temp = D D = C C = B B = (B + rotate(F, S[j])) & 0xFFFFFFFF A = temp
修正后的完整代码
from math import sin, floor import math S = [ 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 ] K = [floor(abs(math.sin(i + 1)) * (2 ** 32)) & 0xFFFFFFFF for i in range(64)] rotate = lambda x, n: ((x << n) | (x >> (32 - n))) & 0xFFFFFFFF def md5(text): a0 = 0x67452301 b0 = 0xefcdab89 c0 = 0x98badcfe d0 = 0x10325476 original_length_bits = len(text) * 8 # 填充第一步:添加0x80 text += b'\x80' # 填充第二步:添加0,使总长度模512等于448位 pad_bits = (448 - ((original_length_bits + 8) % 512)) % 512 text += b'\x00' * (pad_bits // 8) # 填充第三步:添加原始长度的64位小端表示 text += original_length_bits.to_bytes(8, 'little') for i in range(0, len(text), 64): chunk = text[i:i+64] M = [int.from_bytes(chunk[j:j+4], 'little') for j in range(0, 64, 4)] A = a0 B = b0 C = c0 D = d0 for j in range(64): if 0 <= j <= 15: F = (B & C) | ((~B) & D) g = j elif 16 <= j <= 31: F = (D & B) | ((~D) & C) g = ((5 * j) + 1) % 16 elif 32 <= j <= 47: F = B ^ C ^ D g = ((3 * j) + 5) % 16 elif 48 <= j <= 63: F = C ^ (B | (~D)) g = (7 * j) % 16 F = (F + A + K[j] + M[g]) & 0xFFFFFFFF # 修正寄存器更新顺序 temp = D D = C C = B B = (B + rotate(F, S[j])) & 0xFFFFFFFF A = temp a0 = (a0 + A) & 0xFFFFFFFF b0 = (b0 + B) & 0xFFFFFFFF c0 = (c0 + C) & 0xFFFFFFFF d0 = (d0 + D) & 0xFFFFFFFF result = (a0.to_bytes(4, 'little') + b0.to_bytes(4, 'little') + c0.to_bytes(4, 'little') + d0.to_bytes(4, 'little')) return result.hex() text = 'The quick brown fox jumps over the lazy dog'.encode("utf-8") print(md5(text)) # 输出:9e107d9d372bb6826bd81d3542a419d6
验证结果
修正后的代码运行后,输出与预期完全一致。
内容的提问来源于stack exchange,提问作者Shadab Patel
相关产品推荐
相关产品推荐

