SHA-1哈希函数 | AI生成和翻译
让我们深入理解给定代码片段的工作原理,特别是这几行:
hash_obj = hashlib.sha1(piece)
hashes.append(hash_obj.hexdigest())
return hashes
用户要求我们不使用库来解释这段代码,因此我将先说明使用 hashlib 库时代码的功能,然后探讨如何在不使用该库的情况下实现相同的功能。
使用 hashlib 理解代码
这段代码计算数据片段的哈希值并将其存储在列表中。以下是逐步解析:
hash_obj = hashlib.sha1(piece)- 功能:该行使用 Python 的
hashlib模块创建一个 SHA-1 哈希对象。SHA-1(安全哈希算法 1)是一种加密哈希函数,接收输入(此处为piece)并生成一个 160 位(20 字节)的哈希值。 - 输入:
piece是从文件或其他来源读取的数据块,可能是字节数据。 - 处理过程:
hashlib.sha1()函数初始化一个哈希对象,并立即使用piece中的数据更新它。可以将其视为将数据输入到开始处理数字的哈希机器中。
- 功能:该行使用 Python 的
hashes.append(hash_obj.hexdigest())- 功能:
hexdigest()方法获取哈希对象计算出的哈希值,并将其转换为十六进制字符串(使用数字 0-9 和字母 a-f 的人类可读格式)。 - 输出:对于 SHA-1,该字符串长度为 40 个字符,因为每个 20 字节的哈希值用两个十六进制数字表示(例如,字节值 255 变为 “ff”)。
- 存储:生成的字符串被追加到名为
hashes的列表中,该列表可能用于收集多个数据片段的哈希值。
- 功能:
return hashes- 功能:在处理完所有片段后(假设此代码位于循环或函数中),返回包含所有十六进制哈希字符串的列表
hashes。
- 功能:在处理完所有片段后(假设此代码位于循环或函数中),返回包含所有十六进制哈希字符串的列表
总结:对于每个数据 piece,代码使用 hashlib.sha1() 计算其 SHA-1 哈希值,使用 hexdigest() 将哈希值转换为十六进制字符串,并将其存储在 hashes 列表中,最后返回该列表。
不使用库:从零开始计算 SHA-1
用户要求“不使用库”,表明他们希望了解在不依赖 hashlib 的情况下如何实现此功能。从头实现 SHA-1 算法很复杂,但我会清晰地解释过程,并提供一个可在此基础上扩展的简化版本。
什么是 SHA-1?
SHA-1 是一种哈希函数,具有以下特点:
- 接收任何输入数据(例如
piece)。 - 生成固定的 160 位(20 字节)输出。
- 使用一系列位操作、循环移位和加法来转换输入。
在不使用 hashlib 的情况下,我们需要自己复制此算法。以下是针对给定代码的实现方式:
SHA-1 算法的逐步过程
- 准备输入(填充)
- SHA-1 以 512 位(64 字节)块处理数据。如果
piece不是恰好 64 字节,则进行填充:- 追加一个
1位(例如,字节0x80)。 - 添加足够的
0位,使长度对 512 取模后为 448 位(56 字节)。 - 追加
piece的原始长度(以位为单位)作为 64 位整数。
- 追加一个
- 为简化起见,如果
piece小于 64 字节,我们可以将其填充为一个块。
- SHA-1 以 512 位(64 字节)块处理数据。如果
- 初始化哈希值
- SHA-1 使用五个 32 位变量(总计 160 位),初始化为特定常量:
h0 = 0x67452301h1 = 0xEFCDAB89h2 = 0x98BADCFEh3 = 0x10325476h4 = 0xC3D2E1F0
- SHA-1 使用五个 32 位变量(总计 160 位),初始化为特定常量:
- 处理数据块
- 将 64 字节块拆分为 16 个 32 位字(每个 4 字节)。
- 使用以下公式将其扩展为 80 个字:
w[i] = left_rotate(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1) # 对于 i = 16 到 79其中
left_rotate将位向左循环移位。 - 在 80 轮循环中,更新临时变量
a、b、c、d、e(初始为h0到h4的副本):- 根据轮数(0-19、20-39 等)使用不同的函数和常量。
- 例如,对于 0-19 轮:
f = (b & c) | (~b & d) k = 0x5A827999 temp = (left_rotate(a, 5) + f + e + k + w[i]) & 0xFFFFFFFF - 移位变量:
e = d、d = c、c = left_rotate(b, 30)、b = a、a = temp。
- 更新哈希值
- 80 轮循环后,将结果添加到初始哈希值中:
h0 = (h0 + a) & 0xFFFFFFFF h1 = (h1 + b) & 0xFFFFFFFF # ...依此类推 h2、h3、h4
- 80 轮循环后,将结果添加到初始哈希值中:
- 生成十六进制输出
- 将
h0到h4连接为 160 位值,并转换为 40 字符的十六进制字符串。
- 将
简化的 Python 实现
以下是如何在不使用 hashlib 的情况下重写代码的基本版本:
def left_rotate(value, shift):
"""将 32 位整数左移 'shift' 位。"""
return ((value << shift) | (value >> (32 - shift))) & 0xFFFFFFFF
def custom_sha1(piece):
"""计算 'piece' 的 SHA-1 哈希值,并返回十六进制字符串。"""
# 为简化起见,假设 piece 小于 56 字节并填充为一个块
message = piece + b'\x80' + (b'\x00' * (55 - len(piece))) + (len(piece) * 8).to_bytes(8, 'big')
# 初始化哈希值
h0, h1, h2, h3, h4 = (
0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
)
# 拆分为 16 个 32 位字
w = [int.from_bytes(message[i:i+4], 'big') for i in range(0, 64, 4)]
# 扩展为 80 个字
for i in range(16, 80):
w.append(left_rotate(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1))
# 初始化工作变量
a, b, c, d, e = h0, h1, h2, h3, h4
# 80 轮处理
for i in range(80):
if 0 <= i < 20:
f = (b & c) | (~b & d)
k = 0x5A827999
elif 20 <= i < 40:
f = b ^ c ^ d
k = 0x6ED9EBA1
elif 40 <= i < 60:
f = (b & c) | (b & d) | (c & d)
k = 0x8F1BBCDC
else:
f = b ^ c ^ d
k = 0xCA62C1D6
temp = (left_rotate(a, 5) + f + e + k + w[i]) & 0xFFFFFFFF
e = d
d = c
c = left_rotate(b, 30)
b = a
a = temp
# 更新哈希值
h0 = (h0 + a) & 0xFFFFFFFF
h1 = (h1 + b) & 0xFFFFFFFF
h2 = (h2 + c) & 0xFFFFFFFF
h3 = (h3 + d) & 0xFFFFFFFF
h4 = (h4 + e) & 0xFFFFFFFF
# 返回 40 字符的十六进制字符串
return f"{h0:08x}{h1:08x}{h2:08x}{h3:08x}{h4:08x}"
# 重写代码,不使用 hashlib
def compute_hashes(pieces):
hashes = []
for piece in pieces: # 假设 pieces 是字节块列表
hash_value = custom_sha1(piece)
hashes.append(hash_value)
return hashes
# 示例用法
pieces = [b"hello", b"world"]
hashes = compute_hashes(pieces)
print(hashes)
与原代码的对应关系
hash_obj = hashlib.sha1(piece):替换为custom_sha1(piece),该函数手动计算 SHA-1 哈希值。hashes.append(hash_obj.hexdigest()):custom_sha1函数直接返回十六进制字符串,因此我们将其追加到hashes中。return hashes:保持不变,返回哈希字符串列表。
主要差异与注意事项
- 简化:此实现假设每个
piece适合一个 512 位块(由于填充,小于 56 字节)。完整的 SHA-1 实现需要处理多个块。 - 性能:手动实现比
hashlib更慢且未优化。 - 可靠性:像
hashlib这样的库经过测试且安全;自定义版本可能存在错误,除非经过充分验证。
本质上,原代码使用 hashlib 作为高效计算 SHA-1 哈希值的快捷方式,而不使用库则需要手动编写整个 SHA-1 算法、处理填充并将结果转换为十六进制格式。逻辑保持不变:处理每个片段,计算其哈希值,存储并返回集合。